Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas FAUVERGUE2016-12-06 09:21:54 +0000
committerNicolas FAUVERGUE2016-12-06 09:21:54 +0000
commit61c8cacddb76080de3b0b7fec39c7f754a17c3d5 (patch)
tree9c10095a92a991aa00783bc38a423204f5af6804 /plugins
parent8b188c061b4173a396a0f2addb590246326bf75e (diff)
downloadorg.eclipse.papyrus-61c8cacddb76080de3b0b7fec39c7f754a17c3d5.tar.gz
org.eclipse.papyrus-61c8cacddb76080de3b0b7fec39c7f754a17c3d5.tar.xz
org.eclipse.papyrus-61c8cacddb76080de3b0b7fec39c7f754a17c3d5.zip
Bug 502559: [Table] Improve performances of nested filtering
https://bugs.eclipse.org/bugs/show_bug.cgi?id=502559 To improve the performance of filtering: - Don't clear all the filter list to recreate it - For this, we need more information in matchers and matcher editors - Correct a problem in the StringMatcherEditorFactory when the cell is not displayed (it can be possible for the relaxed filtering). Change-Id: Ieb045ac8ecec7b235186f315ea7120e1797046f5 Signed-off-by: Nicolas FAUVERGUE <nicolasfauvergue@gmail.com>
Diffstat (limited to 'plugins')
-rwxr-xr-xplugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/dataprovider/FilterRowDataProvider.java1161
-rwxr-xr-xplugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/filter/AbstractSinglePapyrusMatcher.java235
-rwxr-xr-xplugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/filter/PapyrusFilterStrategy.java163
-rw-r--r--plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/filter/PapyrusThresholdMatcherEditor.java96
-rwxr-xr-xplugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/filter/RegexFindEditor.java104
-rwxr-xr-xplugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/filter/StringMatcherEditorFactory.java159
6 files changed, 1150 insertions, 768 deletions
diff --git a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/dataprovider/FilterRowDataProvider.java b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/dataprovider/FilterRowDataProvider.java
index 75ba4fda298..aea60457151 100755
--- a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/dataprovider/FilterRowDataProvider.java
+++ b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/dataprovider/FilterRowDataProvider.java
@@ -1,580 +1,581 @@
-/*******************************************************************************
- * 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.papyrus.infra.nattable.dataprovider;
-
-
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.eclipse.emf.common.command.Command;
-import org.eclipse.emf.common.command.CompoundCommand;
-import org.eclipse.emf.edit.command.DeleteCommand;
-import org.eclipse.emf.transaction.TransactionalEditingDomain;
-import org.eclipse.nebula.widgets.nattable.NatTable;
-import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
-import org.eclipse.nebula.widgets.nattable.data.IDataProvider;
-import org.eclipse.nebula.widgets.nattable.data.convert.IDisplayConverter;
-import org.eclipse.nebula.widgets.nattable.filterrow.FilterRowDataLayer;
-import org.eclipse.nebula.widgets.nattable.filterrow.IFilterStrategy;
-import org.eclipse.nebula.widgets.nattable.filterrow.event.FilterAppliedEvent;
-import org.eclipse.nebula.widgets.nattable.layer.ILayer;
-import org.eclipse.nebula.widgets.nattable.persistence.IPersistable;
-import org.eclipse.nebula.widgets.nattable.style.DisplayMode;
-import org.eclipse.nebula.widgets.nattable.util.ObjectUtils;
-import org.eclipse.papyrus.infra.nattable.filter.IFilterValueToMatchManager;
-import org.eclipse.papyrus.infra.nattable.filter.configuration.IFilterConfiguration;
-import org.eclipse.papyrus.infra.nattable.manager.table.INattableModelManager;
-import org.eclipse.papyrus.infra.nattable.manager.table.NattableModelManager;
-import org.eclipse.papyrus.infra.nattable.model.nattable.nattableaxis.IAxis;
-import org.eclipse.papyrus.infra.nattable.model.nattable.nattablestyle.NattablestylePackage;
-import org.eclipse.papyrus.infra.nattable.model.nattable.nattablestyle.Style;
-import org.eclipse.papyrus.infra.nattable.utils.NattableConfigAttributes;
-import org.eclipse.papyrus.infra.nattable.utils.TableEditingDomainUtils;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Display;
-
-
-/**
- * Data provider for the filter row
- * <ul>
- * <li>Stores filter strings</li>
- * <li>Applies them to the ca.odell.glazedlists.matchers.MatcherEditor on the ca.odell.glazedlists.FilterList</li>
- * </ul>
- *
- * Duplicated and adapted code from nattable
- */
-public class FilterRowDataProvider<T> implements IDataProvider /* , IPersistable */ {
-
- /**
- * Replacement for the pipe character | that is used for persistence.
- * If regular expressions are used for filtering, the pipe character can be used
- * in the regular expression to specify alternations. As the persistence
- * mechanism in NatTable uses the pipe character for separation of values,
- * the persistence breaks for such cases.
- * By replacing the pipe in the regular expression with some silly uncommon
- * value specified here, we ensure to be able to also persist pipes in the
- * regular expressions, aswell as being backwards compatible with already
- * saved filter row states.
- */
- public static final String PIPE_REPLACEMENT = "°~°"; //$NON-NLS-1$
-
- /**
- * The prefix String that will be used to mark that the following filter
- * value in the persisted state is a collection.
- */
- public static final String FILTER_COLLECTION_PREFIX = "°coll("; //$NON-NLS-1$
-
- /**
- * The {@link IFilterStrategy} to which the set filter value should be applied.
- */
- private final IFilterStrategy<T> filterStrategy;
- /**
- * The column header layer where this {@link IDataProvider} is used for filtering.
- * Needed for retrieval of column indexes and firing according filter events.
- */
- private final ILayer columnHeaderLayer;
- /**
- * The {@link IDataProvider} of the column header.
- * This is necessary to retrieve the real column count of the column header and not a
- * transformed one. (e.g. hiding a column would change the column count in the column header
- * but not in the column header {@link IDataProvider}).
- */
- private final IDataProvider columnHeaderDataProvider;
-
- // /**
- // * The {@link IConfigRegistry} needed to retrieve the {@link IDisplayConverter} for converting
- // * the values on state save/load operations.
- // */
- // private final IConfigRegistry configRegistry;
-
- private final INattableModelManager manager;
- /**
- * Contains the filter objects mapped to the column index.
- * Basically the data storage for the set filters in the filter row so they are
- * visible to the user who entered them.
- */
- private Map<Integer, Object> filterIndexToObjectMap = new HashMap<Integer, Object>();
-
- private Runnable refreshFilterRunnable;
-
- /* Flag to avoid reentrant call to refresh */
- private AtomicBoolean isFilterRefreshing = new AtomicBoolean(false);
-
- // private ResourceSetListener listener;
-
-
- /**
- *
- * @param filterStrategy
- * The {@link IFilterStrategy} to which the set filter value should be applied.
- * @param columnHeaderLayer
- * The column header layer where this {@link IDataProvider} is used for filtering
- * needed for retrieval of column indexes and firing according filter events..
- * @param columnHeaderDataProvider
- * The {@link IDataProvider} of the column header needed to retrieve the real
- * column count of the column header and not a transformed one.
- * @param tableManager
- * The {@link IConfigRegistry} needed to retrieve the {@link IDisplayConverter} for
- * converting the values on state save/load operations.
- */
- public FilterRowDataProvider(IFilterStrategy<T> filterStrategy, ILayer columnHeaderLayer, IDataProvider columnHeaderDataProvider, INattableModelManager tableManager) {
- this.filterStrategy = filterStrategy;
- this.columnHeaderLayer = columnHeaderLayer;
- this.columnHeaderDataProvider = columnHeaderDataProvider;
- this.manager = tableManager;
- // TransactionalEditingDomain domain = TableEditingDomainUtils.getTableEditingDomain(this.manager.getTable());
- // listener = new ResourceSetListener() {
- //
- // @Override
- // public Command transactionAboutToCommit(ResourceSetChangeEvent event) throws RollbackException {
- // // TODO Auto-generated method stub
- // return null;
- // }
- //
- // @Override
- // public void resourceSetChanged(ResourceSetChangeEvent event) {
- // // TODO Auto-generated method stub
- // for (Notification current : event.getNotifications()) {
- // if (current.getNotifier() instanceof IAxis) {
- // IAxis axis = (IAxis) current.getNotifier();
- // EObject parent = axis.eContainer();
- // if (current.getOldValue() instanceof NamedStyle) {
- // NamedStyle style = (NamedStyle) current.getOldValue();
- // if (style.getName().equals(IFilterConfiguration.FILTER_VALUE_TO_MATCH)) {
- // int index = manager.getColumnElementsList().indexOf(axis);
- // getDataValue(index, 0);
- // applyFilter();
- // }
- // }
- // if (current.getNewValue() instanceof NamedStyle) {
- // NamedStyle style = (NamedStyle) current.getOldValue();
- // if (style.getName().equals(IFilterConfiguration.FILTER_VALUE_TO_MATCH)) {
- // int index = manager.getColumnElementsList().indexOf(axis);
- // getDataValue(index, 0);
- // applyFilter();
- // }
- // }
- // }
- //
- // }
- //
- // }
- //
- // @Override
- // public boolean isPrecommitOnly() {
- // // TODO Auto-generated method stub
- // return false;
- // }
- //
- // @Override
- // public boolean isPostcommitOnly() {
- // // TODO Auto-generated method stub
- // return false;
- // }
- //
- // @Override
- // public boolean isAggregatePrecommitListener() {
- // // TODO Auto-generated method stub
- // return false;
- // }
- //
- // @Override
- // public NotificationFilter getFilter() {
- // // TODO Auto-generated method stub
- // return null;
- // }
- // };
- // domain.addResourceSetListener(listener);
- }
-
- /**
- * Returns the map that contains the filter objects mapped to the column index.
- * It is the data storage for the inserted filters into the filter row by the user.
- * <p>
- * Note: Usually it is not intended to modify this Map directly. You should rather call <code>setDataValue(int, int, Object)</code> or <code>clearAllFilters()</code> to modify this Map to ensure consistency in other framework code. It is made visible
- * because there might be code that needs to modify the Map without index transformations or firing events.
- *
- * @return Map that contains the filter objects mapped to the column index.
- */
- public Map<Integer, Object> getFilterIndexToObjectMap() {
- return this.filterIndexToObjectMap;
- }
-
- /**
- * Set the map that contains the filter objects mapped to the column index to be the
- * data storage for the inserted filters into the filter row by the user.
- * <p>
- * Note: Usually it is not intended to set this Map from the outside as it is created in the constructor. But there might be use cases where you e.g. need to connect filter rows to each other. In this case it might be useful to override the local Map with
- * the one form another FilterRowDataProvider. This is not a typical use case, therefore you should use this method carefully!
- *
- * @param filterIndexToObjectMap
- * Map that contains the filter objects mapped to the column index.
- */
- public void setFilterIndexToObjectMap(Map<Integer, Object> filterIndexToObjectMap) {
- this.filterIndexToObjectMap = filterIndexToObjectMap;
- }
-
- @Override
- public int getColumnCount() {
- return columnHeaderDataProvider.getColumnCount();
- }
-
- public void updateMapValue(int columnIndex) {
- if (manager != null) {
- NatTable natTable = (NatTable) manager.getAdapter(NatTable.class);
- IConfigRegistry configRegistry = natTable.getConfigRegistry();
-
-
- IFilterValueToMatchManager loader = getFilterValueToMatchManager(columnIndex);
- if (loader != null) {
- Object columnObject = manager.getColumnElement(columnIndex);
- Object savedValue = loader.getValueToMatch(configRegistry, columnObject);
- // to manage undo/redo
- Object mapValue = filterIndexToObjectMap.get(columnIndex);
- if (savedValue != mapValue) {
- if ((mapValue != null && !mapValue.equals(savedValue)) || (savedValue != null && !savedValue.equals(mapValue))) {
- if (savedValue == null) {
- filterIndexToObjectMap.remove(columnIndex);
- } else {
- filterIndexToObjectMap.put(columnIndex, savedValue);
- }
- applyFilter();
- }
- }
- }
- }
- }
-
- @Override
- public Object getDataValue(int columnIndex, int rowIndex) {
- // NatTable natTable = (NatTable) manager.getAdapter(NatTable.class);
- // IConfigRegistry configRegistry = natTable.getConfigRegistry();
- //
- // if (manager != null) {
- // IFilterValueToMatchManager loader = getFilterValueToMatchManager(columnIndex);
- // if (loader != null) {
- // Object columnObject = manager.getColumnElement(columnIndex);
- // Object savedValue = loader.getValueToMatch(configRegistry, columnObject);
- // // to manage undo/redo
- // Object mapValue = filterIndexToObjectMap.get(columnIndex);
- // if (savedValue != mapValue) {
- // if ((mapValue != null && !mapValue.equals(savedValue)) || (savedValue != null && !savedValue.equals(mapValue))) {
- // if (savedValue == null) {
- // filterIndexToObjectMap.remove(columnIndex);
- // } else {
- // filterIndexToObjectMap.put(columnIndex, savedValue);
- // }
- // applyFilter();
- //
- // }
- // }
- // }
- // }
-
- return filterIndexToObjectMap.get(columnIndex);
- }
-
- /**
- * refresh the view.
- */
- protected void refreshFilterInUIThread() {
- NatTable natTable = getNatTable();
- // Need to refresh, even if (temporarily) invisible
- // (Better alternative?: store refresh event and execute once visible again)
- if (natTable != null && natTable.isDisposed()) {
- return;
- }
-
- // avoid reentrant call
- // Refresh only of we are not already refreshing.
- if (isFilterRefreshing.compareAndSet(false, true)) {
- filterStrategy.applyFilter(filterIndexToObjectMap);
- columnHeaderLayer.fireLayerEvent(new FilterAppliedEvent(columnHeaderLayer));
- isFilterRefreshing.set(false);
- }
- }
-
-
-
- /**
- *
- * @return
- * a new runnable for the refreash action
- */
- private Runnable createRefreshFilterRunnable() {
- return new Runnable() {
-
- @Override
- public void run() {
- // Only run if I'm still pending
- synchronized (this) {
- if (refreshFilterRunnable != this) {
- return;
- }
-
- refreshFilterRunnable = null;
- }
- refreshFilterInUIThread();
- ((NattableModelManager) manager).refreshNatTable();
- }
- };
- }
-
- private NatTable getNatTable() {
- return (NatTable) manager.getAdapter(NatTable.class);
- }
-
- public void applyFilter() {
- // This refresh code has been duplicated from the refresh of the ModelExplorer (class ModelExplorerView)
- final Runnable schedule;
- NatTable natTable = getNatTable();
- if (natTable != null && !natTable.isDisposed()) {
- synchronized (this) {
- if (refreshFilterRunnable == null) {
- // No refresh is yet pending. Schedule one
- schedule = createRefreshFilterRunnable();
- refreshFilterRunnable = schedule;
- } else {
- schedule = null;
- }
- }
-
- if (schedule != null) {
- Control control = natTable;
- Display display = ((control == null) || control.isDisposed()) ? null : control.getDisplay();
-
- if (display != null) {
- // Don't need to schedule a refresh if we have no control or it's disposed
- display.asyncExec(schedule);
- }
- }
- }
- }
-
-
-
- @Override
- public int getRowCount() {
- return 1;
- }
-
- @Override
- public void setDataValue(int columnIndex, int rowIndex, Object newValue) {
- columnIndex = columnHeaderLayer.getColumnIndexByPosition(columnIndex);
- // INattableModelManager manager = configRegistry.getConfigAttribute(NattableConfigAttributes.NATTABLE_MODEL_MANAGER_CONFIG_ATTRIBUTE, DisplayMode.NORMAL, NattableConfigAttributes.NATTABLE_MODEL_MANAGER_ID);
- if (manager != null) {
- NatTable natTable = (NatTable) manager.getAdapter(NatTable.class);
- IConfigRegistry configRegistry = natTable.getConfigRegistry();
-
- IFilterValueToMatchManager loader = getFilterValueToMatchManager(columnIndex);
- if (loader != null) {
- Object columnObject = manager.getColumnElement(columnIndex);
- loader.saveValueToMatch(configRegistry, columnObject, newValue);
- }
- }
- if (ObjectUtils.isNotNull(newValue)) {
- filterIndexToObjectMap.put(columnIndex, newValue);
- } else {
- filterIndexToObjectMap.remove(columnIndex);
- }
-
- filterStrategy.applyFilter(filterIndexToObjectMap);
-
- columnHeaderLayer.fireLayerEvent(new FilterAppliedEvent(columnHeaderLayer));
- }
-
- /**
- *
- * @param columnIndex
- * the index of the column
- * @return
- * the filter value to match manager to use
- */
- private IFilterValueToMatchManager getFilterValueToMatchManager(int columnIndex) {
- StringBuilder builder = new StringBuilder();
- builder.append(FilterRowDataLayer.FILTER_ROW_COLUMN_LABEL_PREFIX);
- builder.append(Integer.valueOf(columnIndex));
- return getConfigRegistry().getConfigAttribute(NattableConfigAttributes.FILTER_VALUE_TO_MATCH_MANAGER, DisplayMode.NORMAL, builder.toString());
- }
-
- /**
- *
- * @return
- * the config registry to used by the nattable widget
- */
- private IConfigRegistry getConfigRegistry() {
- NatTable natTable = (NatTable) this.manager.getAdapter(NatTable.class);
- return natTable.getConfigRegistry();
- }
-
- // Load/save state
- //
- // @Override
- // public void saveState(String prefix, Properties properties) {
- // Map<Integer, String> filterTextByIndex = new HashMap<Integer, String>();
- // for(Integer columnIndex : filterIndexToObjectMap.keySet()) {
- // final IDisplayConverter converter = configRegistry.getConfigAttribute(
- // CellConfigAttributes.DISPLAY_CONVERTER,
- // DisplayMode.NORMAL,
- // FilterRowDataLayer.FILTER_ROW_COLUMN_LABEL_PREFIX + columnIndex);
- //
- // String filterText = getFilterStringRepresentation(filterIndexToObjectMap.get(columnIndex), converter);
- // filterText = filterText.replace("|", PIPE_REPLACEMENT); //$NON-NLS-1$
- // filterTextByIndex.put(columnIndex, filterText);
- // }
- //
- // String string = PersistenceUtils.mapAsString(filterTextByIndex);
- //
- // if (!isEmpty(string)) {
- // properties.put(prefix + FilterRowDataLayer.PERSISTENCE_KEY_FILTER_ROW_TOKENS, string);
- // }
- // }
-
- // @Override
- // public void loadState(String prefix, Properties properties) {
- // filterIndexToObjectMap.clear();
- //
- // try {
- // Object property = properties.get(prefix + FilterRowDataLayer.PERSISTENCE_KEY_FILTER_ROW_TOKENS);
- // Map<Integer, String> filterTextByIndex = PersistenceUtils.parseString(property);
- // for (Integer columnIndex : filterTextByIndex.keySet()) {
- // final IDisplayConverter converter = configRegistry.getConfigAttribute(
- // CellConfigAttributes.DISPLAY_CONVERTER,
- // DisplayMode.NORMAL,
- // FilterRowDataLayer.FILTER_ROW_COLUMN_LABEL_PREFIX + columnIndex);
- //
- // String filterText = filterTextByIndex.get(columnIndex);
- // filterText = filterText.replace(PIPE_REPLACEMENT, "|"); //$NON-NLS-1$
- // filterIndexToObjectMap.put(columnIndex, getFilterFromString(filterText, converter));
- // }
- // } catch (Exception e) {
- // log.error("Error while restoring filter row text!", e); //$NON-NLS-1$
- // }
-
- // filterStrategy.applyFilter(filterIndexToObjectMap);
- // }
-
- /**
- * This method is used to support saving of a filter collection, e.g. in the context of the
- * Excel like filter row. In such cases the filter value is not a simple String but a
- * Collection of filter values that need to be converted to a String representation.
- * As the state persistence is encapsulated to be handled here, we need to take care
- * of such states here also.
- *
- * @param filterValue
- * The filter value object that is used for filtering.
- * @param converter
- * The converter that is used to convert the filter value, which is necessary
- * to support filtering of custom types.
- * @return The String representation of the filter value.
- */
- private String getFilterStringRepresentation(Object filterValue, IDisplayConverter converter) {
- // in case the filter value is a collection of values, we need to create a special
- // string representation
- if (filterValue instanceof Collection) {
- String collectionSpec = FILTER_COLLECTION_PREFIX + filterValue.getClass().getName() + ")"; //$NON-NLS-1$
- StringBuilder builder = new StringBuilder(collectionSpec);
- builder.append("["); //$NON-NLS-1$
- Collection<?> filterCollection = (Collection<?>) filterValue;
- for (Iterator<?> iterator = filterCollection.iterator(); iterator.hasNext();) {
- Object filterObject = iterator.next();
- builder.append(converter.canonicalToDisplayValue(filterObject));
- if (iterator.hasNext())
- builder.append(IPersistable.VALUE_SEPARATOR);
- }
-
- builder.append("]"); //$NON-NLS-1$
- return builder.toString();
- }
- return (String) converter.canonicalToDisplayValue(filterValue);
- }
-
- /**
- * This method is used to support loading of a filter collection, e.g. in the context of the
- * Excel like filter row. In such cases the saved filter value is not a simple String but
- * represents a Collection of filter values that need to be converted to the corresponding values.
- * As the state persistence is encapsulated to be handled here, we need to take care
- * of such states here also.
- *
- * @param filterText
- * The String representation of the applied saved filter.
- * @param converter
- * The converter that is used to convert the filter value, which is necessary
- * to support filtering of custom types.
- * @return The filter value that will be used to apply a filter to the IFilterStrategy
- *
- * @throws InstantiationException
- * @throws IllegalAccessException
- * @throws ClassNotFoundException
- */
- @SuppressWarnings({ "rawtypes", "unchecked" })
- private Object getFilterFromString(String filterText, IDisplayConverter converter) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
- if (filterText.startsWith(FILTER_COLLECTION_PREFIX)) {
- // the filter text represents a collection
- int indexEndCollSpec = filterText.indexOf(")"); //$NON-NLS-1$
- String collectionSpec = filterText.substring(filterText.indexOf("(") + 1, indexEndCollSpec); //$NON-NLS-1$
- Collection filterCollection = (Collection) Class.forName(collectionSpec).newInstance();
-
- // also get rid of the collection marks
- filterText = filterText.substring(indexEndCollSpec + 2, filterText.length() - 1);
- String[] filterSplit = filterText.split(IPersistable.VALUE_SEPARATOR);
- for (String filterString : filterSplit) {
- filterCollection.add(converter.displayToCanonicalValue(filterString));
- }
-
- return filterCollection;
- }
- return converter.displayToCanonicalValue(filterText);
- }
-
- /**
- * Clear all filters that are currently applied.
- */
- public void clearAllFilters() {
- filterIndexToObjectMap.clear();
- filterStrategy.applyFilter(filterIndexToObjectMap);
-
- // we clear the filter
- if (manager != null) {
- CompoundCommand cc = new CompoundCommand("Clear All Filter"); //$NON-NLS-1$
- TransactionalEditingDomain domain = TableEditingDomainUtils.getTableEditingDomain(manager.getTable());
- List<?> columnElement = manager.getColumnElementsList();
- for (Object current : columnElement) {
- if (current instanceof IAxis) {
- Style idToDestroy = ((IAxis) current).getNamedStyle(NattablestylePackage.eINSTANCE.getStringValueStyle(), IFilterConfiguration.FILTER_SYSTEM_ID);
- Style keyToDestroy = ((IAxis) current).getNamedStyle(NattablestylePackage.eINSTANCE.getStyle(), IFilterConfiguration.FILTER_FORCED_BY_USER_ID);
-
- if (idToDestroy != null) {
- Command cmd = DeleteCommand.create(domain, idToDestroy);
- if (cmd != null && cmd.canExecute()) {
- cc.append(cmd);
- }
- }
- if (idToDestroy != null) {
- Command cmd = DeleteCommand.create(domain, keyToDestroy);
- if (cmd != null && cmd.canExecute()) {
- cc.append(cmd);
- }
- }
- }
- }
- if (!cc.isEmpty() && cc.canExecute()) {
- domain.getCommandStack().execute(cc);
- }
- }
-
- }
-}
+/*******************************************************************************
+ * 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.papyrus.infra.nattable.dataprovider;
+
+
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.command.CompoundCommand;
+import org.eclipse.emf.edit.command.DeleteCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.nebula.widgets.nattable.NatTable;
+import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
+import org.eclipse.nebula.widgets.nattable.data.IDataProvider;
+import org.eclipse.nebula.widgets.nattable.data.convert.IDisplayConverter;
+import org.eclipse.nebula.widgets.nattable.filterrow.FilterRowDataLayer;
+import org.eclipse.nebula.widgets.nattable.filterrow.IFilterStrategy;
+import org.eclipse.nebula.widgets.nattable.filterrow.event.FilterAppliedEvent;
+import org.eclipse.nebula.widgets.nattable.layer.ILayer;
+import org.eclipse.nebula.widgets.nattable.persistence.IPersistable;
+import org.eclipse.nebula.widgets.nattable.style.DisplayMode;
+import org.eclipse.nebula.widgets.nattable.util.ObjectUtils;
+import org.eclipse.papyrus.infra.nattable.filter.IFilterValueToMatchManager;
+import org.eclipse.papyrus.infra.nattable.filter.configuration.IFilterConfiguration;
+import org.eclipse.papyrus.infra.nattable.manager.table.INattableModelManager;
+import org.eclipse.papyrus.infra.nattable.manager.table.NattableModelManager;
+import org.eclipse.papyrus.infra.nattable.model.nattable.nattableaxis.IAxis;
+import org.eclipse.papyrus.infra.nattable.model.nattable.nattablestyle.NattablestylePackage;
+import org.eclipse.papyrus.infra.nattable.model.nattable.nattablestyle.Style;
+import org.eclipse.papyrus.infra.nattable.utils.NattableConfigAttributes;
+import org.eclipse.papyrus.infra.nattable.utils.TableEditingDomainUtils;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+
+
+/**
+ * Data provider for the filter row
+ * <ul>
+ * <li>Stores filter strings</li>
+ * <li>Applies them to the ca.odell.glazedlists.matchers.MatcherEditor on the ca.odell.glazedlists.FilterList</li>
+ * </ul>
+ *
+ * Duplicated and adapted code from nattable
+ */
+public class FilterRowDataProvider<T> implements IDataProvider /* , IPersistable */ {
+
+ /**
+ * Replacement for the pipe character | that is used for persistence.
+ * If regular expressions are used for filtering, the pipe character can be used
+ * in the regular expression to specify alternations. As the persistence
+ * mechanism in NatTable uses the pipe character for separation of values,
+ * the persistence breaks for such cases.
+ * By replacing the pipe in the regular expression with some silly uncommon
+ * value specified here, we ensure to be able to also persist pipes in the
+ * regular expressions, aswell as being backwards compatible with already
+ * saved filter row states.
+ */
+ public static final String PIPE_REPLACEMENT = "°~°"; //$NON-NLS-1$
+
+ /**
+ * The prefix String that will be used to mark that the following filter
+ * value in the persisted state is a collection.
+ */
+ public static final String FILTER_COLLECTION_PREFIX = "°coll("; //$NON-NLS-1$
+
+ /**
+ * The {@link IFilterStrategy} to which the set filter value should be applied.
+ */
+ private final IFilterStrategy<T> filterStrategy;
+ /**
+ * The column header layer where this {@link IDataProvider} is used for filtering.
+ * Needed for retrieval of column indexes and firing according filter events.
+ */
+ private final ILayer columnHeaderLayer;
+ /**
+ * The {@link IDataProvider} of the column header.
+ * This is necessary to retrieve the real column count of the column header and not a
+ * transformed one. (e.g. hiding a column would change the column count in the column header
+ * but not in the column header {@link IDataProvider}).
+ */
+ private final IDataProvider columnHeaderDataProvider;
+
+ // /**
+ // * The {@link IConfigRegistry} needed to retrieve the {@link IDisplayConverter} for converting
+ // * the values on state save/load operations.
+ // */
+ // private final IConfigRegistry configRegistry;
+
+ private final INattableModelManager manager;
+ /**
+ * Contains the filter objects mapped to the column index.
+ * Basically the data storage for the set filters in the filter row so they are
+ * visible to the user who entered them.
+ */
+ private Map<Integer, Object> filterIndexToObjectMap = new HashMap<Integer, Object>();
+
+ private Runnable refreshFilterRunnable;
+
+ /* Flag to avoid reentrant call to refresh */
+ private AtomicBoolean isFilterRefreshing = new AtomicBoolean(false);
+
+ // private ResourceSetListener listener;
+
+
+ /**
+ *
+ * @param filterStrategy
+ * The {@link IFilterStrategy} to which the set filter value should be applied.
+ * @param columnHeaderLayer
+ * The column header layer where this {@link IDataProvider} is used for filtering
+ * needed for retrieval of column indexes and firing according filter events..
+ * @param columnHeaderDataProvider
+ * The {@link IDataProvider} of the column header needed to retrieve the real
+ * column count of the column header and not a transformed one.
+ * @param tableManager
+ * The {@link IConfigRegistry} needed to retrieve the {@link IDisplayConverter} for
+ * converting the values on state save/load operations.
+ */
+ public FilterRowDataProvider(IFilterStrategy<T> filterStrategy, ILayer columnHeaderLayer, IDataProvider columnHeaderDataProvider, INattableModelManager tableManager) {
+ this.filterStrategy = filterStrategy;
+ this.columnHeaderLayer = columnHeaderLayer;
+ this.columnHeaderDataProvider = columnHeaderDataProvider;
+ this.manager = tableManager;
+ // TransactionalEditingDomain domain = TableEditingDomainUtils.getTableEditingDomain(this.manager.getTable());
+ // listener = new ResourceSetListener() {
+ //
+ // @Override
+ // public Command transactionAboutToCommit(ResourceSetChangeEvent event) throws RollbackException {
+ // // TODO Auto-generated method stub
+ // return null;
+ // }
+ //
+ // @Override
+ // public void resourceSetChanged(ResourceSetChangeEvent event) {
+ // // TODO Auto-generated method stub
+ // for (Notification current : event.getNotifications()) {
+ // if (current.getNotifier() instanceof IAxis) {
+ // IAxis axis = (IAxis) current.getNotifier();
+ // EObject parent = axis.eContainer();
+ // if (current.getOldValue() instanceof NamedStyle) {
+ // NamedStyle style = (NamedStyle) current.getOldValue();
+ // if (style.getName().equals(IFilterConfiguration.FILTER_VALUE_TO_MATCH)) {
+ // int index = manager.getColumnElementsList().indexOf(axis);
+ // getDataValue(index, 0);
+ // applyFilter();
+ // }
+ // }
+ // if (current.getNewValue() instanceof NamedStyle) {
+ // NamedStyle style = (NamedStyle) current.getOldValue();
+ // if (style.getName().equals(IFilterConfiguration.FILTER_VALUE_TO_MATCH)) {
+ // int index = manager.getColumnElementsList().indexOf(axis);
+ // getDataValue(index, 0);
+ // applyFilter();
+ // }
+ // }
+ // }
+ //
+ // }
+ //
+ // }
+ //
+ // @Override
+ // public boolean isPrecommitOnly() {
+ // // TODO Auto-generated method stub
+ // return false;
+ // }
+ //
+ // @Override
+ // public boolean isPostcommitOnly() {
+ // // TODO Auto-generated method stub
+ // return false;
+ // }
+ //
+ // @Override
+ // public boolean isAggregatePrecommitListener() {
+ // // TODO Auto-generated method stub
+ // return false;
+ // }
+ //
+ // @Override
+ // public NotificationFilter getFilter() {
+ // // TODO Auto-generated method stub
+ // return null;
+ // }
+ // };
+ // domain.addResourceSetListener(listener);
+ }
+
+ /**
+ * Returns the map that contains the filter objects mapped to the column index.
+ * It is the data storage for the inserted filters into the filter row by the user.
+ * <p>
+ * Note: Usually it is not intended to modify this Map directly. You should rather call <code>setDataValue(int, int, Object)</code> or <code>clearAllFilters()</code> to modify this Map to ensure consistency in other framework code. It is made visible
+ * because there might be code that needs to modify the Map without index transformations or firing events.
+ *
+ * @return Map that contains the filter objects mapped to the column index.
+ */
+ public Map<Integer, Object> getFilterIndexToObjectMap() {
+ return this.filterIndexToObjectMap;
+ }
+
+ /**
+ * Set the map that contains the filter objects mapped to the column index to be the
+ * data storage for the inserted filters into the filter row by the user.
+ * <p>
+ * Note: Usually it is not intended to set this Map from the outside as it is created in the constructor. But there might be use cases where you e.g. need to connect filter rows to each other. In this case it might be useful to override the local Map with
+ * the one form another FilterRowDataProvider. This is not a typical use case, therefore you should use this method carefully!
+ *
+ * @param filterIndexToObjectMap
+ * Map that contains the filter objects mapped to the column index.
+ */
+ public void setFilterIndexToObjectMap(Map<Integer, Object> filterIndexToObjectMap) {
+ this.filterIndexToObjectMap = filterIndexToObjectMap;
+ }
+
+ @Override
+ public int getColumnCount() {
+ return columnHeaderDataProvider.getColumnCount();
+ }
+
+ public void updateMapValue(int columnIndex) {
+ if (manager != null) {
+ NatTable natTable = (NatTable) manager.getAdapter(NatTable.class);
+ IConfigRegistry configRegistry = natTable.getConfigRegistry();
+
+
+ IFilterValueToMatchManager loader = getFilterValueToMatchManager(columnIndex);
+ if (loader != null) {
+ Object columnObject = manager.getColumnElement(columnIndex);
+ Object savedValue = loader.getValueToMatch(configRegistry, columnObject);
+ // to manage undo/redo
+ Object mapValue = filterIndexToObjectMap.get(columnIndex);
+ if (savedValue != mapValue) {
+ if ((mapValue != null && !mapValue.equals(savedValue)) || (savedValue != null && !savedValue.equals(mapValue))) {
+ if (savedValue == null) {
+ filterIndexToObjectMap.remove(columnIndex);
+ } else {
+ filterIndexToObjectMap.put(columnIndex, savedValue);
+ }
+ applyFilter();
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public Object getDataValue(int columnIndex, int rowIndex) {
+ // NatTable natTable = (NatTable) manager.getAdapter(NatTable.class);
+ // IConfigRegistry configRegistry = natTable.getConfigRegistry();
+ //
+ // if (manager != null) {
+ // IFilterValueToMatchManager loader = getFilterValueToMatchManager(columnIndex);
+ // if (loader != null) {
+ // Object columnObject = manager.getColumnElement(columnIndex);
+ // Object savedValue = loader.getValueToMatch(configRegistry, columnObject);
+ // // to manage undo/redo
+ // Object mapValue = filterIndexToObjectMap.get(columnIndex);
+ // if (savedValue != mapValue) {
+ // if ((mapValue != null && !mapValue.equals(savedValue)) || (savedValue != null && !savedValue.equals(mapValue))) {
+ // if (savedValue == null) {
+ // filterIndexToObjectMap.remove(columnIndex);
+ // } else {
+ // filterIndexToObjectMap.put(columnIndex, savedValue);
+ // }
+ // applyFilter();
+ //
+ // }
+ // }
+ // }
+ // }
+
+ return filterIndexToObjectMap.get(columnIndex);
+ }
+
+ /**
+ * refresh the view.
+ */
+ protected void refreshFilterInUIThread() {
+ NatTable natTable = getNatTable();
+ // Need to refresh, even if (temporarily) invisible
+ // (Better alternative?: store refresh event and execute once visible again)
+ if (natTable != null && natTable.isDisposed()) {
+ return;
+ }
+
+ // avoid reentrant call
+ // Refresh only of we are not already refreshing.
+ if (isFilterRefreshing.compareAndSet(false, true)) {
+ filterStrategy.applyFilter(filterIndexToObjectMap);
+ columnHeaderLayer.fireLayerEvent(new FilterAppliedEvent(columnHeaderLayer));
+ // Bug 502559: Remove the filtering refresh to false because it is not
+ // a filter strategy re-construction but only an update
+ }
+ }
+
+ /**
+ *
+ * @return
+ * a new runnable for the refreash action
+ */
+ private Runnable createRefreshFilterRunnable() {
+ return new Runnable() {
+
+ @Override
+ public void run() {
+ // Only run if I'm still pending
+ synchronized (this) {
+ if (refreshFilterRunnable != this) {
+ return;
+ }
+
+ refreshFilterRunnable = null;
+ }
+ refreshFilterInUIThread();
+ ((NattableModelManager) manager).refreshNatTable();
+ }
+ };
+ }
+
+ private NatTable getNatTable() {
+ return (NatTable) manager.getAdapter(NatTable.class);
+ }
+
+ public void applyFilter() {
+ // This refresh code has been duplicated from the refresh of the ModelExplorer (class ModelExplorerView)
+ final Runnable schedule;
+ NatTable natTable = getNatTable();
+ if (natTable != null && !natTable.isDisposed()) {
+ synchronized (this) {
+ if (refreshFilterRunnable == null) {
+ // No refresh is yet pending. Schedule one
+ schedule = createRefreshFilterRunnable();
+ refreshFilterRunnable = schedule;
+ } else {
+ schedule = null;
+ }
+ }
+
+ if (schedule != null) {
+ Control control = natTable;
+ Display display = ((control == null) || control.isDisposed()) ? null : control.getDisplay();
+
+ if (display != null) {
+ // Don't need to schedule a refresh if we have no control or it's disposed
+ display.asyncExec(schedule);
+ }
+ }
+
+ isFilterRefreshing.set(true);
+ }
+ }
+
+
+
+ @Override
+ public int getRowCount() {
+ return 1;
+ }
+
+ @Override
+ public void setDataValue(int columnIndex, int rowIndex, Object newValue) {
+ columnIndex = columnHeaderLayer.getColumnIndexByPosition(columnIndex);
+ // INattableModelManager manager = configRegistry.getConfigAttribute(NattableConfigAttributes.NATTABLE_MODEL_MANAGER_CONFIG_ATTRIBUTE, DisplayMode.NORMAL, NattableConfigAttributes.NATTABLE_MODEL_MANAGER_ID);
+ if (manager != null) {
+ NatTable natTable = (NatTable) manager.getAdapter(NatTable.class);
+ IConfigRegistry configRegistry = natTable.getConfigRegistry();
+
+ IFilterValueToMatchManager loader = getFilterValueToMatchManager(columnIndex);
+ if (loader != null) {
+ Object columnObject = manager.getColumnElement(columnIndex);
+ loader.saveValueToMatch(configRegistry, columnObject, newValue);
+ }
+ }
+ if (ObjectUtils.isNotNull(newValue)) {
+ filterIndexToObjectMap.put(columnIndex, newValue);
+ } else {
+ filterIndexToObjectMap.remove(columnIndex);
+ }
+
+ filterStrategy.applyFilter(filterIndexToObjectMap);
+
+ columnHeaderLayer.fireLayerEvent(new FilterAppliedEvent(columnHeaderLayer));
+ }
+
+ /**
+ *
+ * @param columnIndex
+ * the index of the column
+ * @return
+ * the filter value to match manager to use
+ */
+ private IFilterValueToMatchManager getFilterValueToMatchManager(int columnIndex) {
+ StringBuilder builder = new StringBuilder();
+ builder.append(FilterRowDataLayer.FILTER_ROW_COLUMN_LABEL_PREFIX);
+ builder.append(Integer.valueOf(columnIndex));
+ return getConfigRegistry().getConfigAttribute(NattableConfigAttributes.FILTER_VALUE_TO_MATCH_MANAGER, DisplayMode.NORMAL, builder.toString());
+ }
+
+ /**
+ *
+ * @return
+ * the config registry to used by the nattable widget
+ */
+ private IConfigRegistry getConfigRegistry() {
+ NatTable natTable = (NatTable) this.manager.getAdapter(NatTable.class);
+ return natTable.getConfigRegistry();
+ }
+
+ // Load/save state
+ //
+ // @Override
+ // public void saveState(String prefix, Properties properties) {
+ // Map<Integer, String> filterTextByIndex = new HashMap<Integer, String>();
+ // for(Integer columnIndex : filterIndexToObjectMap.keySet()) {
+ // final IDisplayConverter converter = configRegistry.getConfigAttribute(
+ // CellConfigAttributes.DISPLAY_CONVERTER,
+ // DisplayMode.NORMAL,
+ // FilterRowDataLayer.FILTER_ROW_COLUMN_LABEL_PREFIX + columnIndex);
+ //
+ // String filterText = getFilterStringRepresentation(filterIndexToObjectMap.get(columnIndex), converter);
+ // filterText = filterText.replace("|", PIPE_REPLACEMENT); //$NON-NLS-1$
+ // filterTextByIndex.put(columnIndex, filterText);
+ // }
+ //
+ // String string = PersistenceUtils.mapAsString(filterTextByIndex);
+ //
+ // if (!isEmpty(string)) {
+ // properties.put(prefix + FilterRowDataLayer.PERSISTENCE_KEY_FILTER_ROW_TOKENS, string);
+ // }
+ // }
+
+ // @Override
+ // public void loadState(String prefix, Properties properties) {
+ // filterIndexToObjectMap.clear();
+ //
+ // try {
+ // Object property = properties.get(prefix + FilterRowDataLayer.PERSISTENCE_KEY_FILTER_ROW_TOKENS);
+ // Map<Integer, String> filterTextByIndex = PersistenceUtils.parseString(property);
+ // for (Integer columnIndex : filterTextByIndex.keySet()) {
+ // final IDisplayConverter converter = configRegistry.getConfigAttribute(
+ // CellConfigAttributes.DISPLAY_CONVERTER,
+ // DisplayMode.NORMAL,
+ // FilterRowDataLayer.FILTER_ROW_COLUMN_LABEL_PREFIX + columnIndex);
+ //
+ // String filterText = filterTextByIndex.get(columnIndex);
+ // filterText = filterText.replace(PIPE_REPLACEMENT, "|"); //$NON-NLS-1$
+ // filterIndexToObjectMap.put(columnIndex, getFilterFromString(filterText, converter));
+ // }
+ // } catch (Exception e) {
+ // log.error("Error while restoring filter row text!", e); //$NON-NLS-1$
+ // }
+
+ // filterStrategy.applyFilter(filterIndexToObjectMap);
+ // }
+
+ /**
+ * This method is used to support saving of a filter collection, e.g. in the context of the
+ * Excel like filter row. In such cases the filter value is not a simple String but a
+ * Collection of filter values that need to be converted to a String representation.
+ * As the state persistence is encapsulated to be handled here, we need to take care
+ * of such states here also.
+ *
+ * @param filterValue
+ * The filter value object that is used for filtering.
+ * @param converter
+ * The converter that is used to convert the filter value, which is necessary
+ * to support filtering of custom types.
+ * @return The String representation of the filter value.
+ */
+ private String getFilterStringRepresentation(Object filterValue, IDisplayConverter converter) {
+ // in case the filter value is a collection of values, we need to create a special
+ // string representation
+ if (filterValue instanceof Collection) {
+ String collectionSpec = FILTER_COLLECTION_PREFIX + filterValue.getClass().getName() + ")"; //$NON-NLS-1$
+ StringBuilder builder = new StringBuilder(collectionSpec);
+ builder.append("["); //$NON-NLS-1$
+ Collection<?> filterCollection = (Collection<?>) filterValue;
+ for (Iterator<?> iterator = filterCollection.iterator(); iterator.hasNext();) {
+ Object filterObject = iterator.next();
+ builder.append(converter.canonicalToDisplayValue(filterObject));
+ if (iterator.hasNext())
+ builder.append(IPersistable.VALUE_SEPARATOR);
+ }
+
+ builder.append("]"); //$NON-NLS-1$
+ return builder.toString();
+ }
+ return (String) converter.canonicalToDisplayValue(filterValue);
+ }
+
+ /**
+ * This method is used to support loading of a filter collection, e.g. in the context of the
+ * Excel like filter row. In such cases the saved filter value is not a simple String but
+ * represents a Collection of filter values that need to be converted to the corresponding values.
+ * As the state persistence is encapsulated to be handled here, we need to take care
+ * of such states here also.
+ *
+ * @param filterText
+ * The String representation of the applied saved filter.
+ * @param converter
+ * The converter that is used to convert the filter value, which is necessary
+ * to support filtering of custom types.
+ * @return The filter value that will be used to apply a filter to the IFilterStrategy
+ *
+ * @throws InstantiationException
+ * @throws IllegalAccessException
+ * @throws ClassNotFoundException
+ */
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ private Object getFilterFromString(String filterText, IDisplayConverter converter) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+ if (filterText.startsWith(FILTER_COLLECTION_PREFIX)) {
+ // the filter text represents a collection
+ int indexEndCollSpec = filterText.indexOf(")"); //$NON-NLS-1$
+ String collectionSpec = filterText.substring(filterText.indexOf("(") + 1, indexEndCollSpec); //$NON-NLS-1$
+ Collection filterCollection = (Collection) Class.forName(collectionSpec).newInstance();
+
+ // also get rid of the collection marks
+ filterText = filterText.substring(indexEndCollSpec + 2, filterText.length() - 1);
+ String[] filterSplit = filterText.split(IPersistable.VALUE_SEPARATOR);
+ for (String filterString : filterSplit) {
+ filterCollection.add(converter.displayToCanonicalValue(filterString));
+ }
+
+ return filterCollection;
+ }
+ return converter.displayToCanonicalValue(filterText);
+ }
+
+ /**
+ * Clear all filters that are currently applied.
+ */
+ public void clearAllFilters() {
+ filterIndexToObjectMap.clear();
+ filterStrategy.applyFilter(filterIndexToObjectMap);
+
+ // we clear the filter
+ if (manager != null) {
+ CompoundCommand cc = new CompoundCommand("Clear All Filter"); //$NON-NLS-1$
+ TransactionalEditingDomain domain = TableEditingDomainUtils.getTableEditingDomain(manager.getTable());
+ List<?> columnElement = manager.getColumnElementsList();
+ for (Object current : columnElement) {
+ if (current instanceof IAxis) {
+ Style idToDestroy = ((IAxis) current).getNamedStyle(NattablestylePackage.eINSTANCE.getStringValueStyle(), IFilterConfiguration.FILTER_SYSTEM_ID);
+ Style keyToDestroy = ((IAxis) current).getNamedStyle(NattablestylePackage.eINSTANCE.getStyle(), IFilterConfiguration.FILTER_FORCED_BY_USER_ID);
+
+ if (idToDestroy != null) {
+ Command cmd = DeleteCommand.create(domain, idToDestroy);
+ if (cmd != null && cmd.canExecute()) {
+ cc.append(cmd);
+ }
+ }
+ if (idToDestroy != null) {
+ Command cmd = DeleteCommand.create(domain, keyToDestroy);
+ if (cmd != null && cmd.canExecute()) {
+ cc.append(cmd);
+ }
+ }
+ }
+ }
+ if (!cc.isEmpty() && cc.canExecute()) {
+ domain.getCommandStack().execute(cc);
+ }
+ }
+
+ }
+}
diff --git a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/filter/AbstractSinglePapyrusMatcher.java b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/filter/AbstractSinglePapyrusMatcher.java
index 0eb7ed2a6e0..c8095cd36be 100755
--- a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/filter/AbstractSinglePapyrusMatcher.java
+++ b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/filter/AbstractSinglePapyrusMatcher.java
@@ -1,115 +1,120 @@
-/*****************************************************************************
- * Copyright (c) 2015 CEA LIST 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:
- * CEA LIST - Initial API and implementation
- *
- *****************************************************************************/
-
-package org.eclipse.papyrus.infra.nattable.filter;
-
-import java.util.Collection;
-
-import org.eclipse.core.runtime.Assert;
-import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
-import org.eclipse.nebula.widgets.nattable.data.IColumnAccessor;
-
-import ca.odell.glazedlists.matchers.Matcher;
-
-/**
- * Abstract matcher class used by filter
- *
- */
-public abstract class AbstractSinglePapyrusMatcher<E> implements Matcher<E> {
-
- /**
- * the wanted object
- */
- private Object matchOn;
-
- /**
- * the column accesor to use
- */
- private IColumnAccessor<Object> columnAccessor;
-
- /**
- * the index of the column on which we are working
- */
- private int columnIndex;
-
-
- /**
- *
- * Constructor.
- *
- * @param columnAccessor
- * the accessor to use to get cell value
- * @param columnIndex
- * the index of the column on which we are working
- * @param matchOn
- * the object looked for by the filter, it must not be a collection
- */
- public AbstractSinglePapyrusMatcher(IColumnAccessor<Object> columnAccessor, int columnIndex, Object matchOn) {
- this(columnAccessor, columnIndex, matchOn, null);
- }
-
- /**
- *
- * Constructor.
- *
- * @param columnAccessor
- * the accessor to use to get cell value
- * @param columnIndex
- * the index of the column on which we are working
- * @param matchOn
- * the object looked for by the filter, it must not be a collection
- * @param configRegistry
- * the config registry used by the nattable widget
- */
- public AbstractSinglePapyrusMatcher(IColumnAccessor<Object> columnAccessor, int columnIndex, Object matchOn, IConfigRegistry configRegistry) {
- this.matchOn = matchOn;
- Assert.isTrue(!(matchOn instanceof Collection<?>));
- this.columnAccessor = columnAccessor;
- this.columnIndex = columnIndex;
- }
-
- /**
- * @return the wantedObject
- */
- protected final Object getObjectToMatch() {
- return matchOn;
- }
-
- /**
- * @return the accessor
- */
- protected final IColumnAccessor<Object> getColumnAccessor() {
- return columnAccessor;
- }
-
- /**
- * @return the columnIndex
- */
- protected final int getColumnIndex() {
- return columnIndex;
- }
-
-
- /**
- *
- * @param item
- * an object (a row)
- * @return
- * the cell value for this row and the filtered column
- */
- protected Object getCellValueFor(Object item) {
- return getColumnAccessor().getDataValue(item, getColumnIndex());
- }
-
-
-}
+/*****************************************************************************
+ * Copyright (c) 2015 CEA LIST 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:
+ * Vincent LORENZO (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ * Nicolas FAUVERGUE (ALL4TEC) nicolas.fauvergue@all4tec.net - Bug 502559
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.nattable.filter;
+
+import java.util.Collection;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
+import org.eclipse.nebula.widgets.nattable.data.IColumnAccessor;
+
+import ca.odell.glazedlists.matchers.Matcher;
+
+/**
+ * Abstract matcher class used by filter
+ *
+ */
+public abstract class AbstractSinglePapyrusMatcher<E> implements Matcher<E> {
+
+ /**
+ * the wanted object
+ */
+ private Object matchOn;
+
+ /**
+ * the column accesor to use
+ */
+ private IColumnAccessor<Object> columnAccessor;
+
+ /**
+ * the index of the column on which we are working
+ */
+ private int columnIndex;
+
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param columnAccessor
+ * the accessor to use to get cell value
+ * @param columnIndex
+ * the index of the column on which we are working
+ * @param matchOn
+ * the object looked for by the filter, it must not be a collection
+ */
+ public AbstractSinglePapyrusMatcher(IColumnAccessor<Object> columnAccessor, int columnIndex, Object matchOn) {
+ this(columnAccessor, columnIndex, matchOn, null);
+ }
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param columnAccessor
+ * the accessor to use to get cell value
+ * @param columnIndex
+ * the index of the column on which we are working
+ * @param matchOn
+ * the object looked for by the filter, it must not be a collection
+ * @param configRegistry
+ * the config registry used by the nattable widget
+ */
+ public AbstractSinglePapyrusMatcher(IColumnAccessor<Object> columnAccessor, int columnIndex, Object matchOn, IConfigRegistry configRegistry) {
+ this.matchOn = matchOn;
+ Assert.isTrue(!(matchOn instanceof Collection<?>));
+ this.columnAccessor = columnAccessor;
+ this.columnIndex = columnIndex;
+ }
+
+ /**
+ * @return the wantedObject
+ *
+ * @since 3.0
+ */
+ public final Object getObjectToMatch() {
+ return matchOn;
+ }
+
+ /**
+ * @return the accessor
+ */
+ protected final IColumnAccessor<Object> getColumnAccessor() {
+ return columnAccessor;
+ }
+
+ /**
+ * @return the columnIndex
+ *
+ * @since 3.0
+ */
+ public final int getColumnIndex() {
+ return columnIndex;
+ }
+
+
+ /**
+ *
+ * @param item
+ * an object (a row)
+ * @return
+ * the cell value for this row and the filtered column
+ */
+ protected Object getCellValueFor(Object item) {
+ return getColumnAccessor().getDataValue(item, getColumnIndex());
+ }
+
+
+}
diff --git a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/filter/PapyrusFilterStrategy.java b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/filter/PapyrusFilterStrategy.java
index d46d97c3f4d..9d942a12372 100755
--- a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/filter/PapyrusFilterStrategy.java
+++ b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/filter/PapyrusFilterStrategy.java
@@ -7,14 +7,17 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- * CEA LIST - Initial API and implementation
+ * Vincent LORENZO (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ * Nicolas FAUVERGUE (ALL4TEC) nicolas.fauvergue@all4tec.net - Bug 502559
*
*****************************************************************************/
package org.eclipse.papyrus.infra.nattable.filter;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -29,6 +32,8 @@ import org.eclipse.nebula.widgets.nattable.filterrow.IFilterStrategy;
import org.eclipse.nebula.widgets.nattable.style.DisplayMode;
import org.eclipse.osgi.util.NLS;
import org.eclipse.papyrus.infra.nattable.Activator;
+import org.eclipse.papyrus.infra.nattable.filter.RegexFindEditor.RegexFindMatcher;
+import org.eclipse.papyrus.infra.nattable.filter.StringMatcherEditorFactory.PapyrusTextMatcherEditor;
import org.eclipse.papyrus.infra.nattable.manager.table.INattableModelManager;
import org.eclipse.papyrus.infra.nattable.manager.table.NattableModelManager;
import org.eclipse.papyrus.infra.nattable.model.nattable.NattablePackage;
@@ -97,7 +102,7 @@ public class PapyrusFilterStrategy implements IFilterStrategy<Object>, IDisposab
/**
*
* @return
- * the table manager
+ * the table manager
*
*/
private INattableModelManager getTableManager() {
@@ -188,17 +193,18 @@ public class PapyrusFilterStrategy implements IFilterStrategy<Object>, IDisposab
/**
* Create GlazedLists matcher editors and apply them to facilitate filtering.
+ * {@inheritDoc}
*/
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
- public void applyFilter(Map<Integer, Object> filterIndexToObjectMap) {
+ public void applyFilter(final Map<Integer, Object> filterIndexToObjectMap) {
// find the lock and the matcher to use, it depends on the table invert axis state
ReadWriteLock filterLock = getReadWriteLockToUse();
CompositeMatcherEditor<Object> matcherEditor = getMatcherEditorToUse();
// wait until all listeners had the chance to handle the clear event
try {
filterLock.writeLock().lock();
- matcherEditor.getMatcherEditors().clear();
+ clearMarcherEditors(matcherEditor, filterIndexToObjectMap);
} finally {
filterLock.writeLock().unlock();
}
@@ -222,14 +228,16 @@ public class PapyrusFilterStrategy implements IFilterStrategy<Object>, IDisposab
if (matcherCreator != null) {
if (value instanceof Collection<?>) {
Collection<?> coll = (Collection<?>) value;
- Iterator<?> iter = coll.iterator();
- CompositeMatcherEditor<Object> composite = new CompositeMatcherEditor<Object>();
- composite.setMode(CompositeMatcherEditor.OR);
- while (iter.hasNext()) {
- Object next = iter.next();
- composite.getMatcherEditors().addAll(matcherCreator.instantiateMatcherEditors(columnAccessor, columnIndex, next, configRegistry));
+ if(!coll.isEmpty()){
+ Iterator<?> iter = coll.iterator();
+ CompositeMatcherEditor<Object> composite = new CompositeMatcherEditor<Object>();
+ composite.setMode(CompositeMatcherEditor.OR);
+ while (iter.hasNext()) {
+ Object next = iter.next();
+ composite.getMatcherEditors().addAll(matcherCreator.instantiateMatcherEditors(columnAccessor, columnIndex, next, configRegistry));
+ }
+ matcherEditors.add(composite);
}
- matcherEditors.add(composite);
} else {
matcherEditors.addAll(matcherCreator.instantiateMatcherEditors(columnAccessor, columnIndex, value, configRegistry));
}
@@ -240,11 +248,14 @@ public class PapyrusFilterStrategy implements IFilterStrategy<Object>, IDisposab
}
// wait until all listeners had the chance to handle the clear event
- try {
- filterLock.writeLock().lock();
- matcherEditor.getMatcherEditors().addAll(matcherEditors);
- } finally {
- filterLock.writeLock().unlock();
+ if (!matcherEditors.isEmpty()) {
+ try {
+ filterLock.writeLock().lock();
+ matcherEditor.setMode(CompositeMatcherEditor.AND);
+ matcherEditor.getMatcherEditors().addAll(matcherEditors);
+ } finally {
+ filterLock.writeLock().unlock();
+ }
}
} catch (Exception e) {
@@ -252,6 +263,126 @@ public class PapyrusFilterStrategy implements IFilterStrategy<Object>, IDisposab
}
}
+ /**
+ * This allows to clear the needed editor which are not compliant with the map of filters by columns.
+ *
+ * @param rootMatcherEditor
+ * The existing matcher editors.
+ * @param filterIndexToObjectMap
+ * The map of filters by columns.
+ */
+ protected void clearMarcherEditors(final CompositeMatcherEditor<Object> rootMatcherEditor, final Map<Integer, Object> filterIndexToObjectMap) {
+ final Iterator<MatcherEditor<Object>> subMatchersEditor = rootMatcherEditor.getMatcherEditors().iterator();
+ while (subMatchersEditor.hasNext()) {
+ final MatcherEditor<Object> subMatcherEditor = subMatchersEditor.next();
+
+ // If this is a composite matcher editor, check its content
+ if (subMatcherEditor instanceof CompositeMatcherEditor) {
+ if (!isCompositeSubMatcherExist((CompositeMatcherEditor<Object>) subMatcherEditor, filterIndexToObjectMap)) {
+ // If the composite is not corresponding with the filter map, remove it
+ subMatchersEditor.remove();
+ }
+
+ // If this is a papyrus matcher, check its column and its object to match
+ } else if (subMatcherEditor.getMatcher() instanceof AbstractSinglePapyrusMatcher) {
+ int columnIndex = ((AbstractSinglePapyrusMatcher<Object>) subMatcherEditor.getMatcher()).getColumnIndex();
+
+ // The column does not exist anymore in the filter map, remove the matcher
+ if (!filterIndexToObjectMap.containsKey(columnIndex)) {
+ subMatchersEditor.remove();
+ } else {
+ // The column exist, check the object to match
+ final Object objectToMatch = ((AbstractSinglePapyrusMatcher<Object>) subMatcherEditor.getMatcher()).getObjectToMatch();
+ final Object value = filterIndexToObjectMap.get(columnIndex);
+
+ // If the object to match is equals, remove the matcher, else remove the filter from the filters map
+ if (!objectToMatch.equals(value)) {
+ subMatchersEditor.remove();
+ } else {
+ filterIndexToObjectMap.remove(columnIndex);
+ }
+ }
+
+ // In other case, remove the filter, it must be recalculated
+ } else {
+ subMatchersEditor.remove();
+ }
+
+ // If the composite does not contain any matcher editor, remove it
+ if (((CompositeMatcherEditor<Object>) subMatcherEditor).getMatcherEditors().isEmpty()) {
+ subMatchersEditor.remove();
+ }
+ }
+ }
+
+ /**
+ * Check if the composite matcher editor exist in the filters map.
+ *
+ * @param subCompositeMatcher
+ * The composite matcher editor.
+ * @param filterIndexToObjectMap
+ * The filters map.
+ * @return <code>true</code> if the composite matcher editor already exist and is the same than in the filters map, <code>false</code> otherwise.
+ */
+ @SuppressWarnings("rawtypes")
+ protected boolean isCompositeSubMatcherExist(final CompositeMatcherEditor<Object> subCompositeMatcher, final Map<Integer, Object> filterIndexToObjectMap) {
+ boolean result = false;
+ int columnIndex = -1;
+ List<Object> objectsToMatch = new ArrayList<Object>();
+ String matchingMode = ""; ////$NON-NLS-1$
+
+ // Loop on matcher editors
+ final Iterator<MatcherEditor<Object>> matchersEditor = subCompositeMatcher.getMatcherEditors().iterator();
+ while (matchersEditor.hasNext()) {
+ final MatcherEditor<Object> matcherEditor = matchersEditor.next();
+
+ // Check if this is a papyrus matcher
+ if (matcherEditor.getMatcher() instanceof AbstractSinglePapyrusMatcher) {
+ // Get the first column index, the following must be the same
+ if (-1 == columnIndex) {
+ columnIndex = ((AbstractSinglePapyrusMatcher<Object>) matcherEditor.getMatcher()).getColumnIndex();
+ }
+ objectsToMatch.add(((AbstractSinglePapyrusMatcher<Object>) matcherEditor.getMatcher()).getObjectToMatch());
+
+ // If this is a RegexFindMatcher, the object to match must contains 'regex:' more than objects to match
+ if (matcherEditor.getMatcher() instanceof RegexFindMatcher) {
+ matchingMode = PapyrusTextMatchingMode.REGEX_FIND.getMode();
+ }
+ }
+
+ if (matcherEditor instanceof PapyrusTextMatcherEditor) {
+ if (-1 == columnIndex) {
+ columnIndex = ((PapyrusTextMatcherEditor) matcherEditor).getColumnIndex();
+ }
+ objectsToMatch.add(((PapyrusTextMatcherEditor) matcherEditor).getObjectToMatch());
+
+ matchingMode = ((PapyrusTextMatcherEditor) matcherEditor).getPapyrusMode();
+ }
+
+ if (matcherEditor instanceof PapyrusThresholdMatcherEditor) {
+ if (-1 == columnIndex) {
+ columnIndex = ((PapyrusThresholdMatcherEditor) matcherEditor).getColumnIndex();
+ }
+ objectsToMatch.add(((PapyrusThresholdMatcherEditor) matcherEditor).getObjectToMatch());
+ }
+ }
+
+ // Check if the column if existing
+ if (-1 != columnIndex && filterIndexToObjectMap.containsKey(columnIndex)) {
+ final Object value = filterIndexToObjectMap.get(columnIndex);
+
+ // Check if the value in filters map is corresponding to the matcher editors.
+ if ((value instanceof Collection && ((Collection<?>) value).containsAll(objectsToMatch) && objectsToMatch.containsAll((Collection<?>) value))
+ || (1 == objectsToMatch.size() && (value.equals(matchingMode + objectsToMatch.get(0)) || value.equals(objectsToMatch.get(0))))) {
+ // In this case, remove the filter from the filters map.
+ filterIndexToObjectMap.remove(columnIndex);
+ result = true;
+ }
+ }
+
+ return result;
+ }
+
protected FilterList<?> getRowFilterList() {
return ((NattableModelManager) this.manager).getHorizontalFilterEventList();
}
diff --git a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/filter/PapyrusThresholdMatcherEditor.java b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/filter/PapyrusThresholdMatcherEditor.java
index 9bf2ffdbab2..b1ac475bf8a 100644
--- a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/filter/PapyrusThresholdMatcherEditor.java
+++ b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/filter/PapyrusThresholdMatcherEditor.java
@@ -9,6 +9,7 @@
*
* Contributors:
* Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ * Nicolas FAUVERGUE (ALL4TEC) nicolas.fauvergue@all4tec.net - Bug 502559
*
*****************************************************************************/
@@ -59,6 +60,20 @@ public class PapyrusThresholdMatcherEditor<E, T> extends AbstractMatcherEditor<E
private FunctionList.Function<E, T> function;
/**
+ * The column index of filter.
+ *
+ * @since 3.0
+ */
+ private int columnIndex;
+
+ /**
+ * The object to match.
+ *
+ * @since 3.0
+ */
+ private Object objectToMatch;
+
+ /**
* Construct an instance that will require elements to be greater than the
* threshold (which is not initially set) and relies on the threshold
* object and elements in the list implementing {@link Comparable}.
@@ -131,20 +146,59 @@ public class PapyrusThresholdMatcherEditor<E, T> extends AbstractMatcherEditor<E
* threshold.
*/
public PapyrusThresholdMatcherEditor(T threshold, MatchOperation operation, Comparator<T> comparator, FunctionList.Function<E, T> function) {
- if (operation == null)
- operation = GREATER_THAN;
- if (comparator == null)
- comparator = (Comparator<T>) GlazedLists.comparableComparator();
- if (function == null)
- function = (FunctionList.Function<E, T>) GlazedListsImpl.identityFunction();
+ this(threshold, operation, comparator, function, -1, null);
+ }
- this.operation = operation;
- this.comparator = comparator;
+ /**
+ * Construct an instance.
+ *
+ * @param threshold
+ * the initial threshold, or null if none.
+ * @param operation
+ * the operation to determine what relation list elements
+ * should have to the threshold in order to match (i.e., be visible).
+ * Specifying null will use {@link #GREATER_THAN}.
+ * @param comparator
+ * determines how objects compare with the threshold value.
+ * If null, the threshold object and list elements must implement {@link Comparable}.
+ * @param function
+ * an optional Function which produces a value fit to be
+ * compared against the threshold. This argument is optional, and if
+ * it is <tt>null</tt>, the raw values will compared against the
+ * threshold.
+ * @param columnIndex
+ * The column index of the filter to apply.
+ * @param objectToMatch
+ * The object to match.
+ *
+ * @since 3.0
+ */
+ public PapyrusThresholdMatcherEditor(final T threshold, final MatchOperation operation, final Comparator<T> comparator, final FunctionList.Function<E, T> function, final int columnIndex, final Object objectToMatch) {
+ MatchOperation modifiedOperation = operation;
+ if (null == modifiedOperation) {
+ modifiedOperation = GREATER_THAN;
+ }
+
+ Comparator<T> modifiedComparator = comparator;
+ if (null == modifiedComparator) {
+ modifiedComparator = (Comparator<T>) GlazedLists.comparableComparator();
+ }
+
+ FunctionList.Function<E, T> modifiedFunction = function;
+ if (null == modifiedFunction) {
+ modifiedFunction = (FunctionList.Function<E, T>) GlazedListsImpl.identityFunction();
+ }
+
+ this.operation = modifiedOperation;
+ this.comparator = modifiedComparator;
this.threshold = threshold;
- this.function = function;
+ this.function = modifiedFunction;
+
+ this.columnIndex = columnIndex;
+ this.objectToMatch = objectToMatch;
// if this is our first matcher, it's automatically a constrain
- currentMatcher = operation.instance(comparator, threshold, function);
+ currentMatcher = modifiedOperation.instance(modifiedComparator, threshold, modifiedFunction);
fireChanged(currentMatcher);
}
@@ -168,6 +222,28 @@ public class PapyrusThresholdMatcherEditor<E, T> extends AbstractMatcherEditor<E
}
/**
+ * Get the column index.
+ *
+ * @return The column index.
+ *
+ * @since 3.0
+ */
+ public int getColumnIndex() {
+ return columnIndex;
+ }
+
+ /**
+ * Get the object to match.
+ *
+ * @return The object to match.
+ *
+ * @since 3.0
+ */
+ public Object getObjectToMatch() {
+ return objectToMatch;
+ }
+
+ /**
* Update the operation used to determine what relation list elements should
* have to the threshold in order to match (i.e. be visible). Must be non-null.
*
diff --git a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/filter/RegexFindEditor.java b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/filter/RegexFindEditor.java
index 0628a3915d0..65aecdd6f8d 100755
--- a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/filter/RegexFindEditor.java
+++ b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/filter/RegexFindEditor.java
@@ -7,7 +7,8 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- * CEA LIST - Initial API and implementation
+ * Vincent LORENZO (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ * Nicolas FAUVERGUE (ALL4TEC) nicolas.fauvergue@all4tec.net - Bug 502559
*
*****************************************************************************/
@@ -44,10 +45,14 @@ public class RegexFindEditor extends AbstractPapyrusMatcherEditor {
/**
* Constructor.
*
- * @param columnAccesor
+ * @param columnAccessor
+ * The accessor to use to get cell value.
* @param columnIndex
+ * The index of the column on which we are working.
* @param matchOn
+ * The object looked for by the filter, it must not be a collection.
* @param configRegistry
+ * The config registry used by the nattable widget.
*/
public RegexFindEditor(IColumnAccessor<Object> columnAccesor, int columnIndex, Object matchOn, IConfigRegistry configRegistry) {
super(columnAccesor, columnIndex, matchOn, configRegistry);
@@ -55,45 +60,76 @@ public class RegexFindEditor extends AbstractPapyrusMatcherEditor {
}
/**
+ * {@inheritDoc}
+ *
* @see org.eclipse.papyrus.infra.nattable.filter.AbstractPapyrusMatcherEditor#createMatcher(org.eclipse.nebula.widgets.nattable.data.IColumnAccessor, int, java.lang.Object, org.eclipse.nebula.widgets.nattable.config.IConfigRegistry)
- *
- * @param columnAccesor
- * @param columnIndex
- * @param matchOn
- * @param configRegistry
- * @return
*/
@Override
- protected Matcher<Object> createMatcher(IColumnAccessor<Object> columnAccesor, final int columnIndex, final Object matchOn, final IConfigRegistry configRegistry) {
+ protected Matcher<Object> createMatcher(final IColumnAccessor<Object> columnAccesor, final int columnIndex, final Object matchOn, final IConfigRegistry configRegistry) {
Assert.isTrue(matchOn instanceof String);
- return new Matcher<Object>() {
-
- @Override
- public boolean matches(Object item) {
- if (matchOn == null || ((String) matchOn).isEmpty()) {
- return true;
- }
+ return new RegexFindMatcher(columnAccesor, columnIndex, matchOn, configRegistry);
+ }
+
+ /**
+ * The regex find matcher.
+ *
+ * @since 3.0
+ */
+ public class RegexFindMatcher extends AbstractSinglePapyrusMatcher<Object>{
- Pattern pattern;
- try {
- pattern = Pattern.compile((String) matchOn);
- } catch (Exception e) {
- // when the entered regex is not valid, we don't filter the rows
- return true;
- }
+ /**
+ * The needed config registry.
+ */
+ protected IConfigRegistry configRegistry;
+
+ /**
+ * Constructor.
+ *
+ * @param columnAccessor
+ * The accessor to use to get cell value.
+ * @param columnIndex
+ * The index of the column on which we are working.
+ * @param matchOn
+ * The object looked for by the filter, it must not be a collection.
+ * @param configRegistry
+ * The config registry used by the nattable widget.
+ */
+ public RegexFindMatcher(final IColumnAccessor<Object> columnAccessor, final int columnIndex, final Object matchOn, final IConfigRegistry configRegistry) {
+ super(columnAccessor, columnIndex, matchOn, configRegistry);
+ this.configRegistry = configRegistry;
+ }
- INattableModelManager manager = configRegistry.getConfigAttribute(NattableConfigAttributes.NATTABLE_MODEL_MANAGER_CONFIG_ATTRIBUTE, DisplayMode.NORMAL, NattableConfigAttributes.NATTABLE_MODEL_MANAGER_ID);
- int index = manager.getRowElementsList().indexOf(item);
- BodyLayerStack stack = manager.getBodyLayerStack();
- ILayerCell cell = stack.getCellByPosition(columnIndex, index);
- Object value = CellManagerFactory.INSTANCE.getCrossValue(manager.getColumnElement(columnIndex), item, manager);
- final IDisplayConverter displayConverter = configRegistry.getConfigAttribute(FILTER_DISPLAY_CONVERTER, NORMAL, FILTER_ROW_COLUMN_LABEL_PREFIX + columnIndex);
- Object res = displayConverter.canonicalToDisplayValue(cell, configRegistry, value);
- String str = (String) res;
+ /**
+ * {@inheritDoc}
+ *
+ * @see ca.odell.glazedlists.matchers.Matcher#matches(java.lang.Object)
+ */
+ @Override
+ public boolean matches(final Object item) {
+ if (null == getObjectToMatch() || ((String) getObjectToMatch()).isEmpty()) {
+ return true;
+ }
- java.util.regex.Matcher m = pattern.matcher(str);
- return m.find();
+ Pattern pattern;
+ try {
+ pattern = Pattern.compile((String) getObjectToMatch());
+ } catch (Exception e) {
+ // when the entered regex is not valid, we don't filter the rows
+ return true;
}
- };
+
+ final INattableModelManager manager = configRegistry.getConfigAttribute(NattableConfigAttributes.NATTABLE_MODEL_MANAGER_CONFIG_ATTRIBUTE, DisplayMode.NORMAL, NattableConfigAttributes.NATTABLE_MODEL_MANAGER_ID);
+ final int index = manager.getRowElementsList().indexOf(item);
+ final BodyLayerStack stack = manager.getBodyLayerStack();
+ final ILayerCell cell = stack.getCellByPosition(getColumnIndex(), index);
+ final Object value = CellManagerFactory.INSTANCE.getCrossValue(manager.getColumnElement(getColumnIndex()), item, manager);
+ final IDisplayConverter displayConverter = configRegistry.getConfigAttribute(FILTER_DISPLAY_CONVERTER, NORMAL, FILTER_ROW_COLUMN_LABEL_PREFIX + getColumnIndex());
+ final Object res = displayConverter.canonicalToDisplayValue(cell, configRegistry, value);
+ final String str = (String) res;
+
+ final java.util.regex.Matcher m = pattern.matcher(str);
+ return m.find();
+ }
+
}
}
diff --git a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/filter/StringMatcherEditorFactory.java b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/filter/StringMatcherEditorFactory.java
index 9fdc0725ca0..f4d6fc82af3 100755
--- a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/filter/StringMatcherEditorFactory.java
+++ b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/filter/StringMatcherEditorFactory.java
@@ -7,7 +7,8 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- * CEA LIST - Initial API and implementation
+ * Vincent LORENZO (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ * Nicolas FAUVERGUE (ALL4TEC) nicolas.fauvergue@all4tec.net - Bug 502559
*
*****************************************************************************/
@@ -34,18 +35,21 @@ import org.eclipse.nebula.widgets.nattable.filterrow.ParseResult;
import org.eclipse.nebula.widgets.nattable.filterrow.ParseResult.MatchType;
import org.eclipse.nebula.widgets.nattable.filterrow.TextMatchingMode;
import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell;
+import org.eclipse.nebula.widgets.nattable.layer.cell.LayerCell;
import org.eclipse.nebula.widgets.nattable.style.DisplayMode;
import org.eclipse.papyrus.infra.nattable.layerstack.BodyLayerStack;
import org.eclipse.papyrus.infra.nattable.manager.cell.CellManagerFactory;
import org.eclipse.papyrus.infra.nattable.manager.table.INattableModelManager;
import org.eclipse.papyrus.infra.nattable.model.nattable.nattableaxisconfiguration.TreeFillingConfiguration;
import org.eclipse.papyrus.infra.nattable.utils.AxisUtils;
+import org.eclipse.papyrus.infra.nattable.utils.LabelProviderCellContextElementWrapper;
import org.eclipse.papyrus.infra.nattable.utils.NattableConfigAttributes;
import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.FunctionList;
import ca.odell.glazedlists.FunctionList.Function;
+import ca.odell.glazedlists.TextFilterable;
import ca.odell.glazedlists.TextFilterator;
import ca.odell.glazedlists.matchers.CompositeMatcherEditor;
import ca.odell.glazedlists.matchers.MatcherEditor;
@@ -127,14 +131,13 @@ public class StringMatcherEditorFactory<T> implements IPapyrusMatcherEditorFacto
List<ParseResult> parseResults = FilterRowUtils.parse(filterText, textDelimiter, textMatchingMode);
- for (ParseResult parseResult : parseResults)
- {
+ for (ParseResult parseResult : parseResults) {
MatchType matchOperation = parseResult.getMatchOperation();
if (matchOperation == MatchType.NONE) {
- stringMatcherEditors.add(getTextMatcherEditor(columnIndex, textMatchingMode, displayConverter, parseResult.getValueToMatch(), columnAccessor, configRegistry));
+ stringMatcherEditors.add(getTextMatcherEditor(columnIndex, papyrusTextMatchingMode, textMatchingMode, displayConverter, parseResult.getValueToMatch(), columnAccessor, configRegistry));
} else {
Object threshold = displayConverter.displayToCanonicalValue(parseResult.getValueToMatch());
- matcherEditors.add(getThresholdMatcherEditor(columnIndex, threshold, comparator, columnValueProvider, matchOperation, configRegistry));
+ matcherEditors.add(getThresholdMatcherEditor(columnIndex, threshold, wantedValue, comparator, columnValueProvider, matchOperation, configRegistry));
}
}
}
@@ -159,7 +162,7 @@ public class StringMatcherEditorFactory<T> implements IPapyrusMatcherEditorFacto
* @param columnLabel
* the label of the column
* @return
- * the matching mode to use, according to the table configuration and the wanted value
+ * the matching mode to use, according to the table configuration and the wanted value
*/
protected PapyrusTextMatchingMode getTextMatchingMode(String wantedValue, IConfigRegistry configRegistry, String columnLabel) {
PapyrusTextMatchingMode papyrusMatchingMode = configRegistry.getConfigAttribute(NattableConfigAttributes.STRING_FILTER_MATCHING_MODE, NORMAL, columnLabel);
@@ -247,7 +250,9 @@ public class StringMatcherEditorFactory<T> implements IPapyrusMatcherEditorFacto
* of the column for which the matcher editor is being set up
* @param configRegistry
* the config registry used by the nattable widget
+ * @deprecated since 3.0
*/
+ @Deprecated
protected PapyrusThresholdMatcherEditor<T, Object> getThresholdMatcherEditor(Integer columnIndex, Object threshold, Comparator<Object> comparator, Function<T, Object> columnValueProvider, MatchType matchOperation, IConfigRegistry configRegistry) {
PapyrusThresholdMatcherEditor<T, Object> thresholdMatcherEditor = new PapyrusThresholdMatcherEditor<T, Object>(
threshold,
@@ -262,6 +267,33 @@ public class StringMatcherEditorFactory<T> implements IPapyrusMatcherEditorFacto
}
/**
+ * Set up a threshold matcher for tokens like '&gt;20', '&lt;=10' etc.
+ *
+ * @param columnIndex
+ * of the column for which the matcher editor is being set up
+ * @param configRegistry
+ * the config registry used by the nattable widget
+ * @param objectToMatch
+ * The object to match.
+ * @since 3.0
+ */
+ protected PapyrusThresholdMatcherEditor<T, Object> getThresholdMatcherEditor(final Integer columnIndex, final Object threshold, final Object objectToMatch, Comparator<Object> comparator, final Function<T, Object> columnValueProvider,
+ final MatchType matchOperation, final IConfigRegistry configRegistry) {
+ PapyrusThresholdMatcherEditor<T, Object> thresholdMatcherEditor = new PapyrusThresholdMatcherEditor<T, Object>(
+ threshold,
+ null,
+ comparator,
+ columnValueProvider,
+ columnIndex,
+ objectToMatch) {
+
+ };
+
+ FilterRowUtils.setMatchOperation(thresholdMatcherEditor, matchOperation);
+ return thresholdMatcherEditor;
+ }
+
+ /**
* @return Function which exposes the content of the given column index from the row object
*/
protected FunctionList.Function<T, Object> getColumnValueProvider(final int columnIndex, final IColumnAccessor<T> columnAccessor) {
@@ -282,9 +314,30 @@ public class StringMatcherEditorFactory<T> implements IPapyrusMatcherEditorFacto
* text entered by the user in the filter row
* @param configRegistry
* the config registry used by the nattable widget
+ * @deprecated since 3.0
*/
+ @Deprecated
protected TextMatcherEditor<T> getTextMatcherEditor(Integer columnIndex, TextMatchingMode textMatchingMode, IDisplayConverter converter, String filterText, final IColumnAccessor<T> columnAccessor, IConfigRegistry configRegistry) {
- TextMatcherEditor<T> textMatcherEditor = new TextMatcherEditor<T>(getTextFilterator(columnIndex, converter, columnAccessor, configRegistry));
+ final PapyrusTextMatcherEditor<T> textMatcherEditor = new PapyrusTextMatcherEditor<T>(getTextFilterator(columnIndex, converter, columnAccessor, configRegistry), columnIndex, filterText, PapyrusTextMatchingMode.REGEX_FIND);
+ textMatcherEditor.setFilterText(new String[] { filterText });
+ textMatcherEditor.setMode(getGlazedListsTextMatcherEditorMode(textMatchingMode));
+ return textMatcherEditor;
+ }
+
+ /**
+ * Sets up a text matcher editor for String tokens
+ *
+ * @param columnIndex
+ * of the column for which the matcher editor is being set up
+ * @param filterText
+ * text entered by the user in the filter row
+ * @param configRegistry
+ * the config registry used by the nattable widget
+ * @since 3.0
+ */
+ protected TextMatcherEditor<T> getTextMatcherEditor(final Integer columnIndex, final PapyrusTextMatchingMode papyrusTextMatchingMode, final TextMatchingMode textMatchingMode, final IDisplayConverter converter, final String filterText,
+ final IColumnAccessor<T> columnAccessor, final IConfigRegistry configRegistry) {
+ final PapyrusTextMatcherEditor<T> textMatcherEditor = new PapyrusTextMatcherEditor<T>(getTextFilterator(columnIndex, converter, columnAccessor, configRegistry), columnIndex, filterText, papyrusTextMatchingMode);
textMatcherEditor.setFilterText(new String[] { filterText });
textMatcherEditor.setMode(getGlazedListsTextMatcherEditorMode(textMatchingMode));
return textMatcherEditor;
@@ -300,20 +353,27 @@ public class StringMatcherEditorFactory<T> implements IPapyrusMatcherEditorFacto
@Override
public void getFilterStrings(List<String> objectAsListOfStrings, T rowObject) {
Object representedObject = AxisUtils.getRepresentedElement(rowObject);
- if(representedObject instanceof TreeFillingConfiguration){
- return ;
+ if (representedObject instanceof TreeFillingConfiguration) {
+ return;
}
INattableModelManager manager = configRegistry.getConfigAttribute(NattableConfigAttributes.NATTABLE_MODEL_MANAGER_CONFIG_ATTRIBUTE, DisplayMode.NORMAL, NattableConfigAttributes.NATTABLE_MODEL_MANAGER_ID);
int index = manager.getRowElementsList().indexOf(rowObject);
BodyLayerStack stack = manager.getBodyLayerStack();
ILayerCell cell = stack.getBodyDataLayer().getCellByPosition(columnIndex, index);
- if(cell==null){
- //we probably have a problem
- return;
- }
+
Object value = CellManagerFactory.INSTANCE.getCrossValue(manager.getColumnElement(columnIndex), rowObject, manager);
+
+ // The cell must be not displayed because the filter can be relaxed (less constrained)
+ if(null == cell){
+ cell = new LabelProviderCellContextElementWrapper();
+ ((LabelProviderCellContextElementWrapper)cell).setConfigRegistry(configRegistry);
+ ((LabelProviderCellContextElementWrapper)cell).setCell(new LayerCell(stack.getBodyDataLayer(), columnIndex, index));
+ }
+
+ // The cell must be not displayed because the filter can be relaxed (less constrained)
final IDisplayConverter displayConverter = configRegistry.getConfigAttribute(FILTER_DISPLAY_CONVERTER, NORMAL, FILTER_ROW_COLUMN_LABEL_PREFIX + columnIndex);
Object res = displayConverter.canonicalToDisplayValue(cell, configRegistry, value);
+
if (res instanceof String) {
objectAsListOfStrings.add((String) res);
} else if (res instanceof Collection<?>) {
@@ -342,4 +402,77 @@ public class StringMatcherEditorFactory<T> implements IPapyrusMatcherEditorFacto
return TextMatcherEditor.CONTAINS;
}
}
+
+ /**
+ * The text matcher editor for Papyrus.
+ *
+ * @param <E>
+ * Type of filtered object.
+ */
+ public class PapyrusTextMatcherEditor<E> extends TextMatcherEditor<E> {
+
+ /**
+ * The column index of filter.
+ */
+ private int columnIndex;
+
+ /**
+ * The object to match.
+ */
+ private Object objectToMatch;
+
+ /**
+ * The papyrus mode as string.
+ */
+ private String papyrusMode;
+
+ /**
+ * Constructor.
+ *
+ * @param filterator
+ * The object that will extract filter Strings from each
+ * object in the <code>source</code>; <code>null</code> indicates the
+ * list elements implement {@link TextFilterable}.
+ * @param columnIndex
+ * The column index.
+ * @param matchOn
+ * The object to match.
+ * @param papyrusTextMatchingMode
+ * The papyrus matching mode.
+ */
+ public PapyrusTextMatcherEditor(final TextFilterator<? super E> filterator, final int columnIndex, final Object matchOn, final PapyrusTextMatchingMode papyrusTextMatchingMode) {
+ super(filterator);
+ this.columnIndex = columnIndex;
+ this.objectToMatch = matchOn;
+ this.papyrusMode = papyrusTextMatchingMode.getMode();
+ }
+
+ /**
+ * Get the column index.
+ *
+ * @return The column index.
+ */
+ public int getColumnIndex() {
+ return columnIndex;
+ }
+
+ /**
+ * Get the object to match.
+ *
+ * @return The object to match.
+ */
+ public Object getObjectToMatch() {
+ return objectToMatch;
+ }
+
+ /**
+ * Get the papyrus mode as String.
+ *
+ * @return The papyrus mode as String.
+ */
+ public String getPapyrusMode() {
+ return papyrusMode;
+ }
+
+ }
}

Back to the top