/******************************************************************************* * 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.List; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Tree; import org.eclipse.riena.navigation.IModuleGroupNode; import org.eclipse.riena.navigation.IModuleNode; import org.eclipse.riena.navigation.INavigationNode; import org.eclipse.riena.navigation.ISubModuleNode; import org.eclipse.riena.ui.swt.utils.MouseWheelAdapter; import org.eclipse.riena.ui.swt.utils.SwtUtilities; /** * This class provides basic parts of scrolling logic for the navigation. * * @since 3.0 */ public abstract class AbstractScrollingSupport { /** * @deprecated use {@link MouseWheelAdapter#SCROLLING_STEP} */ @Deprecated protected static final int SCROLLING_STEP = 20; protected final IModuleNavigationComponentProvider navigationComponentProvider; public AbstractScrollingSupport(final IModuleNavigationComponentProvider navigationComponentProvider) { this.navigationComponentProvider = navigationComponentProvider; initMouseWheelObserver(getNavigationComponent()); } /** * Scrolls to the active navigation element. */ public abstract void scroll(); /** * Scrolls the navigation so that given composite is visible. * * @param topComp * title composite * @param bottomComp * body composite * @return {@code true} scrolling was necessary. */ protected abstract boolean scrollTo(final Composite topComp, final Composite bottomComp); /** * Scrolls the navigation so that the selected tree item is visible. * * @param tree * tree of the navigation * @return {@code true} scrolling was necessary. */ protected abstract boolean scrollTo(final Tree tree); /** * Scrolls up. * * @param pixels * amount of pixels for one scrolling step */ protected abstract void scrollUp(final int pixels); /** * Scrolls down * * @param pixels * amount of pixels for one scrolling step */ protected abstract void scrollDown(final int pixels); /** * Scrolls to the given module node. * * @param module * module node * @return {@code true} scrolling was necessary */ protected boolean scrollTo(final IModuleNode module) { boolean result = false; if (module != null) { final ModuleView moduleView = navigationComponentProvider.getModuleViewForNode(module); if (moduleView == null) { return result; } final boolean isClosed = moduleView.getOpenHeight() == 0; if (isClosed) { result = scrollTo(moduleView.getTitle(), moduleView.getBody()); } else { final int moduleHeight = moduleView.getParent().getSize().y; if (moduleHeight < getNavigationComponentHeight()) { // only show title if the whole module fits into the available height // prevents flicker result = scrollTo(moduleView.getTitle(), moduleView.getBody()); } result = result || scrollTo(moduleView.getTree()); } } return result; } /** * Returns the active navigation node. * * @return active navigation node; {@code null} if no active node was found */ protected INavigationNode<?> getActiveNode() { final IModuleGroupNode group = navigationComponentProvider.getActiveModuleGroupNode(); IModuleNode module = null; ISubModuleNode submodule = null; if (group != null) { for (final IModuleNode candidate : group.getChildren()) { if (candidate.isActivated()) { module = candidate; break; } } } if (module != null) { submodule = getActiveSubModuleNode(module.getChildren()); } return submodule != null ? submodule : module != null ? module : group; } /** * Returns the active sub module node. * * @param nodes * list of all (sibling) sub module nodes * @return sub module node; {@code null} if no active node was found */ protected ISubModuleNode getActiveSubModuleNode(final List<ISubModuleNode> nodes) { ISubModuleNode result = null; for (final ISubModuleNode candidate : nodes) { if (candidate.isActivated()) { final ISubModuleNode activeChild = getActiveSubModuleNode(candidate.getChildren()); result = activeChild != null ? activeChild : candidate; break; } } return result; } /** * Returns the height of the scrolled component. * * @return height */ protected int getScrolledComponentHeight() { return getScrolledComponent().getBounds().height; } protected Composite getScrolledComponent() { return navigationComponentProvider.getScrolledComponent(); } /** * Returns the height of the navigation component. * * @return height */ protected int getNavigationComponentHeight() { return getNavigationComponent().getBounds().height; } protected Composite getNavigationComponent() { return navigationComponentProvider.getNavigationComponent(); } /** * Determines if scrolling is needed. * * @return {@code true} if we need scrolling */ protected boolean mayScroll() { final int navigationComponentHeight = getNavigationComponentHeight(); return getScrolledComponentHeight() > navigationComponentHeight && navigationComponentHeight > 0; } // helping methods ////////////////// private void initMouseWheelObserver(final Composite control) { if (SwtUtilities.isDisposed(control)) { return; } new MouseWheelAdapter(control, new MouseWheelAdapter.Scroller() { @Override public boolean mayScroll() { return AbstractScrollingSupport.this.mayScroll(); } @Override public void scrollUp(final int scrollingStep) { AbstractScrollingSupport.this.scrollUp(scrollingStep); } @Override public void scrollDown(final int scrollingStep) { AbstractScrollingSupport.this.scrollDown(scrollingStep); } }); } }