/** update the visual representation of the selection state of this DrawableView */ protected synchronized void updateSelectionState() { final boolean selected = globalSelectionModel.isSelected(getFileID()); Platform.runLater( () -> { setBorder(selected ? SELECTED_BORDER : UNSELECTED_BORDER); }); }
@SuppressWarnings("deprecation") protected void initialize() { followUpToggle.setOnAction( (ActionEvent t) -> { if (followUpToggle.isSelected() == true) { globalSelectionModel.clearAndSelect(fileID); try { AddDrawableTagAction.getInstance().addTag(TagUtils.getFollowUpTagName(), ""); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to add follow up tag. Could not load TagName.", ex); } } else { // TODO: convert this to an action! final ImageGalleryController controller = ImageGalleryController.getDefault(); try { // remove file from old category group controller .getGroupManager() .removeFromGroup( new GroupKey<TagName>(DrawableAttribute.TAGS, TagUtils.getFollowUpTagName()), fileID); List<ContentTag> contentTagsByContent = Case.getCurrentCase() .getServices() .getTagsManager() .getContentTagsByContent(file); for (ContentTag ct : contentTagsByContent) { if (ct.getName() .getDisplayName() .equals(TagUtils.getFollowUpTagName().getDisplayName())) { Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(ct); } } IngestServices.getInstance() .fireModuleDataEvent( new ModuleDataEvent( "TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); // NON-NLS controller .getGroupManager() .handleFileUpdate( FileUpdateEvent.newUpdateEvent( Collections.singleton(fileID), DrawableAttribute.TAGS)); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); } } }); }
/** * An abstract base class for {@link DrawableTile} and {@link SlideShowView}, since they share a * similar node tree and many behaviors, other implementers of {@link DrawableView}s should * implement the interface directly */ public abstract class DrawableViewBase extends AnchorPane implements DrawableView { private static final Logger LOGGER = Logger.getLogger(DrawableViewBase.class.getName()); private static final Border UNSELECTED_BORDER = new Border( new BorderStroke( Color.GRAY, BorderStrokeStyle.SOLID, new CornerRadii(2), new BorderWidths(3))); private static final Border SELECTED_BORDER = new Border( new BorderStroke( Color.BLUE, BorderStrokeStyle.SOLID, new CornerRadii(2), new BorderWidths(3))); // TODO: do this in CSS? -jm protected static final Image videoIcon = new Image("org/sleuthkit/autopsy/imagegallery/images/video-file.png"); protected static final Image hashHitIcon = new Image("org/sleuthkit/autopsy/imagegallery/images/hashset_hits.png"); protected static final Image followUpIcon = new Image("org/sleuthkit/autopsy/imagegallery/images/flag_red.png"); protected static final Image followUpGray = new Image("org/sleuthkit/autopsy/imagegallery/images/flag_gray.png"); protected static final FileIDSelectionModel globalSelectionModel = FileIDSelectionModel.getInstance(); /** displays the icon representing video files */ @FXML protected ImageView fileTypeImageView; /** displays the icon representing hash hits */ @FXML protected ImageView hashHitImageView; /** displays the icon representing follow up tag */ @FXML protected ImageView followUpImageView; @FXML protected ToggleButton followUpToggle; /** the label that shows the name of the represented file */ @FXML protected Label nameLabel; @FXML protected BorderPane imageBorder; private static ContextMenu contextMenu; private DrawableFile<?> file; private Long fileID; /** the groupPane this {@link DrawableViewBase} is embedded in */ private final GroupPane groupPane; private boolean registered = false; GroupPane getGroupPane() { return groupPane; } protected DrawableViewBase(GroupPane groupPane) { this.groupPane = groupPane; globalSelectionModel .getSelected() .addListener( (Observable observable) -> { updateSelectionState(); }); // set up mouse listener // TODO: split this between DrawableTile and SingleDrawableViewBase addEventFilter( MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent t) { switch (t.getButton()) { case PRIMARY: if (t.getClickCount() == 1) { if (t.isControlDown()) { globalSelectionModel.toggleSelection(fileID); } else { groupPane.makeSelection(t.isShiftDown(), fileID); } } else if (t.getClickCount() > 1) { groupPane.activateSlideShowViewer(fileID); } break; case SECONDARY: if (t.getClickCount() == 1) { if (globalSelectionModel.isSelected(fileID) == false) { groupPane.makeSelection(false, fileID); } } if (contextMenu != null) { contextMenu.hide(); } final ContextMenu groupContextMenu = groupPane.getContextMenu(); if (groupContextMenu != null) { groupContextMenu.hide(); } contextMenu = buildContextMenu(); contextMenu.show(DrawableViewBase.this, t.getScreenX(), t.getScreenY()); break; } t.consume(); } private ContextMenu buildContextMenu() { final ArrayList<MenuItem> menuItems = new ArrayList<>(); menuItems.add(CategorizeAction.getPopupMenu()); menuItems.add(AddDrawableTagAction.getInstance().getPopupMenu()); final MenuItem extractMenuItem = new MenuItem("Extract File(s)"); extractMenuItem.setOnAction( (ActionEvent t) -> { SwingUtilities.invokeLater( () -> { TopComponent etc = WindowManager.getDefault() .findTopComponent(ImageGalleryTopComponent.PREFERRED_ID); ExtractAction.getInstance() .actionPerformed(new java.awt.event.ActionEvent(etc, 0, null)); }); }); menuItems.add(extractMenuItem); MenuItem contentViewer = new MenuItem("Show Content Viewer"); contentViewer.setOnAction( (ActionEvent t) -> { SwingUtilities.invokeLater( () -> { new NewWindowViewAction( "Show Content Viewer", new FileNode(getFile().getAbstractFile())) .actionPerformed(null); }); }); menuItems.add(contentViewer); MenuItem externalViewer = new MenuItem("Open in External Viewer"); final ExternalViewerAction externalViewerAction = new ExternalViewerAction( "Open in External Viewer", new FileNode(getFile().getAbstractFile())); externalViewer.setDisable(externalViewerAction.isEnabled() == false); externalViewer.setOnAction( (ActionEvent t) -> { SwingUtilities.invokeLater( () -> { externalViewerAction.actionPerformed(null); }); }); menuItems.add(externalViewer); Collection<? extends ContextMenuActionsProvider> menuProviders = Lookup.getDefault().lookupAll(ContextMenuActionsProvider.class); for (ContextMenuActionsProvider provider : menuProviders) { for (final Action act : provider.getActions()) { if (act instanceof Presenter.Popup) { Presenter.Popup aact = (Presenter.Popup) act; menuItems.add(SwingMenuItemAdapter.create(aact.getPopupPresenter())); } } } ContextMenu contextMenu = new ContextMenu(menuItems.toArray(new MenuItem[] {})); contextMenu.setAutoHide(true); return contextMenu; } }); } @ThreadConfined(type = ThreadType.UI) protected abstract void clearContent(); protected abstract void disposeContent(); protected abstract Runnable getContentUpdateRunnable(); protected abstract String getTextForLabel(); @SuppressWarnings("deprecation") protected void initialize() { followUpToggle.setOnAction( (ActionEvent t) -> { if (followUpToggle.isSelected() == true) { globalSelectionModel.clearAndSelect(fileID); try { AddDrawableTagAction.getInstance().addTag(TagUtils.getFollowUpTagName(), ""); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to add follow up tag. Could not load TagName.", ex); } } else { // TODO: convert this to an action! final ImageGalleryController controller = ImageGalleryController.getDefault(); try { // remove file from old category group controller .getGroupManager() .removeFromGroup( new GroupKey<TagName>(DrawableAttribute.TAGS, TagUtils.getFollowUpTagName()), fileID); List<ContentTag> contentTagsByContent = Case.getCurrentCase() .getServices() .getTagsManager() .getContentTagsByContent(file); for (ContentTag ct : contentTagsByContent) { if (ct.getName() .getDisplayName() .equals(TagUtils.getFollowUpTagName().getDisplayName())) { Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(ct); } } IngestServices.getInstance() .fireModuleDataEvent( new ModuleDataEvent( "TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); // NON-NLS controller .getGroupManager() .handleFileUpdate( FileUpdateEvent.newUpdateEvent( Collections.singleton(fileID), DrawableAttribute.TAGS)); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); } } }); } @Override public DrawableFile<?> getFile() { if (fileID != null) { if (file == null || file.getId() != fileID) { try { file = ImageGalleryController.getDefault().getFileFromId(fileID); } catch (TskCoreException ex) { LOGGER.log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileID, ex); file = null; } } return file; } else { return null; } } protected boolean hasFollowUp() throws TskCoreException { String followUpTagName = TagUtils.getFollowUpTagName().getDisplayName(); Collection<TagName> tagNames = DrawableAttribute.TAGS.getValue(getFile()); return tagNames.stream().anyMatch((tn) -> tn.getDisplayName().equals(followUpTagName)); } @Override public synchronized Long getFileID() { return fileID; } @Override public synchronized void handleTagsChanged(Collection<Long> ids) { if (fileID != null && ids.contains(fileID)) { updateFollowUpIcon(); } } protected synchronized void updateFollowUpIcon() { if (file != null) { try { boolean hasFollowUp = hasFollowUp(); Platform.runLater( () -> { followUpImageView.setImage(hasFollowUp ? followUpIcon : followUpGray); followUpToggle.setSelected(hasFollowUp); }); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); } } } @Override public synchronized void setFile(final Long fileID) { if (Objects.equals(fileID, this.fileID) == false) { this.fileID = fileID; disposeContent(); if (this.fileID == null || Case.isCaseOpen() == false) { if (registered == true) { ImageGalleryController.getDefault().getCategoryManager().unregisterListener(this); TagUtils.unregisterListener(this); registered = false; } file = null; Platform.runLater( () -> { clearContent(); }); } else { if (registered == false) { ImageGalleryController.getDefault().getCategoryManager().registerListener(this); TagUtils.registerListener(this); registered = true; } file = null; getFile(); updateSelectionState(); updateCategoryBorder(); updateFollowUpIcon(); updateUI(); Platform.runLater(getContentUpdateRunnable()); } } } private void updateUI() { final boolean isVideo = getFile().isVideo(); final boolean hasHashSetHits = hasHashHit(); final String text = getTextForLabel(); Platform.runLater( () -> { fileTypeImageView.setImage(isVideo ? videoIcon : null); hashHitImageView.setImage(hasHashSetHits ? hashHitIcon : null); nameLabel.setText(text); nameLabel.setTooltip(new Tooltip(text)); }); } /** update the visual representation of the selection state of this DrawableView */ protected synchronized void updateSelectionState() { final boolean selected = globalSelectionModel.isSelected(getFileID()); Platform.runLater( () -> { setBorder(selected ? SELECTED_BORDER : UNSELECTED_BORDER); }); } @Override public Region getCategoryBorderRegion() { return imageBorder; } @Subscribe @Override public synchronized void handleCategoryChanged(CategoryChangeEvent evt) { if (evt.getIds().contains(getFileID())) { updateCategoryBorder(); } } }
protected DrawableViewBase(GroupPane groupPane) { this.groupPane = groupPane; globalSelectionModel .getSelected() .addListener( (Observable observable) -> { updateSelectionState(); }); // set up mouse listener // TODO: split this between DrawableTile and SingleDrawableViewBase addEventFilter( MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent t) { switch (t.getButton()) { case PRIMARY: if (t.getClickCount() == 1) { if (t.isControlDown()) { globalSelectionModel.toggleSelection(fileID); } else { groupPane.makeSelection(t.isShiftDown(), fileID); } } else if (t.getClickCount() > 1) { groupPane.activateSlideShowViewer(fileID); } break; case SECONDARY: if (t.getClickCount() == 1) { if (globalSelectionModel.isSelected(fileID) == false) { groupPane.makeSelection(false, fileID); } } if (contextMenu != null) { contextMenu.hide(); } final ContextMenu groupContextMenu = groupPane.getContextMenu(); if (groupContextMenu != null) { groupContextMenu.hide(); } contextMenu = buildContextMenu(); contextMenu.show(DrawableViewBase.this, t.getScreenX(), t.getScreenY()); break; } t.consume(); } private ContextMenu buildContextMenu() { final ArrayList<MenuItem> menuItems = new ArrayList<>(); menuItems.add(CategorizeAction.getPopupMenu()); menuItems.add(AddDrawableTagAction.getInstance().getPopupMenu()); final MenuItem extractMenuItem = new MenuItem("Extract File(s)"); extractMenuItem.setOnAction( (ActionEvent t) -> { SwingUtilities.invokeLater( () -> { TopComponent etc = WindowManager.getDefault() .findTopComponent(ImageGalleryTopComponent.PREFERRED_ID); ExtractAction.getInstance() .actionPerformed(new java.awt.event.ActionEvent(etc, 0, null)); }); }); menuItems.add(extractMenuItem); MenuItem contentViewer = new MenuItem("Show Content Viewer"); contentViewer.setOnAction( (ActionEvent t) -> { SwingUtilities.invokeLater( () -> { new NewWindowViewAction( "Show Content Viewer", new FileNode(getFile().getAbstractFile())) .actionPerformed(null); }); }); menuItems.add(contentViewer); MenuItem externalViewer = new MenuItem("Open in External Viewer"); final ExternalViewerAction externalViewerAction = new ExternalViewerAction( "Open in External Viewer", new FileNode(getFile().getAbstractFile())); externalViewer.setDisable(externalViewerAction.isEnabled() == false); externalViewer.setOnAction( (ActionEvent t) -> { SwingUtilities.invokeLater( () -> { externalViewerAction.actionPerformed(null); }); }); menuItems.add(externalViewer); Collection<? extends ContextMenuActionsProvider> menuProviders = Lookup.getDefault().lookupAll(ContextMenuActionsProvider.class); for (ContextMenuActionsProvider provider : menuProviders) { for (final Action act : provider.getActions()) { if (act instanceof Presenter.Popup) { Presenter.Popup aact = (Presenter.Popup) act; menuItems.add(SwingMenuItemAdapter.create(aact.getPopupPresenter())); } } } ContextMenu contextMenu = new ContextMenu(menuItems.toArray(new MenuItem[] {})); contextMenu.setAutoHide(true); return contextMenu; } }); }