/******************************************************************************* * Copyright (c) 2012, 2013 Original authors 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: * Original authors and others - initial API and implementation ******************************************************************************/ package org.eclipse.nebula.widgets.nattable.viewport; import org.eclipse.nebula.widgets.nattable.NatTable; import org.eclipse.nebula.widgets.nattable.layer.IUniqueIndexLayer; import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer.MoveDirectionEnum; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; public abstract class ScrollBarHandlerTemplate implements Listener { public static final int DEFAULT_OFFSET = 1; protected final ViewportLayer viewportLayer; protected final IUniqueIndexLayer scrollableLayer; protected final IScroller<?> scroller; /** * Flag to remember if the scroll bar is moved by dragging. Needed because * if the scroll bar is moved by dragging, there will be another event that * is handled for releasing the drag mode. We only need to handle the * dragging once, otherwise if the DialogErrorHandling strategy is used, the * dialog would be showed twice. */ private boolean dragging = false; /** * Flag to remember if the drag operation should be handled or not. The * value will be set on trying to commit an possible open editor. If that is * not possible, the value will be set to <code>false</code> which will * result in not performing a scrolling operation. * <p> * This is necessary to avoid inconsistent state when having an editor that * contains invalid data and you are trying to scroll. If scrolling would be * handled, the open editor wouldn't close which results in broken * rendering. * </p> */ private boolean globalHandle = true; /** * The table control of this scroll bar handler. * <p> * Required in order to close the active editor when the user starts to * scroll * </p> */ private NatTable table; public ScrollBarHandlerTemplate(ViewportLayer viewportLayer, IScroller<?> scroller) { this.viewportLayer = viewportLayer; this.scrollableLayer = viewportLayer.getScrollableLayer(); this.scroller = scroller; this.scroller.addListener(SWT.Selection, this); } public void dispose() { if (this.scroller != null && !this.scroller.isDisposed()) { this.scroller.removeListener(SWT.Selection, this); } } @Override public void handleEvent(Event event) { if (!this.dragging) { // Only try to commit and close an possible open editor once // when starting the drag operation. Otherwise the conversion // and validation errors would raise multiple times. if (this.table != null && !this.table.commitAndCloseActiveCellEditor()) { this.globalHandle = false; } } boolean handle = this.globalHandle; if (event.detail == SWT.DRAG) { this.dragging = true; } else { // dragging is finished so we reset the global states this.dragging = false; this.globalHandle = true; } if (handle && event.widget == this.scroller.getUnderlying()) { setViewportOrigin(getViewportMinimumOrigin() + this.scroller.getSelection()); setScrollIncrement(); event.doit = false; } else { adjustScrollBar(); } } void adjustScrollBar() { if (this.scroller.isDisposed()) { return; } int startPixel = getViewportOrigin() - getViewportMinimumOrigin(); this.scroller.setSelection(startPixel); } void recalculateScrollBarSize() { if (this.scroller.isDisposed()) { return; } int max = getScrollableLayerSpan() - getViewportMinimumOrigin(); if (!this.scroller.isDisposed()) { this.scroller.setMaximum(max); } int viewportWindowSpan = getViewportWindowSpan(); int thumbSize; if (viewportWindowSpan < max && viewportWindowSpan != 0) { thumbSize = viewportWindowSpan; this.scroller.setEnabled(true); this.scroller.setVisible(true); setScrollIncrement(); this.scroller.setPageIncrement(viewportWindowSpan); } else { thumbSize = max; this.scroller.setEnabled(false); this.scroller.setVisible(false); } this.scroller.setThumb(thumbSize); adjustScrollBar(); } void setScrollIncrement() { int scrollIncrement = Math.min(getScrollIncrement(), getViewportWindowSpan() / 4); this.scroller.setIncrement(scrollIncrement); } /** * Sets the table belonging to this handler. * <p> * The table is required to close the active editor when scrolling. If the * table is NOT set then the active editor will stay open during the * scrolling leading to drawing errors. * </p> * * @param table * the table */ void setTable(NatTable table) { this.table = table; } /** * Methods to be implemented by the Horizontal/Vertical scroll bar handlers. * * @return */ abstract int getViewportWindowSpan(); abstract int getScrollableLayerSpan(); abstract boolean keepScrolling(); abstract int getViewportOrigin(); abstract int getViewportMinimumOrigin(); abstract void setViewportOrigin(int pixel); abstract MoveDirectionEnum scrollDirectionForEventDetail(int eventDetail); abstract int getScrollIncrement(); }