Java tutorial
/* * Copyright (c) 2013-2014, Neuro4j.org * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.neuro4j.studio.debug.ui.views; import java.util.ArrayList; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.debug.internal.ui.viewers.breadcrumb.IBreadcrumbDropDownSite; import org.eclipse.debug.internal.ui.viewers.breadcrumb.TreeViewerDropDown; import org.eclipse.debug.internal.ui.viewers.model.ILabelUpdateListener; import org.eclipse.debug.internal.ui.viewers.model.SubTreeModelViewer; import org.eclipse.debug.internal.ui.viewers.model.TreeModelContentProvider; import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDeltaVisitor; import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta; import org.eclipse.debug.internal.ui.views.launch.LaunchViewMessages; import org.eclipse.debug.ui.contexts.AbstractDebugContextProvider; import org.eclipse.debug.ui.contexts.DebugContextEvent; import org.eclipse.debug.ui.contexts.IDebugContextListener; import org.eclipse.debug.ui.contexts.IDebugContextProvider; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.viewers.AbstractTreeViewer; import org.eclipse.jface.viewers.BaseLabelProvider; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ITreePathContentProvider; import org.eclipse.jface.viewers.ITreePathLabelProvider; import org.eclipse.jface.viewers.ITreeSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TreePath; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.jface.viewers.ViewerLabel; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MenuDetectEvent; import org.eclipse.swt.events.MenuDetectListener; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.progress.UIJob; /** * @since 3.5 */ public class LaunchViewBreadcrumb extends AbstractBreadcrumb implements IDebugContextListener, ILabelUpdateListener { private static class Input { final TreePath fPath; Input(TreePath path) { fPath = path; } public boolean equals(Object obj) { return obj instanceof Input && ((fPath == null && ((Input) obj).fPath == null) || (fPath != null && fPath.equals(((Input) obj).fPath))); } public int hashCode() { return fPath == null ? 0 : fPath.hashCode(); } } private static class ContentProvider implements ITreePathContentProvider { private static final Object[] EMPTY_ELEMENTS_ARRAY = new Object[0]; public Input fInput; public Object[] getChildren(TreePath parentPath) { if (hasChildren(parentPath)) { return new Object[] { fInput.fPath.getSegment(parentPath.getSegmentCount()) }; } return EMPTY_ELEMENTS_ARRAY; } public TreePath[] getParents(Object element) { // Not supported return new TreePath[] { TreePath.EMPTY }; } public boolean hasChildren(TreePath parentPath) { if (parentPath.getSegmentCount() == 0) { return fInput != null; } else if (fInput != null && fInput.fPath != null && fInput.fPath.getSegmentCount() > parentPath.getSegmentCount()) { for (int i = 0; i < parentPath.getSegmentCount(); i++) { if (i >= fInput.fPath.getSegmentCount()) { return false; } else { Object parentElement = parentPath.getSegment(i); Object contextElement = fInput.fPath.getSegment(i); if (!parentElement.equals(contextElement)) { return false; } } } return true; } return false; } public Object[] getElements(Object inputElement) { if (fInput != null && fInput.fPath != null) { return getChildren(TreePath.EMPTY); } else { return new Object[] { fgEmptyDebugContextElement }; } } public void dispose() { fInput = null; } public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { if (newInput instanceof Input) { fInput = ((Input) newInput); } else { fInput = null; } } } private class LabelProvider extends BaseLabelProvider implements ITreePathLabelProvider { public void updateLabel(ViewerLabel label, TreePath elementPath) { if (fgEmptyDebugContextElement.equals(elementPath.getLastSegment())) { label.setText(LaunchViewMessages.Breadcrumb_NoActiveContext); label.setImage(null); } else { ViewerLabel treeViewerLabel = fTreeViewer.getElementLabel(elementPath, null); if (treeViewerLabel == null) { label.setText(LaunchViewMessages.Breadcrumb_NoActiveContext); label.setImage(null); } else { label.setText(treeViewerLabel.getText()); label.setTooltipText(treeViewerLabel.getText()); label.setImage(treeViewerLabel.getImage()); label.setFont(treeViewerLabel.getFont()); label.setForeground(treeViewerLabel.getForeground()); label.setBackground(treeViewerLabel.getBackground()); } } } } private final FlowLaunchView fView; private final TreeModelViewer fTreeViewer; private final IDebugContextProvider fTreeViewerContextProvider; private Input fBreadcrumbInput; static final private Object fgEmptyDebugContextElement = new Object(); private BreadcrumbViewer fViewer; private boolean fRefreshBreadcrumb = false; private class BreadcrumbContextProvider extends AbstractDebugContextProvider implements IDebugContextListener, ISelectionChangedListener { private ISelection fBreadcrumbSelection = null; BreadcrumbContextProvider() { super(fView); fViewer.addSelectionChangedListener(this); fBreadcrumbSelection = fViewer.getSelection(); fTreeViewerContextProvider.addDebugContextListener(this); } public ISelection getActiveContext() { if (fBreadcrumbSelection != null && !fBreadcrumbSelection.isEmpty()) { return fBreadcrumbSelection; } else { ISelection treeViewerSelection = fTreeViewerContextProvider.getActiveContext(); return treeViewerSelection != null ? treeViewerSelection : StructuredSelection.EMPTY; } } void dispose() { fViewer.removeSelectionChangedListener(this); fTreeViewerContextProvider.removeDebugContextListener(this); } public void debugContextChanged(DebugContextEvent event) { fire(new DebugContextEventAdapter(this, getActiveContext(), event.getFlags())); } public void selectionChanged(SelectionChangedEvent event) { ISelection oldContext = getActiveContext(); fBreadcrumbSelection = event.getSelection(); if (!getActiveContext().equals(oldContext)) { fire(new DebugContextEventAdapter(this, getActiveContext(), DebugContextEvent.ACTIVATED)); } } } private BreadcrumbContextProvider fBreadcrumbContextProvider; public LaunchViewBreadcrumb(FlowLaunchView view, TreeModelViewer treeViewer, IDebugContextProvider contextProvider) { fView = view; fTreeViewer = treeViewer; fTreeViewer.addLabelUpdateListener(this); fTreeViewerContextProvider = contextProvider; fBreadcrumbInput = new Input(getPathForSelection(fTreeViewerContextProvider.getActiveContext())); fTreeViewerContextProvider.addDebugContextListener(this); } protected void activateBreadcrumb() { } protected void deactivateBreadcrumb() { if (fViewer.isDropDownOpen()) { Shell shell = fViewer.getDropDownShell(); if (shell != null && !shell.isDisposed()) { shell.close(); } } } protected BreadcrumbViewer createViewer(Composite parent) { fViewer = new BreadcrumbViewer(parent, SWT.NONE) { protected Control createDropDown(Composite dropDownParent, IBreadcrumbDropDownSite site, TreePath path) { return createDropDownControl(dropDownParent, site, path); } }; // Force the layout of the breadcrumb viewer so that we may calcualte // its proper size. parent.pack(true); fViewer.setContentProvider(new ContentProvider()); fViewer.setLabelProvider(new LabelProvider()); createMenuManager(); fViewer.setInput(getCurrentInput()); fBreadcrumbContextProvider = new BreadcrumbContextProvider(); return fViewer; } protected void createMenuManager() { MenuManager menuMgr = new MenuManager("#PopUp"); //$NON-NLS-1$ menuMgr.setRemoveAllWhenShown(true); menuMgr.addMenuListener(new IMenuListener() { public void menuAboutToShow(IMenuManager mgr) { fView.fillContextMenu(mgr); } }); final Menu menu = menuMgr.createContextMenu(fViewer.getControl()); // register the context menu such that other plug-ins may contribute to it if (fView.getSite() != null) { fView.getSite().registerContextMenu(menuMgr, fViewer); } fView.addContextMenuManager(menuMgr); fViewer.addMenuDetectListener(new MenuDetectListener() { public void menuDetected(MenuDetectEvent event) { menu.setLocation(event.x + 10, event.y + 10); menu.setVisible(true); while (!menu.isDisposed() && menu.isVisible()) { if (!menu.getDisplay().readAndDispatch()) menu.getDisplay().sleep(); } } }); } protected Object getCurrentInput() { return fBreadcrumbInput; } protected boolean open(ISelection selection) { // Let the drop-down control implementation itself handle activating a new context. return false; } public void dispose() { fBreadcrumbContextProvider = null; fTreeViewerContextProvider.removeDebugContextListener(this); fTreeViewer.removeLabelUpdateListener(this); fBreadcrumbContextProvider.dispose(); fViewer = null; super.dispose(); } public void debugContextChanged(DebugContextEvent event) { if (fView.isBreadcrumbVisible()) { fBreadcrumbInput = new Input(getPathForSelection(event.getContext())); if ((event.getFlags() & DebugContextEvent.ACTIVATED) != 0) { setInput(getCurrentInput()); // If the context was activated, then clear the selection in breadcrumb // so that the activated context will become the active context for the // window. fViewer.setSelection(StructuredSelection.EMPTY); } else { refresh(); } } } public void labelUpdateStarted(ILabelUpdate update) { } public void labelUpdateComplete(ILabelUpdate update) { if (fBreadcrumbInput != null && fBreadcrumbInput.fPath != null) { if (fBreadcrumbInput.fPath.startsWith(update.getElementPath(), null)) { synchronized (this) { fRefreshBreadcrumb = true; } } } } public void labelUpdatesBegin() { } public void labelUpdatesComplete() { boolean refresh = false; synchronized (this) { refresh = fRefreshBreadcrumb; fRefreshBreadcrumb = false; } if (fView.isBreadcrumbVisible() && refresh) { new UIJob(fViewer.getControl().getDisplay(), "refresh breadcrumb") { //$NON-NLS-1$ { setSystem(true); } public IStatus runInUIThread(IProgressMonitor monitor) { refresh(); return Status.OK_STATUS; } }.schedule(); } } IDebugContextProvider getContextProvider() { return fBreadcrumbContextProvider; } int getHeight() { return fViewer.getControl().getSize().y; } void clearSelection() { fViewer.setSelection(StructuredSelection.EMPTY); } private TreePath getPathForSelection(ISelection selection) { if (selection instanceof ITreeSelection && !selection.isEmpty()) { return ((ITreeSelection) selection).getPaths()[0]; } return null; } public Control createDropDownControl(Composite parent, final IBreadcrumbDropDownSite site, TreePath paramPath) { TreeViewerDropDown dropDownTreeViewer = new TreeViewerDropDown() { SubTreeModelViewer fDropDownViewer; protected TreeViewer createTreeViewer(Composite composite, int style, final TreePath path) { fDropDownViewer = new SubTreeModelViewer(composite, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.VIRTUAL | SWT.POP_UP, fTreeViewer.getPresentationContext()); Object launchViewInput = fTreeViewer.getInput(); fDropDownViewer.setInput(launchViewInput, path.getParentPath()); ViewerFilter[] filters = fTreeViewer.getFilters(); fDropDownViewer.setFilters(filters); ModelDelta stateDelta = new ModelDelta(launchViewInput, IModelDelta.NO_CHANGE); fTreeViewer.saveElementState(TreePath.EMPTY, stateDelta, IModelDelta.EXPAND | IModelDelta.SELECT); // If we do not want to expand the elements in the drop-down. // Prune the delta to only select the element in the // top-most list. if (!fView.getBreadcrumbDropDownAutoExpand()) { final ModelDelta prunedDelta = new ModelDelta(launchViewInput, IModelDelta.NO_CHANGE); stateDelta.accept(new IModelDeltaVisitor() { ModelDelta copy = prunedDelta; public boolean visit(IModelDelta delta, int depth) { TreePath deltaPath = getViewerTreePath(delta); if (deltaPath.getSegmentCount() == 0) { // skip copying the root element, only copy it's child count copy.setChildCount(delta.getChildCount()); } else if (deltaPath.getSegmentCount() != 0 && path.startsWith(deltaPath, null)) { // Build up the delta copy along the path of the drop-down element. copy = copy.addNode(delta.getElement(), delta.getIndex(), delta.getFlags(), delta.getChildCount()); } // If the delta is for the drop-down element, set its select flag and stop traversing // the delta.. if (deltaPath.equals(path)) { copy.setFlags(IModelDelta.SELECT | IModelDelta.REVEAL); return false; } // Continue traversing the delta. return true; } private TreePath getViewerTreePath(IModelDelta node) { ArrayList list = new ArrayList(); IModelDelta parentDelta = node.getParentDelta(); while (parentDelta != null) { list.add(0, node.getElement()); node = parentDelta; parentDelta = node.getParentDelta(); } return new TreePath(list.toArray()); } }); stateDelta = prunedDelta; } fDropDownViewer.updateViewer(stateDelta); fDropDownViewer.addLabelUpdateListener(new ILabelUpdateListener() { public void labelUpdateComplete(ILabelUpdate update) { } public void labelUpdatesBegin() { } public void labelUpdateStarted(ILabelUpdate update) { } public void labelUpdatesComplete() { new UIJob(fViewer.getControl().getDisplay(), "resize breadcrub dropdown") { //$NON-NLS-1$ { setSystem(true); } public IStatus runInUIThread(IProgressMonitor monitor) { site.updateSize(); return Status.OK_STATUS; } }.schedule(); } }); return fDropDownViewer; } protected void openElement(ISelection selection) { if (fTreeViewer.getControl().isDisposed()) { return; } if (selection != null && (selection instanceof ITreeSelection) && !selection.isEmpty()) { // Create the path to the root element of the drop-down viewer. Need to calcualte // indexes and counts for the delta in order for the selection from the drop-down // viewer to work properly. TreeModelContentProvider contentProvider = (TreeModelContentProvider) fTreeViewer .getContentProvider(); TreePath path = TreePath.EMPTY; int count = fTreeViewer.getChildCount(path); count = contentProvider.viewToModelCount(path, count); ModelDelta rootDelta = new ModelDelta(fTreeViewer.getInput(), -1, IModelDelta.NO_CHANGE, count); TreePath rootPath = fDropDownViewer.getRootPath(); ModelDelta delta = rootDelta; for (int i = 0; i < rootPath.getSegmentCount(); i++) { Object element = rootPath.getSegment(i); int index = fTreeViewer.findElementIndex(path, element); index = contentProvider.viewToModelIndex(path, index); path = path.createChildPath(element); count = fTreeViewer.getChildCount(path); count = contentProvider.viewToModelCount(path, count); delta = delta.addNode(rootPath.getSegment(i), index, IModelDelta.NO_CHANGE, count); } // Create the delta and save the drop-down viewer's state to it. fDropDownViewer.saveElementState(TreePath.EMPTY, delta, IModelDelta.EXPAND | IModelDelta.SELECT); // Add the IModelDelta.FORCE flag to override the current selection in view. rootDelta.accept(new IModelDeltaVisitor() { public boolean visit(IModelDelta paramDelta, int depth) { if ((paramDelta.getFlags() & IModelDelta.SELECT) != 0) { ((ModelDelta) paramDelta).setFlags(paramDelta.getFlags() | IModelDelta.FORCE); } return true; } }); // If elements in the drop-down were auto-expanded, then collapse the drop-down's sub tree in the // full viewer. After the drop-down's full expansion state is saved out to the tree viewer, the // tree viewer will accurately reflect the state changes made by the user. if (fView.getBreadcrumbDropDownAutoExpand()) { fTreeViewer.collapseToLevel(rootPath, AbstractTreeViewer.ALL_LEVELS); } // Save the state of the drop-down out into the tree viewer. fTreeViewer.updateViewer(rootDelta); fViewer.setSelection(StructuredSelection.EMPTY); site.close(); } super.openElement(selection); } }; return dropDownTreeViewer.createDropDown(parent, site, paramPath); } }