From 8df7151d15cedfffd4d934f0d2108f880eae778f Mon Sep 17 00:00:00 2001 From: millmanorama Date: Thu, 4 May 2017 15:00:00 +0200 Subject: [PATCH] cleanup, refactor DataResultViewerTable.java --- .../autopsy/corecomponents/Bundle.properties | 3 - .../corecomponents/DataResultViewerTable.form | 2 +- .../corecomponents/DataResultViewerTable.java | 301 +++++++++--------- 3 files changed, 153 insertions(+), 153 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties index 183a66a263..14b3c47fa7 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties @@ -90,11 +90,8 @@ DataContentViewerString.setDataView.errorNoText=(offset {0}-{1} contains no text DataContentViewerString.title=Strings DataContentViewerString.toolTip=Displays ASCII and Unicode strings extracted from the file. DataResultPanel.pleasewaitNodeDisplayName=Please Wait... -DataResultViewerTable.firstColLbl=Name DataResultViewerTable.illegalArgExc.noChildFromParent=Could not get a child Node from the given parent. DataResultViewerTable.illegalArgExc.childWithoutPropertySet=Child Node does not have the regular PropertySet. -DataResultViewerTable.title=Table -DataResultViewerTable.pleasewaitNodeDisplayName=Please Wait... DataResultViewerThumbnail.title=Thumbnail DataResultViewerThumbnail.goToPageTextField.msgDlg=Please enter a valid page number between 1 and {0} DataResultViewerThumbnail.goToPageTextField.err=Invalid page number diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.form b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.form index 199e2be329..d8b83f1dff 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.form @@ -31,7 +31,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java index cb94bd231e..a0c2635874 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java @@ -35,19 +35,16 @@ import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.prefs.Preferences; +import java.util.stream.Stream; import javax.swing.JTable; import javax.swing.ListSelectionModel; -import javax.swing.RowSorter; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ListSelectionEvent; import javax.swing.event.TableColumnModelEvent; import javax.swing.event.TableColumnModelListener; import javax.swing.table.TableCellRenderer; -import javax.swing.table.TableColumn; -import javax.swing.table.TableColumnModel; import org.netbeans.swing.etable.ETableColumn; -import org.netbeans.swing.etable.ETableColumnModel; import org.netbeans.swing.outline.DefaultOutlineCellRenderer; import org.netbeans.swing.outline.DefaultOutlineModel; import org.netbeans.swing.outline.Outline; @@ -67,16 +64,21 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined; /** * DataResult sortable table viewer + * + * @@@ Restore implementation of DataResultViewerTable as a DataResultViewer + * service provider when DataResultViewers can be made compatible with node + * multiple selection actions. */ -// @@@ Restore implementation of DataResultViewerTable as a DataResultViewer -// service provider when DataResultViewers can be made compatible with node -// multiple selection actions. //@ServiceProvider(service = DataResultViewer.class) public class DataResultViewerTable extends AbstractDataResultViewer { private static final long serialVersionUID = 1L; - private final String firstColumnLabel = NbBundle.getMessage(DataResultViewerTable.class, "DataResultViewerTable.firstColLbl"); + @NbBundle.Messages("DataResultViewerTable.firstColLbl=Name") + static private final String FIRST_COLUMN_LABEL = Bundle.DataResultViewerTable_firstColLbl(); + @NbBundle.Messages("DataResultViewerTable.pleasewaitNodeDisplayName=Please Wait...") + private static final String PLEASEWAIT_NODE_DISPLAY_NAME = Bundle.DataResultViewerTable_pleasewaitNodeDisplayName(); + private static final Color TAGGED_COLOR = new Color(200, 210, 220); /* * The properties map: * @@ -88,13 +90,16 @@ public class DataResultViewerTable extends AbstractDataResultViewer { */ private final Map> propertiesMap = new TreeMap<>(); private final PleasewaitNodeListener pleasewaitNodeListener = new PleasewaitNodeListener(); - private static final String PLEASEWAIT_NODE_DISPLAY_NAME = NbBundle.getMessage(DataResultViewerTable.class, "DataResultViewerTable.pleasewaitNodeDisplayName"); - private static final Color TAGGED_COLOR = new Color(200, 210, 220); + private Node currentRoot; // When a column in the table is moved, these two variables keep track of where // the column started and where it ended up. private int startColumnIndex = -1; private int endColumnIndex = -1; + + /* + * Convience reference to internal Outline. + */ private Outline outline; /** @@ -123,28 +128,12 @@ public class DataResultViewerTable extends AbstractDataResultViewer { outline = outlineView.getOutline(); outline.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); - - // don't show the root node - outline.setRootVisible(false); + outline.setRootVisible(false); // don't show the root node outline.setDragEnabled(false); + outline.setDefaultRenderer(Object.class, new ColorTagCustomRenderer()); // add a listener so that when columns are moved, the new order is stored outline.getColumnModel().addColumnModelListener(new TableColumnModelListener() { - @Override - public void columnAdded(TableColumnModelEvent e) { - } - - @Override - public void columnRemoved(TableColumnModelEvent e) { - } - - @Override - public void columnMarginChanged(ChangeEvent e) { - } - - @Override - public void columnSelectionChanged(ListSelectionEvent e) { - } @Override public void columnMoved(TableColumnModelEvent e) { @@ -169,39 +158,51 @@ public class DataResultViewerTable extends AbstractDataResultViewer { } endColumnIndex = toIndex; - // This array contains the keys of propertiesMap in order - int[] indicesList = new int[propertiesMap.size()]; - int pos = 0; - for (int key : propertiesMap.keySet()) { - indicesList[pos++] = key; - } + // This list contains the keys of propertiesMap in order + ArrayList indicesList = new ArrayList<>(propertiesMap.keySet()); int leftIndex = Math.min(fromIndex, toIndex); int rightIndex = Math.max(fromIndex, toIndex); // Now we can copy the range of keys that have been affected by // the column movement - int[] range = Arrays.copyOfRange(indicesList, leftIndex, rightIndex + 1); - int rangeSize = range.length; + List range = indicesList.subList(leftIndex, rightIndex + 1); + int rangeSize = range.size(); - // column moved right, shift all properties left, put in moved - // property at the rightmost index if (fromIndex < toIndex) { - Property movedProp = propertiesMap.get(range[0]); + // column moved right, shift all properties left, put in moved + // property at the rightmost index + Property movedProp = propertiesMap.get(range.get(0)); for (int i = 0; i < rangeSize - 1; i++) { - propertiesMap.put(range[i], propertiesMap.get(range[i + 1])); + propertiesMap.put(range.get(i), propertiesMap.get(range.get(i + 1))); } - propertiesMap.put(range[rangeSize - 1], movedProp); - } // column moved left, shift all properties right, put in moved - // property at the leftmost index - else { - Property movedProp = propertiesMap.get(range[rangeSize - 1]); + propertiesMap.put(range.get(rangeSize - 1), movedProp); + } else { + // column moved left, shift all properties right, put in moved + // property at the leftmost index + Property movedProp = propertiesMap.get(range.get(rangeSize - 1)); for (int i = rangeSize - 1; i > 0; i--) { - propertiesMap.put(range[i], propertiesMap.get(range[i - 1])); + propertiesMap.put(range.get(i), propertiesMap.get(range.get(i - 1))); } - propertiesMap.put(range[0], movedProp); + propertiesMap.put(range.get(0), movedProp); } storeState(); } + + @Override + public void columnAdded(TableColumnModelEvent e) { + } + + @Override + public void columnRemoved(TableColumnModelEvent e) { + } + + @Override + public void columnMarginChanged(ChangeEvent e) { + } + + @Override + public void columnSelectionChanged(ListSelectionEvent e) { + } }); // add a listener to move columns back if user tries to move the first column out of place @@ -238,6 +239,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer { * @param n Node to expand */ @Override + public void expandNode(Node n) { super.expandNode(n); @@ -255,7 +257,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer { // //GEN-BEGIN:initComponents private void initComponents() { - outlineView = new OutlineView(this.firstColumnLabel); + outlineView = new OutlineView(DataResultViewerTable.FIRST_COLUMN_LABEL); outlineView.addComponentListener(new java.awt.event.ComponentAdapter() { public void componentResized(java.awt.event.ComponentEvent evt) { @@ -282,29 +284,45 @@ public class DataResultViewerTable extends AbstractDataResultViewer { // End of variables declaration//GEN-END:variables /** - * Gets regular Bean property set properties from all children and, - * recursively, subchildren of Node. Note: won't work out the box for lazy - * load - you need to set all children props for the parent by hand + * Gets properties from all children and, recursively, subchildren of Node. + * Note: won't work out the box for lazy load - you need to set all children + * props for the parent by hand * - * @param parent Node with at least one child to get properties from - * @param rows max number of rows to retrieve properties for (can be used - * for memory optimization) + * JMTODO: This is 'search' goes depth first. Is that really what we want + * when getting child headers? + * + * @param node the Node to get properties for. + * + * @return A List of properties. */ - private void getAllChildPropertyHeadersRec(Node parent, int rows, Set> propertiesAcc) { + static private List> getAllChildProperties(Node node) { + // This is a set because we add properties of up to 100 child nodes, and we want unique properties + Set> propertiesAcc = new LinkedHashSet<>(); + getAllChildPropertiesHelper(node, 100, propertiesAcc); + return new ArrayList<>(propertiesAcc); + } + + /** + * Helper to get the properties from all children and, recursively, + * subchildren of Node. Note: won't work out the box for lazy load - you + * need to set all children props for the parent by hand + * + * @param parent Node with at least one child to get properties from + * @param maxRows max number of rows to retrieve properties for (can + * be used for memory optimization) + * @param propertiesAcc Accumulator for properties. + */ + static private void getAllChildPropertiesHelper(Node parent, int maxRows, Set> propertiesAcc) { Children children = parent.getChildren(); int childCount = 0; for (Node child : children.getNodes()) { - if (++childCount > rows) { + if (++childCount > maxRows) { return; } for (PropertySet ps : child.getPropertySets()) { - final Property[] props = ps.getProperties(); - final int propsNum = props.length; - for (int j = 0; j < propsNum; ++j) { - propertiesAcc.add(props[j]); - } + propertiesAcc.addAll(Arrays.asList(ps.getProperties())); } - getAllChildPropertyHeadersRec(child, rows, propertiesAcc); + getAllChildPropertiesHelper(child, maxRows, propertiesAcc); } } @@ -313,12 +331,6 @@ public class DataResultViewerTable extends AbstractDataResultViewer { return true; } - /** - * Thread note: Make sure to run this in the EDT as it causes GUI - * operations. - * - * @param selectedNode - */ @Override @ThreadConfined(type = ThreadConfined.ThreadType.AWT) public void setNode(Node selectedNode) { @@ -448,49 +460,6 @@ public class DataResultViewerTable extends AbstractDataResultViewer { loadSort(); - /** - * This custom renderer extends the renderer that was already being used - * by the outline table. This renderer colors a row if the tags property - * of the node is not empty. - */ - class ColorTagCustomRenderer extends DefaultOutlineCellRenderer { - - private static final long serialVersionUID = 1L; - - @Override - public Component getTableCellRendererComponent(JTable table, - Object value, boolean isSelected, boolean hasFocus, int row, int col) { - - Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col); - // only override the color if a node is not selected - if (!isSelected) { - Node node = currentRoot.getChildren().getNodeAt(table.convertRowIndexToModel(row)); - boolean tagFound = false; - if (node != null) { - Node.PropertySet[] propSets = node.getPropertySets(); - if (propSets.length != 0) { - // currently, a node has only one property set, named Sheet.PROPERTIES ("properties") - Node.Property[] props = propSets[0].getProperties(); - for (Property prop : props) { - if (prop.getName().equals("Tags")) { - try { - tagFound = !prop.getValue().equals(""); - } catch (IllegalAccessException | InvocationTargetException ignore) { - } - break; - } - } - } - } - //if the node does have associated tags, set its background color - if (tagFound) { - component.setBackground(TAGGED_COLOR); - } - } - return component; - } - } - outline.setDefaultRenderer(Object.class, new ColorTagCustomRenderer()); } /** @@ -505,20 +474,20 @@ public class DataResultViewerTable extends AbstractDataResultViewer { final Preferences preferences = NbPreferences.forModule(DataResultViewerTable.class); // Store the current order of the columns into settings for (Map.Entry> entry : propertiesMap.entrySet()) { - preferences.put(getColumnPositionKey(tfn.getColumnOrderKey(), entry.getValue().getName()), String.valueOf(entry.getKey())); + preferences.put(getColumnPositionKey(tfn, entry.getValue().getName()), String.valueOf(entry.getKey())); } - int numCols = ov.getOutline().getColumnModel().getColumnCount(); + int numCols = outline.getColumnModel().getColumnCount(); for (int i = 0; i < numCols; i++) { - ETableColumn etc = (ETableColumn) ov.getOutline().getColumnModel().getColumn(i); + ETableColumn etc = (ETableColumn) outline.getColumnModel().getColumn(i); if (etc.isSorted()) { - preferences.put(getColumnSortOrderKey(tfn.getColumnOrderKey(), etc.getIdentifier().toString()), String.valueOf(etc.isAscending())); - preferences.put(getColumnSortRankKey(tfn.getColumnOrderKey(), etc.getIdentifier().toString()), String.valueOf(etc.getSortRank())); - preferences.put(getColumnSortOrderKey(tfn.getColumnOrderKey(), etc.getIdentifier().toString()), String.valueOf(etc.isAscending())); - preferences.put(getColumnSortRankKey(tfn.getColumnOrderKey(), etc.getIdentifier().toString()), String.valueOf(etc.getSortRank())); + preferences.put(getColumnSortOrderKey(tfn, etc.getIdentifier().toString()), String.valueOf(etc.isAscending())); + preferences.put(getColumnSortRankKey(tfn, etc.getIdentifier().toString()), String.valueOf(etc.getSortRank())); + preferences.put(getColumnSortOrderKey(tfn, etc.getIdentifier().toString()), String.valueOf(etc.isAscending())); + preferences.put(getColumnSortRankKey(tfn, etc.getIdentifier().toString()), String.valueOf(etc.getSortRank())); } else { - preferences.remove(getColumnSortOrderKey(tfn.getColumnOrderKey(), etc.getIdentifier().toString())); - preferences.remove(getColumnSortRankKey(tfn.getColumnOrderKey(), etc.getIdentifier().toString())); + preferences.remove(getColumnSortOrderKey(tfn, etc.getIdentifier().toString())); + preferences.remove(getColumnSortRankKey(tfn, etc.getIdentifier().toString())); } } } @@ -537,8 +506,8 @@ public class DataResultViewerTable extends AbstractDataResultViewer { Map indexMap = new TreeMap<>(); propertiesMap.entrySet().forEach((entry) -> { - Boolean sortOrder = Boolean.valueOf(preferences.get(getColumnSortOrderKey(tfn.getColumnOrderKey(), entry.getValue().getName()), "true")); - Integer sortRank = Integer.valueOf(preferences.get(getColumnSortRankKey(tfn.getColumnOrderKey(), entry.getValue().getName()), "0")); + Boolean sortOrder = Boolean.valueOf(preferences.get(getColumnSortOrderKey(tfn, entry.getValue().getName()), "true")); + Integer sortRank = Integer.valueOf(preferences.get(getColumnSortRankKey(tfn, entry.getValue().getName()), "0")); //if the sort rank is undefined, it will be defaulted to 0 , unsorted. orderMap.put(sortRank, sortOrder); @@ -558,20 +527,14 @@ public class DataResultViewerTable extends AbstractDataResultViewer { * @return a List> of the preferences in order */ private synchronized List> loadColumnOrder() { - // This is a set because we add properties of up to 100 child nodes, and we want unique properties - Set> propertiesAcc = new LinkedHashSet<>(); - this.getAllChildPropertyHeadersRec(currentRoot, 100, propertiesAcc); - - List> props = new ArrayList<>(propertiesAcc); + List> props = getAllChildProperties(currentRoot); // If node is not table filter node, use default order for columns - TableFilterNode tfn; - if (currentRoot instanceof TableFilterNode) { - tfn = (TableFilterNode) currentRoot; - } else { + if (!(currentRoot instanceof TableFilterNode)) { // The node is not a TableFilterNode, columns are going to be in default order return props; } + TableFilterNode tfn = (TableFilterNode) currentRoot; propertiesMap.clear(); /* @@ -583,10 +546,9 @@ public class DataResultViewerTable extends AbstractDataResultViewer { int offset = props.size(); boolean noPreviousSettings = true; - final Preferences preferences = NbPreferences.forModule(DataResultViewerTable.class - ); + final Preferences preferences = NbPreferences.forModule(DataResultViewerTable.class); for (Property prop : props) { - Integer value = Integer.valueOf(preferences.get(getColumnPositionKey(tfn.getColumnOrderKey(), prop.getName()), "-1")); + Integer value = Integer.valueOf(preferences.get(getColumnPositionKey(tfn, prop.getName()), "-1")); if (value >= 0 && value < offset && !propertiesMap.containsKey(value)) { propertiesMap.put(value, prop); noPreviousSettings = false; @@ -601,7 +563,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer { if (noPreviousSettings) { ArrayList keys = new ArrayList<>(propertiesMap.keySet()); for (int key : keys) { - propertiesMap.put(key - props.size(), propertiesMap.remove(key)); + propertiesMap.put(key - offset, propertiesMap.remove(key)); } } @@ -613,35 +575,34 @@ public class DataResultViewerTable extends AbstractDataResultViewer { * store the column position into a preference file. * * @param propName Property of the column - * @param type The type of the current node + * @param node The current node to use as a base for the property key. * * @return A generated key for the preference file */ - private String getColumnPositionKey(String type, String propName) { - return getColumnKeyBase(type, propName) + ".column"; + private String getColumnPositionKey(TableFilterNode node, String propName) { + return getColumnKeyBase(node, propName) + ".column"; //NON-NLS } - private String getColumnSortOrderKey(String type, String propName) { - return getColumnKeyBase(type, propName) + ".sortOrder"; + private String getColumnSortOrderKey(TableFilterNode node, String propName) { + return getColumnKeyBase(node, propName) + ".sortOrder";//NON-NLS } - private String getColumnSortRankKey(String type, String propName) { - return getColumnKeyBase(type, propName) + ".sortRank"; + private String getColumnSortRankKey(TableFilterNode node, String propName) { + return getColumnKeyBase(node, propName) + ".sortRank";//NON-NLS } - private static String getColumnKeyBase(String type, String propName) { - return stripNonAlphanumeric(type) + "." + stripNonAlphanumeric(propName); + private static String getColumnKeyBase(TableFilterNode node, String propName) { + return stripNonAlphanumeric(node.getColumnOrderKey()) + "." + stripNonAlphanumeric(propName); } private static String stripNonAlphanumeric(String str) { - return str.replaceAll("[^a-zA-Z0-9_]", ""); + return str.replaceAll("[^a-zA-Z0-9_]", "");//NON-NLS } @Override - public String - getTitle() { - return NbBundle.getMessage(DataResultViewerTable.class, - "DataResultViewerTable.title"); + @NbBundle.Messages("DataResultViewerTable.title=Table") + public String getTitle() { + return Bundle.DataResultViewerTable_title(); } @Override @@ -686,4 +647,46 @@ public class DataResultViewerTable extends AbstractDataResultViewer { .noneMatch(PLEASEWAIT_NODE_DISPLAY_NAME::equals); } } + + /** + * This custom renderer extends the renderer that was already being used by + * the outline table. This renderer colors a row if the tags property of the + * node is not empty. + */ + class ColorTagCustomRenderer extends DefaultOutlineCellRenderer { + + private static final long serialVersionUID = 1L; + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) { + + Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col); + // only override the color if a node is not selected + if (!isSelected) { + Node node = currentRoot.getChildren().getNodeAt(table.convertRowIndexToModel(row)); + boolean tagFound = false; + if (node != null) { + Node.PropertySet[] propSets = node.getPropertySets(); + if (propSets.length != 0) { + // currently, a node has only one property set, named Sheet.PROPERTIES ("properties") + Node.Property[] props = propSets[0].getProperties(); + for (Property prop : props) { + if ("Tags".equals(prop.getName())) {//NON-NLS + try { + tagFound = !prop.getValue().equals(""); + } catch (IllegalAccessException | InvocationTargetException ignore) { + } + break; + } + } + } + } + //if the node does have associated tags, set its background color + if (tagFound) { + component.setBackground(TAGGED_COLOR); + } + } + return component; + } + } }