blob: 387b9341943d0694a9dfe06a982541510aa78197 [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2003, 2008 IBM Corporation 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:
* IBM Corporation - initial API and implementation
****************************************************************************/
package org.eclipse.gmf.runtime.diagram.ui.dialogs.sortfilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.Assert;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.UnexecutableCommand;
import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.ListCompartmentEditPart;
import org.eclipse.gmf.runtime.diagram.ui.internal.dialogs.sortfilter.SortFilterContentProvider;
import org.eclipse.gmf.runtime.diagram.ui.internal.dialogs.sortfilter.SortFilterDialog;
import org.eclipse.gmf.runtime.diagram.ui.internal.l10n.DiagramUIPluginImages;
import org.eclipse.gmf.runtime.diagram.ui.l10n.DiagramUIMessages;
import org.eclipse.gmf.runtime.diagram.ui.requests.ChangeSortFilterRequest;
import org.eclipse.gmf.runtime.notation.Filtering;
import org.eclipse.gmf.runtime.notation.FilteringStyle;
import org.eclipse.gmf.runtime.notation.NotationPackage;
import org.eclipse.gmf.runtime.notation.Sorting;
import org.eclipse.gmf.runtime.notation.SortingDirection;
import org.eclipse.gmf.runtime.notation.SortingStyle;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.jface.preference.PreferenceManager;
import org.eclipse.jface.preference.PreferenceNode;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.CheckboxCellEditor;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
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.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.PropertyPage;
/**
* SortFilterPage extends <code>PropertyPage</code> by adding a Table and
* Filter controls for SortFilterPage.CHILD_PAGE types and only a Filter control
* for SortFilterPage.ROOT_PAGE types.
*
* @author jcorchis
*/
public class SortFilterPage extends PropertyPage {
/** Menu strings */
static final private String MOVE_UP_TOOL_TIP = DiagramUIMessages.SortFilter_moveItemUp;
static final private String MOVE_DOWN_TOOL_TIP = DiagramUIMessages.SortFilter_moveItemDown;
/** filter list labels */
static private final String FILTER_ITEMS_CONTAINING = DiagramUIMessages.SortFilter_filterItemsListLabel;
static private final String FILTER_ITEMS_LIST = DiagramUIMessages.SortFilter_fitlerListLabel;
/** Tool tips and labels for the filter buttons */
static private final String ADD_TO = DiagramUIMessages.SortFilter_addTo;
private final String ADD_TO_LABEL = "<"; //$NON-NLS-1$
static private final String REMOVE_FROM = DiagramUIMessages.SortFilter_removeFrom;
private final String REMOVE_FROM_LABEL = ">"; //$NON-NLS-1$
static private final String ADD_ALL = DiagramUIMessages.SortFilter_addAll;
private final String ADD_ALL_LABEL = "<<"; //$NON-NLS-1$
static private final String REMOVE_ALL = DiagramUIMessages.SortFilter_removeAll;
private final String REMOVE_ALL_LABEL = ">>"; //$NON-NLS-1$
/** the collection's elements (rows) */
private List elementCollection = null;
private List baseElements = null;
/** table viewer */
private TableViewer tableViewer = null;
/** ToolItem widgets */
private ToolItem moveUpToolItem = null;
private ToolItem moveDownToolItem = null;
/** List item widgets */
private org.eclipse.swt.widgets.List filterList = null;
private org.eclipse.swt.widgets.List filters = null;
private Button addTo = null;
private Button removeFrom = null;
private Button addAllTo = null;
private Button removeAllFrom = null;
/** Filter button IDs */
private final int ADD_TO_ID = 0;
private final int REMOVE_FROM_ID = 1;
private final int ADD_ALL_TO_ID = 2;
private final int REMOVE_ALL_FROM_ID = 3;
/** Height (in list items) for the filter items lists */
private int LIST_HEIGHT = 8;
/** The collection Column list for this page */
private List collectionColumns = null;
private SortFilterLabelProvider labelProvider = null;
private Map filterMap = null;
private String[] filterStrings = null;
private String filterAppliesTo = null;
private Sorting _sorting = Sorting.NONE_LITERAL;
private List _sortedObjects = Collections.EMPTY_LIST;
private Map _sortingKeys = Collections.EMPTY_MAP;
private String _sortColumn;
private SortingDirection _sortingDirection = SortingDirection.ASCENDING_LITERAL;
private Filtering _filtering = Filtering.NONE_LITERAL;
private List _filteredObjects = Collections.EMPTY_LIST;
private List _filteringKeys = Collections.EMPTY_LIST;
private List elementCollectionBackUp = Collections.EMPTY_LIST;
private Sorting _sortingBackUp = _sorting;
private Filtering _filteringBackUp = _filtering;
/**
* List of items that are shown as an alternate view. This is a list of
* EE that are shown as an alternate view.
* (e.g. an attribute shown as an association). These are not to appear
* in the dialog at all so the user cannot filter/unfilter them.
*/
private List _shownAsAlternateViewItems = Collections.EMPTY_LIST;
private GraphicalEditPart editPart = null;
/**
* the root page
*/
public static final String ROOT_PAGE = "root_page"; //$NON-NLS-1$
/**
* the child page
*/
public static final String CHILD_PAGE = "child_page"; //$NON-NLS-1$
private String pageType;
/**
* Constructor for a Sort/Filter page.
* @param pageType either ROOT_PAGE or CHILD_PAGE
* @param editPart an instance of <code>ListCompartmentEditPart</code>. Null for ROOT_PAGE types.
* @param collectionColumns a list of <code>SortFilterColumns</code> that define
* the Sort/Filter table. Null for ROOT_PAGE types
* @param labelProvider <code>SorFilterLabelProvider</code> which provides the data for the table
*/
public SortFilterPage(
String pageType,
GraphicalEditPart editPart,
List collectionColumns,
SortFilterLabelProvider labelProvider) {
this.pageType = pageType;
this.editPart = editPart;
if (pageType.equals(CHILD_PAGE)) {
Assert.isTrue(editPart instanceof ListCompartmentEditPart);
Assert.isTrue(labelProvider != null);
// Loads the current state for the sorting/filtering
tokenizeSortProperty();
tokenizeFilterProperty();
}
this.collectionColumns = collectionColumns;
this.labelProvider = labelProvider;
}
/**
* Adds the filter list and the table for the Table's input.
* @param ancestor the parent <code>Composite</code>
* @see org.eclipse.jface.preference.PreferencePage#createContents(Composite)
*/
protected Control createContents(Composite ancestor) {
if (pageType == ROOT_PAGE)
noDefaultAndApplyButton();
// setup layout
Composite parent = new Composite(ancestor, SWT.NULL);
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.numColumns = 2;
parent.setLayout(layout);
// setup child widgets
if (filterStrings != null && filterStrings.length != 0)
createFilterLists(parent);
if (this.pageType == CHILD_PAGE) {
createTable(parent);
createToolBar(parent);
// set focus and selection
if (elementCollection != null && !elementCollection.isEmpty()) {
// set the selection to the first row
tableViewer.setSelection(
new StructuredSelection(elementCollection.get(0)));
}
if (_filtering == Filtering.AUTOMATIC_LITERAL)
refreshList();
tableViewer.getTable().setFocus();
handleSelection();
}
if (ROOT_PAGE.equals(pageType)) {
PlatformUI.getWorkbench().getHelpSystem().setHelp(ancestor,
"org.eclipse.gmf.runtime.diagram.ui.egmf0400"); //$NON-NLS-1$
} else {
PlatformUI.getWorkbench().getHelpSystem().setHelp(ancestor,
"org.eclipse.gmf.runtime.diagram.ui.egmf0500"); //$NON-NLS-1$
}
return parent;
}
/**
* Creates the filtering list widgets
* @param ancestor the ancestor
*/
private void createFilterLists(Composite ancestor) {
// Do not show the filter lists if not filter criteria
// is defined.
if (filterStrings.length == 0)
return;
//setup layout
Composite parent = new Composite(ancestor, SWT.NULL);
Composite dummy = new Composite(ancestor, SWT.NULL);
GridData dgd = new GridData();
dgd.widthHint = 0;
dummy.setLayoutData(dgd);
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.numColumns = 3;
parent.setLayout(layout);
// Create the possible filter items list
Label filterItemsLabel = new Label(parent, SWT.LEFT);
filterItemsLabel.setText(FILTER_ITEMS_CONTAINING);
GridData gd = new GridData();
gd.horizontalAlignment = GridData.HORIZONTAL_ALIGN_BEGINNING;
filterItemsLabel.setLayoutData(gd);
// Create the possible filter items list
//Label emptyLabel =
new Label(parent, SWT.LEFT);
// Create the possible filter items list
Label filterItemLabel = new Label(parent, SWT.LEFT);
filterItemLabel.setText(FILTER_ITEMS_LIST);
GridData gd2 = new GridData();
gd2.horizontalAlignment = GridData.BEGINNING;
filterItemLabel.setLayoutData(gd2);
// Create the possible filter items list
filters =
new org.eclipse.swt.widgets.List(
parent,
SWT.MULTI | SWT.BORDER | SWT.V_SCROLL);
GridData gridData = new GridData(GridData.VERTICAL_ALIGN_FILL);
gridData.verticalSpan = 1;
gridData.widthHint = 80;
int listHeight = filters.getItemHeight() * LIST_HEIGHT;
Rectangle trim = filters.computeTrim(0, 0, 0, listHeight);
gridData.heightHint = trim.height;
filters.setLayoutData(gridData);
// Create a new composite for the buttons and add
// stack them vertically
Composite buttonComposite = new Composite(parent, SWT.NULL);
GridLayout buttonLayout = new GridLayout();
buttonLayout.marginHeight = 0;
buttonLayout.marginWidth = 0;
buttonLayout.numColumns = 1;
buttonComposite.setLayout(buttonLayout);
GridData buttGD =
new GridData(GridData.FILL_VERTICAL | GridData.CENTER);
buttGD.horizontalSpan = 1;
buttGD.widthHint = 30;
buttonComposite.setLayoutData(buttGD);
removeFrom = new Button(buttonComposite, SWT.PUSH);
removeFrom.setText(REMOVE_FROM_LABEL);
removeFrom.setToolTipText(REMOVE_FROM);
removeFrom.setLayoutData(makeArrowButtonGridData(removeFrom));
removeFrom.setData(new Integer(REMOVE_FROM_ID));
removeFrom.addSelectionListener(buttonSelectionAdapter);
removeFrom.setEnabled(false);
addTo = new Button(buttonComposite, SWT.PUSH);
addTo.setText(ADD_TO_LABEL);
addTo.setToolTipText(ADD_TO);
addTo.setLayoutData(makeArrowButtonGridData(addTo));
addTo.setData(new Integer(ADD_TO_ID));
addTo.addSelectionListener(buttonSelectionAdapter);
addTo.setEnabled(false);
removeAllFrom = new Button(buttonComposite, SWT.PUSH);
removeAllFrom.setText(REMOVE_ALL_LABEL);
removeAllFrom.setToolTipText(REMOVE_ALL);
removeAllFrom.setLayoutData(makeArrowButtonGridData(removeAllFrom));
removeAllFrom.setData(new Integer(REMOVE_ALL_FROM_ID));
removeAllFrom.addSelectionListener(buttonSelectionAdapter);
addAllTo = new Button(buttonComposite, SWT.PUSH);
addAllTo.setText(ADD_ALL_LABEL);
addAllTo.setToolTipText(ADD_ALL);
addAllTo.setLayoutData(makeArrowButtonGridData(addAllTo));
addAllTo.setData(Integer.valueOf(ADD_ALL_TO_ID));
addAllTo.addSelectionListener(buttonSelectionAdapter);
// Add the possible list of filter items
this.filterList =
new org.eclipse.swt.widgets.List(
parent,
SWT.MULTI | SWT.BORDER | SWT.V_SCROLL);
GridData gridData2 = new GridData(GridData.VERTICAL_ALIGN_FILL);
gridData2.verticalSpan = 1;
gridData2.widthHint = 80;
int listHeight2 = filterList.getItemHeight() * LIST_HEIGHT;
Rectangle trim2 = filterList.computeTrim(0, 0, 0, listHeight2);
gridData.heightHint = trim2.height;
filterList.setLayoutData(gridData2);
filters.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
removeFrom.setEnabled(filters.getSelectionCount() > 0);
}
});
filterList.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
addTo.setEnabled(filterList.getSelectionCount() > 0);
}
});
populateFilterLists();
}
/**
* SelectionAdapter for the filtering buttons. Calls <code>buttonPressed()</code>
* to handle the action.
*
* @author jcorchis
*/
class ButtonSelectionAdapter extends SelectionAdapter {
public void widgetSelected(SelectionEvent event) {
buttonPressed(((Integer) event.widget.getData()).intValue());
}
}
/** Instance of the ButtonSelectionAdapter used for all filtering buttons. */
private ButtonSelectionAdapter buttonSelectionAdapter =
new ButtonSelectionAdapter();
/**
* Creates GridData for the moveup and movedown toolbar buttons.
* @param control button
* @return the <code>GridData</code>
*/
protected GridData makeArrowButtonGridData(Control control) {
GC gc = new GC(control);
gc.setFont(control.getFont());
//fill horizontal to make them all the same size
GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
gridData.heightHint = 24;
gc.dispose();
return gridData;
}
/**
* Handles the button pressed event on the filter criteria. Move the items
* between the lists based on the selection and but button pressed.
*/
private void buttonPressed(int buttonId) {
String[] items = {
};
switch (buttonId) {
case ADD_TO_ID :
items = filterList.getSelection();
for (int i = 0; i < items.length; i++) {
filters.add(items[i]);
filterList.remove(items[i]);
}
addTo.setEnabled(false);
break;
case REMOVE_FROM_ID :
items = filters.getSelection();
for (int i = 0; i < items.length; i++) {
filterList.add(items[i]);
filters.remove(items[i]);
}
removeFrom.setEnabled(false);
break;
case ADD_ALL_TO_ID :
items = filterList.getItems();
for (int i = 0; i < items.length; i++) {
filters.add(items[i]);
filterList.remove(items[i]);
}
break;
case REMOVE_ALL_FROM_ID :
items = filters.getItems();
for (int i = 0; i < items.length; i++) {
filters.remove(items[i]);
filterList.add(items[i]);
}
break;
}
updateFilteringKeysFromControls();
if (pageType == CHILD_PAGE) {
refreshList();
} else if (pageType == ROOT_PAGE) {
PreferenceManager preferenceManager =
((SortFilterDialog) getContainer()).getPreferenceManager();
Iterator nodes =
preferenceManager
.getElements(PreferenceManager.PRE_ORDER)
.iterator();
while (nodes.hasNext()) {
PreferenceNode node = (PreferenceNode) nodes.next();
SortFilterPage page = (SortFilterPage) node.getPage();
if (page == this) {
continue;
}
if (Arrays.equals(filterStrings, page.getFilterList())) {
page._filteringKeys = new ArrayList(_filteringKeys.size());
page._filteringKeys.addAll(_filteringKeys);
page._filtering = _filtering;
page.populateFilterLists();
page.refreshList();
page.updateApplyButton();
}
}
}
updateApplyButton();
}
/**
* Helper method which returns an <code>String[]</code> of column names
* which some of the TableViewer class expects.
* @return the String[] of column names
*/
private String[] getColumnProperties() {
String[] columnProperties =
new String[tableViewer.getColumnProperties().length];
Object[] columnNames = tableViewer.getColumnProperties();
for (int i = 0; i < columnNames.length; i++) {
columnProperties[i] = (String) columnNames[i];
}
return columnProperties;
}
private void updateFilteringKeysFromControls() {
String[] theFilterStrings = filters.getItems();
if (theFilterStrings.length == 0) {
_filtering = Filtering.NONE_LITERAL;
_filteringKeys = Collections.EMPTY_LIST;
} else {
_filtering = Filtering.AUTOMATIC_LITERAL;
if (_filteringKeys != null) {
_filteringKeys = new ArrayList();
}
for (int i = 0; i < theFilterStrings.length; i++) {
_filteringKeys.add(theFilterStrings[i]);
}
}
}
/**
* Updates the table items to reflect the change in the filtering lists.
*/
void refreshList() {
int filterColumn = findColumnIndexFromProperty(filterAppliesTo);
if (filterColumn == -1)
return;
// Set the matching items in this list as not visible
for (int j = 0; j < elementCollection.size(); j++) {
String cell = labelProvider.getColumnText(elementCollection.get(j),
filterColumn);
((SortFilterElement) elementCollection.get(j))
.setVisible(!_filteringKeys.contains(cell));
}
if (tableViewer != null)
tableViewer.refresh();
}
/**
* Creates table viewer and builds table contents
* @param parent the parent composite
*/
private void createTable(Composite parent) {
tableViewer =
new TableViewer(
parent,
SWT.MULTI
| SWT.FULL_SELECTION
| SWT.H_SCROLL
| SWT.V_SCROLL
| SWT.BORDER);
// setup table widget
tableViewer.setUseHashlookup(true);
Table table = tableViewer.getTable();
table.setHeaderVisible(true);
table.setLinesVisible(true);
GridData data = new GridData(GridData.FILL_BOTH);
data.grabExcessHorizontalSpace = true;
data.grabExcessVerticalSpace = true;
data.horizontalSpan = 1;
data.widthHint = convertWidthInCharsToPixels(30);
table.setLayoutData(data);
table.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
handleSelection();
}
});
// Add the columns to the table
final String[] columnNames = new String[collectionColumns.size()];
int i = 0;
Iterator iter = collectionColumns.iterator();
while (iter.hasNext()) {
SortFilterCollectionColumn columnInfo =
(SortFilterCollectionColumn) iter.next();
TableColumn column =
new TableColumn(table, columnInfo.getAlignment());
column.setText(columnInfo.getCaption());
column.setResizable(columnInfo.isResizable());
column.setWidth(columnInfo.getWidth());
column.setAlignment(columnInfo.getAlignment());
if (columnInfo.getColumnSorter() != null) {
column.addSelectionListener(
new HeaderSelectionListener(
(SortFilterViewerSorter) columnInfo.getColumnSorter(),
tableViewer));
// Intialize the table sorter
if (_sortColumn != null && column.getText().equals(_sortColumn)) {
SortFilterViewerSorter sorter =
(SortFilterViewerSorter) columnInfo.getColumnSorter();
if (sorter != null) {
if (SortingDirection.ASCENDING_LITERAL
.equals(_sortingDirection)) {
// Use the ascending image
Image image = DiagramUIPluginImages.DESC_SORT_ARROW_UP.createImage();
column.setImage(image);
column.pack();
} else if (SortingDirection.DESCENDING_LITERAL
.equals(_sortingDirection)) {
sorter.toggleSortingDirection();
// Use the descending image
Image image = DiagramUIPluginImages.DESC_SORT_ARROW_DN.createImage();
column.setImage(image);
column.pack();
}
}
tableViewer.setSorter(sorter);
}
}
columnNames[i++] = columnInfo.getCaption();
}
// setup table viewer
tableViewer.setContentProvider(new SortFilterContentProvider());
if (labelProvider != null)
tableViewer.setLabelProvider(labelProvider);
tableViewer.setColumnProperties(columnNames);
tableViewer.setCellModifier(new SortFilterCellModifier());
// Can only changes the first column - the visible column
CellEditor[] editors = new CellEditor[collectionColumns.size()];
editors[0] = new CheckboxCellEditor(table);
for (i = 1; i < collectionColumns.size(); i++) {
editors[i] = null;
}
tableViewer.setCellEditors(editors);
if (elementCollection != null && !elementCollection.isEmpty())
tableViewer.setInput(elementCollection);
// Update the model
TableItem[] tableItems = tableViewer.getTable().getItems();
List newModel = new ArrayList();
for (i = 0; i < tableItems.length; i++) {
SortFilterElement ey = (SortFilterElement) tableItems[i].getData();
newModel.add(i, ey);
}
tableViewer.setInput(newModel);
elementCollection = newModel;
createBackUp();
// pack column widths
TableColumn[] tableColumns = table.getColumns();
for (i = 0; i < tableColumns.length; i++) {
tableColumns[i].pack();
}
}
/**
* Creates toolbar
* @param ancestor the parent composite
*/
private void createToolBar(Composite ancestor) {
Composite parent = new Composite(ancestor, SWT.NULL);
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.verticalSpacing = 0;
layout.horizontalSpacing = 0;
parent.setLayout(layout);
GridData gridData = new GridData(GridData.VERTICAL_ALIGN_BEGINNING);
parent.setLayoutData(gridData);
//to simulate a vertical toolbar (not possible), create a separate toolbar for each button
ToolBar toolBar = new ToolBar(parent, SWT.FLAT);
Image imageUp = DiagramUIPluginImages.DESC_UP_PATH.createImage();
moveUpToolItem = new ToolItem(toolBar, SWT.PUSH);
moveUpToolItem.setEnabled(false);
moveUpToolItem.setToolTipText(MOVE_UP_TOOL_TIP);
moveUpToolItem.setImage(imageUp);
moveUpToolItem.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
moveUpElements();
}
});
ToolBar toolBarDown = new ToolBar(parent, SWT.FLAT);
Image imageDown = DiagramUIPluginImages.DESC_DOWN_PATH.createImage();
moveDownToolItem = new ToolItem(toolBarDown, SWT.PUSH);
moveDownToolItem.setEnabled(false);
moveDownToolItem.setToolTipText(MOVE_DOWN_TOOL_TIP);
moveDownToolItem.setImage(imageDown);
moveDownToolItem.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
moveDownElements();
}
});
}
/**
* Move up the selected items from the table
*/
private void moveUpElements() {
int c = tableViewer.getTable().getSelectionCount();
if (c == 0)
return;
int[] selectionIndexes = tableViewer.getTable().getSelectionIndices();
List model = (ArrayList) ((ArrayList) tableViewer.getInput());
for (int i = 0; i < selectionIndexes.length; i++) {
SortFilterElement element =
(SortFilterElement) model.get(selectionIndexes[i] - 1);
model.set(selectionIndexes[i] - 1, model.get(selectionIndexes[i]));
model.set(selectionIndexes[i], element);
}
tableViewer.setSorter(null);
tableViewer.refresh();
_sorting = isSameOrder(elementCollection, baseElements) ? Sorting.NONE_LITERAL
: Sorting.MANUAL_LITERAL;
_sortingKeys = Collections.EMPTY_MAP;
handleSelection();
updateApplyButton();
}
/**
* Move down the selected items from the table
*/
private void moveDownElements() {
int selectionCount = tableViewer.getTable().getSelectionCount();
if (selectionCount == 0)
return;
List model = (ArrayList) ((ArrayList) tableViewer.getInput());
int[] selectionIndexes = tableViewer.getTable().getSelectionIndices();
for (int i = selectionIndexes.length - 1; i >= 0; i--) {
SortFilterElement element =
(SortFilterElement) model.get(selectionIndexes[i] + 1);
model.set(selectionIndexes[i] + 1, model.get(selectionIndexes[i]));
model.set(selectionIndexes[i], element);
}
tableViewer.setSorter(null);
tableViewer.refresh();
_sorting = isSameOrder(elementCollection, baseElements) ? Sorting.NONE_LITERAL
: Sorting.MANUAL_LITERAL;
_sortingKeys = Collections.EMPTY_MAP;
handleSelection();
updateApplyButton();
}
/**
* Compares two sort filter element lists based on the equality of data fields
* only.
* @param elements1 <code>List</code> of sort filter elements
* @param elements2 <code>List</code> of sort filter elements
* @return <code>true</code> if both lists are e
*/
private boolean isSameOrder(List elements1, List elements2) {
Iterator itr1 = elements1.iterator();
Iterator itr2 = elements2.iterator();
while (itr1.hasNext() && itr2.hasNext()) {
SortFilterElement element1 = (SortFilterElement)itr1.next();
SortFilterElement element2 = (SortFilterElement)itr2.next();
if (!element1.getData().equals(element2.getData()))
return false;
}
return !itr1.hasNext() && !itr2.hasNext();
}
/**
* The table viewer selection has changed. Update the toolbar and menu enablements
*/
private void handleSelection() {
ISelection selection = tableViewer.getSelection();
if (selection == null
|| !(selection instanceof IStructuredSelection)) {
return;
}
IStructuredSelection structuredSelection =
(IStructuredSelection) selection;
List selectionList = structuredSelection.toList();
boolean selectionEmpty = structuredSelection.isEmpty();
boolean firstRowSelected = true;
boolean lastRowSelected = true;
if (!selectionEmpty) {
SortFilterElement element =
(SortFilterElement) selectionList.get(0);
if (tableViewer.getElementAt(0).equals(element)) {
firstRowSelected = true;
} else {
firstRowSelected = false;
}
element =
(SortFilterElement) selectionList.get(selectionList.size() - 1);
if (tableViewer
.getElementAt(tableViewer.getTable().getItemCount() - 1)
.equals(element)) {
lastRowSelected = true;
} else {
lastRowSelected = false;
}
}
if (moveUpToolItem != null) {
moveUpToolItem.setEnabled(!firstRowSelected && !selectionEmpty);
}
if (moveDownToolItem != null) {
moveDownToolItem.setEnabled(!lastRowSelected && !selectionEmpty);
}
}
/**
* Used to populate to
* @return the list used to populate the possible filter list
*/
private String[] getFilterList() {
return filterStrings;
}
/**
*
* @param filterMap
* @param property
*/
public void setFilter(Map filterMap, String property) {
if (filterMap != null) {
this.filterMap = filterMap;
Object[] filterArray = filterMap.keySet().toArray();
this.filterStrings = new String[filterArray.length];
for (int i = 0; i < filterArray.length; i++) {
filterStrings[i] = (String) filterArray[i];
}
this.filterAppliesTo = property;
}
}
/**
* find the column index using a property
* @param property the proerty to use
* @return the column index
*/
private int findColumnIndexFromProperty(String property) {
for (int i = 0; i < collectionColumns.size(); i++) {
if (((SortFilterCollectionColumn)collectionColumns.get(i)).getCaption().equals(property))
return i;
}
return -1;
}
/**
* Sets the input for the table.
* @param sortFilterElements the semantic children for thie <code>IView</code>
*/
public void setInput(List sortFilterElements) {
// Remove elements that are not to be shown in the dialog at all.
List updatedSortFilterElements = new ArrayList();
for (Iterator iter = sortFilterElements.iterator(); iter.hasNext();) {
SortFilterElement element = (SortFilterElement) iter.next();
updatedSortFilterElements.add(element);
}
// Cache the provided elements for the Reset Default button
baseElements = new ArrayList(updatedSortFilterElements.size());
for (Iterator itr = updatedSortFilterElements.iterator(); itr.hasNext();) {
baseElements.add(new SortFilterElement(((SortFilterElement)itr.next()).getData()));
}
// For the manual Ahoc sorting and filtering we manually initialize the
// items
if (_filtering == Filtering.MANUAL_LITERAL) {
// Use the list of filtered items to initialize the table.
// Any new items will not be filtered.
if (!updatedSortFilterElements.isEmpty()) {
if (_filteredObjects != null && _filteredObjects.size() > 0) {
for (int i = 0; i < _filteredObjects.size(); i++) {
EObject eObject = (EObject)_filteredObjects.get(i);
for (int j = 0; j < updatedSortFilterElements.size(); j++) {
SortFilterElement element = (SortFilterElement) updatedSortFilterElements
.get(j);
if (eObject.equals(element.getData())) {
element.setVisible(false);
}
}
}
}
}
}
if (_sorting == Sorting.MANUAL_LITERAL) { // Add hoc sorting
if (!updatedSortFilterElements.isEmpty()) {
if (_sortedObjects != null && _sortedObjects.size() > 0) {
// Order the elements by the specified index
elementCollection =
new ArrayList(updatedSortFilterElements.size());
for (int i = 0; i < _sortedObjects.size(); i++) {
EObject element = (EObject) _sortedObjects.get(i);
for (int j = 0; j < updatedSortFilterElements.size(); j++) {
SortFilterElement e = (SortFilterElement) updatedSortFilterElements
.get(j);
if (element.equals(e.getData())) {
elementCollection.add(e);
}
}
}
// Add any new children to the end of the list
// so they will appear at the botton of the
// list compartment
List missingElements = new ArrayList(updatedSortFilterElements);
missingElements.removeAll(elementCollection);
elementCollection.addAll(missingElements);
}
}
} else { // Use semantic order
elementCollection = updatedSortFilterElements;
}
createBackUp();
}
/**
*
* @param sortFilterElements
* @param hiddenContents
*/
public void setContents(List sortFilterElements, List hiddenContents) {
setInput(sortFilterElements);
// Cache the items not to be shown in the dialog, but are otherwise filtered.
this._shownAsAlternateViewItems = hiddenContents;
}
/**
* Resets all element to visible and uses the model storage
* ordering for the sorting.
*/
protected void performDefaults() {
_filtering = Filtering.NONE_LITERAL;
_filteredObjects = Collections.EMPTY_LIST;
// Reset the filter list if they exist
if (filterStrings != null) {
if (!_filteringKeys.isEmpty()) {
_filteringKeys = Collections.EMPTY_LIST;
populateFilterLists();
}
}
_sorting = Sorting.NONE_LITERAL;
_sortingKeys = Collections.EMPTY_MAP;
_sortedObjects = Collections.EMPTY_LIST;
tableViewer.setSorter(null);
TableColumn[] columns = tableViewer.getTable().getColumns();
for (int i = 0; i < columns.length; i++) {
columns[i].setImage(null);
}
List input = (List)tableViewer.getInput();
input.clear();
for (int i=0; i<baseElements.size(); i++) {
input.add(new SortFilterElement( ((SortFilterElement)baseElements.get(i)).getData() ));
}
tableViewer.refresh();
updateApplyButton();
}
/**
* Writes the sorting/filtering specified by the dialog
*/
protected void performApply() {
Command sortAndFilteringCommand = getApplyCommand();
if (sortAndFilteringCommand != null
&& sortAndFilteringCommand.canExecute()) {
editPart.getRoot().getViewer().getEditDomain().getCommandStack()
.execute(sortAndFilteringCommand);
createBackUp();
}
updateApplyButton();
}
/**
* Creates the command that needs to be executed for this page when "Ok" is
* pressed. It's different from {@link #getApplyCommand()}, because it checks
* whether the page is dirty or not.
* @return <code>Command</code> to be executed per this page
*/
public Command getCommand() {
if (isDirty())
return getApplyCommand();
return null;
}
/**
* Returns a <code>Command</code> that set both the sorting and filtering
* for this particular list compartment.
*
* @return the command
*/
public Command getApplyCommand() {
Command cmd = UnexecutableCommand.INSTANCE;
if (CHILD_PAGE.equals(pageType)) {
List newSortedObjects = Collections.EMPTY_LIST;
if (_sorting.equals(Sorting.MANUAL_LITERAL)) {
newSortedObjects = new ArrayList();
for (Iterator itr = elementCollection.iterator(); itr.hasNext();) {
SortFilterElement element = (SortFilterElement) itr.next();
newSortedObjects.add(element.getData());
}
}
List newFilteredObjects = Collections.EMPTY_LIST;
if (_filtering.equals(Filtering.MANUAL_LITERAL)) {
newFilteredObjects = new ArrayList();
for (Iterator itr = elementCollection.iterator(); itr.hasNext();) {
SortFilterElement element = (SortFilterElement) itr.next();
if (!element.isVisible()) {
newFilteredObjects.add(element.getData());
}
}
if (_filtering.equals(Filtering.MANUAL_LITERAL) && newFilteredObjects.size() == 0) {
_filtering = Filtering.NONE_LITERAL;
}
}
// Add the objects filtered otherwise.
if (!_shownAsAlternateViewItems.isEmpty()
&& Collections.EMPTY_LIST.equals(newFilteredObjects)) {
newFilteredObjects = new ArrayList();
}
newFilteredObjects.addAll(_shownAsAlternateViewItems);
ChangeSortFilterRequest request = new ChangeSortFilterRequest(
_filtering, newFilteredObjects, _filteringKeys, _sorting,
newSortedObjects, _sortingKeys);
cmd = editPart.getCommand(request);
}
return cmd;
}
/**
* Populates the filter lists based on the _filteringKeys
* and the filter criteria.
*/
private void populateFilterLists() {
if (filterMap != null && !filterMap.isEmpty() && filterList != null && filters != null) {
filterList.removeAll();
filters.removeAll();
Set keySet = filterMap.keySet();
Iterator i = keySet.iterator();
if (_filtering == Filtering.AUTOMATIC_LITERAL) {
// Set the values of the filtered and unfiltered string
while (i.hasNext()) {
String filterString = (String) i.next();
if (_filteringKeys.contains(filterString)) {
filters.add(filterString);
} else {
filterList.add(filterString);
}
}
} else {
// Add all filter strings to the possible filter list
while (i.hasNext()) {
String filterString = (String) i.next();
filterList.add(filterString);
}
}
}
}
/**
* Caches ID_FILTERING, ID_FILTERED_OBJECTS and ID_FILTERING_KEYS values for local access.
*/
private void tokenizeFilterProperty() {
Object model = editPart.getModel();
if (model instanceof View){
View view = (View)model;
FilteringStyle style = (FilteringStyle) view.getStyle(NotationPackage.eINSTANCE.getFilteringStyle());
if (style != null) {
_filtering = style.getFiltering();
_filteredObjects = style.eIsSet(NotationPackage.eINSTANCE.getFilteringStyle_FilteredObjects())
? new ArrayList(style.getFilteredObjects())
: Collections.EMPTY_LIST;
_filteringKeys = style.eIsSet(NotationPackage.eINSTANCE.getFilteringStyle_FilteringKeys())
? new ArrayList(style.getFilteringKeys())
: Collections.EMPTY_LIST;
}
}
}
/**
* Caches ID_SORTING, ID_SORTED_OBJECTS and ID_SORTING_KEYS values for local access.
*/
private void tokenizeSortProperty() {
Object model = editPart.getModel();
if (model instanceof View){
View view = (View)model;
SortingStyle style = (SortingStyle)view.getStyle(NotationPackage.eINSTANCE.getSortingStyle());
if (style != null) {
_sorting = style.getSorting();
_sortedObjects = style.eIsSet(NotationPackage.eINSTANCE.getSortingStyle_SortedObjects())
? new ArrayList(style.getSortedObjects())
: Collections.EMPTY_LIST;
_sortingKeys = style.eIsSet(NotationPackage.eINSTANCE.getSortingStyle_SortingKeys())
? new HashMap(style.getSortingKeys())
: Collections.EMPTY_MAP;
// Currently, only one sorting column can be defined.
if (_sortingKeys.size() > 0) {
Set keySet = _sortingKeys.keySet();
Iterator iter = keySet.iterator();
if (iter.hasNext()) {
_sortColumn = (String) iter.next();
_sortingDirection = (SortingDirection) _sortingKeys.get(_sortColumn);
}
}
}
}
}
/**
* SortFilterCellModifiers. Simple cell modifiers for the first column only
*
* @author jcorchis
*/
public class SortFilterCellModifier implements ICellModifier {
/**
* Only allows the visibility property to be modified.
* @see org.eclipse.jface.viewers.ICellModifier#canModify(java.lang.Object, java.lang.String)
*/
public boolean canModify(Object element, String property) {
int columnIndex = findPropertyIndex(property);
if (columnIndex == 0) {
return true;
}
return true;
}
/**
* Gets the value of the table's cell.
* @param element the SortFilterElement
* @param property the table property
* @return the cell's value
* @see org.eclipse.jface.viewers.ICellModifier#getValue(java.lang.Object, java.lang.String)
*/
public Object getValue(Object element, String property) {
SortFilterElement item = (SortFilterElement) element;
// Find the index of the column
Object result = null;
int columnIndex = findPropertyIndex(property);
if (columnIndex == 0) {
result = Boolean.valueOf(item.isVisible());
}
return result;
}
/**
* Modifies the visibility of the compartment item.
* @param element the SortFilterElement
* @param property the table property
* @param value the cell's new value
* @see org.eclipse.jface.viewers.ICellModifier#modify(java.lang.Object, java.lang.String, java.lang.Object)
*/
public void modify(Object element, String property, Object value) {
boolean newValue = ((Boolean) value).booleanValue();
TableItem tableItem = (TableItem) element;
SortFilterElement item = (SortFilterElement) tableItem.getData();
int columnIndex = findPropertyIndex(property);
if (columnIndex == 0) {
TableItem[] tableItems = tableViewer.getTable().getItems();
for (int j = 0; j < tableItems.length; j++) {
SortFilterElement data =
(SortFilterElement) tableItems[j].getData();
if (data.equals(item)) {
(
(SortFilterElement) tableViewer.getElementAt(
j)).setVisible(
newValue);
tableViewer.update(
new Object[] { tableViewer.getElementAt(j)},
new String[] { getColumnProperties()[0] });
}
}
tableViewer.update(
new Object[] { element },
new String[] { getColumnProperties()[0] });
// Remove all the filtering criteria since the user
// is filtering in an ad hoc manner
if (filterStrings != null) {
String[] items = filters.getItems();
for (int i = 0; i < items.length; i++) {
filterList.add(items[i]);
filters.remove(items[i]);
}
}
_filteringKeys = Collections.EMPTY_LIST;
_filtering = newValue ? Filtering.NONE_LITERAL : Filtering.MANUAL_LITERAL;
if (newValue) {
Iterator itr = elementCollection.iterator();
while (itr.hasNext()) {
if (!baseElements.contains(itr.next())) {
_filtering = Filtering.MANUAL_LITERAL;
break;
}
}
}
updateApplyButton();
}
}
/**
* Maps the column property to the index the property appears.
* @param property the column property
* @return the appearance index of the property
*/
private int findPropertyIndex(String property) {
Object[] columnNames = tableViewer.getColumnProperties();
for (int i = 0; i < columnNames.length; i++) {
if (((String) columnNames[i]).equals(property))
return i;
}
return -1;
}
}
/**
* <code>SelectionListener</code> implementation for selection on the Table's column
* headers. Header selection event will sort the table by the column selected,
* both ascending and descending, as well as insert the an image in the selected column
* header to indicate the sort order. This listener treats both a single and double clicks
* as the same to support different OS selection firing.
*
* @author jcorchis
*/
class HeaderSelectionListener implements SelectionListener {
private SortFilterViewerSorter sorter;
private TableViewer _tableViewer;
/**
* Constructor for the HeaderSelectionListener
* @param sorter the <code>TableViewer</code> sorter
* @param tableViewer the <code>TableViewer</code>
*/
public HeaderSelectionListener(
SortFilterViewerSorter sorter,
TableViewer tableViewer) {
this.sorter = sorter;
_tableViewer = tableViewer;
}
/* (non-Javadoc)
* @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
*/
public void widgetSelected(SelectionEvent e) {
// Handle click to sort
handleEvent(e);
}
/* (non-Javadoc)
* @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent)
*/
public void widgetDefaultSelected(SelectionEvent e) {
// Handle double click to sort
handleEvent(e);
}
private void handleEvent(SelectionEvent e) {
// Clear any existing header images
TableColumn[] columns = _tableViewer.getTable().getColumns();
for (int i = 0; i < columns.length; i++) {
columns[i].setImage(null);
}
// Add the image based on the sort
int columnIndex = 0;
if (e.widget instanceof TableColumn) {
TableColumn column = (TableColumn) e.widget;
columnIndex = findColumnIndexFromProperty(column.getText());
if (columnIndex != -1) {
Image image = null;
SortFilterViewerSorter newSorter =
(SortFilterViewerSorter) _tableViewer.getSorter();
if (newSorter != null) {
newSorter.toggleSortingDirection();
if (newSorter == null
|| SortingDirection.ASCENDING_LITERAL
.equals(newSorter.getSortingDirection())) {
// Use the ascending image
image = DiagramUIPluginImages.DESC_SORT_ARROW_UP
.createImage();
} else {
// Use the descending image
image = DiagramUIPluginImages.DESC_SORT_ARROW_DN
.createImage();
}
columns[columnIndex].setImage(image);
}
}
}
if (sorter != null) {
// Does the actual sorting
_tableViewer.setSorter(null);
// Necessary to use ascending/descending sorting
_tableViewer.setSorter(getSorter());
// Update the model
TableItem[] tableItems = _tableViewer.getTable().getItems();
List newModel = new ArrayList();
for (int i = 0; i < tableItems.length; i++) {
SortFilterElement ey =
(SortFilterElement) tableItems[i].getData();
newModel.add(i, ey);
}
elementCollection.clear();
elementCollection.addAll(newModel);
_tableViewer.refresh();
_sorting = Sorting.AUTOMATIC_LITERAL;
Object[] columnNames = tableViewer.getColumnProperties();
if (_sortingKeys != Collections.EMPTY_MAP) {
_sortingKeys.clear();
} else {
_sortingKeys = new HashMap();
}
_sortingKeys.put(columnNames[columnIndex], getSorter().getSortingDirection());
handleSelection();
updateApplyButton();
}
}
/**
* gets the sorter
* @return the sorter
*/
public SortFilterViewerSorter getSorter() {
return sorter;
}
}
/**
* Method to allow the ROOT page to set the possible filter
* items for this page.
* @param filterCriteriaList
*/
void setFilterCriteria(String[] filterCriteriaList) {
filters.setItems(filterCriteriaList);
}
/**
* Checks whether this page is filtering it's contents.
* @return <code>true</code> if this page is filtering it's contents.
*/
boolean isFiltering() {
return filterStrings == null ? false : (filters.getItems().length != 0);
}
/**
* Method to allows the ROOT page to set the filter criteria of a CHILD page.
* @param criteriaList the filter criteria
*/
void setCriteria(String[] criteriaList) {
filterList.setItems(criteriaList);
}
/* (non-Javadoc)
* @see org.eclipse.jface.preference.PreferencePage#updateApplyButton()
*/
protected void updateApplyButton() {
if (getApplyButton() != null)
getApplyButton().setEnabled(isValid() && isDirty());
}
/* (non-Javadoc)
* @see org.eclipse.jface.preference.PreferencePage#createControl(org.eclipse.swt.widgets.Composite)
*/
public void createControl(Composite parent) {
super.createControl(parent);
updateApplyButton();
}
/**
* Determines whether the page contains changes that can be applied.
* @return <code>true</code> if page is dirty
*/
protected boolean isDirty() {
if (pageType == ROOT_PAGE
|| _filteringBackUp != _filtering
|| _sortingBackUp != _sorting)
return true;
return !elementCollection.equals(elementCollectionBackUp);
}
/**
* Creates the back up of the initial data to determine whether the page
* has applicable changes later on.
*/
private void createBackUp() {
_filteringBackUp = _filtering;
_sortingBackUp = _sorting;
elementCollectionBackUp = new ArrayList(elementCollection.size());
for (Iterator itr = elementCollection.iterator(); itr.hasNext();) {
SortFilterElement element = (SortFilterElement) itr.next();
elementCollectionBackUp.add(new SortFilterElement(element
.isVisible(), element.getData()));
}
}
}