finished event handling in RowHideShowLayer and created GlazedListsRowHideShowLayer
diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/hideshow/RowHideShowLayer.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/hideshow/RowHideShowLayer.java index 0054dfa..04191ed 100644 --- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/hideshow/RowHideShowLayer.java +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/hideshow/RowHideShowLayer.java
@@ -56,68 +56,77 @@ public void handleLayerEvent(ILayerEvent event) { if (event instanceof IStructuralChangeEvent) { IStructuralChangeEvent structuralChangeEvent = (IStructuralChangeEvent) event; - if (structuralChangeEvent.isVerticalStructureChanged() && structuralChangeEvent.convertToLocal(this)) { + if (structuralChangeEvent.isVerticalStructureChanged()) { Collection<StructuralDiff> rowDiffs = structuralChangeEvent.getRowDiffs(); - if (rowDiffs != null) { - List<Integer> toRemove = new ArrayList<Integer>(); - for (Iterator<StructuralDiff> diffIterator = rowDiffs.iterator(); diffIterator.hasNext();) { - StructuralDiff rowDiff = diffIterator.next(); - if (rowDiff.getDiffType() != null && rowDiff.getDiffType().equals(DiffTypeEnum.DELETE)) { - Range beforePositionRange = rowDiff.getBeforePositionRange(); - for (Iterator<Integer> it = this.hiddenRowIndexes.iterator(); it.hasNext();) { - Integer hiddenRow = it.next(); - if (hiddenRow == beforePositionRange.start) { - toRemove.add(hiddenRow); - diffIterator.remove(); - //FIXME modify other row indexes - } - } - } - } - - handleVerticalStructureUpdates(rowDiffs); + if (rowDiffs != null && !rowDiffs.isEmpty()) { + handleRowDelete(rowDiffs); + handleRowInsert(rowDiffs); } } } super.handleLayerEvent(event); } - - protected void handleVerticalStructureUpdates(Collection<StructuralDiff> rowDiffs) { - for (StructuralDiff rowDiff : rowDiffs) { + /** + * Will check for events that indicate that a rows has been deleted. In that case the stored + * hidden indexes need to be updated because the index of the rows might have changed. + * E.g. Row with index 3 is hidden in this layer, deleting row at index 1 will cause the row at index + * 3 to be moved at index 2. Without transforming the index regarding the delete event, the wrong + * row would be hidden. + * @param rowDiffs The collection of {@link StructuralDiff}s to handle + */ + protected void handleRowDelete(Collection<StructuralDiff> rowDiffs) { + List<Integer> toRemove = new ArrayList<Integer>(); + for (Iterator<StructuralDiff> diffIterator = rowDiffs.iterator(); diffIterator.hasNext();) { + StructuralDiff rowDiff = diffIterator.next(); if (rowDiff.getDiffType() != null && rowDiff.getDiffType().equals(DiffTypeEnum.DELETE)) { Range beforePositionRange = rowDiff.getBeforePositionRange(); - Set<Integer> modifiedHiddenRows = new HashSet<Integer>(); - for (Integer hiddenRow : this.hiddenRowIndexes) { - if (hiddenRow != beforePositionRange.start) { - //the deleted row was not hidden before - //if it was hidden it will not be added to the new collection - if (hiddenRow > beforePositionRange.start) { - //if the hidden row was before the deleted row - //we need to lower the index because of missing a row - modifiedHiddenRows.add(hiddenRow-1); - } - else { - modifiedHiddenRows.add(hiddenRow); - } - } - } - RowHideShowLayer.this.hiddenRowIndexes.clear(); - RowHideShowLayer.this.hiddenRowIndexes.addAll(modifiedHiddenRows); + toRemove.add(underlyingLayer.getRowIndexByPosition(beforePositionRange.start)); } - else if (rowDiff.getDiffType() != null && rowDiff.getDiffType().equals(DiffTypeEnum.ADD)) { + } + //remove the hidden row indexes that are deleted + this.hiddenRowIndexes.removeAll(toRemove); + + //modify hidden row indexes regarding the deleted rows + Set<Integer> modifiedHiddenRows = new HashSet<Integer>(); + for (Integer hiddenRow : this.hiddenRowIndexes) { + //check number of removed indexes that are lower than the current one + int deletedBefore = 0; + for (Integer removed : toRemove) { + if (removed < hiddenRow) { + deletedBefore++; + } + } + modifiedHiddenRows.add(hiddenRow-deletedBefore); + } + this.hiddenRowIndexes.clear(); + this.hiddenRowIndexes.addAll(modifiedHiddenRows); + } + + /** + * Will check for events that indicate that a rows are added. In that case the stored + * hidden indexes need to be updated because the index of the rows might have changed. + * E.g. Row with index 3 is hidden in this layer, adding a row at index 1 will cause the row at index + * 3 to be moved to index 4. Without transforming the index regarding the add event, the wrong + * row would be hidden. + * @param rowDiffs The collection of {@link StructuralDiff}s to handle + */ + protected void handleRowInsert(Collection<StructuralDiff> rowDiffs) { + for (StructuralDiff rowDiff : rowDiffs) { + if (rowDiff.getDiffType() != null && rowDiff.getDiffType().equals(DiffTypeEnum.ADD)) { Range beforePositionRange = rowDiff.getBeforePositionRange(); Set<Integer> modifiedHiddenRows = new HashSet<Integer>(); + int beforeIndex = underlyingLayer.getRowIndexByPosition(beforePositionRange.start); for (Integer hiddenRow : this.hiddenRowIndexes) { - if (hiddenRow >= beforePositionRange.start) { + if (hiddenRow >= beforeIndex) { modifiedHiddenRows.add(hiddenRow+1); } else { modifiedHiddenRows.add(hiddenRow); } } - RowHideShowLayer.this.hiddenRowIndexes.clear(); - RowHideShowLayer.this.hiddenRowIndexes.addAll(modifiedHiddenRows); + this.hiddenRowIndexes.clear(); + this.hiddenRowIndexes.addAll(modifiedHiddenRows); } } } @@ -175,24 +184,11 @@ fireLayerEvent(new HideRowPositionsEvent(this, rowPositions)); } - public void showRowIndexes(int[] rowIndexes) { - Set<Integer> rowIndexesSet = new HashSet<Integer>(); - for (int i = 0; i < rowIndexes.length; i++) { - rowIndexesSet.add(Integer.valueOf(rowIndexes[i])); - } - hiddenRowIndexes.removeAll(rowIndexesSet); + public void showRowIndexes(Collection<Integer> rowIndexes) { + hiddenRowIndexes.removeAll(rowIndexes); invalidateCache(); fireLayerEvent(new ShowRowPositionsEvent(this, getRowPositionsByIndexes(rowIndexes))); } - - protected void showRowIndexes(Collection<Integer> rowIndexes) { - for (int rowIndex : rowIndexes) { - hiddenRowIndexes.remove(Integer.valueOf(rowIndex)); - } - invalidateCache(); - // Since we are exposing this method for showing individual rows, a structure event must be fired here. - fireLayerEvent(new ShowRowPositionsEvent(this, rowIndexes)); - } public void showAllRows() { Collection<Integer> hiddenRows = new ArrayList<Integer>(hiddenRowIndexes); @@ -201,7 +197,7 @@ fireLayerEvent(new ShowRowPositionsEvent(this, hiddenRows)); } - private Collection<Integer> getRowPositionsByIndexes(int[] rowIndexes) { + private Collection<Integer> getRowPositionsByIndexes(Collection<Integer> rowIndexes) { Collection<Integer> rowPositions = new HashSet<Integer>(); for (int rowIndex : rowIndexes) { rowPositions.add(Integer.valueOf(getRowPositionByIndex(rowIndex)));
diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/hideshow/command/MultiRowShowCommand.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/hideshow/command/MultiRowShowCommand.java index 8dbbe85..6c9e176 100644 --- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/hideshow/command/MultiRowShowCommand.java +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/hideshow/command/MultiRowShowCommand.java
@@ -10,23 +10,39 @@ ******************************************************************************/ package org.eclipse.nebula.widgets.nattable.hideshow.command; +import java.util.ArrayList; +import java.util.Collection; + import org.eclipse.nebula.widgets.nattable.command.AbstractContextFreeCommand; +/** + * Command for showing hidden rows again. + */ public class MultiRowShowCommand extends AbstractContextFreeCommand { - private final int[] rowIndexes; + /** + * The indexes of the rows that should be showed again. + */ + private final Collection<Integer> rowIndexes; - public MultiRowShowCommand(int[] rowIndexes) { + /** + * + * @param rowIndexes The indexes of the rows that should be showed again. + */ + public MultiRowShowCommand(Collection<Integer> rowIndexes) { this.rowIndexes = rowIndexes; } - protected MultiRowShowCommand(MultiRowShowCommand command) { - rowIndexes = new int[command.rowIndexes.length]; - System.arraycopy(command.rowIndexes, 0, rowIndexes, 0, command.rowIndexes.length); - } - - public int[] getRowIndexes() { + /** + * + * @return The indexes of the rows that should be showed again. + */ + public Collection<Integer> getRowIndexes() { return rowIndexes; } + @Override + public MultiRowShowCommand cloneCommand() { + return new MultiRowShowCommand(new ArrayList<Integer>(this.rowIndexes)); + } }
diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/hideshow/command/MultiRowShowCommandHandler.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/hideshow/command/MultiRowShowCommandHandler.java index 5a0563e..911cb4d 100644 --- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/hideshow/command/MultiRowShowCommandHandler.java +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/hideshow/command/MultiRowShowCommandHandler.java
@@ -27,8 +27,7 @@ @Override protected boolean doCommand(MultiRowShowCommand command) { - int[] columnIndexes = command.getRowIndexes(); - rowHideShowLayer.showRowIndexes(columnIndexes); + rowHideShowLayer.showRowIndexes(command.getRowIndexes()); return true; }
diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/tree/TreeLayer.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/tree/TreeLayer.java index f110629..9b376f3 100644 --- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/tree/TreeLayer.java +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/tree/TreeLayer.java
@@ -12,7 +12,6 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.TreeSet; @@ -134,10 +133,6 @@ * @param parentIndex The index of the row that shows the node that should be collapsed */ public void collapseTreeRow(int parentIndex) { - //TODO remember the hidden rows before collapse because they will be deleted - //when using GlazedLists for collapse and therefore need to be restored on expand -// storeHiddenRowStates(this.treeRowModel.getChildIndexes(parentIndex)); - List<Integer> rowIndexes = this.treeRowModel.collapse(parentIndex); List<Integer> rowPositions = new ArrayList<Integer>(); for (Integer rowIndex : rowIndexes) { @@ -160,10 +155,6 @@ List<Integer> rowIndexes = this.treeRowModel.expand(parentIndex); this.hiddenRowIndexes.removeAll(rowIndexes); invalidateCache(); - - //TODO restore the hidden states -// restoreHiddenRowStates(); - fireLayerEvent(new ShowRowPositionsEvent(this, rowIndexes)); } @@ -178,34 +169,6 @@ return (underlyingLayer.getRowPositionByIndex(rowIndex) == -1); } - private List<Integer> hiddenCollapsed = new ArrayList<Integer>(); - - private void storeHiddenRowStates(List<Integer> collapsed) { - for (Integer rowIndex : collapsed) { - if (isHiddenInUnderlyingLayer(rowIndex)) { - hiddenCollapsed.add(rowIndex); - } - } - } - - private void restoreHiddenRowStates() { - List<Integer> hidePositions = new ArrayList<Integer>(); - for (Iterator<Integer> iterator = hiddenCollapsed.iterator(); iterator.hasNext();) { - Integer rowIndex = iterator.next(); - if (!isHiddenInUnderlyingLayer(rowIndex)) { - hidePositions.add(getRowPositionByIndex(rowIndex)); - iterator.remove(); - } - } - if (!hidePositions.isEmpty()) { - int[] positions = new int[hidePositions.size()]; - for (int i = 0; i < hidePositions.size(); i++) { - positions[i] = hidePositions.get(i); - } - new MultiRowHideCommand(this, positions); - } - } - @Override public boolean doCommand(ILayerCommand command) { //special command transformations are needed to hide also child nodes
diff --git a/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/_500_Layers/_532_GlazedListsRowHideShowExample.java b/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/_500_Layers/_532_GlazedListsRowHideShowExample.java new file mode 100644 index 0000000..979ff09 --- /dev/null +++ b/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/_500_Layers/_532_GlazedListsRowHideShowExample.java
@@ -0,0 +1,164 @@ +/******************************************************************************* + * Copyright (c) 2013 Dirk Fauth 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: + * Dirk Fauth <dirk.fauth@gmail.com> - initial API and implementation + *******************************************************************************/ +package org.eclipse.nebula.widgets.nattable.examples._500_Layers; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.nebula.widgets.nattable.NatTable; +import org.eclipse.nebula.widgets.nattable.config.DefaultNatTableStyleConfiguration; +import org.eclipse.nebula.widgets.nattable.data.IDataProvider; +import org.eclipse.nebula.widgets.nattable.data.IRowDataProvider; +import org.eclipse.nebula.widgets.nattable.data.IRowIdAccessor; +import org.eclipse.nebula.widgets.nattable.data.ReflectiveColumnPropertyAccessor; +import org.eclipse.nebula.widgets.nattable.examples.AbstractNatExample; +import org.eclipse.nebula.widgets.nattable.examples.data.person.Person; +import org.eclipse.nebula.widgets.nattable.examples.data.person.PersonService; +import org.eclipse.nebula.widgets.nattable.examples.runner.StandaloneNatExampleRunner; +import org.eclipse.nebula.widgets.nattable.extension.glazedlists.DetailGlazedListsEventLayer; +import org.eclipse.nebula.widgets.nattable.extension.glazedlists.GlazedListsDataProvider; +import org.eclipse.nebula.widgets.nattable.extension.glazedlists.hideshow.GlazedListsRowHideShowLayer; +import org.eclipse.nebula.widgets.nattable.grid.data.DefaultColumnHeaderDataProvider; +import org.eclipse.nebula.widgets.nattable.grid.data.DefaultCornerDataProvider; +import org.eclipse.nebula.widgets.nattable.grid.data.DefaultRowHeaderDataProvider; +import org.eclipse.nebula.widgets.nattable.grid.layer.ColumnHeaderLayer; +import org.eclipse.nebula.widgets.nattable.grid.layer.CornerLayer; +import org.eclipse.nebula.widgets.nattable.grid.layer.DefaultColumnHeaderDataLayer; +import org.eclipse.nebula.widgets.nattable.grid.layer.DefaultRowHeaderDataLayer; +import org.eclipse.nebula.widgets.nattable.grid.layer.GridLayer; +import org.eclipse.nebula.widgets.nattable.grid.layer.RowHeaderLayer; +import org.eclipse.nebula.widgets.nattable.layer.DataLayer; +import org.eclipse.nebula.widgets.nattable.layer.ILayer; +import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer; +import org.eclipse.nebula.widgets.nattable.ui.menu.AbstractHeaderMenuConfiguration; +import org.eclipse.nebula.widgets.nattable.ui.menu.PopupMenuBuilder; +import org.eclipse.nebula.widgets.nattable.viewport.ViewportLayer; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; + +import ca.odell.glazedlists.EventList; +import ca.odell.glazedlists.FilterList; +import ca.odell.glazedlists.GlazedLists; + +/** + * Simple example showing how to add the row hide/show functionality to a grid that is build + * using GlazedLists and how to add the corresponding actions to the row header menu. + * + * @author Dirk Fauth + * + */ +public class _532_GlazedListsRowHideShowExample extends AbstractNatExample { + + public static void main(String[] args) throws Exception { + StandaloneNatExampleRunner.run(new _532_GlazedListsRowHideShowExample()); + } + + @Override + public String getDescription() { + return "This example shows the usage of the row hide/show functionality within a grid and " + + "its corresponding actions in the row header menu using the GlazedLists extension. " + + "If you perform a right click on the row header, you are able to hide the current selected " + + "row or show all rows again."; + } + + @Override + public Control createExampleControl(Composite parent) { + //property names of the Person class + String[] propertyNames = {"firstName", "lastName", "gender", "married", "birthday"}; + + //mapping from property to label, needed for column header labels + Map<String, String> propertyToLabelMap = new HashMap<String, String>(); + propertyToLabelMap.put("firstName", "Firstname"); + propertyToLabelMap.put("lastName", "Lastname"); + propertyToLabelMap.put("gender", "Gender"); + propertyToLabelMap.put("married", "Married"); + propertyToLabelMap.put("birthday", "Birthday"); + + //build the body layer stack + //Usually you would create a new layer stack by extending AbstractIndexLayerTransform and + //setting the ViewportLayer as underlying layer. But in this case using the ViewportLayer + //directly as body layer is also working. + + //first wrap the base list in a GlazedLists EventList and a FilterList so it is possible to filter + EventList<Person> eventList = GlazedLists.eventList(PersonService.getPersons(10)); + FilterList<Person> filterList = new FilterList<Person>(eventList); + + //use the GlazedListsDataProvider for some performance tweaks + final IRowDataProvider<Person> bodyDataProvider = new GlazedListsDataProvider<Person>(filterList, + new ReflectiveColumnPropertyAccessor<Person>(propertyNames)); + //create the IRowIdAccessor that is necessary for row hide/show + final IRowIdAccessor<Person> rowIdAccessor = new IRowIdAccessor<Person>() { + @Override + public Serializable getRowId(Person rowObject) { + return rowObject.getId(); + } + }; + + DataLayer bodyDataLayer = new DataLayer(bodyDataProvider); + + //add a GlazedLists event layer that is responsible for updating the grid on list changes + DetailGlazedListsEventLayer<Person> glazedListsEventLayer = + new DetailGlazedListsEventLayer<Person>(bodyDataLayer, filterList); + + GlazedListsRowHideShowLayer<Person> rowHideShowLayer = new GlazedListsRowHideShowLayer<Person>( + glazedListsEventLayer, bodyDataProvider, rowIdAccessor, filterList); + + SelectionLayer selectionLayer = new SelectionLayer(rowHideShowLayer); + ViewportLayer viewportLayer = new ViewportLayer(selectionLayer); + + //build the column header layer + IDataProvider columnHeaderDataProvider = new DefaultColumnHeaderDataProvider(propertyNames, propertyToLabelMap); + DataLayer columnHeaderDataLayer = new DefaultColumnHeaderDataLayer(columnHeaderDataProvider); + ILayer columnHeaderLayer = new ColumnHeaderLayer(columnHeaderDataLayer, viewportLayer, selectionLayer); + + //build the row header layer + IDataProvider rowHeaderDataProvider = new DefaultRowHeaderDataProvider(bodyDataProvider); + DataLayer rowHeaderDataLayer = new DefaultRowHeaderDataLayer(rowHeaderDataProvider); + ILayer rowHeaderLayer = new RowHeaderLayer(rowHeaderDataLayer, viewportLayer, selectionLayer); + + //build the corner layer + IDataProvider cornerDataProvider = new DefaultCornerDataProvider(columnHeaderDataProvider, rowHeaderDataProvider); + DataLayer cornerDataLayer = new DataLayer(cornerDataProvider); + ILayer cornerLayer = new CornerLayer(cornerDataLayer, rowHeaderLayer, columnHeaderLayer); + + //build the grid layer + GridLayer gridLayer = new GridLayer(viewportLayer, columnHeaderLayer, rowHeaderLayer, cornerLayer); + + //turn the auto configuration off as we want to add our header menu configuration + NatTable natTable = new NatTable(parent, gridLayer, false); + + //as the autoconfiguration of the NatTable is turned off, we have to add the + //DefaultNatTableStyleConfiguration manually + natTable.addConfiguration(new DefaultNatTableStyleConfiguration()); + + //add the header menu configuration for adding the column header menu with hide/show actions + natTable.addConfiguration(new AbstractHeaderMenuConfiguration(natTable) { + + @Override + protected PopupMenuBuilder createRowHeaderMenu(NatTable natTable) { + return new PopupMenuBuilder(natTable) + .withHideRowMenuItem() + .withShowAllRowsMenuItem(); + } + + @Override + protected PopupMenuBuilder createCornerMenu(NatTable natTable) { + return super.createCornerMenu(natTable) + .withHideRowMenuItem(); + } + }); + natTable.configure(); + + return natTable; + } + +}
diff --git a/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/data/person/ExtendedPersonWithAddress.java b/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/data/person/ExtendedPersonWithAddress.java index bb8747f..4ac3ac4 100644 --- a/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/data/person/ExtendedPersonWithAddress.java +++ b/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/data/person/ExtendedPersonWithAddress.java
@@ -29,11 +29,11 @@ private String filename; @SuppressWarnings("deprecation") - public ExtendedPersonWithAddress(String firstName, String lastName, + public ExtendedPersonWithAddress(int id, String firstName, String lastName, Gender gender, boolean married, Date birthday, Address address, String password, String description, double money, List<String> favouriteFood, List<String> favouriteDrinks) { - super(firstName, lastName, gender, married, birthday, address); + super(id, firstName, lastName, gender, married, birthday, address); this.password = password; this.description = description;
diff --git a/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/data/person/Person.java b/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/data/person/Person.java index 88999d4..a46257e 100644 --- a/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/data/person/Person.java +++ b/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/data/person/Person.java
@@ -7,15 +7,19 @@ MALE, FEMALE } + private final int id; private String firstName; private String lastName; private Gender gender; private boolean married; private Date birthday; - public Person() { } + public Person(int id) { + this.id = id; + } - public Person(String firstName, String lastName, Gender gender, boolean married, Date birthday) { + public Person(int id, String firstName, String lastName, Gender gender, boolean married, Date birthday) { + this.id = id; this.firstName = firstName; this.lastName = lastName; this.gender = gender; @@ -24,6 +28,13 @@ } /** + * @return the id + */ + public int getId() { + return id; + } + + /** * @return the firstName */ public String getFirstName() {
diff --git a/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/data/person/PersonService.java b/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/data/person/PersonService.java index 0bb10f5..22a8b07 100644 --- a/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/data/person/PersonService.java +++ b/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/data/person/PersonService.java
@@ -27,7 +27,7 @@ List<Person> result = new ArrayList<Person>(); for (int i = 0; i < numberOfPersons; i++) { - result.add(createPerson()); + result.add(createPerson(i)); } return result; @@ -42,7 +42,7 @@ List<PersonWithAddress> result = new ArrayList<PersonWithAddress>(); for (int i = 0; i < numberOfPersons; i++) { - result.add(new PersonWithAddress(createPerson(), createAddress())); + result.add(new PersonWithAddress(createPerson(i), createAddress())); } return result; @@ -57,7 +57,7 @@ List<ExtendedPersonWithAddress> result = new ArrayList<ExtendedPersonWithAddress>(); for (int i = 0; i < numberOfPersons; i++) { - result.add(new ExtendedPersonWithAddress(createPerson(), createAddress(), + result.add(new ExtendedPersonWithAddress(createPerson(i), createAddress(), generateSimplePassword(), createRandomLengthText(), createRandomMoneyAmount(), createFavouriteFood(), createFavouriteDrinks())); } @@ -70,14 +70,14 @@ * and enrich them with random generated married state and birthday date. * @return */ - private static Person createPerson() { + private static Person createPerson(int id) { String[] maleNames = {"Bart", "Homer", "Lenny", "Carl", "Waylon", "Ned", "Timothy"}; String[] femaleNames = {"Marge", "Lisa", "Maggie", "Edna", "Helen", "Jessica"}; String[] lastNames = {"Simpson", "Leonard", "Carlson", "Smithers", "Flanders", "Krabappel", "Lovejoy"}; Random randomGenerator = new Random(); - Person result = new Person(); + Person result = new Person(id); result.setGender(Gender.values()[randomGenerator.nextInt(2)]); if (result.getGender().equals(Gender.MALE)) {
diff --git a/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/data/person/PersonWithAddress.java b/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/data/person/PersonWithAddress.java index 1e07498..4979dec 100644 --- a/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/data/person/PersonWithAddress.java +++ b/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/data/person/PersonWithAddress.java
@@ -7,14 +7,14 @@ private Address address; - public PersonWithAddress(String firstName, String lastName, Gender gender, + public PersonWithAddress(int id, String firstName, String lastName, Gender gender, boolean married, Date birthday, Address address) { - super(firstName, lastName, gender, married, birthday); + super(id, firstName, lastName, gender, married, birthday); this.address = address; } public PersonWithAddress(Person person, Address address) { - super(person.getFirstName(), person.getLastName(), person.getGender(), + super(person.getId(), person.getFirstName(), person.getLastName(), person.getGender(), person.isMarried(), person.getBirthday()); this.address = address; }
diff --git a/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/examples/_100_Layers/TreeGridExample.java b/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/examples/_100_Layers/TreeGridExample.java index 26f4e0c..6d4ea20 100644 --- a/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/examples/_100_Layers/TreeGridExample.java +++ b/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/examples/_100_Layers/TreeGridExample.java
@@ -28,7 +28,7 @@ import org.eclipse.nebula.widgets.nattable.extension.glazedlists.GlazedListsDataProvider; import org.eclipse.nebula.widgets.nattable.extension.glazedlists.GlazedListsEventLayer; import org.eclipse.nebula.widgets.nattable.extension.glazedlists.GlazedListsSortModel; -import org.eclipse.nebula.widgets.nattable.extension.glazedlists.NewGlazedListsEventLayer; +import org.eclipse.nebula.widgets.nattable.extension.glazedlists.DetailGlazedListsEventLayer; import org.eclipse.nebula.widgets.nattable.extension.glazedlists.tree.GlazedListTreeData; import org.eclipse.nebula.widgets.nattable.extension.glazedlists.tree.GlazedListTreeRowModel; import org.eclipse.nebula.widgets.nattable.grid.data.DefaultColumnHeaderDataProvider; @@ -104,8 +104,8 @@ // GlazedListsEventLayer<Datum> glazedListsEventLayer = // new GlazedListsEventLayer<Datum>(bodyDataLayer, treeList); - NewGlazedListsEventLayer<Datum> glazedListsEventLayer = - new NewGlazedListsEventLayer<Datum>(bodyDataLayer, treeList); + DetailGlazedListsEventLayer<Datum> glazedListsEventLayer = + new DetailGlazedListsEventLayer<Datum>(bodyDataLayer, treeList); // Body layer ColumnReorderLayer columnReorderLayer = new ColumnReorderLayer(glazedListsEventLayer);
diff --git a/org.eclipse.nebula.widgets.nattable.extension.glazedlists/META-INF/MANIFEST.MF b/org.eclipse.nebula.widgets.nattable.extension.glazedlists/META-INF/MANIFEST.MF index 8a216b0..3d4e19f 100644 --- a/org.eclipse.nebula.widgets.nattable.extension.glazedlists/META-INF/MANIFEST.MF +++ b/org.eclipse.nebula.widgets.nattable.extension.glazedlists/META-INF/MANIFEST.MF
@@ -9,6 +9,7 @@ org.eclipse.nebula.widgets.nattable.extension.glazedlists.groupBy, org.eclipse.nebula.widgets.nattable.extension.glazedlists.groupBy.action, org.eclipse.nebula.widgets.nattable.extension.glazedlists.groupBy.command, + org.eclipse.nebula.widgets.nattable.extension.glazedlists.hideshow, org.eclipse.nebula.widgets.nattable.extension.glazedlists.tree Import-Package: ca.odell.glazedlists, ca.odell.glazedlists.event, @@ -34,6 +35,7 @@ org.eclipse.nebula.widgets.nattable.grid.data, org.eclipse.nebula.widgets.nattable.grid.layer, org.eclipse.nebula.widgets.nattable.hideshow, + org.eclipse.nebula.widgets.nattable.hideshow.command, org.eclipse.nebula.widgets.nattable.hideshow.event, org.eclipse.nebula.widgets.nattable.layer, org.eclipse.nebula.widgets.nattable.layer.cell,
diff --git a/org.eclipse.nebula.widgets.nattable.extension.glazedlists/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/NewGlazedListsEventLayer.java b/org.eclipse.nebula.widgets.nattable.extension.glazedlists/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/DetailGlazedListsEventLayer.java similarity index 75% rename from org.eclipse.nebula.widgets.nattable.extension.glazedlists/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/NewGlazedListsEventLayer.java rename to org.eclipse.nebula.widgets.nattable.extension.glazedlists/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/DetailGlazedListsEventLayer.java index 9ce17c7..e1f37b4 100644 --- a/org.eclipse.nebula.widgets.nattable.extension.glazedlists/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/NewGlazedListsEventLayer.java +++ b/org.eclipse.nebula.widgets.nattable.extension.glazedlists/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/DetailGlazedListsEventLayer.java
@@ -32,13 +32,30 @@ import ca.odell.glazedlists.event.ListEventListener; /** + * This layer acts as the event listener for: + * <ol> + * <li>Glazed list events - {@link ListEvent} + * <li>Bean updates - PropertyChangeEvent(s) + * </ol> + * + * Compared to the GlazedListsEventLayer, this layer does not conflate events and only + * fire a single RowStructuralRefreshEvent for all events within 100ms. Instead it will + * fire a corresponding NatTable event with the detail information for every {@link ListEvent} + * fired by the GlazedLists immediately. + * + * @param <T> Type of the bean in the backing list. + * * @author Dirk Fauth * */ -public class NewGlazedListsEventLayer<T> extends AbstractLayerTransform +public class DetailGlazedListsEventLayer<T> extends AbstractLayerTransform implements IUniqueIndexLayer, ListEventListener<T>, PropertyChangeListener { - private static final Scheduler scheduler = new Scheduler(NewGlazedListsEventLayer.class.getSimpleName()); + /** + * The scheduler needed to add cleanup tasks which are scheduled after handling + * glazedlists events. + */ + private static final Scheduler scheduler = new Scheduler(DetailGlazedListsEventLayer.class.getSimpleName()); /** * The underlying layer of type {@link IUniqueIndexLayer} @@ -57,16 +74,27 @@ */ private EventList<T> eventList; - + /** + * The {@link ListEvent} that was handled before. Needed to ensure that the same event + * is not processed several times. Will be reset by the cleanup task 100ms after the handling. + */ private ListEvent<T> lastFiredEvent; - + /** + * The current scheduled cleanup task which is stored to ensure that at most only one cleanup + * task is active at any time and it can be stopped if the NatTable itself is disposed to avoid + * still active background tasks that get never be done. + */ private ScheduledFuture<?> cleanupFuture; /** - * @param underlyingLayer + * Create a new {@link DetailGlazedListsEventLayer} which is in fact a {@link ListEventListener} + * that listens to GlazedLists events and translate them into events that are understandable + * by the NatTable. + * @param underlyingLayer The underlying layer of type {@link IUniqueIndexLayer} + * @param eventList The {@link EventList} this layer should be added as listener. */ - public NewGlazedListsEventLayer(IUniqueIndexLayer underlyingLayer, EventList<T> eventList) { + public DetailGlazedListsEventLayer(IUniqueIndexLayer underlyingLayer, EventList<T> eventList) { super(underlyingLayer); this.underlyingLayer = underlyingLayer; @@ -115,7 +143,7 @@ cleanupFuture = scheduler.schedule(new Runnable() { @Override public void run() { - NewGlazedListsEventLayer.this.lastFiredEvent = null; + DetailGlazedListsEventLayer.this.lastFiredEvent = null; } }, 100L); } @@ -126,7 +154,7 @@ public boolean doCommand(ILayerCommand command) { if (command instanceof DisposeResourcesCommand) { //ensure to kill a possible running cleanup task - if (cleanupFuture == null || cleanupFuture.isDone() || cleanupFuture.isCancelled()) { + if (cleanupFuture != null && !cleanupFuture.isDone() && !cleanupFuture.isCancelled()) { scheduler.unschedule(cleanupFuture); } }
diff --git a/org.eclipse.nebula.widgets.nattable.extension.glazedlists/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/hideshow/GlazedListsMultiRowHideCommandHandler.java b/org.eclipse.nebula.widgets.nattable.extension.glazedlists/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/hideshow/GlazedListsMultiRowHideCommandHandler.java new file mode 100644 index 0000000..3d89ea7 --- /dev/null +++ b/org.eclipse.nebula.widgets.nattable.extension.glazedlists/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/hideshow/GlazedListsMultiRowHideCommandHandler.java
@@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2013 Dirk Fauth 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: + * Dirk Fauth <dirk.fauth@gmail.com> - initial API and implementation + *******************************************************************************/ +package org.eclipse.nebula.widgets.nattable.extension.glazedlists.hideshow; + +import org.eclipse.nebula.widgets.nattable.command.AbstractLayerCommandHandler; +import org.eclipse.nebula.widgets.nattable.hideshow.command.MultiRowHideCommand; + +/** + * Command handler for handling {@link MultiRowHideCommand}s in a NatTable that uses GlazedLists. + * + * @author Dirk Fauth + * + */ +public class GlazedListsMultiRowHideCommandHandler<T> extends AbstractLayerCommandHandler<MultiRowHideCommand>{ + + /** + * The {@link GlazedListsRowHideShowLayer} where this command handler should operate on. + */ + private final GlazedListsRowHideShowLayer<T> rowHideShowLayer; + + /** + * + * @param rowHideShowLayer The {@link GlazedListsRowHideShowLayer} where this command handler should operate on. + */ + public GlazedListsMultiRowHideCommandHandler(GlazedListsRowHideShowLayer<T> rowHideShowLayer) { + this.rowHideShowLayer = rowHideShowLayer; + } + + @Override + public Class<MultiRowHideCommand> getCommandClass() { + return MultiRowHideCommand.class; + } + + @Override + protected boolean doCommand(MultiRowHideCommand command) { + rowHideShowLayer.hideRowPositions(command.getRowPositions()); + return true; + } + +}
diff --git a/org.eclipse.nebula.widgets.nattable.extension.glazedlists/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/hideshow/GlazedListsMultiRowShowCommandHandler.java b/org.eclipse.nebula.widgets.nattable.extension.glazedlists/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/hideshow/GlazedListsMultiRowShowCommandHandler.java new file mode 100644 index 0000000..c78c3ac --- /dev/null +++ b/org.eclipse.nebula.widgets.nattable.extension.glazedlists/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/hideshow/GlazedListsMultiRowShowCommandHandler.java
@@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2013 Dirk Fauth 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: + * Dirk Fauth <dirk.fauth@gmail.com> - initial API and implementation + *******************************************************************************/ +package org.eclipse.nebula.widgets.nattable.extension.glazedlists.hideshow; + +import org.eclipse.nebula.widgets.nattable.command.AbstractLayerCommandHandler; +import org.eclipse.nebula.widgets.nattable.hideshow.command.MultiRowShowCommand; + +/** + * Command handler for handling {@link MultiRowShowCommand}s in a NatTable that uses GlazedLists. + * + * @author Dirk Fauth + * + */ +public class GlazedListsMultiRowShowCommandHandler<T> extends AbstractLayerCommandHandler<MultiRowShowCommand> { + + /** + * The {@link GlazedListsRowHideShowLayer} where this command handler should operate on. + */ + private final GlazedListsRowHideShowLayer<T> rowHideShowLayer; + + /** + * + * @param rowHideShowLayer The {@link GlazedListsRowHideShowLayer} where this command handler should operate on. + */ + public GlazedListsMultiRowShowCommandHandler(GlazedListsRowHideShowLayer<T> rowHideShowLayer) { + this.rowHideShowLayer = rowHideShowLayer; + } + + @Override + public Class<MultiRowShowCommand> getCommandClass() { + return MultiRowShowCommand.class; + } + + @Override + protected boolean doCommand(MultiRowShowCommand command) { + rowHideShowLayer.showRowIndexes(command.getRowIndexes()); + return true; + } + +}
diff --git a/org.eclipse.nebula.widgets.nattable.extension.glazedlists/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/hideshow/GlazedListsRowHideCommandHandler.java b/org.eclipse.nebula.widgets.nattable.extension.glazedlists/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/hideshow/GlazedListsRowHideCommandHandler.java new file mode 100644 index 0000000..d07e4a0 --- /dev/null +++ b/org.eclipse.nebula.widgets.nattable.extension.glazedlists/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/hideshow/GlazedListsRowHideCommandHandler.java
@@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2013 Dirk Fauth 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: + * Dirk Fauth <dirk.fauth@gmail.com> - initial API and implementation + *******************************************************************************/ +package org.eclipse.nebula.widgets.nattable.extension.glazedlists.hideshow; + +import static java.util.Arrays.asList; + +import org.eclipse.nebula.widgets.nattable.command.AbstractLayerCommandHandler; +import org.eclipse.nebula.widgets.nattable.hideshow.command.RowHideCommand; + +/** + * Command handler for handling {@link RowHideCommand}s in a NatTable that uses GlazedLists. + * + * @author Dirk Fauth + * + */ +public class GlazedListsRowHideCommandHandler<T> extends AbstractLayerCommandHandler<RowHideCommand> { + + /** + * The {@link GlazedListsRowHideShowLayer} where this command handler should operate on. + */ + private final GlazedListsRowHideShowLayer<T> rowHideShowLayer; + + /** + * + * @param rowHideShowLayer The {@link GlazedListsRowHideShowLayer} where this command handler should operate on. + */ + public GlazedListsRowHideCommandHandler(GlazedListsRowHideShowLayer<T> rowHideShowLayer) { + this.rowHideShowLayer = rowHideShowLayer; + } + + @Override + public Class<RowHideCommand> getCommandClass() { + return RowHideCommand.class; + } + + @Override + protected boolean doCommand(RowHideCommand command) { + rowHideShowLayer.hideRowPositions(asList(command.getRowPosition())); + return true; + } +}
diff --git a/org.eclipse.nebula.widgets.nattable.extension.glazedlists/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/hideshow/GlazedListsRowHideShowLayer.java b/org.eclipse.nebula.widgets.nattable.extension.glazedlists/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/hideshow/GlazedListsRowHideShowLayer.java new file mode 100644 index 0000000..9d3c876 --- /dev/null +++ b/org.eclipse.nebula.widgets.nattable.extension.glazedlists/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/hideshow/GlazedListsRowHideShowLayer.java
@@ -0,0 +1,277 @@ +/******************************************************************************* + * Copyright (c) 2013 Dirk Fauth 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: + * Dirk Fauth <dirk.fauth@gmail.com> - initial API and implementation + *******************************************************************************/ +package org.eclipse.nebula.widgets.nattable.extension.glazedlists.hideshow; + +import java.io.Serializable; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import org.eclipse.nebula.widgets.nattable.command.ILayerCommandHandler; +import org.eclipse.nebula.widgets.nattable.data.IRowDataProvider; +import org.eclipse.nebula.widgets.nattable.data.IRowIdAccessor; +import org.eclipse.nebula.widgets.nattable.layer.AbstractLayerTransform; +import org.eclipse.nebula.widgets.nattable.layer.ILayer; +import org.eclipse.nebula.widgets.nattable.layer.IUniqueIndexLayer; + +import ca.odell.glazedlists.FilterList; +import ca.odell.glazedlists.matchers.AbstractMatcherEditor; +import ca.odell.glazedlists.matchers.CompositeMatcherEditor; +import ca.odell.glazedlists.matchers.Matcher; +import ca.odell.glazedlists.matchers.MatcherEditor; + +/** + * Adds the functionality for manually hiding rows in a NatTable that is based on GlazedLists. + * Technically it will filter items by id in the {@link FilterList}. + * <p> + * Note: If you want to add row hide/show AND filtering to your NatTable, you need to use the + * DefaultGlazedListsStaticFilterStrategy and add the {@link Matcher} that is used by + * this command as a static {@link MatcherEditor}. Otherwise these two functions will not work + * correctly together. + * + * @author Dirk Fauth + * + * TODO add IPersistable + */ +public class GlazedListsRowHideShowLayer<T> extends AbstractLayerTransform implements IUniqueIndexLayer { + + /** + * The collection of row id's that are hidden. + */ + private final Set<Serializable> rowIdsToHide = new HashSet<Serializable>(); + + /** + * The {@link IRowIdAccessor} that is used to extract the id out of the row object. + * This is necessary to determine the row object to hide in terms of content. + */ + private final IRowIdAccessor<T> rowIdAccessor; + + /** + * The {@link IRowDataProvider} needed to get the object at a given position so it + * is possible to retrieve the id that is used for filtering. + */ + private final IRowDataProvider<T> rowDataProvider; + + /** + * The {@link MatcherEditor} that is used to filter the rows with the specified id's. + */ + private final HideRowMatcherEditor hideRowByIdMatcherEditor = new HideRowMatcherEditor(); + + /** + * Creates a {@link GlazedListsRowHideShowLayer} for adding row hide/show for GlazedLists based + * NatTables. Using this constructor will only instantiate this layer. To use this correctly + * you need to register the local row hide {@link MatcherEditor} against the {@link FilterList} yourself. + * @param underlyingLayer The underlying layer. + * @param rowDataProvider The {@link IRowDataProvider} needed to get the object at a given position so it + * is possible to retrieve the id that is used for filtering. + * @param rowIdAccessor The {@link IRowIdAccessor} that is used to extract the id out of the row object. + * This is necessary to determine the row object to hide in terms of content. + */ + public GlazedListsRowHideShowLayer( + ILayer underlyingLayer, IRowDataProvider<T> rowDataProvider, IRowIdAccessor<T> rowIdAccessor) { + super(underlyingLayer); + if (rowIdAccessor == null) { + throw new IllegalArgumentException("rowIdAccessor can not be null!"); //$NON-NLS-1$ + } + + this.rowDataProvider = rowDataProvider; + this.rowIdAccessor = rowIdAccessor; + + registerCommandHandlers(); + } + + /** + * Creates a {@link GlazedListsRowHideShowLayer} for adding row hide/show for GlazedLists based + * NatTables. Using this constructor will add the {@link MatcherEditor} to the given {@link FilterList}. + * This might not work correctly in combination with other filters like e.g. the filter row. + * @param underlyingLayer The underlying layer. + * @param rowDataProvider The {@link IRowDataProvider} needed to get the object at a given position so it + * is possible to retrieve the id that is used for filtering. + * @param rowIdAccessor The {@link IRowIdAccessor} that is used to extract the id out of the row object. + * This is necessary to determine the row object to hide in terms of content. + * @param filterList The {@link FilterList} to apply the local row hide {@link Matcher} to. + */ + public GlazedListsRowHideShowLayer( + ILayer underlyingLayer, IRowDataProvider<T> rowDataProvider, IRowIdAccessor<T> rowIdAccessor, FilterList<T> filterList) { + super(underlyingLayer); + if (rowIdAccessor == null) { + throw new IllegalArgumentException("rowIdAccessor can not be null!"); //$NON-NLS-1$ + } + if (filterList == null) { + throw new IllegalArgumentException("filterList can not be null!"); //$NON-NLS-1$ + } + + this.rowDataProvider = rowDataProvider; + this.rowIdAccessor = rowIdAccessor; + + filterList.setMatcherEditor(this.hideRowByIdMatcherEditor); + + registerCommandHandlers(); + } + + /** + * Creates a {@link GlazedListsRowHideShowLayer} for adding row hide/show for GlazedLists based + * NatTables. Using this constructor will add the {@link MatcherEditor} to the given + * {@link CompositeMatcherEditor}. This way it is possible to add more filter logic than only the + * row hide filter. + * @param underlyingLayer The underlying layer. + * @param rowDataProvider The {@link IRowDataProvider} needed to get the object at a given position so it + * is possible to retrieve the id that is used for filtering. + * @param rowIdAccessor The {@link IRowIdAccessor} that is used to extract the id out of the row object. + * This is necessary to determine the row object to hide in terms of content. + * @param matcherEditor The {@link CompositeMatcherEditor} to which the local row hide {@link Matcher} + * should be added. + */ + public GlazedListsRowHideShowLayer( + ILayer underlyingLayer, IRowDataProvider<T> rowDataProvider, IRowIdAccessor<T> rowIdAccessor, CompositeMatcherEditor<T> matcherEditor) { + super(underlyingLayer); + if (rowIdAccessor == null) { + throw new IllegalArgumentException("rowIdAccessor can not be null!"); //$NON-NLS-1$ + } + if (matcherEditor == null) { + throw new IllegalArgumentException("matcherEditor can not be null!"); //$NON-NLS-1$ + } + + this.rowDataProvider = rowDataProvider; + this.rowIdAccessor = rowIdAccessor; + + matcherEditor.getMatcherEditors().add(this.hideRowByIdMatcherEditor); + + registerCommandHandlers(); + } + + /** + * Register the {@link ILayerCommandHandler} that will handle the row hide/show events + * for this layer. + */ + protected void registerCommandHandlers() { + registerCommandHandler(new GlazedListsRowHideCommandHandler<T>(this)); + registerCommandHandler(new GlazedListsMultiRowHideCommandHandler<T>(this)); + registerCommandHandler(new GlazedListsShowAllRowsCommandHandler<T>(this)); + registerCommandHandler(new GlazedListsMultiRowShowCommandHandler<T>(this)); + } + + /** + * Hide the rows at the given positions. Will collect the id's of the rows at + * the given positions as this layer operates on content rather than positions. + * @param rowPositions The positions of the rows to hide. + */ + public void hideRowPositions(Collection<Integer> rowPositions) { + Collection<Serializable> rowIds = new HashSet<Serializable>(); + for (Integer rowPos : rowPositions) { + int rowIndex = getRowIndexByPosition(rowPos); + rowIds.add(rowIdAccessor.getRowId(rowDataProvider.getRowObject(rowIndex))); + } + hideRows(rowIds); + } + + /** + * Hide the rows at the given indexes. Will collect the id's of the rows at + * the given positions as this layer operates on content rather than positions. + * @param rowIndexes The indexes of the rows to hide. + */ + public void hideRowIndexes(Collection<Integer> rowIndexes) { + Collection<Serializable> rowIds = new HashSet<Serializable>(); + for (Integer rowIndex : rowIndexes) { + rowIds.add(rowIdAccessor.getRowId(rowDataProvider.getRowObject(rowIndex))); + } + hideRows(rowIds); + } + + /** + * Show the rows with the given indexes again. Will collect the id's of the rows at + * the given positions as this layer operates on content rather than positions. + * @param rowIndexes The indexes of the rows that should be showed again. + */ + public void showRowIndexes(Collection<Integer> rowIndexes) { + Collection<Serializable> rowIds = new HashSet<Serializable>(); + for (Integer rowIndex : rowIndexes) { + rowIds.add(rowIdAccessor.getRowId(rowDataProvider.getRowObject(rowIndex))); + } + showRows(rowIds); + } + + /** + * Hide the rows that contain the objects with the given row ids. + * @param rowIds The row ids of the rows that should be hidden. + */ + public void hideRows(Collection<Serializable> rowIds) { + this.rowIdsToHide.addAll(rowIds); + this.hideRowByIdMatcherEditor.fireChange(); + } + + /** + * Show the rows that contain the objects with the given row ids. + * Will of course only have impact if those rows are currently hidden. + * @param rowIds The row ids of the rows that should be showed. + */ + public void showRows(Collection<Serializable> rowIds) { + this.rowIdsToHide.removeAll(rowIds); + this.hideRowByIdMatcherEditor.fireChange(); + } + + /** + * Show all rows that where previously hidden. + */ + public void showAllRows() { + this.rowIdsToHide.clear(); + this.hideRowByIdMatcherEditor.fireChange(); + } + + /** + * @return The {@link MatcherEditor} that is used to filter the rows with the specified id's. + */ + public MatcherEditor<T> getMatcherEditor() { + return this.hideRowByIdMatcherEditor; + } + + @Override + public int getColumnPositionByIndex(int columnIndex) { + return ((IUniqueIndexLayer) getUnderlyingLayer()).getColumnPositionByIndex(columnIndex); + } + + @Override + public int getRowPositionByIndex(int rowIndex) { + return ((IUniqueIndexLayer) getUnderlyingLayer()).getRowPositionByIndex(rowIndex); + } + + /** + * {@link MatcherEditor} implementation that will only match objects that are not hidden by + * id. It also enables to fire change events to indicate changes to the filter. + * + * @author Dirk Fauth + * + */ + class HideRowMatcherEditor extends AbstractMatcherEditor<T> { + /** + * The {@link Matcher} that is used to filter the rows with the specified id's. + */ + private final Matcher<T> hideRowByIdMatcher = new Matcher<T>() { + @Override + public boolean matches(T rowObject) { + return !rowIdsToHide.contains(rowIdAccessor.getRowId(rowObject)); + } + }; + + @Override + public Matcher<T> getMatcher() { + return this.hideRowByIdMatcher; + } + + /** + * Fire a change so the listeners can be informed about a change for the {@link Matcher} + */ + public void fireChange() { + fireChanged(this.hideRowByIdMatcher); + } + } + +}
diff --git a/org.eclipse.nebula.widgets.nattable.extension.glazedlists/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/hideshow/GlazedListsShowAllRowsCommandHandler.java b/org.eclipse.nebula.widgets.nattable.extension.glazedlists/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/hideshow/GlazedListsShowAllRowsCommandHandler.java new file mode 100644 index 0000000..9a1e021 --- /dev/null +++ b/org.eclipse.nebula.widgets.nattable.extension.glazedlists/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/hideshow/GlazedListsShowAllRowsCommandHandler.java
@@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2013 Dirk Fauth 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: + * Dirk Fauth <dirk.fauth@gmail.com> - initial API and implementation + *******************************************************************************/ +package org.eclipse.nebula.widgets.nattable.extension.glazedlists.hideshow; + +import org.eclipse.nebula.widgets.nattable.command.AbstractLayerCommandHandler; +import org.eclipse.nebula.widgets.nattable.hideshow.command.ShowAllRowsCommand; + +/** + * Command handler to show all rows again that are currently hidden in the context of + * using GlazedLists. + * + * @author Dirk Fauth + * + */ +public class GlazedListsShowAllRowsCommandHandler<T> extends AbstractLayerCommandHandler<ShowAllRowsCommand> { + + /** + * The {@link GlazedListsRowHideShowLayer} where this command handler should operate on. + */ + private final GlazedListsRowHideShowLayer<T> rowHideShowLayer; + + /** + * + * @param rowHideShowLayer The {@link GlazedListsRowHideShowLayer} to operate on. + */ + public GlazedListsShowAllRowsCommandHandler(GlazedListsRowHideShowLayer<T> rowHideShowLayer) { + this.rowHideShowLayer = rowHideShowLayer; + } + + @Override + public Class<ShowAllRowsCommand> getCommandClass() { + return ShowAllRowsCommand.class; + } + + @Override + protected boolean doCommand(ShowAllRowsCommand command) { + rowHideShowLayer.showAllRows(); + return true; + } + +}