blob: da55ed5aa47a3657d3e7d8fc640549c6b8ebb643 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 2020 Original authors and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* 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) {
// ensure that the keep in viewport setting is reset if there is one
// active
this.viewportLayer.setKeepInViewportRowPosition(-1);
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);
}
adjustScrollBar();
int viewportWindowSpan = getViewportWindowSpan();
if (viewportWindowSpan < max && viewportWindowSpan != 0) {
this.scroller.setThumb(viewportWindowSpan);
this.scroller.setEnabled(true);
this.scroller.setVisible(true);
setScrollIncrement();
this.scroller.setPageIncrement(viewportWindowSpan);
} else {
this.scroller.setThumb(max);
this.scroller.setEnabled(false);
this.scroller.setVisible(viewportWindowSpan == 0 && max > 0);
}
}
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();
}