Skip to content

Package: GridTableViewerComposite$2

GridTableViewerComposite$2

nameinstructionbranchcomplexitylinemethod
getHeaderHeight()
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getHeaderVisible()
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getItemCount()
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getItemHeight()
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
isDisposed()
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
{...}
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%

Coverage

1: /*******************************************************************************
2: * Copyright (c) 2011-2019 EclipseSource Muenchen GmbH and others.
3: *
4: * All rights reserved. This program and the accompanying materials
5: * are made available under the terms of the Eclipse Public License 2.0
6: * which accompanies this distribution, and is available at
7: * https://www.eclipse.org/legal/epl-2.0/
8: *
9: * SPDX-License-Identifier: EPL-2.0
10: *
11: * Contributors:
12: * Alexandra Buzila - initial API and implementation
13: * Johannes Faltermeier - initial API and implementation
14: * Christian W. Damus - bugs 534829, 530314, 547271
15: ******************************************************************************/
16: package org.eclipse.emf.ecp.view.spi.table.nebula.grid;
17:
18: import java.util.HashMap;
19: import java.util.List;
20: import java.util.Map;
21: import java.util.Objects;
22: import java.util.function.Consumer;
23: import java.util.function.Function;
24: import java.util.regex.Pattern;
25: import java.util.regex.PatternSyntaxException;
26:
27: import org.eclipse.core.databinding.observable.value.IObservableValue;
28: import org.eclipse.core.databinding.observable.value.IValueChangeListener;
29: import org.eclipse.core.databinding.observable.value.ValueChangeEvent;
30: import org.eclipse.core.databinding.observable.value.WritableValue;
31: import org.eclipse.core.runtime.Adapters;
32: import org.eclipse.emf.databinding.EMFDataBindingContext;
33: import org.eclipse.emf.ecp.edit.spi.swt.table.ECPFilterableCell;
34: import org.eclipse.emf.ecp.view.spi.table.nebula.grid.GridControlSWTRenderer.CustomGridTableViewer;
35: import org.eclipse.emf.ecp.view.spi.table.nebula.grid.menu.GridColumnAction;
36: import org.eclipse.emf.ecp.view.spi.table.nebula.grid.messages.Messages;
37: import org.eclipse.emfforms.common.Feature;
38: import org.eclipse.emfforms.common.Property;
39: import org.eclipse.emfforms.spi.swt.table.AbstractTableViewerComposite;
40: import org.eclipse.emfforms.spi.swt.table.ColumnConfiguration;
41: import org.eclipse.emfforms.spi.swt.table.TableConfiguration;
42: import org.eclipse.emfforms.spi.swt.table.TableControl;
43: import org.eclipse.emfforms.spi.swt.table.TableViewerComparator;
44: import org.eclipse.emfforms.spi.swt.table.TableViewerSWTCustomization;
45: import org.eclipse.jface.action.IAction;
46: import org.eclipse.jface.action.IMenuListener;
47: import org.eclipse.jface.action.IMenuListener2;
48: import org.eclipse.jface.action.IMenuManager;
49: import org.eclipse.jface.action.MenuManager;
50: import org.eclipse.jface.layout.AbstractColumnLayout;
51: import org.eclipse.jface.viewers.CellLabelProvider;
52: import org.eclipse.jface.viewers.Viewer;
53: import org.eclipse.jface.viewers.ViewerCell;
54: import org.eclipse.jface.viewers.ViewerColumn;
55: import org.eclipse.jface.viewers.ViewerFilter;
56: import org.eclipse.nebula.jface.gridviewer.GridColumnLayout;
57: import org.eclipse.nebula.jface.gridviewer.GridTableViewer;
58: import org.eclipse.nebula.jface.gridviewer.GridViewerColumn;
59: import org.eclipse.nebula.jface.gridviewer.GridViewerRow;
60: import org.eclipse.nebula.widgets.grid.Grid;
61: import org.eclipse.nebula.widgets.grid.GridColumn;
62: import org.eclipse.nebula.widgets.grid.GridItem;
63: import org.eclipse.swt.SWT;
64: import org.eclipse.swt.events.ControlListener;
65: import org.eclipse.swt.events.MouseEvent;
66: import org.eclipse.swt.events.MouseTrackAdapter;
67: import org.eclipse.swt.events.SelectionAdapter;
68: import org.eclipse.swt.events.SelectionEvent;
69: import org.eclipse.swt.graphics.Point;
70: import org.eclipse.swt.widgets.Composite;
71: import org.eclipse.swt.widgets.Menu;
72: import org.eclipse.swt.widgets.Widget;
73:
74: /**
75: * A {@link Composite} containing a {@link GridTableViewer}.
76: *
77: * @author Jonas Helming
78: *
79: */
80: public class GridTableViewerComposite extends AbstractTableViewerComposite<GridTableViewer> {
81:
82:         private static final Map<Feature, Function<GridTableViewerComposite, ? extends IMenuListener>> FEATURE_MENU_LISTENERS = new HashMap<>();
83:
84:         private static final Map<Feature, Function<GridTableViewerComposite, ? extends ViewerFilter>> FEATURE_VIEWER_FILTERS = new HashMap<>();
85:
86:         private GridTableViewer gridTableViewer;
87:         private Point lastKnownPointer;
88:
89:         private final IObservableValue<Feature> activeFilteringMode = new WritableValue<>();
90:
91:         private TableViewerComparator comparator;
92:
93:         private List<Integer> sortableColumns;
94:
95:         static {
96:                 FEATURE_MENU_LISTENERS.put(TableConfiguration.FEATURE_COLUMN_HIDE_SHOW,
97:                         comp -> comp.new ColumnHideShowMenuListener());
98:                 FEATURE_MENU_LISTENERS.put(TableConfiguration.FEATURE_COLUMN_FILTER,
99:                         comp -> comp.new ColumnFilterMenuListener(ColumnConfiguration.FEATURE_COLUMN_FILTER,
100:                                 Messages.GridTableViewerComposite_toggleFilterControlsAction));
101:                 FEATURE_MENU_LISTENERS.put(TableConfiguration.FEATURE_COLUMN_REGEX_FILTER,
102:                         comp -> comp.new ColumnFilterMenuListener(ColumnConfiguration.FEATURE_COLUMN_REGEX_FILTER,
103:                                 Messages.GridTableViewerComposite_toggleRegexFilterControlsAction));
104:
105:                 FEATURE_VIEWER_FILTERS.put(TableConfiguration.FEATURE_COLUMN_FILTER,
106:                         comp -> comp.new GridColumnFilterViewerFilter());
107:                 FEATURE_VIEWER_FILTERS.put(TableConfiguration.FEATURE_COLUMN_REGEX_FILTER,
108:                         comp -> comp.new GridColumnRegexFilterViewerFilter());
109:         }
110:
111:         /**
112:          * Default constructor.
113:          *
114:          * @param parent the parent {@link Composite}
115:          * @param style the style bits
116:          * @param inputObject the input object
117:          * @param customization the {@link TableViewerSWTCustomization}
118:          * @param title the title
119:          * @param tooltip the tooltip
120:          */
121:         public GridTableViewerComposite(Composite parent, int style, Object inputObject,
122:                 TableViewerSWTCustomization customization,
123:                 IObservableValue title, IObservableValue tooltip) {
124:
125:                 super(parent, style, inputObject, customization, title, tooltip);
126:
127:                 activeFilteringMode.addValueChangeListener(this::handleFilteringMode);
128:         }
129:
130:         @Override
131:         public void dispose() {
132:                 activeFilteringMode.dispose();
133:
134:                 super.dispose();
135:         }
136:
137:         @Override
138:         public GridTableViewer getTableViewer() {
139:                 return gridTableViewer;
140:         }
141:
142:         @Override
143:         protected GridTableViewer createTableViewer(TableViewerSWTCustomization<GridTableViewer> customization,
144:                 Composite viewerComposite) {
145:                 gridTableViewer = customization.createTableViewer(viewerComposite);
146:                 gridTableViewer.getControl().addMouseMoveListener(event -> lastKnownPointer = new Point(event.x, event.y));
147:                 gridTableViewer.getControl().addMouseTrackListener(new MouseTrackAdapter() {
148:                         @Override
149:                         public void mouseExit(MouseEvent event) {
150:                                 lastKnownPointer = null;
151:                         }
152:                 });
153:                 return gridTableViewer;
154:         }
155:
156:         @Override
157:         protected void configureContextMenu(GridTableViewer tableViewer) {
158:                 final MenuManager menuMgr = new MenuManager();
159:                 menuMgr.setRemoveAllWhenShown(true);
160:
161:                 mapFeatures(FEATURE_MENU_LISTENERS::get, menuMgr::addMenuListener);
162:
163:                 final Menu menu = menuMgr.createContextMenu(tableViewer.getControl());
164:                 tableViewer.getControl().setMenu(menu);
165:         }
166:
167:         private <T> void mapFeatures(Function<Feature, Function<? super GridTableViewerComposite, T>> mapper,
168:                 Consumer<? super T> action) {
169:
170:                 getEnabledFeatures().stream().map(mapper).filter(Objects::nonNull)
171:                         .map(f -> f.apply(this)).forEach(action);
172:         }
173:
174:         @Override
175:         protected void configureViewerFilters(GridTableViewer tableViewer) {
176:                 mapFeatures(FEATURE_VIEWER_FILTERS::get, tableViewer::addFilter);
177:         }
178:
179:         @Override
180:         protected AbstractColumnLayout createLayout(Composite viewerComposite) {
181:                 final GridColumnLayout layout = new GridColumnLayout();
182:                 viewerComposite.setLayout(layout);
183:                 return layout;
184:         }
185:
186:         @Override
187:         public Widget[] getColumns() {
188:                 return gridTableViewer.getGrid().getColumns();
189:         }
190:
191:         @Override
192:         public void addColumnListener(ControlListener columnlistener) {
193:                 for (int i = 0; i < gridTableViewer.getGrid().getColumns().length; i++) {
194:                         final GridColumn gridColumn = gridTableViewer.getGrid().getColumns()[i];
195:                         gridColumn.addControlListener(columnlistener);
196:                 }
197:         }
198:
199:         @Override
200:         public TableControl getTableControl() {
201:                 return new TableControl() {
202:
203:                         @Override
204:                         public boolean isDisposed() {
205:                                 return getTableViewer().getGrid().isDisposed();
206:                         }
207:
208:                         @Override
209:                         public int getItemHeight() {
210:                                 return getTableViewer().getGrid().getItemHeight();
211:                         }
212:
213:                         @Override
214:                         public boolean getHeaderVisible() {
215:                                 return getTableViewer().getGrid().getHeaderVisible();
216:                         }
217:
218:                         @Override
219:                         public int getHeaderHeight() {
220:                                 return getTableViewer().getGrid().getHeaderHeight();
221:                         }
222:
223:                         @Override
224:                         public int getItemCount() {
225:                                 return getTableViewer().getGrid().getItemCount();
226:                         }
227:                 };
228:         }
229:
230:         @Override
231:         protected ViewerColumn createColumn(final ColumnConfiguration config,
232:                 EMFDataBindingContext emfDataBindingContext, final GridTableViewer tableViewer) {
233:
234:                 final GridViewerColumn column = new GridViewerColumnBuilder(config)
235:                         .withDatabinding(emfDataBindingContext)
236:                         .build(tableViewer);
237:
238:                 return column;
239:         }
240:
241:         @Override
242:         public void setComparator(final TableViewerComparator comparator, List<Integer> sortableColumns) {
243:                 this.comparator = comparator;
244:                 this.sortableColumns = sortableColumns;
245:                 for (int i = 0; i < getTableViewer().getGrid().getColumns().length; i++) {
246:                         if (!sortableColumns.contains(i)) {
247:                                 continue;
248:                         }
249:                         final int j = i;
250:                         final GridColumn tableColumn = getTableViewer().getGrid().getColumns()[i];
251:                         final SelectionAdapter selectionAdapter = new SelectionAdapter() {
252:                                 @Override
253:                                 public void widgetSelected(SelectionEvent e) {
254:                                         setCompareColumn(j);
255:                                 }
256:                         };
257:                         tableColumn.addSelectionListener(selectionAdapter);
258:                 }
259:
260:         }
261:
262:         private GridColumn getCurrentColumn() {
263:                 GridColumn result = null;
264:                 final Grid grid = getTableViewer().getGrid();
265:
266:                 if (lastKnownPointer == null) {
267:                         // For testability, especially in RCPTT, we may not have any real
268:                         // tracking of the mouse pointer. So, hope there's a selection
269:                         final Point[] selectedCells = grid.getCellSelection();
270:                         if (selectedCells != null && selectedCells.length > 0) {
271:                                 result = grid.getColumn(selectedCells[0].x);
272:                         }
273:                 } else {
274:                         result = grid.getColumn(lastKnownPointer);
275:                 }
276:
277:                 return result;
278:         }
279:
280:         private ColumnConfiguration getCurrentColumnConfig() {
281:                 final GridColumn column = getCurrentColumn();
282:                 if (column == null) {
283:                         return null;
284:                 }
285:                 return getColumnConfiguration(column);
286:         }
287:
288:         /**
289:          * Query the currently active filtering mode, if filtering is engaged.
290:          *
291:          * @return one the {@linkplain ColumnConfiguration#FEATURE_COLUMN_FILTER filtering features}
292:          * indicating the filtering mode that is active, or {@code null} if the grid is not filtered
293:          *
294:          * @since 1.21
295:          * @see #setFilteringMode(Feature)
296:          * @see ColumnConfiguration#FEATURE_COLUMN_FILTER
297:          * @see ColumnConfiguration#FEATURE_COLUMN_REGEX_FILTER
298:          */
299:         public Feature getFilteringMode() {
300:                 return activeFilteringMode == null ? null : activeFilteringMode.getValue();
301:         }
302:
303:         /**
304:          * Set the currently active filtering mode.
305:          *
306:          * @param filteringFeature one the {@linkplain ColumnConfiguration#FEATURE_COLUMN_FILTER filtering features}
307:          * indicating the filtering mode that is active, or {@code null} if the grid is not to be filtered
308:          *
309:          * @throws IllegalStateException if the composite is not yet initialized
310:          * @throws IllegalArgumentException if the {@code filteringFeature} is not supported by my
311:          * table configuration ({@code null}, excepted, of course)
312:          *
313:          * @since 1.21
314:          * @see #getFilteringMode()
315:          * @see ColumnConfiguration#FEATURE_COLUMN_FILTER
316:          * @see ColumnConfiguration#FEATURE_COLUMN_REGEX_FILTER
317:          */
318:         public void setFilteringMode(Feature filteringFeature) {
319:                 if (activeFilteringMode == null) {
320:                         // This can happen while superclass constructor is running, which
321:                         // calls into polymorphic methods overridden in this class
322:                         throw new IllegalStateException();
323:                 }
324:                 if (filteringFeature != null && !getEnabledFeatures().contains(filteringFeature)) {
325:                         throw new IllegalArgumentException(filteringFeature.toString());
326:                 }
327:
328:                 activeFilteringMode.setValue(filteringFeature);
329:         }
330:
331:         /**
332:          * Respond to a change of filtering mode by showing/hiding filter controls
333:          * in the columns as appropriate.
334:          *
335:          * @param event the change in the filtering mode
336:          */
337:         private void handleFilteringMode(ValueChangeEvent<? extends Feature> event) {
338:                 final Boolean showFilterControl = getFilteringMode() != null;
339:
340:                 boolean recalculateHeader = false;
341:                 for (final Widget widget : getColumns()) {
342:                         final Property<Boolean> showProperty = getColumnConfiguration(widget).showFilterControl();
343:                         if (!showFilterControl.equals(showProperty.getValue())) {
344:                                 recalculateHeader = true;
345:                                 showProperty.setValue(showFilterControl);
346:                         }
347:                 }
348:
349:                 if (recalculateHeader) {
350:                         getTableViewer().getGrid().recalculateHeader();
351:                 }
352:         }
353:
354:         //
355:         // Nested types
356:         //
357:
358:         /**
359:          * A grid column action whose enablement depends on a enablement of a
360:          * {@linkplain ColumnConfiguration#getEnabledFeatures() configuration feature}.
361:          */
362:         private abstract class FeatureBasedColumnAction extends GridColumnAction {
363:
364:                 private final Feature feature;
365:
366:                 {
367:                         setCurrentColumnProvider(GridTableViewerComposite.this::getCurrentColumn);
368:                 }
369:
370:                 FeatureBasedColumnAction(GridTableViewerComposite gridTableViewerComposite, String actionLabel,
371:                         Feature feature) {
372:
373:                         super(gridTableViewerComposite, actionLabel);
374:
375:                         this.feature = feature;
376:                 }
377:
378:                 FeatureBasedColumnAction(GridTableViewerComposite gridTableViewerComposite, String actionLabel, int style,
379:                         Feature feature) {
380:
381:                         super(gridTableViewerComposite, actionLabel, style);
382:
383:                         this.feature = feature;
384:                 }
385:
386:                 @Override
387:                 public boolean isEnabled() {
388:                         return super.isEnabled() && getEnabledFeatures().contains(feature);
389:                 }
390:
391:         }
392:
393:         /**
394:          * Column hide/show menu listener.
395:          *
396:          * @author Mat Hansen
397:          *
398:          */
399:         private class ColumnHideShowMenuListener implements IMenuListener {
400:
401:                 @Override
402:                 public void menuAboutToShow(IMenuManager manager) {
403:                         final ColumnConfiguration columnConfiguration = getCurrentColumnConfig();
404:                         if (columnConfiguration == null) {
405:                                 return;
406:                         }
407:                         manager.add(new FeatureBasedColumnAction(GridTableViewerComposite.this,
408:                                 Messages.GridTableViewerComposite_hideColumnAction, ColumnConfiguration.FEATURE_COLUMN_HIDE_SHOW) {
409:                                 @Override
410:                                 public void run() {
411:                                         columnConfiguration.visible().setValue(Boolean.FALSE);
412:                                 }
413:                         });
414:                         manager.add(new FeatureBasedColumnAction(GridTableViewerComposite.this,
415:                                 Messages.GridTableViewerComposite_showAllColumnsAction, ColumnConfiguration.FEATURE_COLUMN_HIDE_SHOW) {
416:                                 @Override
417:                                 public void run() {
418:                                         for (final Widget widget : getColumns()) {
419:                                                 getGridTableViewer().getColumnConfiguration(widget).visible().setValue(Boolean.TRUE);
420:                                         }
421:                                 }
422:
423:                                 @Override
424:                                 public boolean isEnabled() {
425:                                         return super.isEnabled() && hasHiddenColumns();
426:                                 }
427:
428:                                 boolean hasHiddenColumns() {
429:                                         for (final Widget widget : getColumns()) {
430:                                                 if (!getGridTableViewer().getColumnConfiguration(widget).visible().getValue()) {
431:                                                         return true;
432:                                                 }
433:                                         }
434:                                         return false;
435:                                 }
436:                         });
437:                 }
438:
439:         }
440:
441:         /**
442:          * Common definition of a filtering menu listener.
443:          *
444:          * @author Mat Hansen
445:          *
446:          */
447:         private class ColumnFilterMenuListener implements IMenuListener2 {
448:                 private final IValueChangeListener<Feature> radioListener = this::handleRadio;
449:                 private final Feature feature;
450:                 private final String label;
451:
452:                 private GridColumnAction action;
453:
454:                 ColumnFilterMenuListener(Feature feature, String label) {
455:                         super();
456:
457:                         this.feature = feature;
458:                         this.label = label;
459:                 }
460:
461:                 @Override
462:                 public void menuAboutToShow(IMenuManager manager) {
463:                         final ColumnConfiguration columnConfiguration = getCurrentColumnConfig();
464:                         if (columnConfiguration == null) {
465:                                 return;
466:                         }
467:
468:                         action = createAction(feature, label, columnConfiguration);
469:                         action.setChecked(getFilteringMode() == feature);
470:
471:                         manager.add(action);
472:                         activeFilteringMode.addValueChangeListener(radioListener);
473:                 }
474:
475:                 @Override
476:                 public void menuAboutToHide(IMenuManager manager) {
477:                         activeFilteringMode.removeValueChangeListener(radioListener);
478:                         action = null;
479:                 }
480:
481:                 GridColumnAction createAction(Feature feature, String label, ColumnConfiguration columnConfiguration) {
482:                         return new FeatureBasedColumnAction(GridTableViewerComposite.this, label, IAction.AS_RADIO_BUTTON,
483:                                 feature) {
484:
485:                                 @Override
486:                                 public void run() {
487:                                         if (getFilteringMode() == feature) {
488:                                                 // We're toggling filtering off
489:                                                 setFilteringMode(null);
490:                                         } else {
491:                                                 // We're setting filtering to my mode
492:                                                 setFilteringMode(feature);
493:                                         }
494:                                 }
495:                         };
496:                 }
497:
498:                 void handleRadio(ValueChangeEvent<? extends Feature> event) {
499:                         action.setChecked(event.getObservableValue().getValue() == feature);
500:                 }
501:
502:         }
503:
504:         /**
505:          * Common viewer filter implementation for column filters.
506:          *
507:          * @author Mat Hansen
508:          *
509:          */
510:         private abstract class AbstractGridColumnFilterViewerFilter extends ViewerFilter {
511:
512:                 private final Feature feature;
513:
514:                 private final GridTableViewer tableViewer;
515:                 private final Grid grid;
516:
517:                 /**
518:                  * Initializes me with the filtering feature that I implement.
519:                  *
520:                  * @param feature my defining feature
521:                  */
522:                 AbstractGridColumnFilterViewerFilter(Feature feature) {
523:                         super();
524:
525:                         this.feature = feature;
526:
527:                         tableViewer = getTableViewer();
528:                         grid = tableViewer.getGrid();
529:                 }
530:
531:                 @Override
532:                 public boolean select(Viewer viewer, Object parentElement, Object element) {
533:                         if (!isApplicable(viewer)) {
534:                                 return true;
535:                         }
536:
537:                         GridItem dummyItem = null;
538:                         GridViewerRow viewerRow = null;
539:
540:                         try {
541:                                 for (final Widget widget : getColumns()) {
542:                                         final ColumnConfiguration config = getColumnConfiguration(widget);
543:
544:                                         // Do we even have a filter to apply?
545:                                         final Object filter = config.matchFilter().getValue();
546:                                         if (filter == null || String.valueOf(filter).isEmpty()) {
547:                                                 continue;
548:                                         }
549:
550:                                         final GridColumn column = (GridColumn) widget;
551:                                         final int columnIndex = tableViewer.getGrid().indexOf(column);
552:                                         final CellLabelProvider labelProvider = tableViewer.getLabelProvider(columnIndex);
553:
554:                                         // Optimize for the standard case
555:                                         final ECPFilterableCell filterable = Adapters.adapt(labelProvider, ECPFilterableCell.class);
556:                                         if (filterable != null) {
557:                                                 // Just get the text and filter it
558:                                                 final String text = filterable.getFilterableText(element);
559:                                                 if (!matchesColumnFilter(text, filter)) {
560:                                                         return false;
561:                                                 }
562:                                         } else {
563:                                                 // We have a filter, but we need something to filter on
564:                                                 if (dummyItem == null) {
565:                                                         grid.setRedraw(false);
566:                                                         dummyItem = new GridItem(grid, SWT.NONE);
567:
568:                                                         dummyItem.setData(element);
569:                                                         viewerRow = (GridViewerRow) ((CustomGridTableViewer) tableViewer)
570:                                                                 .getViewerRowFromItem(dummyItem);
571:                                                 }
572:
573:                                                 // Update the cell, the slow way
574:                                                 final ViewerCell cell = viewerRow.getCell(columnIndex);
575:                                                 labelProvider.update(cell);
576:
577:                                                 if (!matchesColumnFilter(cell.getText(), filter)) {
578:                                                         return false;
579:                                                 }
580:                                         }
581:                                 }
582:                         } finally {
583:                                 if (dummyItem != null) {
584:                                         dummyItem.dispose();
585:                                         grid.setRedraw(true);
586:                                 }
587:                         }
588:
589:                         return true;
590:                 }
591:
592:                 protected boolean isApplicable(Viewer viewer) {
593:                         return getFilteringMode() == feature;
594:                 }
595:
596:                 /**
597:                  * Test whether the given value/filter combination matches.
598:                  *
599:                  * @param value the value to test
600:                  * @param filterValue the filter value
601:                  * @return true if the value matches the filter value
602:                  */
603:                 protected abstract boolean matchesColumnFilter(Object value, Object filterValue);
604:
605:         }
606:
607:         /**
608:          * Viewer filter for column simple filter support.
609:          *
610:          * @author Mat Hansen
611:          *
612:          */
613:         private class GridColumnFilterViewerFilter extends AbstractGridColumnFilterViewerFilter {
614:
615:                 /**
616:                  * The Constructor.
617:                  */
618:                 GridColumnFilterViewerFilter() {
619:                         super(ColumnConfiguration.FEATURE_COLUMN_FILTER);
620:                 }
621:
622:                 @Override
623:                 protected boolean matchesColumnFilter(Object value, Object filterValue) {
624:
625:                         if (filterValue == null) {
626:                                 return false;
627:                         }
628:
629:                         return String.valueOf(value).toLowerCase()
630:                                 .contains(String.valueOf(filterValue).toLowerCase());
631:                 }
632:
633:         }
634:
635:         /**
636:          * Viewer filter for column regular expression filter support.
637:          */
638:         private class GridColumnRegexFilterViewerFilter extends AbstractGridColumnFilterViewerFilter {
639:
640:                 private Object rawFilter;
641:                 private Pattern pattern;
642:
643:                 /**
644:                  * Initializes me.
645:                  */
646:                 GridColumnRegexFilterViewerFilter() {
647:                         super(ColumnConfiguration.FEATURE_COLUMN_REGEX_FILTER);
648:                 }
649:
650:                 @Override
651:                 protected boolean matchesColumnFilter(Object value, Object filterValue) {
652:
653:                         if (!Objects.equals(filterValue, rawFilter)) {
654:                                 // Cache a new pattern, if possible
655:                                 pattern = parse(String.valueOf(filterValue));
656:                         }
657:
658:                         if (pattern == null) {
659:                                 // Couldn't parse it. Everything will match (user should be able to see examples
660:                                 // in the data to formulate a pattern)
661:                                 return true;
662:                         }
663:
664:                         return pattern.matcher(String.valueOf(value)).find();
665:                 }
666:
667:                 protected Pattern parse(String regex) {
668:                         Pattern result = null;
669:
670:                         try {
671:                                 result = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
672:                         } catch (final PatternSyntaxException e) {
673:                                 // This is normal while the user is formulating the pattern
674:                         }
675:
676:                         return result;
677:                 }
678:         }
679:
680:         @Override
681:         public void setCompareColumn(int columnIndex) {
682:                 // Reset other columns to avoid left over sort indicators
683:                 for (final int index : sortableColumns) {
684:                         final GridColumn column = getTableViewer().getGrid().getColumns()[index];
685:                         if (index != columnIndex && column.getSort() != SWT.NONE) {
686:                                 column.setSort(SWT.NONE);
687:                         }
688:                 }
689:                 comparator.setColumn(columnIndex);
690:                 final GridColumn tableColumn = getTableViewer().getGrid().getColumns()[columnIndex];
691:                 tableColumn.setSort(comparator.getDirection());
692:                 gridTableViewer.refresh();
693:         }
694:
695: }