diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/events/TagAddedEvent.java b/Core/src/org/sleuthkit/autopsy/casemodule/events/TagAddedEvent.java index 365a3c0ff8..1f679c47a3 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/events/TagAddedEvent.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/events/TagAddedEvent.java @@ -39,7 +39,7 @@ abstract class TagAddedEvent extends AutopsyEvent implements Seri private transient T tag; /** - * The id of the tag that was added. This will bu used to re-load the + * The id of the tag that was added. This will be used to re-load the * transient tag from the database. */ private final Long tagID; diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java index 17a0bfda95..a3e87e3008 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.corecomponents; +import java.awt.Color; import java.awt.Component; import java.awt.Cursor; import java.awt.FontMetrics; @@ -26,6 +27,7 @@ import java.awt.dnd.DnDConstants; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.beans.PropertyChangeEvent; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashSet; @@ -41,6 +43,7 @@ import javax.swing.event.ListSelectionEvent; import javax.swing.event.TableColumnModelEvent; import javax.swing.event.TableColumnModelListener; import javax.swing.table.TableCellRenderer; +import org.netbeans.swing.outline.DefaultOutlineCellRenderer; import org.netbeans.swing.outline.DefaultOutlineModel; import org.openide.explorer.ExplorerManager; import org.openide.explorer.view.OutlineView; @@ -66,6 +69,8 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer; //@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"); /* The properties map maps * key: stored value of column index -> value: property at that index @@ -76,6 +81,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer { private final Map> propertiesMap = new TreeMap<>(); private final DummyNodeListener dummyNodeListener = new DummyNodeListener(); private static final String DUMMY_NODE_DISPLAY_NAME = NbBundle.getMessage(DataResultViewerTable.class, "DataResultViewerTable.dummyNodeDisplayName"); + 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. @@ -113,6 +119,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer { ov.getOutline().setRootVisible(false); ov.getOutline().setDragEnabled(false); + // add a listener so that when columns are moved, the new order is stored ov.getOutline().getColumnModel().addColumnModelListener(new TableColumnModelListener() { @Override public void columnAdded(TableColumnModelEvent e) { @@ -183,6 +190,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer { } }); + // add a listener to move columns back if user tries to move the first column out of place ov.getOutline().getTableHeader().addMouseListener(new MouseAdapter() { @Override public void mouseReleased(MouseEvent e) { @@ -387,7 +395,6 @@ public class DataResultViewerTable extends AbstractDataResultViewer { ov.getOutline().setAutoResizeMode((props.size() > 0) ? JTable.AUTO_RESIZE_OFF : JTable.AUTO_RESIZE_ALL_COLUMNS); if (root.getChildren().getNodesCount() != 0) { - final Graphics graphics = ov.getGraphics(); if (graphics != null) { final FontMetrics metrics = graphics.getFontMetrics(); @@ -397,7 +404,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer { for (int column = 0; column < ov.getOutline().getModel().getColumnCount(); column++) { int firstColumnPadding = (column == 0) ? 32 : 0; - int columnWidthLimit = (column == 0) ? 250 : 350; + int columnWidthLimit = (column == 0) ? 350 : 300; int valuesWidth = 0; // find the maximum width needed to fit the values for the first 100 rows, at most @@ -421,6 +428,48 @@ public class DataResultViewerTable extends AbstractDataResultViewer { // if there's no content just auto resize all columns ov.getOutline().setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); } + + /** + * 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; + } + } + ov.getOutline().setDefaultRenderer(Object.class, new ColorTagCustomRenderer()); } /** @@ -547,11 +596,8 @@ public class DataResultViewerTable extends AbstractDataResultViewer { if (SwingUtilities.isEventDispatchThread()) { setupTable(nme.getNode()); } else { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - setupTable(nme.getNode()); - } + SwingUtilities.invokeLater(() -> { + setupTable(nme.getNode()); }); } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java index 0458ec9a59..e3c750826d 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java @@ -1,15 +1,15 @@ /* * Autopsy Forensic Browser - * - * Copyright 2011-2014 Basis Technology Corp. + * + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,17 +20,24 @@ package org.sleuthkit.autopsy.datamodel; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.util.ArrayList; +import java.util.List; import org.openide.nodes.Children; import java.util.Map; import java.util.logging.Level; +import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; +import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TskCoreException; /** @@ -103,9 +110,23 @@ public abstract class AbstractAbstractFileNode extends A // case was closed. Remove listeners so that we don't get called with a stale case handle removeListeners(); } + } else if (eventType.equals(Case.Events.CONTENT_TAG_ADDED.toString())) { + ContentTagAddedEvent event = (ContentTagAddedEvent) evt; + if (event.getAddedTag().getContent().equals(content)) { + updateSheet(); + } + } else if (eventType.equals(Case.Events.CONTENT_TAG_DELETED.toString())) { + ContentTagDeletedEvent event = (ContentTagDeletedEvent) evt; + if (event.getDeletedTagInfo().getContentID() == content.getId()) { + updateSheet(); + } } }; + private void updateSheet() { + this.setSheet(createSheet()); + } + // Note: this order matters for the search result, changed it if the order of property headers on the "KeywordSearchNode"changed public static enum AbstractFilePropertyType { @@ -278,6 +299,24 @@ public abstract class AbstractAbstractFileNode extends A map.put(AbstractFilePropertyType.MIMETYPE.toString(), content.getMIMEType() == null ? "" : content.getMIMEType()); } + /** + * Used by subclasses of AbstractAbstractFileNode to add the tags property + * to their sheets. + * @param ss the modifiable Sheet.Set returned by Sheet.get(Sheet.PROPERTIES) + */ + protected void addTagProperty(Sheet.Set ss) { + final String NO_DESCR = NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.addFileProperty.desc"); + List tags; + try { + tags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(content); + } catch (TskCoreException ex) { + tags = new ArrayList<>(); + LOGGER.log(Level.SEVERE, "Failed to get tags for content " + content.getName(), ex); + } + ss.put(new NodeProperty<>("Tags", NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.addFileProperty.tags.displayName"), + NO_DESCR, tags.stream().map(t -> t.getName().getDisplayName()).collect(Collectors.joining(", ")))); + } + static String getContentDisplayName(AbstractFile file) { String name = file.getName(); switch (name) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractFsContentNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractFsContentNode.java index 5beca1dbc4..a6db3c1df1 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractFsContentNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractFsContentNode.java @@ -84,6 +84,9 @@ public abstract class AbstractFsContentNode extends Abst ss.put(new NodeProperty<>(HIDE_PARENT, HIDE_PARENT, HIDE_PARENT, HIDE_PARENT)); } + // add tags property to the sheet + addTagProperty(ss); + return s; } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java index 5975044f60..7d15bb2101 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java @@ -18,6 +18,8 @@ */ package org.sleuthkit.autopsy.datamodel; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; @@ -25,6 +27,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.logging.Level; +import java.util.stream.Collectors; import javax.swing.Action; import org.apache.commons.lang3.StringUtils; import org.openide.nodes.Children; @@ -35,6 +38,10 @@ import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagAddedEvent; +import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent; +import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.timeline.actions.ViewArtifactInTimelineAction; import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction; import org.sleuthkit.datamodel.AbstractFile; @@ -43,6 +50,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.Tag; import org.sleuthkit.datamodel.TskCoreException; /** @@ -70,6 +78,39 @@ public class BlackboardArtifactNode extends DisplayableItemNode { private static final Integer[] SHOW_FILE_METADATA = new Integer[]{ BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(),}; + private final PropertyChangeListener pcl = new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + String eventType = evt.getPropertyName(); + if (eventType.equals(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED.toString())) { + BlackBoardArtifactTagAddedEvent event = (BlackBoardArtifactTagAddedEvent) evt; + if (event.getAddedTag().getArtifact().equals(artifact)) { + updateSheet(); + } + } else if (eventType.equals(Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED.toString())) { + BlackBoardArtifactTagDeletedEvent event = (BlackBoardArtifactTagDeletedEvent) evt; + if (event.getDeletedTagInfo().getArtifactID() == artifact.getArtifactID()) { + updateSheet(); + } + } else if (eventType.equals(Case.Events.CONTENT_TAG_ADDED.toString())) { + ContentTagAddedEvent event = (ContentTagAddedEvent) evt; + if (event.getAddedTag().getContent().equals(associated)) { + updateSheet(); + } + } else if (eventType.equals(Case.Events.CONTENT_TAG_DELETED.toString())) { + ContentTagDeletedEvent event = (ContentTagDeletedEvent) evt; + if (event.getDeletedTagInfo().getContentID()== associated.getId()) { + updateSheet(); + } + } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { + if (evt.getNewValue() == null) { + // case was closed. Remove listeners so that we don't get called with a stale case handle + removeListeners(); + } + } + } + }; + /** * Construct blackboard artifact node from an artifact and using provided * icon @@ -86,6 +127,7 @@ public class BlackboardArtifactNode extends DisplayableItemNode { this.setName(Long.toString(artifact.getArtifactID())); this.setDisplayName(); this.setIconBaseWithExtension(iconPath); + Case.addPropertyChangeListener(pcl); } /** @@ -103,6 +145,11 @@ public class BlackboardArtifactNode extends DisplayableItemNode { this.setName(Long.toString(artifact.getArtifactID())); this.setDisplayName(); this.setIconBaseWithExtension(ExtractedContent.getIconFilePath(artifact.getArtifactTypeID())); //NON-NLS + Case.addPropertyChangeListener(pcl); + } + + private void removeListeners() { + Case.removePropertyChangeListener(pcl); } @Override @@ -157,7 +204,7 @@ public class BlackboardArtifactNode extends DisplayableItemNode { displayName = associated.getName(); } - // If this is a node for a keyword hit on an artifact, we set the + // If this is a node for a keyword hit on an artifact, we set the // display name to be the artifact type name followed by " Artifact" // e.g. "Messages Artifact". if (artifact != null && artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { @@ -208,6 +255,7 @@ public class BlackboardArtifactNode extends DisplayableItemNode { ss.put(np); } } + final int artifactTypeId = artifact.getArtifactTypeID(); // If mismatch, add props for extension and file type @@ -294,9 +342,24 @@ public class BlackboardArtifactNode extends DisplayableItemNode { } } + // add properties for tags + List tags = new ArrayList<>(); + try { + tags.addAll(Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact)); + tags.addAll(Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(associated)); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to get tags for artifact " + artifact.getDisplayName(), ex); + } + ss.put(new NodeProperty<>("Tags", NbBundle.getMessage(AbstractAbstractFileNode.class, "BlackboardArtifactNode.createSheet.tags.displayName"), + NO_DESCR, tags.stream().map(t -> t.getName().getDisplayName()).collect(Collectors.joining(", ")))); + return s; } + private void updateSheet() { + this.setSheet(createSheet()); + } + private String getRootParentName() { String parentName = associated.getName(); Content parent = associated; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java index 3ff339e98d..4647298931 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-2014 Basis Technology Corp. + * Copyright 2013-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties index df8ec72cb6..4b9d0225a6 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties @@ -270,3 +270,8 @@ DeleteReportAction.actionDisplayName.multipleReports=Delete Reports DeleteReportAction.actionPerformed.showConfirmDialog.title=Confirm Deletion DeleteReportAction.actionPerformed.showConfirmDialog.single.msg=Do you want to delete 1 report from the case? DeleteReportAction.actionPerformed.showConfirmDialog.multiple.msg=Do you want to delete {0} reports from the case? +AbstractAbstractFileNode.addFileProperty.desc=no description +AbstractAbstractFileNode.addFileProperty.tags.name=Tags +AbstractAbstractFileNode.addFileProperty.tags.displayName=Tags +BlackboardArtifactNode.createSheet.tags.name=Tags +BlackboardArtifactNode.createSheet.tags.displayName=Tags \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java index a1d78644dd..74ab98d517 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -42,6 +42,8 @@ import org.sleuthkit.datamodel.TskCoreException; */ class ContentTagNode extends DisplayableItemNode { + private static final Logger LOGGER = Logger.getLogger(ContentTagNode.class.getName()); + private static final String ICON_PATH = "org/sleuthkit/autopsy/images/blue-tag-icon-16.png"; //NON-NLS private final ContentTag tag; @@ -60,7 +62,7 @@ class ContentTagNode extends DisplayableItemNode { try { contentPath = content.getUniquePath(); } catch (TskCoreException ex) { - Logger.getLogger(ContentTagNode.class.getName()).log(Level.SEVERE, "Failed to get path for content (id = " + content.getId() + ")", ex); //NON-NLS + LOGGER.log(Level.SEVERE, "Failed to get path for content (id = " + content.getId() + ")", ex); //NON-NLS contentPath = NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.unavail.path"); } AbstractFile file = content instanceof AbstractFile ? (AbstractFile) content : null; @@ -103,6 +105,7 @@ class ContentTagNode extends DisplayableItemNode { NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileSize.displayName"), "", content.getSize())); + return propertySheet; } @@ -115,7 +118,7 @@ class ContentTagNode extends DisplayableItemNode { if (file != null) { actions.add(ViewFileInTimelineAction.createViewFileAction(file)); } - actions.add(null); // Adds a menu item separator. + actions.add(null); // Adds a menu item separator. actions.add(DeleteContentTagAction.getInstance()); return actions.toArray(new Action[actions.size()]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java index 73f4d95cd0..7ac9e37398 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2014 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,6 +23,7 @@ import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.logging.Level; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; @@ -103,7 +104,7 @@ public class DataSourcesNode extends DisplayableItemNode { currentKeys = Case.getCurrentCase().getDataSources(); setKeys(currentKeys); } catch (TskCoreException | IllegalStateException ex) { - logger.severe("Error getting data sources: " + ex.getMessage()); // NON-NLS + logger.log(Level.SEVERE, "Error getting data sources: {0}", ex.getMessage()); // NON-NLS setKeys(Collections.emptySet()); } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java index f81fd46e08..c7b8983be0 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2015 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -346,7 +346,7 @@ public class KeywordHits implements AutopsyVisitableItem { public class ListNode extends DisplayableItemNode implements Observer { - private String listName; + private final String listName; public ListNode(String listName) { super(Children.create(new TermFactory(listName), true), Lookups.singleton(listName)); @@ -411,7 +411,7 @@ public class KeywordHits implements AutopsyVisitableItem { private class TermFactory extends ChildFactory.Detachable implements Observer { - private String setName; + private final String setName; private TermFactory(String setName) { super(); @@ -447,8 +447,8 @@ public class KeywordHits implements AutopsyVisitableItem { public class TermNode extends DisplayableItemNode implements Observer { - private String setName; - private String keyword; + private final String setName; + private final String keyword; public TermNode(String setName, String keyword) { super(Children.create(new HitsFactory(setName, keyword), true), Lookups.singleton(keyword)); @@ -509,8 +509,8 @@ public class KeywordHits implements AutopsyVisitableItem { public class HitsFactory extends ChildFactory.Detachable implements Observer { - private String keyword; - private String setName; + private final String keyword; + private final String setName; public HitsFactory(String setName, String keyword) { super(); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java index 0e97757401..495737488b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java @@ -86,6 +86,9 @@ public class LayoutFileNode extends AbstractAbstractFileNode { ss.put(new NodeProperty<>(entry.getKey(), entry.getKey(), NO_DESCR, entry.getValue())); } + // add tags property to the sheet + addTagProperty(ss); + return s; } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java index e2f701d044..ecccb26272 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-2014 Basis Technology Corp. + * Copyright 2013-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; +import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -74,7 +75,9 @@ public class LocalFileNode extends AbstractAbstractFileNode { for (Map.Entry entry : map.entrySet()) { ss.put(new NodeProperty<>(entry.getKey(), entry.getKey(), NO_DESCR, entry.getValue())); } - // @@@ add more properties here... + + // add tags property to the sheet + addTagProperty(ss); return s; } @@ -82,9 +85,7 @@ public class LocalFileNode extends AbstractAbstractFileNode { @Override public Action[] getActions(boolean context) { List actionsList = new ArrayList<>(); - for (Action a : super.getActions(true)) { - actionsList.add(a); - } + actionsList.addAll(Arrays.asList(super.getActions(true))); actionsList.add(new ViewContextAction(NbBundle.getMessage(this.getClass(), "LocalFileNode.viewFileInDir.text"), this.content)); actionsList.add(null); // creates a menu separator actionsList.add(new NewWindowViewAction( diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index 2d89ef3cca..b8127fe5a7 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2015 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -46,8 +46,8 @@ import org.sleuthkit.datamodel.TskCoreException; * factory built on top of the NetBeans Children.Keys class. */ public class Tags implements AutopsyVisitableItem { - // Creation of a RootNode object corresponding to a Tags object is done - // by a CreateAutopsyNodeVisitor dispatched from the AbstractContentChildren + // Creation of a RootNode object corresponding to a Tags object is done + // by a CreateAutopsyNodeVisitor dispatched from the AbstractContentChildren // override of Children.Keys.createNodes(). private final TagResults tagResults = new TagResults(); @@ -325,7 +325,7 @@ public class Tags implements AutopsyVisitableItem { public class ContentTagTypeNode extends DisplayableItemNode implements Observer { private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS - private TagName tagName; + private final TagName tagName; public ContentTagTypeNode(TagName tagName) { super(Children.create(new ContentTagNodeFactory(tagName), true), Lookups.singleton(tagName.getDisplayName() + " " + CONTENT_DISPLAY_NAME)); @@ -423,7 +423,7 @@ public class Tags implements AutopsyVisitableItem { */ public class BlackboardArtifactTagTypeNode extends DisplayableItemNode implements Observer { - private TagName tagName; + private final TagName tagName; private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS public BlackboardArtifactTagTypeNode(TagName tagName) { @@ -505,7 +505,7 @@ public class Tags implements AutopsyVisitableItem { // The blackboard artifact tags to be wrapped are used as the keys. return new BlackboardArtifactTagNode(key); } - + @Override public void update(Observable o, Object arg) { refresh(true); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java index 9cf67f4649..246c6d6e1d 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java @@ -148,6 +148,7 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode entry : map.entrySet()) { ss.put(new NodeProperty<>(entry.getKey(), entry.getKey(), NO_DESCR, entry.getValue())); } + addTagProperty(ss); } else { ss.put(new NodeProperty<>(Bundle.VirtualDirectoryNode_createSheet_type_name(), Bundle.VirtualDirectoryNode_createSheet_type_displayName(),