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;
66 @SuppressWarnings(
"deprecation")
67 private static final ARTIFACT_TYPE[] GPS_ARTIFACT_TYPES = {
68 ARTIFACT_TYPE.TSK_GPS_BOOKMARK,
69 ARTIFACT_TYPE.TSK_GPS_LAST_KNOWN_LOCATION,
70 ARTIFACT_TYPE.TSK_GPS_ROUTE,
71 ARTIFACT_TYPE.TSK_GPS_SEARCH,
72 ARTIFACT_TYPE.TSK_GPS_TRACK,
73 ARTIFACT_TYPE.TSK_GPS_TRACKPOINT,
74 ARTIFACT_TYPE.TSK_METADATA_EXIF
81 "GeoFilterPanel_DataSource_List_Title=Data Sources",
82 "GeoFilterPanel_ArtifactType_List_Title=Types"
84 @SuppressWarnings(
"unchecked")
87 numberModel =
new SpinnerNumberModel(10, 1, Integer.MAX_VALUE, 1);
91 dsCheckboxPanel = (CheckBoxListPanel<DataSource>)dsCBPanel;
92 dsCheckboxPanel.setPanelTitle(Bundle.GeoFilterPanel_DataSource_List_Title());
93 dsCheckboxPanel.setPanelTitleIcon(
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/images/image.png")));
94 dsCheckboxPanel.setSetAllSelected(
true);
96 atCheckboxPanel = (CheckBoxListPanel<ARTIFACT_TYPE>)atCBPanel;
97 atCheckboxPanel.setPanelTitle(Bundle.GeoFilterPanel_ArtifactType_List_Title());
98 atCheckboxPanel.setPanelTitleIcon(
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/images/extracted_content.png")));
99 atCheckboxPanel.setSetAllSelected(
true);
103 public void setEnabled(
boolean enabled) {
104 applyButton.setEnabled(enabled);
105 mostRecentButton.setEnabled(enabled);
106 allButton.setEnabled(enabled);
107 showWaypointsWOTSCheckBox.setEnabled(enabled && mostRecentButton.isSelected());
108 dsCheckboxPanel.setEnabled(enabled);
109 atCheckboxPanel.setEnabled(enabled);
110 daysLabel.setEnabled(enabled);
111 daysSpinner.setEnabled(enabled);
117 void updateDataSourceList() {
118 DataSourceUpdater updater =
new DataSourceUpdater();
125 void clearDataSourceList() {
126 dsCheckboxPanel.clearList();
127 atCheckboxPanel.clearList();
130 boolean hasDataSources() {
131 return !dsCheckboxPanel.isEmpty();
139 void addActionListener(ActionListener listener) {
140 applyButton.addActionListener(listener);
151 "GeoFilterPanel_empty_dataSource=Unable to apply filter, please select one or more data sources.",
152 "GeoFilterPanel_empty_artifactType=Unable to apply filter, please select one or more artifact types."
154 GeoFilter getFilterState() throws GeoLocationUIException {
155 List<DataSource> dataSources = dsCheckboxPanel.getSelectedElements();
156 if (dataSources.isEmpty()) {
157 throw new GeoLocationUIException(Bundle.GeoFilterPanel_empty_dataSource());
160 List<ARTIFACT_TYPE> artifactTypes = atCheckboxPanel.getSelectedElements();
161 if (artifactTypes.isEmpty()) {
162 throw new GeoLocationUIException(Bundle.GeoFilterPanel_empty_artifactType());
164 return new GeoFilter(allButton.isSelected(),
165 showWaypointsWOTSCheckBox.isSelected(),
166 numberModel.getNumber().intValue(),
175 private void updateWaypointOptions() {
176 boolean selected = mostRecentButton.isSelected();
177 showWaypointsWOTSCheckBox.setEnabled(selected);
178 daysSpinner.setEnabled(selected);
186 @SuppressWarnings(
"unchecked")
188 private
void initComponents() {
189 java.awt.GridBagConstraints gridBagConstraints;
191 javax.swing.ButtonGroup buttonGroup =
new javax.swing.ButtonGroup();
192 javax.swing.JPanel waypointSettings =
new javax.swing.JPanel();
193 allButton =
new javax.swing.JRadioButton();
194 mostRecentButton =
new javax.swing.JRadioButton();
195 showWaypointsWOTSCheckBox =
new javax.swing.JCheckBox();
196 daysSpinner =
new javax.swing.JSpinner(numberModel);
197 daysLabel =
new javax.swing.JLabel();
198 showLabel =
new javax.swing.JLabel();
199 javax.swing.JPanel buttonPanel =
new javax.swing.JPanel();
200 applyButton =
new javax.swing.JButton();
201 javax.swing.JLabel optionsLabel =
new javax.swing.JLabel();
202 dsCBPanel =
new CheckBoxListPanel<DataSource>();
203 atCBPanel =
new CheckBoxListPanel<ARTIFACT_TYPE>();
205 setMinimumSize(
new java.awt.Dimension(10, 700));
206 setPreferredSize(
new java.awt.Dimension(300, 700));
207 setLayout(
new java.awt.GridBagLayout());
209 waypointSettings.setBorder(javax.swing.BorderFactory.createTitledBorder(
org.openide.util.NbBundle.getMessage(GeoFilterPanel.class,
"GeoFilterPanel.waypointSettings.border.title")));
210 waypointSettings.setLayout(
new java.awt.GridBagLayout());
212 buttonGroup.add(allButton);
213 allButton.setSelected(
true);
214 org.openide.awt.Mnemonics.setLocalizedText(allButton,
org.openide.util.NbBundle.getMessage(GeoFilterPanel.class,
"GeoFilterPanel.allButton.text"));
215 allButton.addActionListener(
new java.awt.event.ActionListener() {
216 public void actionPerformed(java.awt.event.ActionEvent evt) {
217 allButtonActionPerformed(evt);
220 gridBagConstraints =
new java.awt.GridBagConstraints();
221 gridBagConstraints.gridx = 0;
222 gridBagConstraints.gridy = 1;
223 gridBagConstraints.gridwidth = 4;
224 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
225 gridBagConstraints.weightx = 1.0;
226 waypointSettings.add(allButton, gridBagConstraints);
228 buttonGroup.add(mostRecentButton);
229 org.openide.awt.Mnemonics.setLocalizedText(mostRecentButton,
org.openide.util.NbBundle.getMessage(GeoFilterPanel.class,
"GeoFilterPanel.mostRecentButton.text"));
230 mostRecentButton.addActionListener(
new java.awt.event.ActionListener() {
231 public void actionPerformed(java.awt.event.ActionEvent evt) {
232 mostRecentButtonActionPerformed(evt);
235 gridBagConstraints =
new java.awt.GridBagConstraints();
236 gridBagConstraints.gridx = 0;
237 gridBagConstraints.gridy = 2;
238 gridBagConstraints.gridwidth = 2;
239 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
240 waypointSettings.add(mostRecentButton, gridBagConstraints);
242 org.openide.awt.Mnemonics.setLocalizedText(showWaypointsWOTSCheckBox,
org.openide.util.NbBundle.getMessage(GeoFilterPanel.class,
"GeoFilterPanel.showWaypointsWOTSCheckBox.text"));
243 showWaypointsWOTSCheckBox.setEnabled(
false);
244 gridBagConstraints =
new java.awt.GridBagConstraints();
245 gridBagConstraints.gridx = 1;
246 gridBagConstraints.gridy = 3;
247 gridBagConstraints.gridwidth = 3;
248 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
249 gridBagConstraints.insets =
new java.awt.Insets(0, -20, 0, 5);
250 waypointSettings.add(showWaypointsWOTSCheckBox, gridBagConstraints);
252 daysSpinner.setEnabled(
false);
253 daysSpinner.setMaximumSize(
new java.awt.Dimension(100, 26));
254 daysSpinner.setPreferredSize(
new java.awt.Dimension(75, 26));
255 gridBagConstraints =
new java.awt.GridBagConstraints();
256 gridBagConstraints.gridx = 2;
257 gridBagConstraints.gridy = 2;
258 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
259 waypointSettings.add(daysSpinner, gridBagConstraints);
261 org.openide.awt.Mnemonics.setLocalizedText(daysLabel,
org.openide.util.NbBundle.getMessage(GeoFilterPanel.class,
"GeoFilterPanel.daysLabel.text"));
262 gridBagConstraints =
new java.awt.GridBagConstraints();
263 gridBagConstraints.gridx = 3;
264 gridBagConstraints.gridy = 2;
265 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
266 gridBagConstraints.weightx = 1.0;
267 gridBagConstraints.insets =
new java.awt.Insets(0, 5, 0, 5);
268 waypointSettings.add(daysLabel, gridBagConstraints);
270 org.openide.awt.Mnemonics.setLocalizedText(showLabel,
org.openide.util.NbBundle.getMessage(GeoFilterPanel.class,
"GeoFilterPanel.showLabel.text"));
271 showLabel.setToolTipText(
org.openide.util.NbBundle.getMessage(GeoFilterPanel.class,
"GeoFilterPanel.showLabel.toolTipText"));
272 gridBagConstraints =
new java.awt.GridBagConstraints();
273 gridBagConstraints.gridx = 0;
274 gridBagConstraints.gridy = 0;
275 gridBagConstraints.insets =
new java.awt.Insets(0, 5, 0, 0);
276 waypointSettings.add(showLabel, gridBagConstraints);
278 gridBagConstraints =
new java.awt.GridBagConstraints();
279 gridBagConstraints.gridx = 0;
280 gridBagConstraints.gridy = 2;
281 gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
282 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
283 gridBagConstraints.weightx = 1.0;
284 gridBagConstraints.insets =
new java.awt.Insets(5, 15, 9, 25);
285 add(waypointSettings, gridBagConstraints);
287 buttonPanel.setLayout(
new java.awt.GridBagLayout());
289 applyButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/images/tick.png")));
290 org.openide.awt.Mnemonics.setLocalizedText(applyButton,
org.openide.util.NbBundle.getMessage(GeoFilterPanel.class,
"GeoFilterPanel.applyButton.text"));
291 gridBagConstraints =
new java.awt.GridBagConstraints();
292 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
293 gridBagConstraints.weightx = 1.0;
294 buttonPanel.add(applyButton, gridBagConstraints);
296 gridBagConstraints =
new java.awt.GridBagConstraints();
297 gridBagConstraints.gridx = 0;
298 gridBagConstraints.gridy = 0;
299 gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
300 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
301 gridBagConstraints.weightx = 1.0;
302 gridBagConstraints.insets =
new java.awt.Insets(9, 15, 0, 25);
303 add(buttonPanel, gridBagConstraints);
305 optionsLabel.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/images/blueGeo16.png")));
306 org.openide.awt.Mnemonics.setLocalizedText(optionsLabel,
org.openide.util.NbBundle.getMessage(GeoFilterPanel.class,
"GeoFilterPanel.optionsLabel.text"));
307 gridBagConstraints =
new java.awt.GridBagConstraints();
308 gridBagConstraints.gridx = 0;
309 gridBagConstraints.gridy = 1;
310 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
311 gridBagConstraints.insets =
new java.awt.Insets(0, 15, 0, 0);
312 add(optionsLabel, gridBagConstraints);
314 dsCBPanel.setMinimumSize(
new java.awt.Dimension(150, 250));
315 dsCBPanel.setPreferredSize(
new java.awt.Dimension(150, 250));
316 gridBagConstraints =
new java.awt.GridBagConstraints();
317 gridBagConstraints.gridx = 0;
318 gridBagConstraints.gridy = 3;
319 gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
320 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
321 gridBagConstraints.weighty = 1.0;
322 gridBagConstraints.insets =
new java.awt.Insets(5, 15, 9, 25);
323 add(dsCBPanel, gridBagConstraints);
325 atCBPanel.setMinimumSize(
new java.awt.Dimension(150, 250));
326 atCBPanel.setPreferredSize(
new java.awt.Dimension(150, 250));
327 gridBagConstraints =
new java.awt.GridBagConstraints();
328 gridBagConstraints.gridx = 0;
329 gridBagConstraints.gridy = 4;
330 gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
331 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
332 gridBagConstraints.weighty = 1.0;
333 gridBagConstraints.insets =
new java.awt.Insets(5, 15, 9, 25);
334 add(atCBPanel, gridBagConstraints);
335 atCBPanel.getAccessibleContext().setAccessibleName(
org.openide.util.NbBundle.getMessage(GeoFilterPanel.class,
"GeoFilterPanel.atCBPanel.AccessibleContext.accessibleName"));
338 private void allButtonActionPerformed(java.awt.event.ActionEvent evt) {
339 updateWaypointOptions();
342 private void mostRecentButtonActionPerformed(java.awt.event.ActionEvent evt) {
343 updateWaypointOptions();
348 private javax.swing.JRadioButton allButton;
349 private javax.swing.JButton applyButton;
350 private javax.swing.JPanel atCBPanel;
351 private javax.swing.JLabel daysLabel;
352 private javax.swing.JSpinner daysSpinner;
353 private javax.swing.JPanel dsCBPanel;
354 private javax.swing.JRadioButton mostRecentButton;
355 private javax.swing.JLabel showLabel;
356 private javax.swing.JCheckBox showWaypointsWOTSCheckBox;
362 final class GeoFilter {
364 private final boolean showAll;
365 private final boolean showWithoutTimeStamp;
366 private final int mostRecentNumDays;
367 private final List<DataSource> dataSources;
368 private final List<ARTIFACT_TYPE> artifactTypes;
388 GeoFilter(
boolean showAll,
boolean withoutTimeStamp,
389 int mostRecentNumDays, List<DataSource> dataSources,
390 List<ARTIFACT_TYPE> artifactTypes) {
391 this.showAll = showAll;
392 this.showWithoutTimeStamp = withoutTimeStamp;
393 this.mostRecentNumDays = mostRecentNumDays;
394 this.dataSources = dataSources;
395 this.artifactTypes = artifactTypes;
403 boolean showAllWaypoints() {
414 boolean showWaypointsWithoutTimeStamp() {
415 return showWithoutTimeStamp;
424 int getMostRecentNumDays() {
425 return mostRecentNumDays;
435 List<DataSource> getDataSources() {
436 return Collections.unmodifiableList(dataSources);
446 List<ARTIFACT_TYPE> getArtifactTypes() {
447 return Collections.unmodifiableList(artifactTypes);
457 final List<Pair<String, DataSource>> dataSources;
458 final Map<ARTIFACT_TYPE, Long> artifactTypes;
460 private Sources(List<Pair<String, DataSource>> dataSources,
461 Map<ARTIFACT_TYPE, Long> artifactTypes) {
462 this.dataSources = dataSources;
463 this.artifactTypes = artifactTypes;
478 List<Pair<String, DataSource>> validSources =
new ArrayList<>();
479 HashMap<ARTIFACT_TYPE, Long> atCountsTotal =
new HashMap<>();
481 for (DataSource dataSource : sleuthkitCase.getDataSources()) {
482 Map<ARTIFACT_TYPE, Long> atCounts =
getGPSDataSources(sleuthkitCase, dataSource);
483 if (!atCounts.isEmpty()) {
484 for (Map.Entry<ARTIFACT_TYPE, Long> entry : atCounts.entrySet()) {
485 atCountsTotal.putIfAbsent(entry.getKey(), 0L);
486 atCountsTotal.put(entry.getKey(), atCountsTotal.get(entry.getKey()) + entry.getValue());
488 String dsName = sleuthkitCase.getContentById(dataSource.getId()).getName();
489 Pair<String, DataSource> pair =
new Pair<>(dsName, dataSource);
490 validSources.add(pair);
493 return new Sources(validSources, atCountsTotal);
509 DataSource dataSource, BlackboardArtifact.ARTIFACT_TYPE artifactType) throws TskCoreException {
512 =
"SELECT count(DISTINCT artIds) AS count FROM"
514 +
" SELECT arts.artifact_id as artIds, * FROM blackboard_artifacts as arts"
515 +
" INNER JOIN blackboard_attributes as attrs"
516 +
" ON attrs.artifact_id = arts.artifact_id"
517 +
" WHERE arts.artifact_type_id = " + artifactType.getTypeID()
518 +
" AND arts.data_source_obj_id = " + dataSource.getId()
519 +
" AND arts.review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID()
522 +
"attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID()
523 +
" or attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID()
524 +
" or attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_TRACKPOINTS.getTypeID()
525 +
" or attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_WAYPOINTS.getTypeID()
527 +
" ) as innerTable";
528 try (SleuthkitCase.CaseDbQuery queryResult = sleuthkitCase.executeQuery(queryStr);
529 ResultSet resultSet = queryResult.getResultSet()) {
530 if (resultSet.next()) {
531 count = resultSet.getLong(
"count");
533 }
catch (SQLException ex) {
534 Throwable cause = ex.getCause();
536 logger.log(Level.SEVERE, cause.getMessage(), cause);
538 logger.log(Level.SEVERE, ex.getMessage(), ex);
555 private Map<ARTIFACT_TYPE, Long>
getGPSDataSources(SleuthkitCase sleuthkitCase, DataSource dataSource)
throws TskCoreException {
556 HashMap<ARTIFACT_TYPE, Long> ret =
new HashMap<>();
557 for (BlackboardArtifact.ARTIFACT_TYPE type : GPS_ARTIFACT_TYPES) {
560 ret.put(type, count);
575 Color color = MapWaypoint.getColor(artifactTypeId);
576 BufferedImage img =
new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
578 Graphics g = img.createGraphics();
580 g.fillRect(0, 0, 16, 16);
583 return new ImageIcon(img);
591 }
catch (InterruptedException | ExecutionException ex) {
592 Throwable cause = ex.getCause();
594 logger.log(Level.SEVERE, cause.getMessage(), cause);
596 logger.log(Level.SEVERE, ex.getMessage(), ex);
600 if (sources != null) {
601 for (Pair<String, DataSource> source : sources.dataSources) {
602 dsCheckboxPanel.addElement(source.getKey(), null, source.getValue());
604 for (Map.Entry<ARTIFACT_TYPE, Long> entry : sources.artifactTypes.entrySet()) {
605 String dispName = entry.getKey().getDisplayName() +
" (" + entry.getValue() +
")";
607 atCheckboxPanel.addElement(dispName, icon, entry.getKey());
611 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)