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"/>
<SubComponents>
<Component class="javax.swing.JTable" name="jTable1">
<Component class="javax.swing.JTable" name="artifactsTable">
<Properties>
<Property name="autoCreateRowSorter" type="boolean" value="true"/>
<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;
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,11 +39,11 @@ import org.sleuthkit.datamodel.TskCoreException;
* 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 final DomainArtifactTableModel tableModel;
private static final Logger logger = Logger.getLogger(ArtifactsListPanel.class.getName());
private final DomainArtifactTableModel tableModel;
/**
* Creates new form ArtifactsListPanel.
@ -53,68 +54,62 @@ 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);
}
/**
* 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
void addMouseListener(java.awt.event.MouseAdapter mouseListener) {
artifactsTable.addMouseListener(mouseListener);
}
@Override
void showPopupMenu(JPopupMenu popupMenu, Point point) {
popupMenu.show(artifactsTable, point.x, point.y);
}
@Override
void addSelectionListener(ListSelectionListener listener) {
jTable1.getSelectionModel().addListSelectionListener(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)
void removeListSelectionListener(ListSelectionListener listener) {
jTable1.getSelectionModel().removeListSelectionListener(listener);
@Override
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
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 = jTable1.getSelectionModel().getLeadSelectionIndex();
if (selectedIndex < jTable1.getSelectionModel().getMinSelectionIndex() || jTable1.getSelectionModel().getMaxSelectionIndex() < 0 || selectedIndex > jTable1.getSelectionModel().getMaxSelectionIndex()) {
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));
}
/**
* 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
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
void selectFirst() {
if (!isEmpty()) {
jTable1.setRowSelectionInterval(0, 0);
artifactsTable.setRowSelectionInterval(0, 0);
} else {
jTable1.clearSelection();
artifactsTable.clearSelection();
}
}
@ -125,10 +120,11 @@ class ArtifactsListPanel extends JPanel {
* @param artifactList The list of artifacts to display.
*/
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
@Override
void addArtifacts(List<BlackboardArtifact> artifactList) {
tableModel.setContents(artifactList);
jTable1.validate();
jTable1.repaint();
artifactsTable.validate();
artifactsTable.repaint();
tableModel.fireTableDataChanged();
}
@ -136,7 +132,8 @@ class ArtifactsListPanel extends JPanel {
* Remove all artifacts from the list of artifacts displayed.
*/
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
void clearArtifacts() {
@Override
void clearList() {
tableModel.setContents(new ArrayList<>());
tableModel.fireTableDataChanged();
}
@ -150,19 +147,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 +168,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)
);
}// </editor-fold>//GEN-END:initComponents
@ -204,7 +200,7 @@ class ArtifactsListPanel extends JPanel {
*/
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
void setContents(List<BlackboardArtifact> artifacts) {
jTable1.clearSelection();
artifactsTable.clearSelection();
artifactList.clear();
artifactList.addAll(artifacts);
}
@ -347,6 +343,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
}

View File

@ -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

View File

@ -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());
}
/**

View File

@ -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);
@ -113,7 +114,7 @@ final class DomainArtifactsTabPanel extends JPanel {
void setStatus(ArtifactRetrievalStatus status) {
this.status = status;
if (status == ArtifactRetrievalStatus.UNPOPULATED) {
listPanel.clearArtifacts();
listPanel.clearList();
if (rightPanel != null){
rightPanel.setArtifact(null);
}
@ -131,7 +132,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());

View File

@ -18,10 +18,11 @@
*/
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 +37,7 @@ import org.sleuthkit.datamodel.TskCoreException;
/**
* Panel to display list of artifacts types and descriptions.
*/
class MiniTimelineArtifactListPanel extends JPanel {
class MiniTimelineArtifactListPanel extends AbstractArtifactListPanel {
private static final long serialVersionUID = 1L;
private final TypeDescriptionTableModel tableModel;
@ -53,91 +54,76 @@ 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);
}
/**
* 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
void addMouseListener(java.awt.event.MouseAdapter mouseListener) {
artifactsTable.addMouseListener(mouseListener);
}
@Override
void showPopupMenu(JPopupMenu popupMenu, Point point) {
popupMenu.show(artifactsTable, point.x, point.y);
}
@Override
void addSelectionListener(ListSelectionListener listener) {
jTable1.getSelectionModel().addListSelectionListener(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)
void removeListSelectionListener(ListSelectionListener listener) {
jTable1.getSelectionModel().removeListSelectionListener(listener);
@Override
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
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
void selectFirst() {
if (!isEmpty()) {
jTable1.setRowSelectionInterval(0, 0);
artifactsTable.setRowSelectionInterval(0, 0);
} else {
jTable1.clearSelection();
artifactsTable.clearSelection();
}
}
/**
* 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
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 = jTable1.getSelectionModel().getLeadSelectionIndex();
if (selectedIndex < jTable1.getSelectionModel().getMinSelectionIndex()
|| jTable1.getSelectionModel().getMaxSelectionIndex() < 0
|| selectedIndex > jTable1.getSelectionModel().getMaxSelectionIndex()) {
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));
}
/**
* 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)
void addArtifacts(List<BlackboardArtifact> artifacttList) {
tableModel.setContents(artifacttList);
jTable1.validate();
jTable1.repaint();
@Override
void addArtifacts(List<BlackboardArtifact> 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
void clearList() {
tableModel.setContents(new ArrayList<>());
tableModel.fireTableDataChanged();
@ -149,7 +135,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));
@ -157,10 +143,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);
@ -191,7 +177,7 @@ class MiniTimelineArtifactListPanel extends JPanel {
*/
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
void setContents(List<BlackboardArtifact> artifactList) {
jTable1.clearSelection();
artifactsTable.clearSelection();
this.artifactList.clear();
this.artifactList.addAll(artifactList);
}
@ -266,6 +252,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
}

View File

@ -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) {
@ -73,7 +74,7 @@ class MiniTimelinePanel extends javax.swing.JPanel {
@Override
public void valueChanged(ListSelectionEvent event) {
if (!event.getValueIsAdjusting()) {
artifactListPanel.removeListSelectionListener(artifactListener);
artifactListPanel.removeSelectionListener(artifactListener);
artifactListPanel.clearList();
artifactListPanel.addArtifacts(dateListPanel.getArtifactsForSelectedDate());
artifactListPanel.addSelectionListener(artifactListener);
@ -127,7 +128,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());