blob: c0d3e0f80879d4a6957aaa2ec6df4c4670d81ded [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.columnCategories.gui;
import static org.eclipse.nebula.widgets.nattable.columnChooser.ColumnChooserUtils.getColumnEntryPositions;
import static org.eclipse.nebula.widgets.nattable.util.ObjectUtils.isNotEmpty;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ListViewer;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.nebula.widgets.nattable.Messages;
import org.eclipse.nebula.widgets.nattable.columnCategories.ColumnCategoriesModel;
import org.eclipse.nebula.widgets.nattable.columnCategories.IColumnCategoriesDialogListener;
import org.eclipse.nebula.widgets.nattable.columnCategories.Node;
import org.eclipse.nebula.widgets.nattable.columnCategories.Node.Type;
import org.eclipse.nebula.widgets.nattable.columnChooser.ColumnEntry;
import org.eclipse.nebula.widgets.nattable.columnChooser.gui.AbstractColumnChooserDialog;
import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer.MoveDirectionEnum;
import org.eclipse.nebula.widgets.nattable.util.GUIHelper;
import org.eclipse.nebula.widgets.nattable.util.ObjectUtils;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Shell;
/**
* JFace/SWT based column chooser dialog which displays the available/hidden
* columns in a tree viewer. This tree viewer is based on the
* {@link ColumnCategoriesModel}.
*/
public class ColumnCategoriesDialog extends AbstractColumnChooserDialog {
private final ColumnCategoriesModel model;
private List<ColumnEntry> hiddenColumnEntries;
private List<ColumnEntry> visibleColumnsEntries;
private TreeViewer treeViewer;
private ListViewer listViewer;
private ISelection lastListSelection;
private ListenerList<IColumnCategoriesDialogListener> listeners = new ListenerList<>();
public ColumnCategoriesDialog(Shell shell, ColumnCategoriesModel model,
List<ColumnEntry> hiddenColumnEntries,
List<ColumnEntry> visibleColumnsEntries) {
super(shell);
this.model = model;
this.hiddenColumnEntries = hiddenColumnEntries;
this.visibleColumnsEntries = visibleColumnsEntries;
setShellStyle(SWT.CLOSE | SWT.TITLE | SWT.BORDER | SWT.APPLICATION_MODAL | SWT.RESIZE);
}
@Override
public void populateDialogArea(Composite parent) {
GridDataFactory.fillDefaults().grab(true, true).applyTo(parent);
parent.setLayout(new GridLayout(4, false));
// Labels
createLabels(
parent,
Messages.getString("ColumnChooser.availableColumns"), //$NON-NLS-1$
Messages.getString("ColumnChooser.selectedColumns")); //$NON-NLS-1$
GridData gridData = GridDataFactory.fillDefaults().grab(true, true).create();
// Left tree - column categories
this.treeViewer = new TreeViewer(parent);
populateAvailableTree();
this.treeViewer.getControl().setLayoutData(gridData);
// Add/remove buttons
Composite buttonComposite = new Composite(parent, SWT.NONE);
buttonComposite.setLayout(new GridLayout(1, true));
createAddButton(buttonComposite);
createRemoveButton(buttonComposite);
addListenersToTreeViewer();
// Right list - selected columns
this.listViewer = new ListViewer(parent, SWT.MULTI | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
populateSelectedList();
addListenersToListViewer();
// Up/down buttons
Composite upDownbuttonComposite = new Composite(parent, SWT.NONE);
upDownbuttonComposite.setLayout(new GridLayout(1, true));
createUpButton(upDownbuttonComposite);
createDownButton(upDownbuttonComposite);
}
private void populateSelectedList() {
VisibleColumnsProvider listProvider = new VisibleColumnsProvider(this.visibleColumnsEntries);
this.listViewer.setContentProvider(listProvider);
this.listViewer.setLabelProvider(listProvider);
this.listViewer.setInput(listProvider);
this.listViewer.setContentProvider(listProvider);
this.listViewer.getControl().setLayoutData(GridDataFactory
.fillDefaults()
.grab(true, true)
.create());
}
private void addListenersToTreeViewer() {
this.treeViewer.getControl().addMouseListener(new MouseAdapter() {
@Override
public void mouseDoubleClick(MouseEvent e) {
addSelected();
}
});
}
private void addListenersToListViewer() {
this.listViewer.getControl().addMouseListener(new MouseAdapter() {
@Override
public void mouseDoubleClick(MouseEvent e) {
removeSelected();
}
});
this.listViewer.getControl().addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
boolean controlMask = (e.stateMask & SWT.MOD1) == SWT.MOD1;
if (controlMask && e.keyCode == SWT.ARROW_UP) {
moveSelectedUp();
e.doit = false;
} else if (controlMask && e.keyCode == SWT.ARROW_DOWN) {
moveSelectedDown();
e.doit = false;
}
}
@Override
public void keyReleased(KeyEvent e) {
if (e.character == ' ')
removeSelected();
}
});
}
private void populateAvailableTree() {
AvailableColumnCategoriesProvider provider = new AvailableColumnCategoriesProvider(this.model);
provider.hideEntries(this.visibleColumnsEntries);
this.treeViewer.setContentProvider(provider);
this.treeViewer.setLabelProvider(new ColumnCategoriesLabelProvider(this.hiddenColumnEntries));
this.treeViewer.setInput(provider);
}
private Button createDownButton(Composite upDownbuttonComposite) {
Button downButton = new Button(upDownbuttonComposite, SWT.PUSH);
downButton.setImage(GUIHelper.getImage("arrow_down")); //$NON-NLS-1$
downButton.setLayoutData(GridDataFactory
.fillDefaults()
.grab(false, true)
.align(SWT.CENTER, SWT.CENTER)
.create());
downButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetDefaultSelected(SelectionEvent e) {
widgetSelected(e);
}
@Override
public void widgetSelected(SelectionEvent e) {
moveSelectedDown();
}
});
return downButton;
}
private Button createUpButton(Composite upDownbuttonComposite) {
Button upButton = new Button(upDownbuttonComposite, SWT.PUSH);
upButton.setImage(GUIHelper.getImage("arrow_up")); //$NON-NLS-1$
upButton.setLayoutData(GridDataFactory
.fillDefaults()
.grab(false, true)
.align(SWT.CENTER, SWT.CENTER)
.create());
upButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetDefaultSelected(SelectionEvent e) {
widgetSelected(e);
}
@Override
public void widgetSelected(SelectionEvent e) {
moveSelectedUp();
}
});
return upButton;
}
private Button createRemoveButton(Composite buttonComposite) {
Button removeButton = new Button(buttonComposite, SWT.PUSH);
removeButton.setImage(GUIHelper.getImage("arrow_left")); //$NON-NLS-1$
removeButton.setLayoutData(GridDataFactory
.fillDefaults()
.grab(false, true)
.align(SWT.CENTER, SWT.CENTER)
.create());
removeButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetDefaultSelected(SelectionEvent e) {
widgetSelected(e);
}
@Override
public void widgetSelected(SelectionEvent e) {
removeSelected();
}
});
return removeButton;
}
private Button createAddButton(Composite buttonComposite) {
Button addButton = new Button(buttonComposite, SWT.PUSH);
addButton.setImage(GUIHelper.getImage("arrow_right")); //$NON-NLS-1$
addButton.setLayoutData(GridDataFactory
.fillDefaults()
.grab(false, true)
.align(SWT.CENTER, SWT.CENTER)
.create());
addButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetDefaultSelected(SelectionEvent e) {
widgetSelected(e);
}
@Override
public void widgetSelected(SelectionEvent e) {
addSelected();
}
});
return addButton;
}
// Respond to button clicks / user actions
protected void removeSelected() {
fireItemsRemoved(getColumnPositionsFromListViewer());
}
protected void addSelected() {
fireItemsSelected(getColumnIndexesFromTreeNodes());
}
/**
* Add a {@link IColumnCategoriesDialogListener} that is triggered for
* modifications in the selected tree.
*
* @param listener
* the listener to add.
* @since 2.0
*/
public void addListener(IColumnCategoriesDialogListener listener) {
this.listeners.add(listener);
}
/**
* Remove a {@link IColumnCategoriesDialogListener} that is triggered for
* modifications in the selected tree.
*
* @param listener
* the listener to remove.
* @since 2.0
*/
public void removeListener(IColumnCategoriesDialogListener listener) {
this.listeners.remove(listener);
}
protected final void fireItemsSelected(List<Integer> addedColumnIndexes) {
if (isNotEmpty(addedColumnIndexes)) {
for (IColumnCategoriesDialogListener listener : this.listeners) {
listener.itemsSelected(addedColumnIndexes);
}
}
}
protected final void fireItemsRemoved(List<Integer> removedColumnPositions) {
if (isNotEmpty(removedColumnPositions)) {
for (IColumnCategoriesDialogListener listener : this.listeners) {
listener.itemsRemoved(removedColumnPositions);
}
}
}
protected final void fireItemsMoved(MoveDirectionEnum direction, List<Integer> toPositions) {
for (IColumnCategoriesDialogListener listener : this.listeners) {
listener.itemsMoved(direction, toPositions);
}
}
protected void moveSelectedUp() {
List<Integer> selectedPositions = getColumnEntryPositions(getSelectedColumnEntriesFromListViewer());
// First position selected
if (!selectedPositions.contains(0)) {
fireItemsMoved(MoveDirectionEnum.UP, selectedPositions);
}
}
protected void moveSelectedDown() {
List<Integer> selectedPositions = getColumnEntryPositions(getSelectedColumnEntriesFromListViewer());
// Last position selected
if (!selectedPositions.contains(this.visibleColumnsEntries.size())) {
fireItemsMoved(MoveDirectionEnum.DOWN, selectedPositions);
}
}
/**
* @return selected column position(s) from the list viewer
*/
private List<Integer> getColumnPositionsFromListViewer() {
return getColumnEntryPositions(getSelectedColumnEntriesFromListViewer());
}
private List<ColumnEntry> getSelectedColumnEntriesFromListViewer() {
this.lastListSelection = this.listViewer.getSelection();
Object[] objects = ((StructuredSelection) this.lastListSelection).toArray();
List<ColumnEntry> entries = new ArrayList<>();
for (Object object : objects) {
entries.add((ColumnEntry) object);
}
return entries;
}
/**
* @return selected columns index(s) from the tree viewer
*/
private List<Integer> getColumnIndexesFromTreeNodes() {
Object[] nodes = ((TreeSelection) this.treeViewer.getSelection()).toArray();
List<Integer> indexes = new ArrayList<>();
for (Object object : nodes) {
Node node = (Node) object;
if (Type.COLUMN == node.getType()) {
indexes.add(Integer.parseInt(node.getData()));
}
}
return indexes;
}
public void refresh(List<ColumnEntry> hiddenColumnEntries, List<ColumnEntry> visibleColumnsEntries) {
this.hiddenColumnEntries = hiddenColumnEntries;
this.visibleColumnsEntries = visibleColumnsEntries;
populateAvailableTree();
populateSelectedList();
if (ObjectUtils.isNotNull(this.lastListSelection)) {
this.listViewer.setSelection(this.lastListSelection);
}
}
}