19 package org.sleuthkit.autopsy.geolocation;
22 import java.awt.Color;
23 import java.awt.Graphics;
24 import java.awt.event.ActionListener;
25 import java.awt.image.BufferedImage;
26 import java.sql.ResultSet;
27 import java.sql.SQLException;
28 import java.util.ArrayList;
29 import java.util.Collections;
30 import java.util.HashMap;
31 import java.util.List;
33 import java.util.concurrent.ExecutionException;
34 import java.util.logging.Level;
35 import javafx.util.Pair;
36 import javax.swing.Icon;
37 import javax.swing.ImageIcon;
38 import javax.swing.SpinnerNumberModel;
39 import javax.swing.SwingWorker;
40 import org.openide.util.NbBundle.Messages;
44 import org.
sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
54 class GeoFilterPanel
extends javax.swing.JPanel {
56 final static String INITPROPERTY =
"FilterPanelInitCompleted";
58 private static final long serialVersionUID = 1L;
59 private static final Logger logger = Logger.getLogger(GeoFilterPanel.class.getName());
61 private final SpinnerNumberModel numberModel;
62 private final CheckBoxListPanel<DataSource> dsCheckboxPanel;
63 private final CheckBoxListPanel<ARTIFACT_TYPE> atCheckboxPanel;
65 private final Object initialFilterLock =
new Object();
66 private GeoFilter initialFilter = null;
69 @SuppressWarnings(
"deprecation")
70 private static final ARTIFACT_TYPE[] GPS_ARTIFACT_TYPES = {
71 ARTIFACT_TYPE.TSK_GPS_BOOKMARK,
72 ARTIFACT_TYPE.TSK_GPS_LAST_KNOWN_LOCATION,
73 ARTIFACT_TYPE.TSK_GPS_ROUTE,
74 ARTIFACT_TYPE.TSK_GPS_SEARCH,
75 ARTIFACT_TYPE.TSK_GPS_TRACK,
76 ARTIFACT_TYPE.TSK_GPS_TRACKPOINT,
77 ARTIFACT_TYPE.TSK_METADATA_EXIF,
78 ARTIFACT_TYPE.TSK_GPS_AREA
85 "GeoFilterPanel_DataSource_List_Title=Data Sources",
86 "GeoFilterPanel_ArtifactType_List_Title=Types"
88 @SuppressWarnings(
"unchecked")
91 numberModel =
new SpinnerNumberModel(10, 1, Integer.MAX_VALUE, 1);
95 dsCheckboxPanel = (CheckBoxListPanel<DataSource>) dsCBPanel;
96 dsCheckboxPanel.setPanelTitle(Bundle.GeoFilterPanel_DataSource_List_Title());
97 dsCheckboxPanel.setPanelTitleIcon(
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/images/image.png")));
98 dsCheckboxPanel.setSetAllSelected(
true);
100 atCheckboxPanel = (CheckBoxListPanel<ARTIFACT_TYPE>) atCBPanel;
101 atCheckboxPanel.setPanelTitle(Bundle.GeoFilterPanel_ArtifactType_List_Title());
102 atCheckboxPanel.setPanelTitleIcon(
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/images/extracted_content.png")));
103 atCheckboxPanel.setSetAllSelected(
true);
107 public void setEnabled(
boolean enabled) {
108 applyButton.setEnabled(enabled);
109 mostRecentButton.setEnabled(enabled);
110 allButton.setEnabled(enabled);
111 showWaypointsWOTSCheckBox.setEnabled(enabled && mostRecentButton.isSelected());
112 dsCheckboxPanel.setEnabled(enabled);
113 atCheckboxPanel.setEnabled(enabled);
114 daysLabel.setEnabled(enabled);
115 daysSpinner.setEnabled(enabled);
121 void updateDataSourceList() {
122 DataSourceUpdater updater =
new DataSourceUpdater();
129 void clearDataSourceList() {
130 dsCheckboxPanel.clearList();
131 atCheckboxPanel.clearList();
134 boolean hasDataSources() {
135 return !dsCheckboxPanel.isEmpty();
143 void addActionListener(ActionListener listener) {
144 applyButton.addActionListener(listener);
155 "GeoFilterPanel_empty_dataSource=Unable to apply filter, please select one or more data sources.",
156 "GeoFilterPanel_empty_artifactType=Unable to apply filter, please select one or more artifact types."
158 GeoFilter getFilterState() throws GeoLocationUIException {
159 List<DataSource> dataSources = dsCheckboxPanel.getSelectedElements();
160 if (dataSources.isEmpty()) {
161 throw new GeoLocationUIException(Bundle.GeoFilterPanel_empty_dataSource());
164 List<ARTIFACT_TYPE> artifactTypes = atCheckboxPanel.getSelectedElements();
165 if (artifactTypes.isEmpty()) {
166 throw new GeoLocationUIException(Bundle.GeoFilterPanel_empty_artifactType());
168 return new GeoFilter(allButton.isSelected(),
169 showWaypointsWOTSCheckBox.isSelected(),
170 numberModel.getNumber().intValue(),
182 void setupFilter(GeoFilter filter) {
183 if (filter == null) {
187 dsCheckboxPanel.setSelectedElements(filter.getDataSources() == null ? Collections.emptyList() : filter.getDataSources());
188 atCheckboxPanel.setSelectedElements(filter.getArtifactTypes() == null ? Collections.emptyList() : filter.getArtifactTypes());
190 if (filter.showAllWaypoints()) {
191 allButton.setSelected(
true);
193 mostRecentButton.setSelected(
true);
196 showWaypointsWOTSCheckBox.setSelected(filter.showWaypointsWithoutTimeStamp());
197 numberModel.setValue(filter.getMostRecentNumDays());
208 void setInitialFilterState(GeoFilter filter)
throws GeoLocationUIException {
209 synchronized (initialFilterLock) {
210 if (filter == null) {
211 throw new GeoLocationUIException(
"Unable to set filter state as no filter was provided.");
214 initialFilter = filter;
222 private void updateWaypointOptions() {
223 boolean selected = mostRecentButton.isSelected();
224 showWaypointsWOTSCheckBox.setEnabled(selected);
225 daysSpinner.setEnabled(selected);
233 @SuppressWarnings(
"unchecked")
235 private
void initComponents() {
236 java.awt.GridBagConstraints gridBagConstraints;
238 javax.swing.ButtonGroup buttonGroup =
new javax.swing.ButtonGroup();
239 javax.swing.JPanel waypointSettings =
new javax.swing.JPanel();
240 allButton =
new javax.swing.JRadioButton();
241 mostRecentButton =
new javax.swing.JRadioButton();
242 showWaypointsWOTSCheckBox =
new javax.swing.JCheckBox();
243 daysSpinner =
new javax.swing.JSpinner(numberModel);
244 daysLabel =
new javax.swing.JLabel();
245 showLabel =
new javax.swing.JLabel();
246 javax.swing.JPanel buttonPanel =
new javax.swing.JPanel();
247 applyButton =
new javax.swing.JButton();
248 javax.swing.JLabel optionsLabel =
new javax.swing.JLabel();
249 dsCBPanel =
new CheckBoxListPanel<DataSource>();
250 atCBPanel =
new CheckBoxListPanel<ARTIFACT_TYPE>();
252 setMinimumSize(
new java.awt.Dimension(10, 700));
253 setPreferredSize(
new java.awt.Dimension(300, 700));
254 setLayout(
new java.awt.GridBagLayout());
256 waypointSettings.setBorder(javax.swing.BorderFactory.createTitledBorder(
org.openide.util.NbBundle.getMessage(GeoFilterPanel.class,
"GeoFilterPanel.waypointSettings.border.title")));
257 waypointSettings.setLayout(
new java.awt.GridBagLayout());
259 buttonGroup.add(allButton);
260 allButton.setSelected(
true);
261 org.openide.awt.Mnemonics.setLocalizedText(allButton,
org.openide.util.NbBundle.getMessage(GeoFilterPanel.class,
"GeoFilterPanel.allButton.text"));
262 allButton.addActionListener(
new java.awt.event.ActionListener() {
263 public void actionPerformed(java.awt.event.ActionEvent evt) {
264 allButtonActionPerformed(evt);
267 gridBagConstraints =
new java.awt.GridBagConstraints();
268 gridBagConstraints.gridx = 0;
269 gridBagConstraints.gridy = 1;
270 gridBagConstraints.gridwidth = 4;
271 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
272 gridBagConstraints.weightx = 1.0;
273 waypointSettings.add(allButton, gridBagConstraints);
275 buttonGroup.add(mostRecentButton);
276 org.openide.awt.Mnemonics.setLocalizedText(mostRecentButton,
org.openide.util.NbBundle.getMessage(GeoFilterPanel.class,
"GeoFilterPanel.mostRecentButton.text"));
277 mostRecentButton.addActionListener(
new java.awt.event.ActionListener() {
278 public void actionPerformed(java.awt.event.ActionEvent evt) {
279 mostRecentButtonActionPerformed(evt);
282 gridBagConstraints =
new java.awt.GridBagConstraints();
283 gridBagConstraints.gridx = 0;
284 gridBagConstraints.gridy = 2;
285 gridBagConstraints.gridwidth = 2;
286 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
287 waypointSettings.add(mostRecentButton, gridBagConstraints);
289 org.openide.awt.Mnemonics.setLocalizedText(showWaypointsWOTSCheckBox,
org.openide.util.NbBundle.getMessage(GeoFilterPanel.class,
"GeoFilterPanel.showWaypointsWOTSCheckBox.text"));
290 showWaypointsWOTSCheckBox.setEnabled(
false);
291 gridBagConstraints =
new java.awt.GridBagConstraints();
292 gridBagConstraints.gridx = 1;
293 gridBagConstraints.gridy = 3;
294 gridBagConstraints.gridwidth = 3;
295 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
296 gridBagConstraints.insets =
new java.awt.Insets(0, -20, 0, 5);
297 waypointSettings.add(showWaypointsWOTSCheckBox, gridBagConstraints);
299 daysSpinner.setEnabled(
false);
300 daysSpinner.setMaximumSize(
new java.awt.Dimension(100, 26));
301 daysSpinner.setPreferredSize(
new java.awt.Dimension(75, 26));
302 gridBagConstraints =
new java.awt.GridBagConstraints();
303 gridBagConstraints.gridx = 2;
304 gridBagConstraints.gridy = 2;
305 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
306 waypointSettings.add(daysSpinner, gridBagConstraints);
308 org.openide.awt.Mnemonics.setLocalizedText(daysLabel,
org.openide.util.NbBundle.getMessage(GeoFilterPanel.class,
"GeoFilterPanel.daysLabel.text"));
309 gridBagConstraints =
new java.awt.GridBagConstraints();
310 gridBagConstraints.gridx = 3;
311 gridBagConstraints.gridy = 2;
312 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
313 gridBagConstraints.weightx = 1.0;
314 gridBagConstraints.insets =
new java.awt.Insets(0, 5, 0, 5);
315 waypointSettings.add(daysLabel, gridBagConstraints);
317 org.openide.awt.Mnemonics.setLocalizedText(showLabel,
org.openide.util.NbBundle.getMessage(GeoFilterPanel.class,
"GeoFilterPanel.showLabel.text"));
318 showLabel.setToolTipText(
org.openide.util.NbBundle.getMessage(GeoFilterPanel.class,
"GeoFilterPanel.showLabel.toolTipText"));
319 gridBagConstraints =
new java.awt.GridBagConstraints();
320 gridBagConstraints.gridx = 0;
321 gridBagConstraints.gridy = 0;
322 gridBagConstraints.insets =
new java.awt.Insets(0, 5, 0, 0);
323 waypointSettings.add(showLabel, gridBagConstraints);
325 gridBagConstraints =
new java.awt.GridBagConstraints();
326 gridBagConstraints.gridx = 0;
327 gridBagConstraints.gridy = 2;
328 gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
329 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
330 gridBagConstraints.weightx = 1.0;
331 gridBagConstraints.insets =
new java.awt.Insets(5, 15, 9, 25);
332 add(waypointSettings, gridBagConstraints);
334 buttonPanel.setLayout(
new java.awt.GridBagLayout());
336 applyButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/images/tick.png")));
337 org.openide.awt.Mnemonics.setLocalizedText(applyButton,
org.openide.util.NbBundle.getMessage(GeoFilterPanel.class,
"GeoFilterPanel.applyButton.text"));
338 gridBagConstraints =
new java.awt.GridBagConstraints();
339 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
340 gridBagConstraints.weightx = 1.0;
341 buttonPanel.add(applyButton, gridBagConstraints);
343 gridBagConstraints =
new java.awt.GridBagConstraints();
344 gridBagConstraints.gridx = 0;
345 gridBagConstraints.gridy = 0;
346 gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
347 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
348 gridBagConstraints.weightx = 1.0;
349 gridBagConstraints.insets =
new java.awt.Insets(9, 15, 0, 25);
350 add(buttonPanel, gridBagConstraints);
352 optionsLabel.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/images/blueGeo16.png")));
353 org.openide.awt.Mnemonics.setLocalizedText(optionsLabel,
org.openide.util.NbBundle.getMessage(GeoFilterPanel.class,
"GeoFilterPanel.optionsLabel.text"));
354 gridBagConstraints =
new java.awt.GridBagConstraints();
355 gridBagConstraints.gridx = 0;
356 gridBagConstraints.gridy = 1;
357 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
358 gridBagConstraints.insets =
new java.awt.Insets(0, 15, 0, 0);
359 add(optionsLabel, gridBagConstraints);
361 dsCBPanel.setMinimumSize(
new java.awt.Dimension(150, 250));
362 dsCBPanel.setPreferredSize(
new java.awt.Dimension(150, 250));
363 gridBagConstraints =
new java.awt.GridBagConstraints();
364 gridBagConstraints.gridx = 0;
365 gridBagConstraints.gridy = 3;
366 gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
367 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
368 gridBagConstraints.weighty = 1.0;
369 gridBagConstraints.insets =
new java.awt.Insets(5, 15, 9, 25);
370 add(dsCBPanel, gridBagConstraints);
372 atCBPanel.setMinimumSize(
new java.awt.Dimension(150, 250));
373 atCBPanel.setPreferredSize(
new java.awt.Dimension(150, 250));
374 gridBagConstraints =
new java.awt.GridBagConstraints();
375 gridBagConstraints.gridx = 0;
376 gridBagConstraints.gridy = 4;
377 gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
378 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
379 gridBagConstraints.weighty = 1.0;
380 gridBagConstraints.insets =
new java.awt.Insets(5, 15, 9, 25);
381 add(atCBPanel, gridBagConstraints);
382 atCBPanel.getAccessibleContext().setAccessibleName(
org.openide.util.NbBundle.getMessage(GeoFilterPanel.class,
"GeoFilterPanel.atCBPanel.AccessibleContext.accessibleName"));
385 private void allButtonActionPerformed(java.awt.event.ActionEvent evt) {
386 updateWaypointOptions();
389 private void mostRecentButtonActionPerformed(java.awt.event.ActionEvent evt) {
390 updateWaypointOptions();
395 private javax.swing.JRadioButton allButton;
396 private javax.swing.JButton applyButton;
397 private javax.swing.JPanel atCBPanel;
398 private javax.swing.JLabel daysLabel;
399 private javax.swing.JSpinner daysSpinner;
400 private javax.swing.JPanel dsCBPanel;
401 private javax.swing.JRadioButton mostRecentButton;
402 private javax.swing.JLabel showLabel;
403 private javax.swing.JCheckBox showWaypointsWOTSCheckBox;
412 final List<Pair<String, DataSource>> dataSources;
413 final Map<ARTIFACT_TYPE, Long> artifactTypes;
415 private Sources(List<Pair<String, DataSource>> dataSources,
416 Map<ARTIFACT_TYPE, Long> artifactTypes) {
417 this.dataSources = dataSources;
418 this.artifactTypes = artifactTypes;
433 List<Pair<String, DataSource>> validSources =
new ArrayList<>();
434 HashMap<ARTIFACT_TYPE, Long> atCountsTotal =
new HashMap<>();
436 for (DataSource dataSource : sleuthkitCase.getDataSources()) {
437 Map<ARTIFACT_TYPE, Long> atCounts =
getGPSDataSources(sleuthkitCase, dataSource);
438 if (!atCounts.isEmpty()) {
439 for (Map.Entry<ARTIFACT_TYPE, Long> entry : atCounts.entrySet()) {
440 atCountsTotal.putIfAbsent(entry.getKey(), 0L);
441 atCountsTotal.put(entry.getKey(), atCountsTotal.get(entry.getKey()) + entry.getValue());
443 String dsName = sleuthkitCase.getContentById(dataSource.getId()).getName();
444 Pair<String, DataSource> pair =
new Pair<>(dsName, dataSource);
445 validSources.add(pair);
448 return new Sources(validSources, atCountsTotal);
464 DataSource dataSource, BlackboardArtifact.ARTIFACT_TYPE artifactType) throws TskCoreException {
467 =
"SELECT count(DISTINCT artIds) AS count FROM"
469 +
" SELECT arts.artifact_id as artIds, * FROM blackboard_artifacts as arts"
470 +
" INNER JOIN blackboard_attributes as attrs"
471 +
" ON attrs.artifact_id = arts.artifact_id"
472 +
" WHERE arts.artifact_type_id = " + artifactType.getTypeID()
473 +
" AND arts.data_source_obj_id = " + dataSource.getId()
474 +
" AND arts.review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID()
477 +
"attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID()
478 +
" or attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID()
479 +
" or attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_TRACKPOINTS.getTypeID()
480 +
" or attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_WAYPOINTS.getTypeID()
481 +
" or attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_AREAPOINTS.getTypeID()
483 +
" ) as innerTable";
484 try (SleuthkitCase.CaseDbQuery queryResult = sleuthkitCase.executeQuery(queryStr);
485 ResultSet resultSet = queryResult.getResultSet()) {
486 if (resultSet.next()) {
487 count = resultSet.getLong(
"count");
489 }
catch (SQLException ex) {
490 Throwable cause = ex.getCause();
492 logger.log(Level.SEVERE, cause.getMessage(), cause);
494 logger.log(Level.SEVERE, ex.getMessage(), ex);
511 private Map<ARTIFACT_TYPE, Long>
getGPSDataSources(SleuthkitCase sleuthkitCase, DataSource dataSource)
throws TskCoreException {
512 HashMap<ARTIFACT_TYPE, Long> ret =
new HashMap<>();
513 for (BlackboardArtifact.ARTIFACT_TYPE type : GPS_ARTIFACT_TYPES) {
516 ret.put(type, count);
531 Color color =
MapWaypoint.getColor(artifactTypeId);
532 BufferedImage img =
new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
534 Graphics g = img.createGraphics();
536 g.fillRect(0, 0, 16, 16);
539 return new ImageIcon(img);
547 }
catch (InterruptedException | ExecutionException ex) {
548 Throwable cause = ex.getCause();
550 logger.log(Level.SEVERE, cause.getMessage(), cause);
552 logger.log(Level.SEVERE, ex.getMessage(), ex);
556 if (sources != null) {
557 for (Pair<String, DataSource> source : sources.dataSources) {
558 dsCheckboxPanel.addElement(source.getKey(), null, source.getValue());
560 for (Map.Entry<ARTIFACT_TYPE, Long> entry : sources.artifactTypes.entrySet()) {
561 String dispName = entry.getKey().getDisplayName() +
" (" + entry.getValue() +
")";
563 atCheckboxPanel.addElement(dispName, icon, entry.getKey());
568 synchronized (GeoFilterPanel.this.initialFilterLock) {
569 filter = GeoFilterPanel.this.initialFilter;
570 GeoFilterPanel.this.initialFilter = null;
573 if (filter != null) {
577 GeoFilterPanel.this.firePropertyChange(INITPROPERTY,
false,
true);
Map< ARTIFACT_TYPE, Long > getGPSDataSources(SleuthkitCase sleuthkitCase, DataSource dataSource)
long getGPSDataCount(SleuthkitCase sleuthkitCase, DataSource dataSource, BlackboardArtifact.ARTIFACT_TYPE artifactType)
Sources(List< Pair< String, DataSource >> dataSources, Map< ARTIFACT_TYPE, Long > artifactTypes)
SleuthkitCase getSleuthkitCase()
static Case getCurrentCase()
ImageIcon getImageIcon(int artifactTypeId)