/******************************************************************************* * Copyright (c) 2007, 2014 compeople AG and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * compeople AG - initial API and implementation *******************************************************************************/ package org.eclipse.riena.navigation.ui.swt.views; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.ControlListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Cursor; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.FormAttachment; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.layout.FormLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.riena.core.marker.IMarker; import org.eclipse.riena.core.marker.Markable; import org.eclipse.riena.core.util.ListenerList; import org.eclipse.riena.core.util.Nop; import org.eclipse.riena.core.util.StringUtils; import org.eclipse.riena.internal.ui.ridgets.swt.TreeRidgetLabelProvider; import org.eclipse.riena.navigation.IModuleNode; import org.eclipse.riena.navigation.INavigationNode; import org.eclipse.riena.navigation.ISubApplicationNode; import org.eclipse.riena.navigation.ISubModuleNode; import org.eclipse.riena.navigation.NavigationNodeId; import org.eclipse.riena.navigation.listener.ModuleNodeListener; import org.eclipse.riena.navigation.listener.NavigationTreeObserver; import org.eclipse.riena.navigation.listener.SubModuleNodeListener; import org.eclipse.riena.navigation.model.ModuleGroupNode; import org.eclipse.riena.navigation.model.ModuleNode; import org.eclipse.riena.navigation.model.SubModuleNode; import org.eclipse.riena.navigation.ui.swt.binding.InjectSwtViewBindingDelegate; import org.eclipse.riena.navigation.ui.swt.facades.NavigationFacade; import org.eclipse.riena.navigation.ui.swt.lnf.renderer.ModuleGroupRenderer; import org.eclipse.riena.navigation.ui.swt.lnf.renderer.SubModuleTreeItemMarkerRenderer; import org.eclipse.riena.navigation.ui.swt.presentation.SwtViewProvider; import org.eclipse.riena.ui.core.marker.IIconizableMarker; import org.eclipse.riena.ui.ridgets.controller.IController; import org.eclipse.riena.ui.ridgets.swt.uibinding.AbstractViewBindingDelegate; import org.eclipse.riena.ui.swt.ModuleTitleBar; import org.eclipse.riena.ui.swt.facades.SWTFacade; import org.eclipse.riena.ui.swt.lnf.LnFUpdater; import org.eclipse.riena.ui.swt.lnf.LnfKeyConstants; import org.eclipse.riena.ui.swt.lnf.LnfManager; import org.eclipse.riena.ui.swt.lnf.rienadefault.RienaDefaultLnf; import org.eclipse.riena.ui.swt.utils.SwtUtilities; /** * View of a module. */ public class ModuleView implements INavigationNodeView<ModuleNode> { private static final String WINDOW_RIDGET = "windowRidget"; //$NON-NLS-1$ private final LnFUpdater lnfUpdater = LnFUpdater.getInstance(); private final AbstractViewBindingDelegate binding; private final Composite parent; private Composite body; private Tree subModuleTree; private ModuleNode moduleNode; private boolean pressed; private boolean hover; private ModuleTitleBar title; private BlockManager blockManager; private boolean doNotResize; private NavigationTreeObserver navigationTreeObserver; private final ListenerList<IComponentUpdateListener> updateListeners; private ModuleGroupNode moduleGroupNode; private Map<ISubModuleNode, Set<IMarker>> subModuleMarkerCache; private Listener disabledSubModuleTreeBgPainter; private SubModuleListener subModuleListener; private ModuleListener moduleListener; public ModuleView(final Composite parent) { this.parent = parent; binding = createBinding(); updateListeners = new ListenerList<IComponentUpdateListener>(IComponentUpdateListener.class); initializeSubModuleMarkerCache(); buildView(); } private void initializeSubModuleMarkerCache() { subModuleMarkerCache = new HashMap<ISubModuleNode, Set<IMarker>>(); } public void addUpdateListener(final IComponentUpdateListener listener) { updateListeners.add(listener); } public void setModuleGroupNode(final ModuleGroupNode moduleGroupNode) { this.moduleGroupNode = moduleGroupNode; } /** * @return the moduleGroupNode parent of the moduleNode */ public ModuleGroupNode getModuleGroupNode() { return moduleGroupNode; } public void bind(final ModuleNode node) { moduleNode = node; navigationTreeObserver = new NavigationTreeObserver(); subModuleListener = new SubModuleListener(); navigationTreeObserver.addListener(subModuleListener); moduleListener = new ModuleListener(); navigationTreeObserver.addListener(moduleListener); navigationTreeObserver.addListenerTo(moduleNode); if (getNavigationNode().getNavigationNodeController() instanceof IController) { final IController controller = (IController) node.getNavigationNodeController(); binding.injectRidgets(controller); binding.bind(controller); controller.afterBind(); } } /** * Disposes this module item. */ public void dispose() { if (null != subModuleListener) { navigationTreeObserver.removeListener(subModuleListener); } if (null != moduleListener) { navigationTreeObserver.removeListener(moduleListener); } subModuleMarkerCache.clear(); unbind(); SwtUtilities.dispose(title); SwtUtilities.dispose(getBody()); SwtUtilities.dispose(getTree()); } /** * Returns a rectangle describing the size and location of this module. * * @return the bounds */ public Rectangle getBounds() { final Rectangle bounds = title.getBounds(); if (getNavigationNode().isActivated()) { bounds.height += getBody().getSize().y; } return bounds; } /** * @return the icon */ public String getIcon() { if (getNavigationNode() == null) { return null; } return getNavigationNode().getIcon(); } /** * @return the label */ public String getLabel() { if (getNavigationNode() == null) { return null; } return getNavigationNode().getLabel(); } public ModuleNode getNavigationNode() { return moduleNode; } /** * Returns the height of the open item. * * @return height. */ public int getOpenHeight() { final IModuleNode navigationNode = getNavigationNode(); if ((navigationNode != null) && (navigationNode.isActivated())) { final int depth = navigationNode.calcDepth(); if (depth == 0) { return 0; } else { final int itemHeight = getTree().getItemHeight(); return depth * itemHeight + 1; } } else { return 0; } } /** * @return the activated */ public boolean isActivated() { if (getNavigationNode() == null) { return false; } return getNavigationNode().isActivated(); } /** * @return the closeable */ public boolean isCloseable() { if (getNavigationNode() == null) { return false; } return getNavigationNode().isClosable(); } /** * Returns if the module item is highlighted, because the mouse hovers over the item. * * @return true, if mouse over the module; otherwise false. */ public boolean isHover() { return hover; } /** * Returns if the module item is pressed or not. * * @param pressed * true, if mouse over the module and pressed; otherwise false. */ public boolean isPressed() { return pressed; } /** * Returns whether this view is visible or not. * * @return {@code true} if nod if visible; otherwise {@code false} */ public boolean isVisible() { if (getNavigationNode() == null) { return false; } return getNavigationNode().isVisible(); } /** * Sets if the module item is highlighted, because the mouse hovers over the item.<br> * If the given hover state differs from the current state, the parent of item is redrawn. * * @param hover * true, if mouse over the module; otherwise false. */ public void setHover(final boolean hover) { if (this.hover != hover) { this.hover = hover; if (!parent.isDisposed()) { parent.redraw(); } } } /** * Sets if the module item is pressed or not.<br> * If the given state differs from the current state, the parent of item is redrawn. * * @param pressed * true, if mouse over the module and pressed; otherwise false. */ public void setPressed(final boolean pressed) { if (this.pressed != pressed) { this.pressed = pressed; if (!parent.isDisposed()) { parent.redraw(); } } } public void unbind() { if (getNavigationNode().getNavigationNodeController() instanceof IController) { final IController controller = (IController) getNavigationNode().getNavigationNodeController(); binding.unbind(controller); } navigationTreeObserver.removeListenerFrom(moduleNode); moduleNode = null; } /** * Updates the enabled flag of the title and the sub-module tree and and redraws them. * * @since 3.0 */ public void updateEnabled() { title.setEnabled(getNavigationNode().isEnabled()); subModuleTree.setEnabled(title.isEnabled()); title.redraw(); } public void updateModuleView() { prepareUpdate(); getParent().layout(); } public void prepareUpdate() { boolean currentActiveState = false; if (getNavigationNode() != null) { currentActiveState = getNavigationNode().isActivated(); } if (!SwtUtilities.isDisposed(title)) { layoutTitle(); title.setWindowActive(currentActiveState); } if (!SwtUtilities.isDisposed(getBody())) { if (getBody().isVisible() != currentActiveState) { getBody().setVisible(currentActiveState); } final int height = getOpenHeight(); if (getBody().getSize().y != height) { final FormData formData = new FormData(); formData.top = new FormAttachment(title); formData.left = new FormAttachment(0, 0); formData.right = new FormAttachment(100, 0); formData.height = height; getBody().setLayoutData(formData); } } } /** * Creates a delegate for the binding of view and controller. * * @return delegate for binding */ protected AbstractViewBindingDelegate createBinding() { return new InjectSwtViewBindingDelegate(); } /** * Creates the content of the module body (default: the tree for the sub-modules). * * @param parent * body of the module */ protected void createBodyContent(final Composite parent) { parent.setLayout(new FormLayout()); subModuleTree = new Tree(parent, SWT.NO_SCROLL | SWT.DOUBLE_BUFFERED); subModuleTree.setLinesVisible(false); final RienaDefaultLnf lnf = LnfManager.getLnf(); subModuleTree.setFont(lnf.getFont(LnfKeyConstants.SUB_MODULE_ITEM_FONT)); binding.addUIControl(subModuleTree, "tree"); //$NON-NLS-1$ final FormData formData = new FormData(); formData.top = new FormAttachment(0, 0); formData.left = new FormAttachment(0, 0); formData.right = new FormAttachment(100, 0); formData.bottom = new FormAttachment(100, 0); subModuleTree.setLayoutData(formData); subModuleTree.setData(TreeRidgetLabelProvider.TREE_KIND_KEY, TreeRidgetLabelProvider.TREE_KIND_NAVIGATION); addListeners(); SWTFacade.getDefault().createSubModuleToolTip(subModuleTree, new LabelProvider() { @Override public String getText(final Object element) { final INavigationNode<?> node = (INavigationNode<?>) element; String text = node.getToolTipText(); if (text == null) { text = node.getLabel(); } return text; } }); setTreeBackground(); } /** * @since 3.0 */ protected Listener createDisabledSubModuleTreeBackgroundPainter(final Color disabledBackgroundColor) { return new DisabledSubModuleTreeBackgroundPainter(disabledBackgroundColor); } protected void fireUpdated(final INavigationNode<?> node) { for (final IComponentUpdateListener listener : updateListeners.getListeners()) { listener.update(node); } } public Composite getParent() { return parent; } /** * Returns the title for the module * * @return title */ protected ModuleTitleBar getTitle() { return title; } /** * Returns the tree with the sub-module items. * * @return tree */ protected Tree getTree() { return subModuleTree; } protected void resize() { if (doNotResize) { return; } fireUpdated(null); } /** * @deprecated use {@link setTreeBackground} instead */ @Deprecated protected void setTreeBackGround() { // TODO: When removing the deprecated method in the future don't forget to move the content to the new method ;-) subModuleTree.setBackground(LnfManager.getLnf().getColor("SubModuleTree.background")); //$NON-NLS-1$ } /** * @since 4.0 */ protected void setTreeBackground() { setTreeBackGround(); } Composite getBody() { return body; } // helping methods ////////////////// /** * Adds listeners to the sub-module tree. */ private void addListeners() { getTree().addListener(SWT.Expand, new Listener() { public void handleEvent(final Event event) { // treeDirty = true; handleExpandCollapse(event, true); } }); getTree().addListener(SWT.Collapse, new Listener() { public void handleEvent(final Event event) { // treeDirty = true; handleExpandCollapse(event, false); } }); getTree().addControlListener(new ControlListener() { public void controlResized(final ControlEvent e) { getTree().redraw(); } public void controlMoved(final ControlEvent e) { Nop.reason("nothing todo"); //$NON-NLS-1$ } }); final Listener paintItemListener = new Listener() { public void handleEvent(final Event event) { paintTreeItem(event); } }; SWTFacade.getDefault().addPaintItemListener(getTree(), paintItemListener); NavigationFacade.getDefault().attachModuleNavigationListener(getTree()); final RienaDefaultLnf lnf = LnfManager.getLnf(); Color disabledBackgroundColor = null; if (!lnf.getBooleanSetting(LnfKeyConstants.SUB_MODULE_TREE_DISABLED_BACKGROUND_IS_SWT_DEFAULT)) { disabledBackgroundColor = lnf.getColor(LnfKeyConstants.SUB_MODULE_TREE_BACKGROUND); } disabledSubModuleTreeBgPainter = createDisabledSubModuleTreeBackgroundPainter(disabledBackgroundColor); SWTFacade.getDefault().addEraseItemListener(subModuleTree, disabledSubModuleTreeBgPainter); } private void blockView(final boolean block) { if (blockManager == null) { blockManager = new BlockManager(); } if (block) { blockManager.block(); } else { blockManager.unblock(); } } /** * Builds the composite and the tree of the module view. */ private void buildView() { title = new ModuleTitleBar(getParent(), SWT.NONE); binding.addUIControl(title, WINDOW_RIDGET); // layoutTitle(); SWTFacade.getDefault().createEmbeddedTitleBarToolTip(title); body = new Composite(getParent(), SWT.DOUBLE_BUFFERED); // updateModuleView(); createBodyContent(body); lnfUpdater.updateUIControls(body, true); } /** * Clips (if necessary) the text of the given tree item. * * @param gc * @param item * tree item * @return {@code true}: text of the item changed; {@code false}: text not changed */ private boolean clipSubModuleText(final GC gc, final TreeItem item) { boolean clipped = false; final Rectangle treeBounds = getTree().getBounds(); final Rectangle itemBounds = item.getBounds(); final int maxWidth = treeBounds.width - itemBounds.x - 5; final String longText = getItemText(item); if (longText != null) { final String text = SwtUtilities.clipText(gc, longText, maxWidth); clipped = !StringUtils.equals(longText, text); clipped = clipped || !StringUtils.equals(item.getText(), text); if (clipped) { item.setText(text); } } return clipped; } /** * Clips (if necessary) the text of the given tree item and all child items. * * @param gc * @param item * tree item * @return {@code true}: some texts changed; {@code false}: no text changed */ private boolean clipSubModuleTexts(final GC gc, final TreeItem item) { boolean clipped = clipSubModuleText(gc, item); final TreeItem[] items = item.getItems(); for (final TreeItem childItem : items) { if (clipSubModuleTexts(gc, childItem)) { clipped = true; } } return clipped; } /** * Returns the text of the given item. If the data of the item is a node, so the label of the node is returned. * * @param item * tree item * @return text of item (or label of node) */ private String getItemText(final TreeItem item) { final INavigationNode<?> node = (INavigationNode<?>) item.getData(); if (node != null) { return node.getLabel(); } else { return item.getText(); } } /** * Returns the renderer that paints a module group. * * @return renderer */ private ModuleGroupRenderer getModuleGroupRenderer() { ModuleGroupRenderer renderer = (ModuleGroupRenderer) LnfManager.getLnf().getRenderer(LnfKeyConstants.MODULE_GROUP_RENDERER); if (renderer == null) { renderer = new ModuleGroupRenderer(); } return renderer; } /** * Returns the renderer that paints the markers of a tree item. * * @return renderer */ private SubModuleTreeItemMarkerRenderer getTreeItemRenderer() { SubModuleTreeItemMarkerRenderer renderer = (SubModuleTreeItemMarkerRenderer) LnfManager.getLnf().getRenderer( LnfKeyConstants.SUB_MODULE_TREE_ITEM_MARKER_RENDERER); if (renderer == null) { renderer = new SubModuleTreeItemMarkerRenderer(); } return renderer; } /** * After a node has been expanded or collapsed the size of the module must be updated. * * @param event * the event which occurred * @param expand */ private void handleExpandCollapse(final Event event, final boolean expand) { if (event.item instanceof TreeItem) { final TreeItem item = (TreeItem) event.item; final INavigationNode<?> node = (INavigationNode<?>) item.getData(); node.setExpanded(expand); } resize(); } private void layoutTitle() { final FormData formData = new FormData(); final int index = getModuleGroupNode().getIndexOfChild(getNavigationNode()); if (index == 0) { formData.top = new FormAttachment(0, 0); } else if (index < 0) { formData.top = new FormAttachment(getModuleViewBody(getModuleGroupNode().getChild(getModuleGroupNode().getChildren().size() - 1)), getModuleGroupRenderer().getModuleModuleGap()); } else { formData.top = new FormAttachment(getModuleViewBody(getModuleGroupNode().getChild(index - 1)), getModuleGroupRenderer().getModuleModuleGap()); } formData.left = new FormAttachment(0, 0); formData.right = new FormAttachment(100, 0); formData.height = title.getSize().y; title.setLayoutData(formData); } /** * Locates the body {@link Control} of the given {@link IModuleNode} * * @param child * - the child for which the body control will be located * @return - the body {@link Control} */ private Control getModuleViewBody(final IModuleNode child) { for (final ModuleView moduleView : getModuleGroupRenderer().getItems()) { if (moduleView.getNavigationNode() == child) { return moduleView.getBody(); } } return null; } /** * Paints the markers of the given tree item. * * @param event * the event which occurred */ private void paintTreeItem(final Event event) { if (event.item instanceof TreeItem) { final SubModuleTreeItemMarkerRenderer renderer = getTreeItemRenderer(); renderer.setBounds(event.x, event.y, event.width, event.height); final TreeItem item = (TreeItem) event.item; final SubModuleNode node = (SubModuleNode) item.getData(); if (node != null) { final boolean deep = !item.getExpanded(); final Collection<? extends IMarker> markers = getAllMarkers(node, deep); renderer.setMarkers(markers); } clipSubModuleTexts(event.gc, item); renderer.paint(event.gc, item); } } /** * Returns all (IIconizableMarker) markers of the given node and all of its child nodes (if deep is true). * * @param node * sub-module node * @param deep * {@code true} return also the markers of the child nodes; {@code false} only markers of the given node * @return all markers, that can be displayed in the navigation tree */ // private Collection<? extends IMarker> getAllMarkers(ISubModuleNode node, boolean deep) { // // if ((node == null) || !node.isVisible()) { // return Collections.emptyList(); // } // // Set<IMarker> markers = new HashSet<IMarker>(); // // List<ISubModuleNode> allNodes = new ArrayList<ISubModuleNode>(); // allNodes.add(node); // int i = 0; // while (i < allNodes.size() && deep) { // List<ISubModuleNode> children = allNodes.get(i).getChildren(); // for (ISubModuleNode child : children) { // if (child.isVisible()) { // allNodes.add(child); // markers.addAll(child.getMarkers()); // } // } // i++; // } // // return Markable.getMarkersOfType(markers, IIconizableMarker.class); // // } private Collection<? extends IMarker> getAllMarkers(final ISubModuleNode node, final boolean deep) { if ((node == null) || !node.isVisible()) { return Collections.emptySet(); } final HashSet<IMarker> markers = new HashSet<IMarker>(); fillMarkers(node, deep, markers); return markers; } private void fillMarkers(final ISubModuleNode node, final boolean deep, final Set<IMarker> markers) { if (!node.isVisible()) { return; } markers.addAll(Markable.getMarkersOfType(node.getMarkers(), IIconizableMarker.class)); if (deep) { for (final ISubModuleNode child : node.getChildren()) { fillMarkers(child, deep, markers); } } } private static TreeItem findItem(final TreeItem[] items, final ISubModuleNode source) { for (final TreeItem item : items) { if (item.getData() == source) { return item; } final TreeItem result = item.getItemCount() > 0 ? findItem(item.getItems(), source) : null; if (result != null) { return result; } } return null; } // helping classes ////////////////// /** * After adding of removing a sub-module from this module, the module view must be resized. */ private class ModuleListener extends ModuleNodeListener { @Override public void activated(final IModuleNode source) { super.activated(source); updateModuleView(); } @Override public void block(final IModuleNode source, final boolean block) { blockView(block); } @Override public void disposed(final IModuleNode source) { super.disposed(source); dispose(); } @Override public void markerChanged(final IModuleNode source, final IMarker marker) { super.markerChanged(source, marker); title.setMarkers(source.getMarkers()); updateEnabled(); } @Override public void nodeIdChange(final IModuleNode source, final NavigationNodeId oldId, final NavigationNodeId newId) { if (source.equals(getNavigationNode())) { SwtViewProvider.getInstance().replaceNavigationNodeId(source, oldId, newId); } } } /** * After adding of removing a sub-module from another sub-module, the module view must be resized. */ private class SubModuleListener extends SubModuleNodeListener { @Override public void beforeActivated(final ISubModuleNode source) { /* * SWT feature: when tree.setFocus() is called below, it will fire a selection event in ADDITION of setting the focus. This will trigger activation * of the selected node, which may be different than the 'source' node. * * Workaround: we make sure the tree has already a selection before we go into the activated(...) method, to avoid this selection event. */ final Tree tree = getTree(); if (tree.getSelectionCount() == 0 && tree.getItemCount() > 0) { TreeItem item = findItem(tree.getItems(), source); if (item == null) { item = tree.getItem(0); } tree.select(item); } } @Override public void activated(final ISubModuleNode source) { doNotResize = true; updateExpanded(source); // fix for bug 269221 doNotResize = false; resize(); final TreeItem currentItem = findItem(getTree().getItems(), source); if (null != currentItem) { getTree().select(currentItem); } getTree().setFocus(); } @Override public void childAdded(final ISubModuleNode source, final ISubModuleNode childAdded) { resize(); } @Override public void childRemoved(final ISubModuleNode source, final ISubModuleNode childRemoved) { if (source.getParentOfType(ISubApplicationNode.class).isActivated()) { resize(); } } @Override public void labelChanged(final ISubModuleNode source) { super.labelChanged(source); getTree().redraw(); } @Override public void markerChanged(final ISubModuleNode source, final IMarker marker) { if (isTreeRedrawOnMarkerChanged(source, marker)) { getTree().redraw(); } } private boolean isTreeRedrawOnMarkerChanged(final ISubModuleNode source, final IMarker marker) { Set<IMarker> resultCache = subModuleMarkerCache.get(source); if (resultCache == null) { resultCache = new HashSet<IMarker>(); subModuleMarkerCache.put(source, resultCache); } final Set<IMarker> originalCache = new HashSet<IMarker>(resultCache); if (source.getMarkers().contains(marker)) { resultCache.add(marker); } else { resultCache.remove(marker); } return !resultCache.equals(originalCache); } private void updateExpanded(final ISubModuleNode node) { final INavigationNode<?> nodeParent = node.getParent(); if (nodeParent instanceof ISubModuleNode) { nodeParent.setExpanded(true); updateExpanded((ISubModuleNode) nodeParent); } } @Override public void expandedChanged(final ISubModuleNode source) { super.expandedChanged(source); resize(); } } /** * Blocks and unblocks widgets in this view. Before blocking it saves the current widget state and restores it when unblocking. */ private final class BlockManager { private Cursor titleOldCursor; private Cursor bodyOldCursor; private boolean isBlocked; private boolean treeHasFocus; public void block() { if (!isBlocked) { titleOldCursor = title.getCursor(); title.setCursor(getWaitCursor()); title.setCloseable(false); if (disableTitle()) { title.setEnabled(false); } bodyOldCursor = body.getCursor(); body.setCursor(getWaitCursor()); treeHasFocus = subModuleTree.isFocusControl(); subModuleTree.setEnabled(false); isBlocked = true; } } public void unblock() { isBlocked = false; title.setCursor(titleOldCursor); title.setCloseable(getNavigationNode().isClosable()); title.setEnabled(getNavigationNode().isEnabled()); body.setCursor(bodyOldCursor); subModuleTree.setEnabled(true); if (treeHasFocus) { subModuleTree.setFocus(); treeHasFocus = false; } } private boolean disableTitle() { // when the subapp is disabled: disable the title // when the subapp is enabled but the module disable: keep title as is final ISubApplicationNode subApp = getNavigationNode().getParentOfType(ISubApplicationNode.class); return subApp != null && subApp.isBlocked(); } private Cursor getWaitCursor() { return parent.getDisplay().getSystemCursor(SWT.CURSOR_WAIT); } } private class DisabledSubModuleTreeBackgroundPainter implements Listener { private final Color disabledBackgroundColor; public DisabledSubModuleTreeBackgroundPainter(final Color disabledBackgroundColor) { this.disabledBackgroundColor = disabledBackgroundColor; } public void handleEvent(final Event event) { if (!subModuleTree.isEnabled() && disabledBackgroundColor != null) { final GC gc = event.gc; final Rectangle area = subModuleTree.getClientArea(); final Color foreground = gc.getForeground(); final Color background = gc.getBackground(); gc.setBackground(disabledBackgroundColor); gc.fillRectangle(0, area.y, area.width, area.height); gc.setForeground(foreground); gc.setBackground(background); } } } }