/*******************************************************************************
* Copyright (c) 2013 AGETO Service GmbH 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:
* Gunnar Wagenknecht - initial API and implementation
*******************************************************************************/
package org.eclipse.gyrex.admin.ui.internal.widgets;
import org.eclipse.gyrex.admin.ui.internal.application.AdminUiUtil;
import org.eclipse.gyrex.admin.ui.pages.AdminPage;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ColumnLayoutData;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.IOpenListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.apache.commons.lang.StringUtils;
public abstract class AdminPageWithTree extends AdminPage {
private final class ChangeSortColumnListener extends SelectionAdapter {
/** serialVersionUID */
private static final long serialVersionUID = 1L;
private final SortableColumnsComparator comparator;
private final TreeViewerColumn column;
private final int sortIndex;
private ChangeSortColumnListener(final SortableColumnsComparator comparator, final int sortIndex, final TreeViewerColumn column) {
this.comparator = comparator;
this.sortIndex = sortIndex;
this.column = column;
}
@Override
public void widgetSelected(final SelectionEvent e) {
if (comparator.getColumn() == sortIndex) {
comparator.setReverse(!comparator.isReverse());
} else {
comparator.setColumn(sortIndex);
treeViewer.getTree().setSortColumn(column.getColumn());
}
treeViewer.getTree().setSortDirection(comparator.isReverse() ? SWT.UP : SWT.DOWN);
treeViewer.refresh();
}
}
private final class SortableColumnsComparator extends ViewerComparator {
/** serialVersionUID */
private static final long serialVersionUID = 1L;
private int column;
private boolean reverse;
public SortableColumnsComparator() {
super();
}
@Override
@SuppressWarnings("unchecked")
public int compare(final Viewer viewer, final Object e1, final Object e2) {
final int c1 = getElementCategory(e1, getColumn());
final int c2 = getElementCategory(e2, getColumn());
if (c1 != c2)
return c1 - c2;
final String t1 = StringUtils.trimToEmpty(getElementLabel(e1, getColumn()));
final String t2 = StringUtils.trimToEmpty(getElementLabel(e2, getColumn()));
if (isReverse())
return getComparator().compare(t2, t1);
else
return getComparator().compare(t1, t2);
}
public int getColumn() {
return column;
}
public boolean isReverse() {
return reverse;
}
public void setColumn(final int column) {
this.column = column;
// setting an index resets the reverse flag
reverse = false;
}
public void setReverse(final boolean reverse) {
this.reverse = reverse;
}
}
protected static final int NO_COLUMN = -1;
private final int numberOfColumns;
private Composite composite;
private TreeViewer treeViewer;
private ISelectionChangedListener updateButtonsListener;
public AdminPageWithTree(final int numberOfColumns) {
this.numberOfColumns = numberOfColumns;
}
@Override
public void activate() {
super.activate();
if (treeViewer == null)
return;
treeViewer.setInput(getViewerInput());
updateButtonsListener = new ISelectionChangedListener() {
@Override
public void selectionChanged(final SelectionChangedEvent event) {
updateButtons();
}
};
treeViewer.addSelectionChangedListener(updateButtonsListener);
internalRefresh();
}
protected Button createButton(final Composite parent, final String buttonLabel) {
final Button b = new Button(parent, SWT.NONE);
b.setText(buttonLabel);
b.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
return b;
}
protected abstract void createButtons(final Composite parent);
protected Label createButtonSeparator(final Composite parent) {
final Label separator = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL);
separator.setVisible(false);
final GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
gd.heightHint = 4;
separator.setLayoutData(gd);
return separator;
}
protected abstract ITreeContentProvider createContentProvider();
@Override
public Control createControl(final Composite parent) {
composite = new Composite(parent, SWT.NONE);
composite.setLayout(AdminUiUtil.createGridLayoutWithoutMargin(1, false));
final Control header = createHeader(composite);
if (header != null) {
final GridData gd = AdminUiUtil.createHorzFillData();
gd.verticalIndent = 10;
header.setLayoutData(gd);
if ((composite.getChildren().length != 1) || (header != composite.getChildren()[0]))
throw new IllegalStateException("Please wrap header into its own composite!");
}
final Composite treeContainerWithButtons = new Composite(composite, SWT.NONE);
final GridData gd = AdminUiUtil.createFillData();
gd.verticalIndent = 10;
treeContainerWithButtons.setLayoutData(gd);
treeContainerWithButtons.setLayout(AdminUiUtil.createGridLayoutWithoutMargin(2, false));
final Control filteredTree = createTree(treeContainerWithButtons);
filteredTree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
final Composite buttons = new Composite(treeContainerWithButtons, SWT.NONE);
buttons.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, false, true));
buttons.setLayout(GridLayoutFactory.fillDefaults().create());
createButtons(buttons);
return composite;
}
protected abstract Control createHeader(Composite parent);
protected void createMetricSeparator(final Composite area) {
final Label separator = new Label(area, SWT.SEPARATOR | SWT.VERTICAL);
separator.setData(RWT.CUSTOM_VARIANT, "line-separator");
final GridData gd = new GridData(SWT.CENTER, SWT.FILL, false, false);
gd.widthHint = 24;
separator.setLayoutData(gd);
}
protected Label createMetricText(final Composite parent, final String description) {
final Composite metricParent = new Composite(parent, SWT.NONE);
metricParent.setLayout(GridLayoutFactory.fillDefaults().spacing(0, 0).create());
final Label metricLabel = new Label(metricParent, SWT.RIGHT);
metricLabel.setData(RWT.CUSTOM_VARIANT, "text-xxlarge");
metricLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
final Label descLabel = new Label(metricParent, SWT.RIGHT);
descLabel.setText(description);
descLabel.setData(RWT.CUSTOM_VARIANT, "text-large");
descLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
return metricLabel;
}
protected PatternFilter createPatternFilter() {
if (getNumberOfColumns() == 0) {
final PatternFilter patternFilter = new PatternFilter() {
private static final long serialVersionUID = 1L;
@Override
protected boolean isLeafMatch(final Viewer viewer, final Object element) {
return wordMatches(getElementTextForFiltering(element, NO_COLUMN));
}
};
patternFilter.setIncludeLeadingWildcard(true);
return patternFilter;
} else {
final PatternFilter patternFilter = new PatternFilter() {
private static final long serialVersionUID = 1L;
@Override
protected boolean isLeafMatch(final Viewer viewer, final Object element) {
for (int i = 0; i < getNumberOfColumns(); i++) {
if (wordMatches(getElementTextForFiltering(element, i)))
return true;
}
return false;
}
};
patternFilter.setIncludeLeadingWildcard(true);
return patternFilter;
}
}
protected FilteredTree createTree(final Composite parent) {
final FilteredTree filteredTree = new FilteredTree(parent, SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI, createPatternFilter(), true);
treeViewer = filteredTree.getViewer();
treeViewer.getTree().setHeaderVisible(true);
treeViewer.getTree().setData(RWT.MARKUP_ENABLED, Boolean.TRUE);
final TableLayout layout = new TableLayout();
treeViewer.getTree().setLayout(layout);
treeViewer.setUseHashlookup(true);
treeViewer.setContentProvider(createContentProvider());
final SortableColumnsComparator comparator = new SortableColumnsComparator();
treeViewer.setComparator(comparator);
treeViewer.addOpenListener(new IOpenListener() {
@Override
public void open(final OpenEvent event) {
openSelectedElement();
}
});
treeViewer.setLabelProvider(new ColumnLabelProvider() {
private static final long serialVersionUID = 1L;
@Override
public Image getImage(final Object element) {
return getElementImage(element, NO_COLUMN);
}
@Override
public String getText(final Object element) {
return StringUtils.trimToEmpty(getElementLabel(element, NO_COLUMN));
}
});
// create columns
final int columns = getNumberOfColumns();
for (int i = 0; i < columns; i++) {
final int column = i;
final TreeViewerColumn viewerColumn = new TreeViewerColumn(treeViewer, SWT.LEFT);
viewerColumn.getColumn().setText(getColumnLabel(column));
viewerColumn.setLabelProvider(new ColumnLabelProvider() {
/** serialVersionUID */
private static final long serialVersionUID = 1L;
@Override
public Image getImage(final Object element) {
return getElementImage(element, column);
}
@Override
public String getText(final Object element) {
return StringUtils.trimToEmpty(getElementLabel(element, column));
}
});
final ColumnLayoutData layoutData = getColumnLayoutData(column);
if (layoutData != null) {
layout.addColumnData(layoutData);
}
if (isColumnSortable(column)) {
viewerColumn.getColumn().addSelectionListener(new ChangeSortColumnListener(comparator, column, viewerColumn));
if (treeViewer.getTree().getSortColumn() == null) {
// make the fist sortable column the active sort column
treeViewer.getTree().setSortColumn(viewerColumn.getColumn());
treeViewer.getTree().setSortDirection(comparator.isReverse() ? SWT.UP : SWT.DOWN);
}
}
}
return filteredTree;
}
@Override
public void deactivate() {
super.deactivate();
if (treeViewer != null) {
if (updateButtonsListener != null) {
treeViewer.removeSelectionChangedListener(updateButtonsListener);
updateButtonsListener = null;
}
if (!treeViewer.getTree().isDisposed()) {
treeViewer.setInput(null);
}
}
}
protected abstract String getColumnLabel(final int column);
protected ColumnLayoutData getColumnLayoutData(final int column) {
switch (column) {
case 0:
case 1:
return new ColumnWeightData(30, 50);
default:
return new ColumnWeightData(10, 50);
}
}
protected int getElementCategory(final Object element, final int column) {
return 0;
}
protected Image getElementImage(final Object element, final int column) {
return null;
}
protected abstract String getElementLabel(final Object element, final int column);
protected String getElementTextForFiltering(final Object element, final int column) {
return getElementLabel(element, column);
}
protected String getElementTextForSorting(final Object element, final int column) {
return getElementLabel(element, column);
}
protected final int getNumberOfColumns() {
return numberOfColumns;
}
protected TreeViewer getTreeViewer() {
return treeViewer;
}
protected abstract Object getViewerInput();
final void internalRefresh() {
refresh();
treeViewer.refresh();
updateButtons();
}
protected boolean isColumnSortable(final int column) {
return true;
}
protected void openSelectedElement() {
// no-op
}
protected void refresh() {
// no-op
}
protected abstract void updateButtons();
}