Merge remote-tracking branch 'upstream/develop' into 6735-embedded-file-extractor-retries

This commit is contained in:
Richard Cordovano 2020-12-10 15:44:46 -05:00
commit 30f89ee797
9 changed files with 461 additions and 132 deletions

View File

@ -0,0 +1,122 @@
/*
* Autopsy
*
* Copyright 2020 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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();
/**
* 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.
*
* @param artifactList The list of artifacts to display.
*/
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
abstract void addArtifacts(List<BlackboardArtifact> 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();
}

View File

@ -0,0 +1,219 @@
/*
* Autopsy
*
* Copyright 2020 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.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 AbstractArtifactListPanel listPanel;
private static final Logger logger = Logger.getLogger(ArtifactMenuMouseAdapter.class.getName());
/**
* Create a new ArtifactMenMouseAdapter.
*
* @param listPanel The panel which the menu should be in regards to.
*/
ArtifactMenuMouseAdapter(AbstractArtifactListPanel listPanel) {
this.listPanel = listPanel;
}
@Override
public void mouseClicked(java.awt.event.MouseEvent evt) {
if (!evt.isPopupTrigger() && SwingUtilities.isRightMouseButton(evt) && listPanel != null && !listPanel.isEmpty()) {
if (listPanel.selectAtPoint(evt.getPoint())) {
showPopupMenu(evt);
}
}
}
/**
* 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) {
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 artifact. The list list may contain
* nulls which should be removed or replaced with JSeparators.
*
* @param artifact The artifact to get menu items for.
*
* @return List of menu items.
*
* @throws TskCoreException
*/
private JMenuItem[] getMenuItems(BlackboardArtifact artifact) throws TskCoreException {
List<JMenuItem> menuItems = new ArrayList<>();
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)));
menuItems.add(DeleteFileBlackboardArtifactTagAction.getInstance().getMenuForArtifacts(Arrays.asList(artifact)));
return menuItems.toArray(new JMenuItem[0]);
}
/**
* Gets the Timeline Menu Items for this artifact.
*
* @param artifact The artifact to get menu items for.
*
* @return List of timeline menu items.
*/
private List<JMenuItem> getTimelineMenuItems(BlackboardArtifact artifact) {
List<JMenuItem> 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
* 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 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.
*/
@NbBundle.Messages({
"ArtifactMenuMouseAdapter_ExternalViewer_label=Open in external viewer"
})
private List<JMenuItem> getDataModelActionFactoryMenuItems(BlackboardArtifact artifact, Content content) {
List<JMenuItem> menuItems = new ArrayList<>();
List<Action> 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"
})
private 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.
*/
private 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));
}
}
}

View File

@ -48,7 +48,7 @@
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/> <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents> <SubComponents>
<Component class="javax.swing.JTable" name="jTable1"> <Component class="javax.swing.JTable" name="artifactsTable">
<Properties> <Properties>
<Property name="autoCreateRowSorter" type="boolean" value="true"/> <Property name="autoCreateRowSorter" type="boolean" value="true"/>
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor"> <Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">

View File

@ -18,10 +18,11 @@
*/ */
package org.sleuthkit.autopsy.discovery.ui; package org.sleuthkit.autopsy.discovery.ui;
import java.awt.Point;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import javax.swing.JPanel; import javax.swing.JPopupMenu;
import javax.swing.event.ListSelectionListener; import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel; import javax.swing.table.AbstractTableModel;
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;
@ -38,11 +39,11 @@ import org.sleuthkit.datamodel.TskCoreException;
* Panel to display list of artifacts for selected domain. * Panel to display list of artifacts for selected domain.
* *
*/ */
class ArtifactsListPanel extends JPanel { final class ArtifactsListPanel extends AbstractArtifactListPanel {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final DomainArtifactTableModel tableModel;
private static final Logger logger = Logger.getLogger(ArtifactsListPanel.class.getName()); private static final Logger logger = Logger.getLogger(ArtifactsListPanel.class.getName());
private final DomainArtifactTableModel tableModel;
/** /**
* Creates new form ArtifactsListPanel. * Creates new form ArtifactsListPanel.
@ -53,68 +54,62 @@ class ArtifactsListPanel extends JPanel {
ArtifactsListPanel(BlackboardArtifact.ARTIFACT_TYPE artifactType) { ArtifactsListPanel(BlackboardArtifact.ARTIFACT_TYPE artifactType) {
tableModel = new DomainArtifactTableModel(artifactType); tableModel = new DomainArtifactTableModel(artifactType);
initComponents(); initComponents();
jTable1.getRowSorter().toggleSortOrder(0); artifactsTable.getRowSorter().toggleSortOrder(0);
jTable1.getRowSorter().toggleSortOrder(0); artifactsTable.getRowSorter().toggleSortOrder(0);
} }
/** @Override
* Add a listener to the table of artifacts to perform actions when an void addMouseListener(java.awt.event.MouseAdapter mouseListener) {
* artifact is selected. artifactsTable.addMouseListener(mouseListener);
* }
* @param listener The listener to add to the table of artifacts.
*/ @Override
@ThreadConfined(type = ThreadConfined.ThreadType.AWT) void showPopupMenu(JPopupMenu popupMenu, Point point) {
popupMenu.show(artifactsTable, point.x, point.y);
}
@Override
void addSelectionListener(ListSelectionListener listener) { void addSelectionListener(ListSelectionListener listener) {
jTable1.getSelectionModel().addListSelectionListener(listener); artifactsTable.getSelectionModel().addListSelectionListener(listener);
} }
/** @Override
* Remove a listener from the table of artifacts. void removeSelectionListener(ListSelectionListener listener) {
* artifactsTable.getSelectionModel().removeListSelectionListener(listener);
* @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
* The artifact which is currently selected, null if no artifact is boolean selectAtPoint(Point point) {
* selected. boolean pointSelected = false;
* int row = artifactsTable.rowAtPoint(point);
* @return The currently selected BlackboardArtifact or null if none is if (row < artifactsTable.getRowCount() && row >= 0) {
* selected. artifactsTable.clearSelection();
*/ artifactsTable.addRowSelectionInterval(row, row);
@ThreadConfined(type = ThreadConfined.ThreadType.AWT) pointSelected = true;
}
return pointSelected;
}
@Override
BlackboardArtifact getSelectedArtifact() { BlackboardArtifact getSelectedArtifact() {
int selectedIndex = jTable1.getSelectionModel().getLeadSelectionIndex(); int selectedIndex = artifactsTable.getSelectionModel().getLeadSelectionIndex();
if (selectedIndex < jTable1.getSelectionModel().getMinSelectionIndex() || jTable1.getSelectionModel().getMaxSelectionIndex() < 0 || selectedIndex > jTable1.getSelectionModel().getMaxSelectionIndex()) { if (selectedIndex < artifactsTable.getSelectionModel().getMinSelectionIndex() || artifactsTable.getSelectionModel().getMaxSelectionIndex() < 0 || selectedIndex > artifactsTable.getSelectionModel().getMaxSelectionIndex()) {
return null; return null;
} }
return tableModel.getArtifactByRow(jTable1.convertRowIndexToModel(selectedIndex)); return tableModel.getArtifactByRow(artifactsTable.convertRowIndexToModel(selectedIndex));
} }
/** @Override
* 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)
boolean isEmpty() { boolean isEmpty() {
return tableModel.getRowCount() <= 0; return tableModel.getRowCount() <= 0;
} }
/** @Override
* 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)
void selectFirst() { void selectFirst() {
if (!isEmpty()) { if (!isEmpty()) {
jTable1.setRowSelectionInterval(0, 0); artifactsTable.setRowSelectionInterval(0, 0);
} else { } else {
jTable1.clearSelection(); artifactsTable.clearSelection();
} }
} }
@ -125,10 +120,11 @@ class ArtifactsListPanel extends JPanel {
* @param artifactList The list of artifacts to display. * @param artifactList The list of artifacts to display.
*/ */
@ThreadConfined(type = ThreadConfined.ThreadType.AWT) @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
@Override
void addArtifacts(List<BlackboardArtifact> artifactList) { void addArtifacts(List<BlackboardArtifact> artifactList) {
tableModel.setContents(artifactList); tableModel.setContents(artifactList);
jTable1.validate(); artifactsTable.validate();
jTable1.repaint(); artifactsTable.repaint();
tableModel.fireTableDataChanged(); tableModel.fireTableDataChanged();
} }
@ -136,7 +132,8 @@ class ArtifactsListPanel extends JPanel {
* Remove all artifacts from the list of artifacts displayed. * Remove all artifacts from the list of artifacts displayed.
*/ */
@ThreadConfined(type = ThreadConfined.ThreadType.AWT) @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
void clearArtifacts() { @Override
void clearList() {
tableModel.setContents(new ArrayList<>()); tableModel.setContents(new ArrayList<>());
tableModel.fireTableDataChanged(); tableModel.fireTableDataChanged();
} }
@ -150,19 +147,18 @@ class ArtifactsListPanel extends JPanel {
private void initComponents() { private void initComponents() {
javax.swing.JScrollPane jScrollPane1 = new javax.swing.JScrollPane(); javax.swing.JScrollPane jScrollPane1 = new javax.swing.JScrollPane();
jTable1 = new javax.swing.JTable(); artifactsTable = new javax.swing.JTable();
setOpaque(false); setOpaque(false);
setPreferredSize(new java.awt.Dimension(300, 0)); setPreferredSize(new java.awt.Dimension(300, 0));
jScrollPane1.setBorder(null); jScrollPane1.setBorder(null);
jScrollPane1.setMinimumSize(new java.awt.Dimension(0, 0)); jScrollPane1.setMinimumSize(new java.awt.Dimension(0, 0));
jScrollPane1.setPreferredSize(new java.awt.Dimension(0, 0));
jTable1.setAutoCreateRowSorter(true); artifactsTable.setAutoCreateRowSorter(true);
jTable1.setModel(tableModel); artifactsTable.setModel(tableModel);
jTable1.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); artifactsTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
jScrollPane1.setViewportView(jTable1); jScrollPane1.setViewportView(artifactsTable);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout); this.setLayout(layout);
@ -172,7 +168,7 @@ class ArtifactsListPanel extends JPanel {
); );
layout.setVerticalGroup( layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 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)
); );
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
@ -204,7 +200,7 @@ class ArtifactsListPanel extends JPanel {
*/ */
@ThreadConfined(type = ThreadConfined.ThreadType.AWT) @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
void setContents(List<BlackboardArtifact> artifacts) { void setContents(List<BlackboardArtifact> artifacts) {
jTable1.clearSelection(); artifactsTable.clearSelection();
artifactList.clear(); artifactList.clear();
artifactList.addAll(artifacts); artifactList.addAll(artifacts);
} }
@ -347,6 +343,6 @@ class ArtifactsListPanel extends JPanel {
} }
} }
// Variables declaration - do not modify//GEN-BEGIN:variables // 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 // End of variables declaration//GEN-END:variables
} }

View File

@ -1,3 +1,5 @@
ArtifactMenuMouseAdapter_ExternalViewer_label=Open in external viewer
ArtifactMenuMouseAdapter_label=Extract Files
ArtifactsListPanel.dateColumn.name=Date/Time ArtifactsListPanel.dateColumn.name=Date/Time
ArtifactsListPanel.fileNameColumn.name=Name ArtifactsListPanel.fileNameColumn.name=Name
ArtifactsListPanel.mimeTypeColumn.name=MIME Type ArtifactsListPanel.mimeTypeColumn.name=MIME Type

View File

@ -27,6 +27,7 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.swing.JPanel;
import javax.swing.JSplitPane; import javax.swing.JSplitPane;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.plaf.basic.BasicSplitPaneDivider; import javax.swing.plaf.basic.BasicSplitPaneDivider;
@ -100,6 +101,7 @@ public final class DiscoveryTopComponent extends TopComponent {
} }
}); });
rightSplitPane.setTopComponent(resultsPanel); rightSplitPane.setTopComponent(resultsPanel);
rightSplitPane.setBottomComponent(new JPanel());
} }
/** /**

View File

@ -63,6 +63,7 @@ final class DomainArtifactsTabPanel extends JPanel {
initComponents(); initComponents();
this.artifactType = type; this.artifactType = type;
listPanel = new ArtifactsListPanel(artifactType); listPanel = new ArtifactsListPanel(artifactType);
listPanel.addMouseListener(new ArtifactMenuMouseAdapter(listPanel));
jSplitPane1.setLeftComponent(listPanel); jSplitPane1.setLeftComponent(listPanel);
setRightComponent(); setRightComponent();
listPanel.addSelectionListener(listener); listPanel.addSelectionListener(listener);
@ -113,7 +114,7 @@ final class DomainArtifactsTabPanel extends JPanel {
void setStatus(ArtifactRetrievalStatus status) { void setStatus(ArtifactRetrievalStatus status) {
this.status = status; this.status = status;
if (status == ArtifactRetrievalStatus.UNPOPULATED) { if (status == ArtifactRetrievalStatus.UNPOPULATED) {
listPanel.clearArtifacts(); listPanel.clearList();
if (rightPanel != null){ if (rightPanel != null){
rightPanel.setArtifact(null); rightPanel.setArtifact(null);
} }
@ -131,7 +132,7 @@ final class DomainArtifactsTabPanel extends JPanel {
void handleArtifactSearchResultEvent(DiscoveryEventUtils.ArtifactSearchResultEvent artifactresultEvent) { void handleArtifactSearchResultEvent(DiscoveryEventUtils.ArtifactSearchResultEvent artifactresultEvent) {
if (artifactType == artifactresultEvent.getArtifactType()) { if (artifactType == artifactresultEvent.getArtifactType()) {
SwingUtilities.invokeLater(() -> { SwingUtilities.invokeLater(() -> {
listPanel.removeListSelectionListener(listener); listPanel.removeSelectionListener(listener);
listPanel.addArtifacts(artifactresultEvent.getListOfArtifacts()); listPanel.addArtifacts(artifactresultEvent.getListOfArtifacts());
status = ArtifactRetrievalStatus.POPULATED; status = ArtifactRetrievalStatus.POPULATED;
setEnabled(!listPanel.isEmpty()); setEnabled(!listPanel.isEmpty());

View File

@ -18,10 +18,11 @@
*/ */
package org.sleuthkit.autopsy.discovery.ui; package org.sleuthkit.autopsy.discovery.ui;
import java.awt.Point;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import javax.swing.JPanel; import javax.swing.JPopupMenu;
import javax.swing.event.ListSelectionListener; import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel; import javax.swing.table.AbstractTableModel;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
@ -36,7 +37,7 @@ import org.sleuthkit.datamodel.TskCoreException;
/** /**
* Panel to display list of artifacts types and descriptions. * Panel to display list of artifacts types and descriptions.
*/ */
class MiniTimelineArtifactListPanel extends JPanel { class MiniTimelineArtifactListPanel extends AbstractArtifactListPanel {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final TypeDescriptionTableModel tableModel; private final TypeDescriptionTableModel tableModel;
@ -53,91 +54,76 @@ class MiniTimelineArtifactListPanel extends JPanel {
MiniTimelineArtifactListPanel() { MiniTimelineArtifactListPanel() {
tableModel = new TypeDescriptionTableModel(); tableModel = new TypeDescriptionTableModel();
initComponents(); initComponents();
jTable1.getRowSorter().toggleSortOrder(0); artifactsTable.getRowSorter().toggleSortOrder(0);
jTable1.getRowSorter().toggleSortOrder(0); artifactsTable.getRowSorter().toggleSortOrder(0);
} }
/** @Override
* Add a listener to the table of artifacts to perform actions when a void addMouseListener(java.awt.event.MouseAdapter mouseListener) {
* artifact is selected. artifactsTable.addMouseListener(mouseListener);
* }
* @param listener The listener to add to the table of artifacts.
*/ @Override
@ThreadConfined(type = ThreadConfined.ThreadType.AWT) void showPopupMenu(JPopupMenu popupMenu, Point point) {
popupMenu.show(artifactsTable, point.x, point.y);
}
@Override
void addSelectionListener(ListSelectionListener listener) { void addSelectionListener(ListSelectionListener listener) {
jTable1.getSelectionModel().addListSelectionListener(listener); artifactsTable.getSelectionModel().addListSelectionListener(listener);
} }
/** @Override
* Remove a listener from the table of artifacts. void removeSelectionListener(ListSelectionListener listener) {
* artifactsTable.getSelectionModel().removeListSelectionListener(listener);
* @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
* 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)
boolean isEmpty() { boolean isEmpty() {
return tableModel.getRowCount() <= 0; return tableModel.getRowCount() <= 0;
} }
/** @Override
* 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)
void selectFirst() { void selectFirst() {
if (!isEmpty()) { if (!isEmpty()) {
jTable1.setRowSelectionInterval(0, 0); artifactsTable.setRowSelectionInterval(0, 0);
} else { } else {
jTable1.clearSelection(); artifactsTable.clearSelection();
} }
} }
/** @Override
* The artifact which is currently selected, null if no artifact is boolean selectAtPoint(Point point) {
* selected. boolean pointSelected = false;
* int row = artifactsTable.rowAtPoint(point);
* @return The currently selected BlackboardArtifact or null if none is artifactsTable.clearSelection();
* selected. if (row < artifactsTable.getRowCount() && row >= 0) {
*/ artifactsTable.addRowSelectionInterval(row, row);
@ThreadConfined(type = ThreadConfined.ThreadType.AWT) pointSelected = true;
}
return pointSelected;
}
@Override
BlackboardArtifact getSelectedArtifact() { BlackboardArtifact getSelectedArtifact() {
int selectedIndex = jTable1.getSelectionModel().getLeadSelectionIndex(); int selectedIndex = artifactsTable.getSelectionModel().getLeadSelectionIndex();
if (selectedIndex < jTable1.getSelectionModel().getMinSelectionIndex() if (selectedIndex < artifactsTable.getSelectionModel().getMinSelectionIndex()
|| jTable1.getSelectionModel().getMaxSelectionIndex() < 0 || artifactsTable.getSelectionModel().getMaxSelectionIndex() < 0
|| selectedIndex > jTable1.getSelectionModel().getMaxSelectionIndex()) { || selectedIndex > artifactsTable.getSelectionModel().getMaxSelectionIndex()) {
return null; return null;
} }
return tableModel.getArtifactByRow(jTable1.convertRowIndexToModel(selectedIndex)); return tableModel.getArtifactByRow(artifactsTable.convertRowIndexToModel(selectedIndex));
} }
/** @Override
* Add the specified list of artifacts to the list of artifacts which should void addArtifacts(List<BlackboardArtifact> artifactList) {
* be displayed. tableModel.setContents(artifactList);
* artifactsTable.validate();
* @param artifacttList The list of artifacts to display. artifactsTable.repaint();
*/
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
void addArtifacts(List<BlackboardArtifact> artifacttList) {
tableModel.setContents(artifacttList);
jTable1.validate();
jTable1.repaint();
tableModel.fireTableDataChanged(); tableModel.fireTableDataChanged();
} }
/** @Override
* Remove all artifacts from the list of artifacts displayed.
*/
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
void clearList() { void clearList() {
tableModel.setContents(new ArrayList<>()); tableModel.setContents(new ArrayList<>());
tableModel.fireTableDataChanged(); tableModel.fireTableDataChanged();
@ -149,7 +135,7 @@ class MiniTimelineArtifactListPanel extends JPanel {
private void initComponents() { 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. //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(); javax.swing.JScrollPane jScrollPane1 = new javax.swing.JScrollPane();
jTable1 = new javax.swing.JTable(); artifactsTable = new javax.swing.JTable();
setOpaque(false); setOpaque(false);
setPreferredSize(new java.awt.Dimension(300, 0)); setPreferredSize(new java.awt.Dimension(300, 0));
@ -157,10 +143,10 @@ class MiniTimelineArtifactListPanel extends JPanel {
jScrollPane1.setBorder(null); jScrollPane1.setBorder(null);
jScrollPane1.setMinimumSize(new java.awt.Dimension(0, 0)); jScrollPane1.setMinimumSize(new java.awt.Dimension(0, 0));
jTable1.setAutoCreateRowSorter(true); artifactsTable.setAutoCreateRowSorter(true);
jTable1.setModel(tableModel); artifactsTable.setModel(tableModel);
jTable1.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); artifactsTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
jScrollPane1.setViewportView(jTable1); jScrollPane1.setViewportView(artifactsTable);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout); this.setLayout(layout);
@ -191,7 +177,7 @@ class MiniTimelineArtifactListPanel extends JPanel {
*/ */
@ThreadConfined(type = ThreadConfined.ThreadType.AWT) @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
void setContents(List<BlackboardArtifact> artifactList) { void setContents(List<BlackboardArtifact> artifactList) {
jTable1.clearSelection(); artifactsTable.clearSelection();
this.artifactList.clear(); this.artifactList.clear();
this.artifactList.addAll(artifactList); this.artifactList.addAll(artifactList);
} }
@ -266,6 +252,6 @@ class MiniTimelineArtifactListPanel extends JPanel {
} }
// Variables declaration - do not modify//GEN-BEGIN:variables // 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 // End of variables declaration//GEN-END:variables
} }

View File

@ -51,6 +51,7 @@ class MiniTimelinePanel extends javax.swing.JPanel {
@ThreadConfined(type = ThreadConfined.ThreadType.AWT) @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
MiniTimelinePanel() { MiniTimelinePanel() {
initComponents(); initComponents();
artifactListPanel.addMouseListener(new ArtifactMenuMouseAdapter(artifactListPanel));
artifactListener = new ListSelectionListener() { artifactListener = new ListSelectionListener() {
@Override @Override
public void valueChanged(ListSelectionEvent event) { public void valueChanged(ListSelectionEvent event) {
@ -73,7 +74,7 @@ class MiniTimelinePanel extends javax.swing.JPanel {
@Override @Override
public void valueChanged(ListSelectionEvent event) { public void valueChanged(ListSelectionEvent event) {
if (!event.getValueIsAdjusting()) { if (!event.getValueIsAdjusting()) {
artifactListPanel.removeListSelectionListener(artifactListener); artifactListPanel.removeSelectionListener(artifactListener);
artifactListPanel.clearList(); artifactListPanel.clearList();
artifactListPanel.addArtifacts(dateListPanel.getArtifactsForSelectedDate()); artifactListPanel.addArtifacts(dateListPanel.getArtifactsForSelectedDate());
artifactListPanel.addSelectionListener(artifactListener); artifactListPanel.addSelectionListener(artifactListener);
@ -127,7 +128,7 @@ class MiniTimelinePanel extends javax.swing.JPanel {
void handleMiniTimelineResultEvent(DiscoveryEventUtils.MiniTimelineResultEvent miniTimelineResultEvent) { void handleMiniTimelineResultEvent(DiscoveryEventUtils.MiniTimelineResultEvent miniTimelineResultEvent) {
SwingUtilities.invokeLater(() -> { SwingUtilities.invokeLater(() -> {
dateListPanel.removeListSelectionListener(dateListener); dateListPanel.removeListSelectionListener(dateListener);
artifactListPanel.removeListSelectionListener(artifactListener); artifactListPanel.removeSelectionListener(artifactListener);
dateListPanel.addArtifacts(miniTimelineResultEvent.getResultList()); dateListPanel.addArtifacts(miniTimelineResultEvent.getResultList());
status = DomainArtifactsTabPanel.ArtifactRetrievalStatus.POPULATED; status = DomainArtifactsTabPanel.ArtifactRetrievalStatus.POPULATED;
setEnabled(!dateListPanel.isEmpty()); setEnabled(!dateListPanel.isEmpty());