Autopsy 4.22.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
GeolocationPanel.java
Go to the documentation of this file.
1/*
2 * Autopsy Forensic Browser
3 *
4 * Copyright 2020 Basis Technology Corp.
5 * Contact: carrier <at> sleuthkit <dot> org
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19package org.sleuthkit.autopsy.datasourcesummary.ui;
20
21import java.util.ArrayList;
22import java.util.Arrays;
23import java.util.Collections;
24import java.util.List;
25import java.util.logging.Level;
26import java.util.logging.Logger;
27import java.util.stream.Collectors;
28import java.util.stream.Stream;
29import javax.swing.JButton;
30import org.apache.commons.collections.CollectionUtils;
31import org.apache.commons.lang3.StringUtils;
32import org.apache.commons.lang3.tuple.Pair;
33import org.openide.util.NbBundle.Messages;
34import org.openide.util.actions.CallableSystemAction;
35import org.openide.windows.TopComponent;
36import org.openide.windows.WindowManager;
37import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary.CityCountsList;
38import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary.CityData;
39import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary.CityRecordCount;
40import org.sleuthkit.autopsy.datasourcesummary.datamodel.CityRecord;
41import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel;
42import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult;
43import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker;
44import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents;
45import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher;
46import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel;
47import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel;
48import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel;
49import org.sleuthkit.autopsy.geolocation.GeoFilter;
50import org.sleuthkit.autopsy.geolocation.GeoLocationUIException;
51import org.sleuthkit.autopsy.geolocation.GeolocationTopComponent;
52import org.sleuthkit.autopsy.geolocation.OpenGeolocationAction;
53import org.sleuthkit.datamodel.DataSource;
54
59@Messages({
60 "GeolocationPanel_cityColumn_title=Closest City",
61 "GeolocationPanel_countColumn_title=Count",
62 "GeolocationPanel_onNoCrIngest_message=No results will be shown because the GPX Parser was not run.",
63 "GeolocationPanel_unknownRow_title=Unknown",
64 "GeolocationPanel_mostCommon_tabName=Most Common Cities",
65 "GeolocationPanel_mostRecent_tabName=Most Recent Cities",})
66public class GeolocationPanel extends BaseDataSourceSummaryPanel {
67
71 private static class GeolocationViewModel {
72
73 private final List<Pair<String, Integer>> mostRecentData;
74 private final List<Pair<String, Integer>> mostCommonData;
75
84 GeolocationViewModel(List<Pair<String, Integer>> mostRecentData, List<Pair<String, Integer>> mostCommonData) {
85 this.mostRecentData = mostRecentData;
86 this.mostCommonData = mostCommonData;
87 }
88
94 List<Pair<String, Integer>> getMostRecentData() {
95 return mostRecentData;
96 }
97
103 List<Pair<String, Integer>> getMostCommonData() {
104 return mostCommonData;
105 }
106 }
107
108 private static final long serialVersionUID = 1L;
109 private static final int DAYS_COUNT = 30;
110 private static final int MAX_COUNT = 10;
111
112 // The column indicating the city
114 Bundle.GeolocationPanel_cityColumn_title(),
115 (pair) -> new DefaultCellModel<>(pair.getLeft()),
116 300
117 );
118
119 // The column indicating the count of points seen close to that city
121 Bundle.GeolocationPanel_countColumn_title(),
122 (pair) -> new DefaultCellModel<>(pair.getRight()),
123 100
124 );
125
126 private static final List<ColumnModel<Pair<String, Integer>, DefaultCellModel<?>>> DEFAULT_TEMPLATE = Arrays.asList(
127 CITY_COL,
129 );
130
131 // tables displaying city and number of hits for that city
133 .setKeyFunction((pair) -> pair.getLeft());
134
136 .setKeyFunction((pair) -> pair.getLeft());
137
138 // loadable components on this tab
139 private final List<JTablePanel<?>> tables = Arrays.asList(mostCommonTable, mostRecentTable);
140
141 private final Logger logger = Logger.getLogger(GeolocationPanel.class.getName());
142
143 // means of fetching and displaying data
144 private final List<DataFetchComponents<DataSource, ?>> dataFetchComponents;
145
147
149
151
156 this(new GeolocationSummaryGetter());
157 }
158
165 super(whereUsedData);
166
167 this.whereUsedData = whereUsedData;
168
169 this.geolocationFetcher = (dataSource) -> convertToViewModel(whereUsedData.getCityCounts(dataSource, DAYS_COUNT, MAX_COUNT));
170
171 // set up data acquisition methods
172 dataFetchComponents = Arrays.asList(
175 (result) -> handleData(result)));
176
178 }
179
190
198 private static String getCityName(CityRecord record) {
199 if (record == null) {
200 return null;
201 }
202
203 List<String> cityIdentifiers = Stream.of(record.getCityName(), record.getState(), record.getCountry())
204 .filter(StringUtils::isNotBlank)
205 .collect(Collectors.toList());
206
207 if (cityIdentifiers.size() == 1) {
208 return cityIdentifiers.get(0);
209 } else if (cityIdentifiers.size() == 2) {
210 return String.format("%s, %s", cityIdentifiers.get(0), cityIdentifiers.get(1));
211 } else if (cityIdentifiers.size() >= 3) {
212 return String.format("%s, %s; %s", cityIdentifiers.get(0), cityIdentifiers.get(1), cityIdentifiers.get(2));
213 }
214
215 return null;
216 }
217
226 private Pair<String, Integer> formatRecord(CityRecordCount cityCount) {
227 if (cityCount == null) {
228 return null;
229 }
230
231 String cityName = getCityName(cityCount.getCityRecord());
232 int count = cityCount.getCount();
233 return Pair.of(cityName, count);
234 }
235
246 private List<Pair<String, Integer>> formatList(CityCountsList countsList) {
247 if (countsList == null) {
248 return Collections.emptyList();
249 }
250
251 Stream<CityRecordCount> countsStream = ((countsList.getCounts() == null)
252 ? new ArrayList<CityRecordCount>()
253 : countsList.getCounts()).stream();
254
255 Stream<Pair<String, Integer>> pairStream = countsStream.map((r) -> formatRecord(r));
256
257 Pair<String, Integer> unknownRecord = Pair.of(Bundle.GeolocationPanel_unknownRow_title(), countsList.getOtherCount());
258
259 return Stream.concat(pairStream, Stream.of(unknownRecord))
260 .filter((p) -> p != null && p.getRight() != null && p.getRight() > 0)
261 .sorted((a, b) -> -Integer.compare(a.getRight(), b.getRight()))
262 .limit(MAX_COUNT)
263 .collect(Collectors.toList());
264 }
265
275 if (cityData == null) {
276 return new GeolocationViewModel(Collections.emptyList(), Collections.emptyList());
277 } else {
278 return new GeolocationViewModel(formatList(cityData.getMostRecent()), formatList(cityData.getMostCommon()));
279 }
280 }
281
289 private void showCityContent(DataFetchResult<List<Pair<String, Integer>>> result, JTablePanel<Pair<String, Integer>> table, JButton goToGeolocation) {
290 if (result != null && result.getResultType() == DataFetchResult.ResultType.SUCCESS && CollectionUtils.isNotEmpty(result.getData())) {
291 goToGeolocation.setEnabled(true);
292 }
293
294 table.showDataFetchResult(result);
295 }
296
305 private void openGeolocationWindow(DataSource dataSource, Integer daysLimit) {
306 // notify dialog (if in dialog) should close.
307 notifyParentClose();
308
309 // set the filter
310 TopComponent topComponent = WindowManager.getDefault().findTopComponent(GeolocationTopComponent.class.getSimpleName());
311 if (topComponent instanceof GeolocationTopComponent) {
312 GeolocationTopComponent geoComponent = (GeolocationTopComponent) topComponent;
313
314 GeoFilter filter = (daysLimit == null)
315 ? new GeoFilter(true, false, 0, Arrays.asList(dataSource), whereUsedData.getGeoTypes())
316 : new GeoFilter(false, false, DAYS_COUNT, Arrays.asList(dataSource), whereUsedData.getGeoTypes());
317
318 try {
319 geoComponent.setFilterState(filter);
320 } catch (GeoLocationUIException ex) {
321 logger.log(Level.WARNING, "There was an error setting filters in the GeoLocationTopComponent.", ex);
322 }
323 }
324
325 // open the window
326 OpenGeolocationAction action = CallableSystemAction.get(OpenGeolocationAction.class);
327 if (action == null) {
328 logger.log(Level.WARNING, "Unable to obtain an OpenGeolocationAction instance from CallableSystemAction.");
329 } else {
330 action.performAction();
331 }
332 }
333
337 private void disableNavButtons() {
338 commonViewInGeolocationBtn.setEnabled(false);
339 recentViewInGeolocationBtn.setEnabled(false);
340 }
341
342 @Override
343 protected void fetchInformation(DataSource dataSource) {
346 }
347
348 @Override
349 protected void onNewDataSource(DataSource dataSource) {
352 }
353
354 @Override
355 public void close() {
356 ingestRunningLabel.unregister();
357 super.close();
358 }
359
365 @SuppressWarnings("unchecked")
366 // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
367 private void initComponents() {
368
369 javax.swing.JScrollPane mainScrollPane = new javax.swing.JScrollPane();
370 javax.swing.JPanel mainContentPanel = new javax.swing.JPanel();
371 javax.swing.JPanel ingestRunningPanel = ingestRunningLabel;
372 javax.swing.JLabel mostRecentLabel = new javax.swing.JLabel();
373 javax.swing.Box.Filler filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2));
374 javax.swing.JPanel mostRecentPanel = mostRecentTable;
375 javax.swing.Box.Filler filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2));
376 javax.swing.JLabel withinDistanceLabel = new javax.swing.JLabel();
377 javax.swing.Box.Filler filler3 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 5), new java.awt.Dimension(0, 5), new java.awt.Dimension(0, 5));
378 recentViewInGeolocationBtn = new javax.swing.JButton();
379 javax.swing.Box.Filler filler8 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20));
380 javax.swing.JLabel mostCommonLabel = new javax.swing.JLabel();
381 javax.swing.Box.Filler filler7 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2));
382 javax.swing.JPanel mostCommonPanel = mostCommonTable;
383 javax.swing.Box.Filler filler6 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2));
384 javax.swing.JLabel withinDistanceLabel1 = new javax.swing.JLabel();
385 javax.swing.Box.Filler filler4 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 5), new java.awt.Dimension(0, 5), new java.awt.Dimension(0, 5));
386 commonViewInGeolocationBtn = new javax.swing.JButton();
387 javax.swing.Box.Filler filler5 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 32767));
388
389 mainContentPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10));
390 mainContentPanel.setLayout(new javax.swing.BoxLayout(mainContentPanel, javax.swing.BoxLayout.PAGE_AXIS));
391
392 ingestRunningPanel.setAlignmentX(0.0F);
393 ingestRunningPanel.setMaximumSize(new java.awt.Dimension(32767, 25));
394 ingestRunningPanel.setMinimumSize(new java.awt.Dimension(10, 25));
395 ingestRunningPanel.setPreferredSize(new java.awt.Dimension(10, 25));
396 mainContentPanel.add(ingestRunningPanel);
397
398 org.openide.awt.Mnemonics.setLocalizedText(mostRecentLabel, org.openide.util.NbBundle.getMessage(GeolocationPanel.class, "GeolocationPanel.mostRecentLabel.text")); // NOI18N
399 mainContentPanel.add(mostRecentLabel);
400 mostRecentLabel.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(GeolocationPanel.class, "PastCasesPanel.notableFileLabel.text")); // NOI18N
401
402 filler1.setAlignmentX(0.0F);
403 mainContentPanel.add(filler1);
404
405 mostRecentPanel.setAlignmentX(0.0F);
406 mostRecentPanel.setMaximumSize(new java.awt.Dimension(32767, 106));
407 mostRecentPanel.setMinimumSize(new java.awt.Dimension(100, 106));
408 mostRecentPanel.setPreferredSize(new java.awt.Dimension(100, 106));
409 mainContentPanel.add(mostRecentPanel);
410
411 filler2.setAlignmentX(0.0F);
412 mainContentPanel.add(filler2);
413
414 org.openide.awt.Mnemonics.setLocalizedText(withinDistanceLabel, org.openide.util.NbBundle.getMessage(GeolocationPanel.class, "GeolocationPanel.withinDistanceLabel.text")); // NOI18N
415 mainContentPanel.add(withinDistanceLabel);
416
417 filler3.setAlignmentX(0.0F);
418 mainContentPanel.add(filler3);
419
420 org.openide.awt.Mnemonics.setLocalizedText(recentViewInGeolocationBtn, org.openide.util.NbBundle.getMessage(GeolocationPanel.class, "GeolocationPanel.recentViewInGeolocationBtn.text")); // NOI18N
421 recentViewInGeolocationBtn.setEnabled(false);
422 recentViewInGeolocationBtn.addActionListener(new java.awt.event.ActionListener() {
423 public void actionPerformed(java.awt.event.ActionEvent evt) {
424 recentViewInGeolocationBtnActionPerformed(evt);
425 }
426 });
427 mainContentPanel.add(recentViewInGeolocationBtn);
428
429 filler8.setAlignmentX(0.0F);
430 mainContentPanel.add(filler8);
431
432 org.openide.awt.Mnemonics.setLocalizedText(mostCommonLabel, org.openide.util.NbBundle.getMessage(GeolocationPanel.class, "GeolocationPanel.mostCommonLabel.text")); // NOI18N
433 mainContentPanel.add(mostCommonLabel);
434
435 filler7.setAlignmentX(0.0F);
436 mainContentPanel.add(filler7);
437
438 mostCommonPanel.setAlignmentX(0.0F);
439 mostCommonPanel.setMaximumSize(new java.awt.Dimension(32767, 106));
440 mostCommonPanel.setMinimumSize(new java.awt.Dimension(100, 106));
441 mostCommonPanel.setPreferredSize(new java.awt.Dimension(100, 106));
442 mainContentPanel.add(mostCommonPanel);
443
444 filler6.setAlignmentX(0.0F);
445 mainContentPanel.add(filler6);
446
447 org.openide.awt.Mnemonics.setLocalizedText(withinDistanceLabel1, org.openide.util.NbBundle.getMessage(GeolocationPanel.class, "GeolocationPanel.withinDistanceLabel1.text")); // NOI18N
448 mainContentPanel.add(withinDistanceLabel1);
449
450 filler4.setAlignmentX(0.0F);
451 mainContentPanel.add(filler4);
452
453 org.openide.awt.Mnemonics.setLocalizedText(commonViewInGeolocationBtn, org.openide.util.NbBundle.getMessage(GeolocationPanel.class, "GeolocationPanel.commonViewInGeolocationBtn.text")); // NOI18N
454 commonViewInGeolocationBtn.setEnabled(false);
455 commonViewInGeolocationBtn.addActionListener(new java.awt.event.ActionListener() {
456 public void actionPerformed(java.awt.event.ActionEvent evt) {
457 commonViewInGeolocationBtnActionPerformed(evt);
458 }
459 });
460 mainContentPanel.add(commonViewInGeolocationBtn);
461
462 filler5.setAlignmentX(0.0F);
463 mainContentPanel.add(filler5);
464
465 mainScrollPane.setViewportView(mainContentPanel);
466
467 javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
468 this.setLayout(layout);
469 layout.setHorizontalGroup(
470 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
471 .addComponent(mainScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
472 );
473 layout.setVerticalGroup(
474 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
475 .addComponent(mainScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 746, Short.MAX_VALUE)
476 );
477 }// </editor-fold>//GEN-END:initComponents
478
479 private void recentViewInGeolocationBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_recentViewInGeolocationBtnActionPerformed
480 openGeolocationWindow(getDataSource(), DAYS_COUNT);
481 }//GEN-LAST:event_recentViewInGeolocationBtnActionPerformed
482
483 private void commonViewInGeolocationBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_commonViewInGeolocationBtnActionPerformed
484 openGeolocationWindow(getDataSource(), null);
485 }//GEN-LAST:event_commonViewInGeolocationBtnActionPerformed
486
487
488 // Variables declaration - do not modify//GEN-BEGIN:variables
489 private javax.swing.JButton commonViewInGeolocationBtn;
490 private javax.swing.JButton recentViewInGeolocationBtn;
491 // End of variables declaration//GEN-END:variables
492}
synchronized static Logger getLogger(String name)
Definition Logger.java:124
final DataFetcher< DataSource, GeolocationViewModel > geolocationFetcher
Pair< String, Integer > formatRecord(CityRecordCount cityCount)
void openGeolocationWindow(DataSource dataSource, Integer daysLimit)
void recentViewInGeolocationBtnActionPerformed(java.awt.event.ActionEvent evt)
List< Pair< String, Integer > > formatList(CityCountsList countsList)
static final List< ColumnModel< Pair< String, Integer >, DefaultCellModel<?> > > DEFAULT_TEMPLATE
final List< DataFetchComponents< DataSource, ?> > dataFetchComponents
static final ColumnModel< Pair< String, Integer >, DefaultCellModel<?> > CITY_COL
void handleData(DataFetchResult< GeolocationViewModel > result)
void showCityContent(DataFetchResult< List< Pair< String, Integer > > > result, JTablePanel< Pair< String, Integer > > table, JButton goToGeolocation)
void commonViewInGeolocationBtnActionPerformed(java.awt.event.ActionEvent evt)
final JTablePanel< Pair< String, Integer > > mostCommonTable
GeolocationViewModel convertToViewModel(CityData cityData)
final JTablePanel< Pair< String, Integer > > mostRecentTable
static final ColumnModel< Pair< String, Integer >, DefaultCellModel<?> > COUNT_COL
static< I, O > DataFetchResult< O > getSubResult(DataFetchResult< I > inputResult, Function< I, O > getSubResult)
static< T, C extends GuiCellModel > JTablePanel< T > getJTablePanel(List< ColumnModel< T, C > > columns)

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.