From 745fd46e5f4a36da6164359370556e526587c30e Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 25 Nov 2020 18:13:07 -0500 Subject: [PATCH 1/5] 7067-Add context menus to Artifact lists in discovery --- .../ui/ArtifactListPanelInterface.java | 45 ++++ .../ui/ArtifactMenuMouseAdapter.java | 196 ++++++++++++++++++ .../discovery/ui/ArtifactsListPanel.form | 2 +- .../discovery/ui/ArtifactsListPanel.java | 71 ++++--- .../discovery/ui/Bundle.properties-MERGED | 2 + .../discovery/ui/DomainArtifactsTabPanel.java | 3 +- .../ui/MiniTimelineArtifactListPanel.java | 68 +++--- .../discovery/ui/MiniTimelinePanel.java | 5 +- 8 files changed, 336 insertions(+), 56 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactListPanelInterface.java create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactMenuMouseAdapter.java diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactListPanelInterface.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactListPanelInterface.java new file mode 100644 index 0000000000..e4a0613093 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactListPanelInterface.java @@ -0,0 +1,45 @@ +/* + * Autopsy + * + * Copyright 2020 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.discovery.ui; + +import java.awt.Point; +import java.util.List; +import javax.swing.JPopupMenu; +import javax.swing.event.ListSelectionListener; +import org.sleuthkit.datamodel.BlackboardArtifact; + +interface ArtifactListPanelInterface { + + void addMouseListener(java.awt.event.MouseAdapter mouseListener); + + void showPopupMenu(JPopupMenu popupMenu, Point point); + + BlackboardArtifact getSelectedArtifact(); + + void removeSelectionListener(ListSelectionListener listener); + + void addArtifacts(List artifactList); + + void addSelectionListener(ListSelectionListener listener); + + void selectFirst(); + + boolean isEmpty(); + +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactMenuMouseAdapter.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactMenuMouseAdapter.java new file mode 100644 index 0000000000..97dd10aa9e --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactMenuMouseAdapter.java @@ -0,0 +1,196 @@ +/* + * Autopsy + * + * Copyright 2020 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.discovery.ui; + +import java.awt.event.ActionEvent; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Level; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.JSeparator; +import javax.swing.SwingUtilities; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.actions.AddBlackboardArtifactTagAction; +import org.sleuthkit.autopsy.actions.AddContentTagAction; +import org.sleuthkit.autopsy.actions.DeleteFileBlackboardArtifactTagAction; +import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.DataModelActionsFactory; +import org.sleuthkit.autopsy.datamodel.FileNode; +import org.sleuthkit.autopsy.directorytree.ExportCSVAction; +import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; +import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction; +import org.sleuthkit.autopsy.directorytree.ExtractAction; +import org.sleuthkit.autopsy.directorytree.actionhelpers.ExtractActionHelper; +import org.sleuthkit.autopsy.timeline.actions.ViewArtifactInTimelineAction; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.TskCoreException; + +class ArtifactMenuMouseAdapter extends java.awt.event.MouseAdapter { + + private final ArtifactListPanelInterface listPanel; + private static final Logger logger = Logger.getLogger(ArtifactMenuMouseAdapter.class.getName()); + + ArtifactMenuMouseAdapter() { + listPanel = null; + } + + ArtifactMenuMouseAdapter(ArtifactListPanelInterface listPanel) { + this.listPanel = listPanel; + } + + @Override + public void mouseClicked(java.awt.event.MouseEvent evt) { + if (!evt.isPopupTrigger() && SwingUtilities.isRightMouseButton(evt) && listPanel != null && !listPanel.isEmpty()) { + showPopupMenu(evt); + } + } + + private void showPopupMenu(java.awt.event.MouseEvent event) { + BlackboardArtifact artifact = listPanel.getSelectedArtifact(); + if (artifact == null) { + return; + } + try { + JMenuItem[] items = getMenuItems(artifact); + JPopupMenu popupMenu = new JPopupMenu(); + for (JMenuItem menu : items) { + if (menu != null) { + popupMenu.add(menu); + } else { + popupMenu.add(new JSeparator()); + } + } + listPanel.showPopupMenu(popupMenu, event.getPoint()); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Unable to get source content of artifact with ID: " + artifact.getArtifactID(), ex); + } + } + + /** + * Returns a list of JMenuItems for the waypoint. The list list may contain + * nulls which should be removed or replaced with JSeparators. + * + * @return List of menu items + * + * @throws TskCoreException + */ + private JMenuItem[] getMenuItems(BlackboardArtifact artifact) throws TskCoreException { + List menuItems = new ArrayList<>(); + Content content = artifact.getSleuthkitCase().getContentById(artifact.getObjectID()); + menuItems.addAll(getTimelineMenuItems(artifact)); + menuItems.addAll(getDataModelActionFactoryMenuItems(artifact, content)); + menuItems.add(DeleteFileContentTagAction.getInstance().getMenuForFiles(Arrays.asList((AbstractFile) content))); + menuItems.add(DeleteFileBlackboardArtifactTagAction.getInstance().getMenuForArtifacts(Arrays.asList(artifact))); + return menuItems.toArray(new JMenuItem[0]); + } + + /** + * Gets the Timeline Menu Items for this artifact. + * + * @param artifact Selected artifact + * + * @return List of timeline menu items. + */ + private List getTimelineMenuItems(BlackboardArtifact artifact) { + List menuItems = new ArrayList<>(); + //if this artifact has a time stamp add the action to view it in the timeline + try { + if (ViewArtifactInTimelineAction.hasSupportedTimeStamp(artifact)) { + menuItems.add(new JMenuItem(new ViewArtifactInTimelineAction(artifact))); + } + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Error getting arttribute(s) from blackboard artifact %d.", artifact.getArtifactID()), ex); //NON-NLS + } + + return menuItems; + } + + /** + * Use the DateModelActionsFactory to get some of the basic actions for the + * waypoint. The advantage to using the DataModelActionsFactory is that the + * menu items can be put in a consistent order with other parts of the UI. + * + * @param artifact Artifact for the selected waypoint + * @param content Artifact content + * + * @return List of JMenuItems for the DataModelActionFactory actions + */ + @NbBundle.Messages({ + "ArtifactMenuMouseAdapter_ExternalViewer_label=Open in external viewer" + }) + private List getDataModelActionFactoryMenuItems(BlackboardArtifact artifact, Content content) { + List menuItems = new ArrayList<>(); + List actions = DataModelActionsFactory.getActions(content, true); + for (Action action : actions) { + if (action == null) { + menuItems.add(null); + } else if (action instanceof ExportCSVAction) { + // Do nothing we don't need this menu item. + } else if (action instanceof AddContentTagAction) { + menuItems.add(((AddContentTagAction) action).getMenuForContent(Arrays.asList((AbstractFile) content))); + } else if (action instanceof AddBlackboardArtifactTagAction) { + menuItems.add(((AddBlackboardArtifactTagAction) action).getMenuForContent(Arrays.asList(artifact))); + } else if (action instanceof ExternalViewerShortcutAction) { + // Replace with an ExternalViewerAction + ExternalViewerAction newAction = new ExternalViewerAction(Bundle.ArtifactMenuMouseAdapter_ExternalViewer_label(), new FileNode((AbstractFile) content)); + menuItems.add(new JMenuItem(newAction)); + } else if (action instanceof ExtractAction) { + menuItems.add(new JMenuItem(new ExtractFileAction((AbstractFile) content))); + } else { + menuItems.add(new JMenuItem(action)); + } + } + return menuItems; + } + + /** + * An action class for extracting the related file. + */ + @NbBundle.Messages({ + "ArtifactMenuMouseAdapter_label=Extract Files" + }) + final class ExtractFileAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + final private AbstractFile file; + + /** + * Construct a new ExtractFileAction. + * + * @param file The AbstractFile to be extracted. + */ + ExtractFileAction(AbstractFile file) { + super(Bundle.ArtifactMenuMouseAdapter_label()); + this.file = file; + } + + @Override + public void actionPerformed(ActionEvent e) { + ExtractActionHelper helper = new ExtractActionHelper(); + helper.extract(e, Arrays.asList(file)); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactsListPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactsListPanel.form index e04c0f37d9..3b9f9f4c7a 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactsListPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactsListPanel.form @@ -48,7 +48,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactsListPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactsListPanel.java index 9aa41b3c20..40e087d102 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactsListPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactsListPanel.java @@ -18,10 +18,12 @@ */ package org.sleuthkit.autopsy.discovery.ui; +import java.awt.Point; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import javax.swing.JPanel; +import javax.swing.JPopupMenu; import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import org.apache.commons.io.FilenameUtils; @@ -38,7 +40,7 @@ import org.sleuthkit.datamodel.TskCoreException; * Panel to display list of artifacts for selected domain. * */ -class ArtifactsListPanel extends JPanel { +final class ArtifactsListPanel extends JPanel implements ArtifactListPanelInterface { private static final long serialVersionUID = 1L; private final DomainArtifactTableModel tableModel; @@ -53,8 +55,18 @@ class ArtifactsListPanel extends JPanel { ArtifactsListPanel(BlackboardArtifact.ARTIFACT_TYPE artifactType) { tableModel = new DomainArtifactTableModel(artifactType); initComponents(); - jTable1.getRowSorter().toggleSortOrder(0); - jTable1.getRowSorter().toggleSortOrder(0); + artifactsTable.getRowSorter().toggleSortOrder(0); + artifactsTable.getRowSorter().toggleSortOrder(0); + } + + @Override + public void addMouseListener(java.awt.event.MouseAdapter mouseListener) { + artifactsTable.addMouseListener(mouseListener); + } + + @Override + public void showPopupMenu(JPopupMenu popupMenu, Point point) { + popupMenu.show(artifactsTable, point.x, point.y); } /** @@ -64,8 +76,9 @@ class ArtifactsListPanel extends JPanel { * @param listener The listener to add to the table of artifacts. */ @ThreadConfined(type = ThreadConfined.ThreadType.AWT) - void addSelectionListener(ListSelectionListener listener) { - jTable1.getSelectionModel().addListSelectionListener(listener); + @Override + public void addSelectionListener(ListSelectionListener listener) { + artifactsTable.getSelectionModel().addListSelectionListener(listener); } /** @@ -74,8 +87,9 @@ class ArtifactsListPanel extends JPanel { * @param listener The listener to remove from the table of artifacts. */ @ThreadConfined(type = ThreadConfined.ThreadType.AWT) - void removeListSelectionListener(ListSelectionListener listener) { - jTable1.getSelectionModel().removeListSelectionListener(listener); + @Override + public void removeSelectionListener(ListSelectionListener listener) { + artifactsTable.getSelectionModel().removeListSelectionListener(listener); } /** @@ -86,12 +100,13 @@ class ArtifactsListPanel extends JPanel { * selected. */ @ThreadConfined(type = ThreadConfined.ThreadType.AWT) - BlackboardArtifact getSelectedArtifact() { - int selectedIndex = jTable1.getSelectionModel().getLeadSelectionIndex(); - if (selectedIndex < jTable1.getSelectionModel().getMinSelectionIndex() || jTable1.getSelectionModel().getMaxSelectionIndex() < 0 || selectedIndex > jTable1.getSelectionModel().getMaxSelectionIndex()) { + @Override + public BlackboardArtifact getSelectedArtifact() { + int selectedIndex = artifactsTable.getSelectionModel().getLeadSelectionIndex(); + if (selectedIndex < artifactsTable.getSelectionModel().getMinSelectionIndex() || artifactsTable.getSelectionModel().getMaxSelectionIndex() < 0 || selectedIndex > artifactsTable.getSelectionModel().getMaxSelectionIndex()) { return null; } - return tableModel.getArtifactByRow(jTable1.convertRowIndexToModel(selectedIndex)); + return tableModel.getArtifactByRow(artifactsTable.convertRowIndexToModel(selectedIndex)); } /** @@ -101,7 +116,8 @@ class ArtifactsListPanel extends JPanel { * artifacts. */ @ThreadConfined(type = ThreadConfined.ThreadType.AWT) - boolean isEmpty() { + @Override + public boolean isEmpty() { return tableModel.getRowCount() <= 0; } @@ -110,11 +126,12 @@ class ArtifactsListPanel extends JPanel { * populate the panel to the right. */ @ThreadConfined(type = ThreadConfined.ThreadType.AWT) - void selectFirst() { + @Override + public void selectFirst() { if (!isEmpty()) { - jTable1.setRowSelectionInterval(0, 0); + artifactsTable.setRowSelectionInterval(0, 0); } else { - jTable1.clearSelection(); + artifactsTable.clearSelection(); } } @@ -125,10 +142,11 @@ class ArtifactsListPanel extends JPanel { * @param artifactList The list of artifacts to display. */ @ThreadConfined(type = ThreadConfined.ThreadType.AWT) - void addArtifacts(List artifactList) { + @Override + public void addArtifacts(List artifactList) { tableModel.setContents(artifactList); - jTable1.validate(); - jTable1.repaint(); + artifactsTable.validate(); + artifactsTable.repaint(); tableModel.fireTableDataChanged(); } @@ -150,19 +168,18 @@ class ArtifactsListPanel extends JPanel { private void initComponents() { javax.swing.JScrollPane jScrollPane1 = new javax.swing.JScrollPane(); - jTable1 = new javax.swing.JTable(); + artifactsTable = new javax.swing.JTable(); setOpaque(false); setPreferredSize(new java.awt.Dimension(300, 0)); jScrollPane1.setBorder(null); jScrollPane1.setMinimumSize(new java.awt.Dimension(0, 0)); - jScrollPane1.setPreferredSize(new java.awt.Dimension(0, 0)); - jTable1.setAutoCreateRowSorter(true); - jTable1.setModel(tableModel); - jTable1.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); - jScrollPane1.setViewportView(jTable1); + artifactsTable.setAutoCreateRowSorter(true); + artifactsTable.setModel(tableModel); + artifactsTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); + jScrollPane1.setViewportView(artifactsTable); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -172,7 +189,7 @@ class ArtifactsListPanel extends JPanel { ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 607, Short.MAX_VALUE) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 0, Short.MAX_VALUE) ); }// //GEN-END:initComponents @@ -204,7 +221,7 @@ class ArtifactsListPanel extends JPanel { */ @ThreadConfined(type = ThreadConfined.ThreadType.AWT) void setContents(List artifacts) { - jTable1.clearSelection(); + artifactsTable.clearSelection(); artifactList.clear(); artifactList.addAll(artifacts); } @@ -347,6 +364,6 @@ class ArtifactsListPanel extends JPanel { } } // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JTable jTable1; + private javax.swing.JTable artifactsTable; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED index 7f2aa66a37..a3ec5ac356 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED @@ -1,3 +1,5 @@ +ArtifactMenuMouseAdapter_ExternalViewer_label=Open in external viewer +ArtifactMenuMouseAdapter_label=Extract Files ArtifactsListPanel.dateColumn.name=Date/Time ArtifactsListPanel.fileNameColumn.name=Name ArtifactsListPanel.mimeTypeColumn.name=MIME Type diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainArtifactsTabPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainArtifactsTabPanel.java index c37aca95b0..175fee0f5d 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainArtifactsTabPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainArtifactsTabPanel.java @@ -63,6 +63,7 @@ final class DomainArtifactsTabPanel extends JPanel { initComponents(); this.artifactType = type; listPanel = new ArtifactsListPanel(artifactType); + listPanel.addMouseListener(new ArtifactMenuMouseAdapter(listPanel)); jSplitPane1.setLeftComponent(listPanel); setRightComponent(); listPanel.addSelectionListener(listener); @@ -127,7 +128,7 @@ final class DomainArtifactsTabPanel extends JPanel { void handleArtifactSearchResultEvent(DiscoveryEventUtils.ArtifactSearchResultEvent artifactresultEvent) { if (artifactType == artifactresultEvent.getArtifactType()) { SwingUtilities.invokeLater(() -> { - listPanel.removeListSelectionListener(listener); + listPanel.removeSelectionListener(listener); listPanel.addArtifacts(artifactresultEvent.getListOfArtifacts()); status = ArtifactRetrievalStatus.POPULATED; setEnabled(!listPanel.isEmpty()); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/MiniTimelineArtifactListPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/MiniTimelineArtifactListPanel.java index 7a07108d9d..466cf53474 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/MiniTimelineArtifactListPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/MiniTimelineArtifactListPanel.java @@ -18,10 +18,12 @@ */ package org.sleuthkit.autopsy.discovery.ui; +import java.awt.Point; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import javax.swing.JPanel; +import javax.swing.JPopupMenu; import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import org.apache.commons.lang.StringUtils; @@ -36,7 +38,7 @@ import org.sleuthkit.datamodel.TskCoreException; /** * Panel to display list of dates and counts. */ -class MiniTimelineArtifactListPanel extends JPanel { +class MiniTimelineArtifactListPanel extends JPanel implements ArtifactListPanelInterface { private static final long serialVersionUID = 1L; private final TypeDescriptionTableModel tableModel; @@ -50,8 +52,18 @@ class MiniTimelineArtifactListPanel extends JPanel { MiniTimelineArtifactListPanel() { tableModel = new TypeDescriptionTableModel(); initComponents(); - jTable1.getRowSorter().toggleSortOrder(0); - jTable1.getRowSorter().toggleSortOrder(0); + artifactsTable.getRowSorter().toggleSortOrder(0); + artifactsTable.getRowSorter().toggleSortOrder(0); + } + + @Override + public void addMouseListener(java.awt.event.MouseAdapter mouseListener) { + artifactsTable.addMouseListener(mouseListener); + } + + @Override + public void showPopupMenu(JPopupMenu popupMenu, Point point) { + popupMenu.show(artifactsTable, point.x, point.y); } /** @@ -61,8 +73,9 @@ class MiniTimelineArtifactListPanel extends JPanel { * @param listener The listener to add to the table of artifacts. */ @ThreadConfined(type = ThreadConfined.ThreadType.AWT) - void addSelectionListener(ListSelectionListener listener) { - jTable1.getSelectionModel().addListSelectionListener(listener); + @Override + public void addSelectionListener(ListSelectionListener listener) { + artifactsTable.getSelectionModel().addListSelectionListener(listener); } /** @@ -71,8 +84,9 @@ class MiniTimelineArtifactListPanel extends JPanel { * @param listener The listener to remove from the table of dates. */ @ThreadConfined(type = ThreadConfined.ThreadType.AWT) - void removeListSelectionListener(ListSelectionListener listener) { - jTable1.getSelectionModel().removeListSelectionListener(listener); + @Override + public void removeSelectionListener(ListSelectionListener listener) { + artifactsTable.getSelectionModel().removeListSelectionListener(listener); } /** @@ -81,7 +95,8 @@ class MiniTimelineArtifactListPanel extends JPanel { * @return True if the list of dates is empty, false if there are dates. */ @ThreadConfined(type = ThreadConfined.ThreadType.AWT) - boolean isEmpty() { + @Override + public boolean isEmpty() { return tableModel.getRowCount() <= 0; } @@ -90,11 +105,12 @@ class MiniTimelineArtifactListPanel extends JPanel { * populate the list to the right. */ @ThreadConfined(type = ThreadConfined.ThreadType.AWT) - void selectFirst() { + @Override + public void selectFirst() { if (!isEmpty()) { - jTable1.setRowSelectionInterval(0, 0); + artifactsTable.setRowSelectionInterval(0, 0); } else { - jTable1.clearSelection(); + artifactsTable.clearSelection(); } } @@ -106,12 +122,13 @@ class MiniTimelineArtifactListPanel extends JPanel { * selected. */ @ThreadConfined(type = ThreadConfined.ThreadType.AWT) - BlackboardArtifact getSelectedArtifact() { - int selectedIndex = jTable1.getSelectionModel().getLeadSelectionIndex(); - if (selectedIndex < jTable1.getSelectionModel().getMinSelectionIndex() || jTable1.getSelectionModel().getMaxSelectionIndex() < 0 || selectedIndex > jTable1.getSelectionModel().getMaxSelectionIndex()) { + @Override + public BlackboardArtifact getSelectedArtifact() { + int selectedIndex = artifactsTable.getSelectionModel().getLeadSelectionIndex(); + if (selectedIndex < artifactsTable.getSelectionModel().getMinSelectionIndex() || artifactsTable.getSelectionModel().getMaxSelectionIndex() < 0 || selectedIndex > artifactsTable.getSelectionModel().getMaxSelectionIndex()) { return null; } - return tableModel.getArtifactByRow(jTable1.convertRowIndexToModel(selectedIndex)); + return tableModel.getArtifactByRow(artifactsTable.convertRowIndexToModel(selectedIndex)); } /** @@ -121,10 +138,11 @@ class MiniTimelineArtifactListPanel extends JPanel { * @param dateCountList The list of dates to display. */ @ThreadConfined(type = ThreadConfined.ThreadType.AWT) - void addArtifacts(List dateCountList) { + @Override + public void addArtifacts(List dateCountList) { tableModel.setContents(dateCountList); - jTable1.validate(); - jTable1.repaint(); + artifactsTable.validate(); + artifactsTable.repaint(); tableModel.fireTableDataChanged(); } @@ -143,7 +161,7 @@ class MiniTimelineArtifactListPanel extends JPanel { private void initComponents() { //This class is a refactored copy of ArtifactsListPanel so lacks the form however the init method still constructs the proper UI elements. javax.swing.JScrollPane jScrollPane1 = new javax.swing.JScrollPane(); - jTable1 = new javax.swing.JTable(); + artifactsTable = new javax.swing.JTable(); setOpaque(false); setPreferredSize(new java.awt.Dimension(300, 0)); @@ -151,10 +169,10 @@ class MiniTimelineArtifactListPanel extends JPanel { jScrollPane1.setBorder(null); jScrollPane1.setMinimumSize(new java.awt.Dimension(0, 0)); - jTable1.setAutoCreateRowSorter(true); - jTable1.setModel(tableModel); - jTable1.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); - jScrollPane1.setViewportView(jTable1); + artifactsTable.setAutoCreateRowSorter(true); + artifactsTable.setModel(tableModel); + artifactsTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); + jScrollPane1.setViewportView(artifactsTable); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -185,7 +203,7 @@ class MiniTimelineArtifactListPanel extends JPanel { */ @ThreadConfined(type = ThreadConfined.ThreadType.AWT) void setContents(List artifactList) { - jTable1.clearSelection(); + artifactsTable.clearSelection(); this.artifactList.clear(); this.artifactList.addAll(artifactList); } @@ -260,6 +278,6 @@ class MiniTimelineArtifactListPanel extends JPanel { } // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JTable jTable1; + private javax.swing.JTable artifactsTable; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/MiniTimelinePanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/MiniTimelinePanel.java index ee1dc6a4b5..31c4620760 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/MiniTimelinePanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/MiniTimelinePanel.java @@ -51,6 +51,7 @@ class MiniTimelinePanel extends javax.swing.JPanel { @ThreadConfined(type = ThreadConfined.ThreadType.AWT) MiniTimelinePanel() { initComponents(); + artifactListPanel.addMouseListener(new ArtifactMenuMouseAdapter(artifactListPanel)); artifactListener = new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent event) { @@ -72,7 +73,7 @@ class MiniTimelinePanel extends javax.swing.JPanel { @Override public void valueChanged(ListSelectionEvent event) { if (!event.getValueIsAdjusting()) { - artifactListPanel.removeListSelectionListener(artifactListener); + artifactListPanel.removeSelectionListener(artifactListener); artifactListPanel.addArtifacts(dateListPanel.getArtifactsForSelectedDate()); artifactListPanel.addSelectionListener(artifactListener); artifactListPanel.selectFirst(); @@ -121,7 +122,7 @@ class MiniTimelinePanel extends javax.swing.JPanel { void handleMiniTimelineResultEvent(DiscoveryEventUtils.MiniTimelineResultEvent miniTimelineResultEvent) { SwingUtilities.invokeLater(() -> { dateListPanel.removeListSelectionListener(dateListener); - artifactListPanel.removeListSelectionListener(artifactListener); + artifactListPanel.removeSelectionListener(artifactListener); dateListPanel.addArtifacts(miniTimelineResultEvent.getResultList()); status = DomainArtifactsTabPanel.ArtifactRetrievalStatus.POPULATED; setEnabled(!dateListPanel.isEmpty()); From 88b07940a8228649552cbad23dce75677e22ca39 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 2 Dec 2020 15:33:29 -0500 Subject: [PATCH 2/5] 7067 - fix file that is acted on with artifact actions --- .../discovery/ui/ArtifactMenuMouseAdapter.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactMenuMouseAdapter.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactMenuMouseAdapter.java index 97dd10aa9e..2afd146f82 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactMenuMouseAdapter.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactMenuMouseAdapter.java @@ -45,6 +45,7 @@ import org.sleuthkit.autopsy.directorytree.actionhelpers.ExtractActionHelper; import org.sleuthkit.autopsy.timeline.actions.ViewArtifactInTimelineAction; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.TskCoreException; @@ -90,7 +91,7 @@ class ArtifactMenuMouseAdapter extends java.awt.event.MouseAdapter { } /** - * Returns a list of JMenuItems for the waypoint. The list list may contain + * Returns a list of JMenuItems for the artifact. The list list may contain * nulls which should be removed or replaced with JSeparators. * * @return List of menu items @@ -99,7 +100,14 @@ class ArtifactMenuMouseAdapter extends java.awt.event.MouseAdapter { */ private JMenuItem[] getMenuItems(BlackboardArtifact artifact) throws TskCoreException { List menuItems = new ArrayList<>(); - Content content = artifact.getSleuthkitCase().getContentById(artifact.getObjectID()); + BlackboardAttribute pathIdAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID)); + long contentId; + if (pathIdAttr != null) { + contentId = pathIdAttr.getValueLong(); + } else { + contentId = artifact.getObjectID(); + } + Content content = artifact.getSleuthkitCase().getContentById(contentId); menuItems.addAll(getTimelineMenuItems(artifact)); menuItems.addAll(getDataModelActionFactoryMenuItems(artifact, content)); menuItems.add(DeleteFileContentTagAction.getInstance().getMenuForFiles(Arrays.asList((AbstractFile) content))); @@ -130,11 +138,11 @@ class ArtifactMenuMouseAdapter extends java.awt.event.MouseAdapter { /** * Use the DateModelActionsFactory to get some of the basic actions for the - * waypoint. The advantage to using the DataModelActionsFactory is that the + * artifact. The advantage to using the DataModelActionsFactory is that the * menu items can be put in a consistent order with other parts of the UI. * - * @param artifact Artifact for the selected waypoint - * @param content Artifact content + * @param artifact Artifact for the selected item. + * @param content The file the artifact is in regards to. * * @return List of JMenuItems for the DataModelActionFactory actions */ From 76dd02e5f7f34ba80d9c8db66ef2ab54f51acf37 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 2 Dec 2020 16:28:22 -0500 Subject: [PATCH 3/5] 7067 clean up and comment menu actions --- .../ui/AbstractArtifactListPanel.java | 112 ++++++++++++++++++ .../ui/ArtifactListPanelInterface.java | 47 -------- .../ui/ArtifactMenuMouseAdapter.java | 37 ++++-- .../discovery/ui/ArtifactsListPanel.java | 57 ++------- .../ui/MiniTimelineArtifactListPanel.java | 65 ++-------- 5 files changed, 159 insertions(+), 159 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractArtifactListPanel.java delete mode 100644 Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactListPanelInterface.java diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractArtifactListPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractArtifactListPanel.java new file mode 100644 index 0000000000..3269808a3f --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractArtifactListPanel.java @@ -0,0 +1,112 @@ +/* + * Autopsy + * + * Copyright 2020 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.discovery.ui; + +import java.awt.Point; +import java.util.List; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.event.ListSelectionListener; +import org.sleuthkit.autopsy.coreutils.ThreadConfined; +import org.sleuthkit.datamodel.BlackboardArtifact; + +/** + * Abstract class to define methods expected of a list of artifacts in the + * discovery details section. + */ +abstract class AbstractArtifactListPanel extends JPanel { + + private static final long serialVersionUID = 1L; + + /** + * Add a listener to the table of artifacts to perform actions when an + * artifact is selected. + * + * @param listener The listener to add to the table of artifacts. + */ + @ThreadConfined(type = ThreadConfined.ThreadType.AWT) + abstract void addMouseListener(java.awt.event.MouseAdapter mouseListener); + + /** + * Display the specified JPopupMenu at the specified point. + * + * @param popupMenu The JPopupMenu to display. + * @param point The point the menu should be displayed at. + */ + abstract void showPopupMenu(JPopupMenu popupMenu, Point point); + + /** + * The artifact which is currently selected, null if no artifact is + * selected. + * + * @return The currently selected BlackboardArtifact or null if none is + * selected. + */ + @ThreadConfined(type = ThreadConfined.ThreadType.AWT) + abstract BlackboardArtifact getSelectedArtifact(); + + /** + * Add the specified list of artifacts to the list of artifacts which should + * be displayed. + * + * @param artifactList The list of artifacts to display. + */ + @ThreadConfined(type = ThreadConfined.ThreadType.AWT) + abstract void addArtifacts(List artifactList); + + /** + * Remove a listener from the table of artifacts. + * + * @param listener The listener to remove from the table of artifacts. + */ + @ThreadConfined(type = ThreadConfined.ThreadType.AWT) + abstract void removeSelectionListener(ListSelectionListener listener); + + /** + * Add a listener to the table of artifacts to perform actions when an + * artifact is selected. + * + * @param listener The listener to add to the table of artifacts. + */ + @ThreadConfined(type = ThreadConfined.ThreadType.AWT) + abstract void addSelectionListener(ListSelectionListener listener); + + /** + * Select the first available artifact in the list if it is not empty to + * populate the panel to the right. + */ + @ThreadConfined(type = ThreadConfined.ThreadType.AWT) + abstract void selectFirst(); + + /** + * Remove all artifacts from the list of artifacts displayed. + */ + @ThreadConfined(type = ThreadConfined.ThreadType.AWT) + abstract void clearList(); + + /** + * Whether the list of artifacts is empty. + * + * @return true if the list of artifacts is empty, false if there are + * artifacts. + */ + @ThreadConfined(type = ThreadConfined.ThreadType.AWT) + abstract boolean isEmpty(); + +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactListPanelInterface.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactListPanelInterface.java deleted file mode 100644 index 0fccddb629..0000000000 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactListPanelInterface.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Autopsy - * - * Copyright 2020 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. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.discovery.ui; - -import java.awt.Point; -import java.util.List; -import javax.swing.JPopupMenu; -import javax.swing.event.ListSelectionListener; -import org.sleuthkit.datamodel.BlackboardArtifact; - -interface ArtifactListPanelInterface { - - void addMouseListener(java.awt.event.MouseAdapter mouseListener); - - void showPopupMenu(JPopupMenu popupMenu, Point point); - - BlackboardArtifact getSelectedArtifact(); - - void removeSelectionListener(ListSelectionListener listener); - - void addArtifacts(List artifactList); - - void addSelectionListener(ListSelectionListener listener); - - void selectFirst(); - - void clearList(); - - boolean isEmpty(); - -} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactMenuMouseAdapter.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactMenuMouseAdapter.java index 2afd146f82..ac58ad6f4e 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactMenuMouseAdapter.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactMenuMouseAdapter.java @@ -49,16 +49,21 @@ import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.TskCoreException; +/** + * MouseAdapter to display a context menu on the specified + * AbstractArtifactListPanel when the user right clicks. + */ class ArtifactMenuMouseAdapter extends java.awt.event.MouseAdapter { - private final ArtifactListPanelInterface listPanel; + private final AbstractArtifactListPanel listPanel; private static final Logger logger = Logger.getLogger(ArtifactMenuMouseAdapter.class.getName()); - ArtifactMenuMouseAdapter() { - listPanel = null; - } - - ArtifactMenuMouseAdapter(ArtifactListPanelInterface listPanel) { + /** + * Create a new ArtifactMenMouseAdapter. + * + * @param listPanel The panel which the menu should be in regards to. + */ + ArtifactMenuMouseAdapter(AbstractArtifactListPanel listPanel) { this.listPanel = listPanel; } @@ -69,6 +74,12 @@ class ArtifactMenuMouseAdapter extends java.awt.event.MouseAdapter { } } + /** + * If an artifact is selected display a JPopupMenu which has available + * actions. + * + * @param event The mouseEvent being responded to. + */ private void showPopupMenu(java.awt.event.MouseEvent event) { BlackboardArtifact artifact = listPanel.getSelectedArtifact(); if (artifact == null) { @@ -94,7 +105,9 @@ class ArtifactMenuMouseAdapter extends java.awt.event.MouseAdapter { * Returns a list of JMenuItems for the artifact. The list list may contain * nulls which should be removed or replaced with JSeparators. * - * @return List of menu items + * @param artifact The artifact to get menu items for. + * + * @return List of menu items. * * @throws TskCoreException */ @@ -118,7 +131,7 @@ class ArtifactMenuMouseAdapter extends java.awt.event.MouseAdapter { /** * Gets the Timeline Menu Items for this artifact. * - * @param artifact Selected artifact + * @param artifact The artifact to get menu items for. * * @return List of timeline menu items. */ @@ -141,10 +154,10 @@ class ArtifactMenuMouseAdapter extends java.awt.event.MouseAdapter { * artifact. The advantage to using the DataModelActionsFactory is that the * menu items can be put in a consistent order with other parts of the UI. * - * @param artifact Artifact for the selected item. + * @param artifact The artifact to get menu items for. * @param content The file the artifact is in regards to. * - * @return List of JMenuItems for the DataModelActionFactory actions + * @return List of JMenuItems for the DataModelActionFactory actions. */ @NbBundle.Messages({ "ArtifactMenuMouseAdapter_ExternalViewer_label=Open in external viewer" @@ -180,7 +193,7 @@ class ArtifactMenuMouseAdapter extends java.awt.event.MouseAdapter { @NbBundle.Messages({ "ArtifactMenuMouseAdapter_label=Extract Files" }) - final class ExtractFileAction extends AbstractAction { + private final class ExtractFileAction extends AbstractAction { private static final long serialVersionUID = 1L; final private AbstractFile file; @@ -190,7 +203,7 @@ class ArtifactMenuMouseAdapter extends java.awt.event.MouseAdapter { * * @param file The AbstractFile to be extracted. */ - ExtractFileAction(AbstractFile file) { + private ExtractFileAction(AbstractFile file) { super(Bundle.ArtifactMenuMouseAdapter_label()); this.file = file; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactsListPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactsListPanel.java index 937f90d6e1..ec217a417d 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactsListPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactsListPanel.java @@ -22,7 +22,6 @@ import java.awt.Point; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; -import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; @@ -40,11 +39,11 @@ import org.sleuthkit.datamodel.TskCoreException; * Panel to display list of artifacts for selected domain. * */ -final class ArtifactsListPanel extends JPanel implements ArtifactListPanelInterface { +final class ArtifactsListPanel extends AbstractArtifactListPanel { private static final long serialVersionUID = 1L; - private final DomainArtifactTableModel tableModel; private static final Logger logger = Logger.getLogger(ArtifactsListPanel.class.getName()); + private final DomainArtifactTableModel tableModel; /** * Creates new form ArtifactsListPanel. @@ -60,48 +59,27 @@ final class ArtifactsListPanel extends JPanel implements ArtifactListPanelInterf } @Override - public void addMouseListener(java.awt.event.MouseAdapter mouseListener) { + void addMouseListener(java.awt.event.MouseAdapter mouseListener) { artifactsTable.addMouseListener(mouseListener); } @Override - public void showPopupMenu(JPopupMenu popupMenu, Point point) { + void showPopupMenu(JPopupMenu popupMenu, Point point) { popupMenu.show(artifactsTable, point.x, point.y); } - /** - * Add a listener to the table of artifacts to perform actions when an - * artifact is selected. - * - * @param listener The listener to add to the table of artifacts. - */ - @ThreadConfined(type = ThreadConfined.ThreadType.AWT) @Override - public void addSelectionListener(ListSelectionListener listener) { + void addSelectionListener(ListSelectionListener listener) { artifactsTable.getSelectionModel().addListSelectionListener(listener); } - /** - * Remove a listener from the table of artifacts. - * - * @param listener The listener to remove from the table of artifacts. - */ - @ThreadConfined(type = ThreadConfined.ThreadType.AWT) @Override - public void removeSelectionListener(ListSelectionListener listener) { + void removeSelectionListener(ListSelectionListener listener) { artifactsTable.getSelectionModel().removeListSelectionListener(listener); } - /** - * The artifact which is currently selected, null if no artifact is - * selected. - * - * @return The currently selected BlackboardArtifact or null if none is - * selected. - */ - @ThreadConfined(type = ThreadConfined.ThreadType.AWT) @Override - public BlackboardArtifact getSelectedArtifact() { + BlackboardArtifact getSelectedArtifact() { int selectedIndex = artifactsTable.getSelectionModel().getLeadSelectionIndex(); if (selectedIndex < artifactsTable.getSelectionModel().getMinSelectionIndex() || artifactsTable.getSelectionModel().getMaxSelectionIndex() < 0 || selectedIndex > artifactsTable.getSelectionModel().getMaxSelectionIndex()) { return null; @@ -109,25 +87,13 @@ final class ArtifactsListPanel extends JPanel implements ArtifactListPanelInterf return tableModel.getArtifactByRow(artifactsTable.convertRowIndexToModel(selectedIndex)); } - /** - * Whether the list of artifacts is empty. - * - * @return true if the list of artifacts is empty, false if there are - * artifacts. - */ - @ThreadConfined(type = ThreadConfined.ThreadType.AWT) @Override - public boolean isEmpty() { + boolean isEmpty() { return tableModel.getRowCount() <= 0; } - /** - * Select the first available artifact in the list if it is not empty to - * populate the panel to the right. - */ - @ThreadConfined(type = ThreadConfined.ThreadType.AWT) @Override - public void selectFirst() { + void selectFirst() { if (!isEmpty()) { artifactsTable.setRowSelectionInterval(0, 0); } else { @@ -143,7 +109,7 @@ final class ArtifactsListPanel extends JPanel implements ArtifactListPanelInterf */ @ThreadConfined(type = ThreadConfined.ThreadType.AWT) @Override - public void addArtifacts(List artifactList) { + void addArtifacts(List artifactList) { tableModel.setContents(artifactList); artifactsTable.validate(); artifactsTable.repaint(); @@ -155,7 +121,7 @@ final class ArtifactsListPanel extends JPanel implements ArtifactListPanelInterf */ @ThreadConfined(type = ThreadConfined.ThreadType.AWT) @Override - public void clearList() { + void clearList() { tableModel.setContents(new ArrayList<>()); tableModel.fireTableDataChanged(); } @@ -194,6 +160,7 @@ final class ArtifactsListPanel extends JPanel implements ArtifactListPanelInterf ); }// //GEN-END:initComponents + /** * Table model which allows the artifact table in this panel to mimic a list * of artifacts. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/MiniTimelineArtifactListPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/MiniTimelineArtifactListPanel.java index d0a3c2546b..a15d21f696 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/MiniTimelineArtifactListPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/MiniTimelineArtifactListPanel.java @@ -22,7 +22,6 @@ import java.awt.Point; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; -import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; @@ -38,7 +37,7 @@ import org.sleuthkit.datamodel.TskCoreException; /** * Panel to display list of artifacts types and descriptions. */ -class MiniTimelineArtifactListPanel extends JPanel implements ArtifactListPanelInterface { +class MiniTimelineArtifactListPanel extends AbstractArtifactListPanel { private static final long serialVersionUID = 1L; private final TypeDescriptionTableModel tableModel; @@ -60,57 +59,32 @@ class MiniTimelineArtifactListPanel extends JPanel implements ArtifactListPanelI } @Override - public void addMouseListener(java.awt.event.MouseAdapter mouseListener) { + void addMouseListener(java.awt.event.MouseAdapter mouseListener) { artifactsTable.addMouseListener(mouseListener); } @Override - public void showPopupMenu(JPopupMenu popupMenu, Point point) { + void showPopupMenu(JPopupMenu popupMenu, Point point) { popupMenu.show(artifactsTable, point.x, point.y); } - /** - * Add a listener to the table of artifacts to perform actions when a - * artifact is selected. - * - * @param listener The listener to add to the table of artifacts. - */ - @ThreadConfined(type = ThreadConfined.ThreadType.AWT) @Override - public void addSelectionListener(ListSelectionListener listener) { + void addSelectionListener(ListSelectionListener listener) { artifactsTable.getSelectionModel().addListSelectionListener(listener); } - /** - * Remove a listener from the table of artifacts. - * - * @param listener The listener to remove from the table of artifacts. - */ - @ThreadConfined(type = ThreadConfined.ThreadType.AWT) @Override - public void removeSelectionListener(ListSelectionListener listener) { + void removeSelectionListener(ListSelectionListener listener) { artifactsTable.getSelectionModel().removeListSelectionListener(listener); } - /** - * Whether the list of artifacts is empty. - * - * @return True if the list of artifacts is empty, false if there are - * artifacts. - */ - @ThreadConfined(type = ThreadConfined.ThreadType.AWT) @Override - public boolean isEmpty() { + boolean isEmpty() { return tableModel.getRowCount() <= 0; } - /** - * Select the first available artifact in the list if it is not empty to - * populate the list to the right. - */ - @ThreadConfined(type = ThreadConfined.ThreadType.AWT) @Override - public void selectFirst() { + void selectFirst() { if (!isEmpty()) { artifactsTable.setRowSelectionInterval(0, 0); } else { @@ -118,16 +92,8 @@ class MiniTimelineArtifactListPanel extends JPanel implements ArtifactListPanelI } } - /** - * The artifact which is currently selected, null if no artifact is - * selected. - * - * @return The currently selected BlackboardArtifact or null if none is - * selected. - */ - @ThreadConfined(type = ThreadConfined.ThreadType.AWT) @Override - public BlackboardArtifact getSelectedArtifact() { + BlackboardArtifact getSelectedArtifact() { int selectedIndex = artifactsTable.getSelectionModel().getLeadSelectionIndex(); if (selectedIndex < artifactsTable.getSelectionModel().getMinSelectionIndex() || artifactsTable.getSelectionModel().getMaxSelectionIndex() < 0 @@ -137,27 +103,16 @@ class MiniTimelineArtifactListPanel extends JPanel implements ArtifactListPanelI return tableModel.getArtifactByRow(artifactsTable.convertRowIndexToModel(selectedIndex)); } - /** - * Add the specified list of artifacts to the list of artifacts which should - * be displayed. - * - * @param artifacttList The list of artifacts to display. - */ - @ThreadConfined(type = ThreadConfined.ThreadType.AWT) @Override - public void addArtifacts(List artifactList) { + void addArtifacts(List artifactList) { tableModel.setContents(artifactList); artifactsTable.validate(); artifactsTable.repaint(); tableModel.fireTableDataChanged(); } - /** - * Remove all artifacts from the list of artifacts displayed. - */ - @ThreadConfined(type = ThreadConfined.ThreadType.AWT) @Override - public void clearList() { + void clearList() { tableModel.setContents(new ArrayList<>()); tableModel.fireTableDataChanged(); } From 9e8f4bd284f6b29bf29b33245791035a86cecbdc Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 9 Dec 2020 13:09:47 -0500 Subject: [PATCH 4/5] 7067-put something in rightsplitpane before any searches finish --- .../sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java index 98ced893df..299e1285df 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java @@ -27,6 +27,7 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.List; import java.util.stream.Collectors; +import javax.swing.JPanel; import javax.swing.JSplitPane; import javax.swing.SwingUtilities; import javax.swing.plaf.basic.BasicSplitPaneDivider; @@ -100,6 +101,7 @@ public final class DiscoveryTopComponent extends TopComponent { } }); rightSplitPane.setTopComponent(resultsPanel); + rightSplitPane.setBottomComponent(new JPanel()); } /** From 1c4df721576a3d6b6066a26f3be01f1e4bd83770 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 10 Dec 2020 11:00:14 -0500 Subject: [PATCH 5/5] 7067 select with right click --- .../discovery/ui/AbstractArtifactListPanel.java | 10 ++++++++++ .../discovery/ui/ArtifactMenuMouseAdapter.java | 4 +++- .../autopsy/discovery/ui/ArtifactsListPanel.java | 13 ++++++++++++- .../discovery/ui/MiniTimelineArtifactListPanel.java | 12 ++++++++++++ 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractArtifactListPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractArtifactListPanel.java index 3269808a3f..8380d39a6d 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractArtifactListPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractArtifactListPanel.java @@ -61,6 +61,16 @@ abstract class AbstractArtifactListPanel extends JPanel { @ThreadConfined(type = ThreadConfined.ThreadType.AWT) abstract BlackboardArtifact getSelectedArtifact(); + /** + * Select the row at the specified point. + * + * @param point The point which if a row exists it should be selected. + * + * @return True if a row was selected, false if no row was selected. + */ + @ThreadConfined(type = ThreadConfined.ThreadType.AWT) + abstract boolean selectAtPoint(Point point); + /** * Add the specified list of artifacts to the list of artifacts which should * be displayed. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactMenuMouseAdapter.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactMenuMouseAdapter.java index ac58ad6f4e..f4b7b25954 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactMenuMouseAdapter.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactMenuMouseAdapter.java @@ -70,7 +70,9 @@ class ArtifactMenuMouseAdapter extends java.awt.event.MouseAdapter { @Override public void mouseClicked(java.awt.event.MouseEvent evt) { if (!evt.isPopupTrigger() && SwingUtilities.isRightMouseButton(evt) && listPanel != null && !listPanel.isEmpty()) { - showPopupMenu(evt); + if (listPanel.selectAtPoint(evt.getPoint())) { + showPopupMenu(evt); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactsListPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactsListPanel.java index ec217a417d..19520819c6 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactsListPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactsListPanel.java @@ -78,6 +78,18 @@ final class ArtifactsListPanel extends AbstractArtifactListPanel { artifactsTable.getSelectionModel().removeListSelectionListener(listener); } + @Override + boolean selectAtPoint(Point point) { + boolean pointSelected = false; + int row = artifactsTable.rowAtPoint(point); + if (row < artifactsTable.getRowCount() && row >= 0) { + artifactsTable.clearSelection(); + artifactsTable.addRowSelectionInterval(row, row); + pointSelected = true; + } + return pointSelected; + } + @Override BlackboardArtifact getSelectedArtifact() { int selectedIndex = artifactsTable.getSelectionModel().getLeadSelectionIndex(); @@ -160,7 +172,6 @@ final class ArtifactsListPanel extends AbstractArtifactListPanel { ); }// //GEN-END:initComponents - /** * Table model which allows the artifact table in this panel to mimic a list * of artifacts. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/MiniTimelineArtifactListPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/MiniTimelineArtifactListPanel.java index a15d21f696..01f3d67183 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/MiniTimelineArtifactListPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/MiniTimelineArtifactListPanel.java @@ -92,6 +92,18 @@ class MiniTimelineArtifactListPanel extends AbstractArtifactListPanel { } } + @Override + boolean selectAtPoint(Point point) { + boolean pointSelected = false; + int row = artifactsTable.rowAtPoint(point); + artifactsTable.clearSelection(); + if (row < artifactsTable.getRowCount() && row >= 0) { + artifactsTable.addRowSelectionInterval(row, row); + pointSelected = true; + } + return pointSelected; + } + @Override BlackboardArtifact getSelectedArtifact() { int selectedIndex = artifactsTable.getSelectionModel().getLeadSelectionIndex();