mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-15 09:17:42 +00:00
Cleaned up geolocation threading
This commit is contained in:
parent
767397bcb4
commit
a1d95a9fc9
251
Core/src/org/sleuthkit/autopsy/geolocation/AbstractWaypointFetcher.java
Executable file
251
Core/src/org/sleuthkit/autopsy/geolocation/AbstractWaypointFetcher.java
Executable file
@ -0,0 +1,251 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2019-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.geolocation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationDataException;
|
||||
import org.sleuthkit.autopsy.geolocation.datamodel.Track;
|
||||
import org.sleuthkit.autopsy.geolocation.datamodel.Waypoint;
|
||||
import org.sleuthkit.autopsy.geolocation.datamodel.WaypointBuilder;
|
||||
|
||||
/**
|
||||
* The business logic for filtering waypoints.
|
||||
*/
|
||||
abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilterQueryCallBack {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AbstractWaypointFetcher.class.getName());
|
||||
|
||||
private final GeoFilterPanel.GeoFilter filters;
|
||||
|
||||
/**
|
||||
* Constructs the Waypoint Runner
|
||||
*
|
||||
* @param filters
|
||||
*/
|
||||
AbstractWaypointFetcher(GeoFilterPanel.GeoFilter filters) {
|
||||
this.filters = filters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the waypoints based in the current GeoFilter.
|
||||
*
|
||||
* This function kicks off a process that will send with
|
||||
* handleFilteredWaypointSet being called. Subclasses must implement
|
||||
* handleFitleredWayoiintSet to get the final results.
|
||||
*
|
||||
* @throws GeoLocationDataException
|
||||
*/
|
||||
void getWaypoints() throws GeoLocationDataException {
|
||||
Case currentCase = Case.getCurrentCase();
|
||||
WaypointBuilder.getAllWaypoints(currentCase.getSleuthkitCase(),
|
||||
filters.getDataSources(),
|
||||
filters.showAllWaypoints(),
|
||||
filters.getMostRecentNumDays(),
|
||||
filters.showWaypointsWithoutTimeStamp(),
|
||||
this);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after all of the MapWaypoints are created from all of the
|
||||
* TSK_GPS_XXX objects.
|
||||
*
|
||||
* @param mapWaypoints List of filtered MapWaypoints.
|
||||
*/
|
||||
abstract void handleFilteredWaypointSet(Set<MapWaypoint> mapWaypoints);
|
||||
|
||||
@Override
|
||||
public void process(List<Waypoint> waypoints) {
|
||||
|
||||
List<Track> tracks = null;
|
||||
try {
|
||||
tracks = Track.getTracks(Case.getCurrentCase().getSleuthkitCase(), filters.getDataSources());
|
||||
} catch (GeoLocationDataException ex) {
|
||||
logger.log(Level.WARNING, "Exception thrown while retrieving list of Tracks", ex);
|
||||
}
|
||||
|
||||
List<Waypoint> completeList = createWaypointList(waypoints, tracks);
|
||||
final Set<MapWaypoint> pointSet = MapWaypoint.getWaypoints(completeList);
|
||||
|
||||
handleFilteredWaypointSet(pointSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a complete list of waypoints including the tracks. Takes into
|
||||
* account the current filters and includes waypoints as approprate.
|
||||
*
|
||||
* @param waypoints List of waypoints
|
||||
* @param tracks List of tracks
|
||||
*
|
||||
* @return A list of waypoints including the tracks based on the current
|
||||
* filters.
|
||||
*/
|
||||
private List<Waypoint> createWaypointList(List<Waypoint> waypoints, List<Track> tracks) {
|
||||
final List<Waypoint> completeList = new ArrayList<>();
|
||||
|
||||
if (tracks != null) {
|
||||
Long timeRangeEnd;
|
||||
Long timeRangeStart;
|
||||
if (!filters.showAllWaypoints()) {
|
||||
// Figure out what the most recent time is given the filtered
|
||||
// waypoints and the tracks.
|
||||
timeRangeEnd = getMostRecent(waypoints, tracks);
|
||||
timeRangeStart = timeRangeEnd - (86400 * filters.getMostRecentNumDays());
|
||||
|
||||
completeList.addAll(getWaypointsInRange(timeRangeStart, timeRangeEnd, waypoints));
|
||||
completeList.addAll(getTracksInRange(timeRangeStart, timeRangeEnd, tracks));
|
||||
|
||||
} else {
|
||||
completeList.addAll(waypoints);
|
||||
for (Track track : tracks) {
|
||||
completeList.addAll(track.getPath());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
completeList.addAll(waypoints);
|
||||
}
|
||||
|
||||
return completeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of waypoints that fall into the given time range.
|
||||
*
|
||||
* @param timeRangeStart start timestamp of range (seconds from java epoch)
|
||||
* @param timeRangeEnd start timestamp of range (seconds from java epoch)
|
||||
* @param waypoints List of waypoints to filter.
|
||||
*
|
||||
* @return A list of waypoints that fall into the time range.
|
||||
*/
|
||||
private List<Waypoint> getWaypointsInRange(Long timeRangeStart, Long timeRangeEnd, List<Waypoint> waypoints) {
|
||||
List<Waypoint> completeList = new ArrayList<>();
|
||||
// Add all of the waypoints that fix into the time range.
|
||||
if (waypoints != null) {
|
||||
for (Waypoint point : waypoints) {
|
||||
Long time = point.getTimestamp();
|
||||
if ((time == null && filters.showWaypointsWithoutTimeStamp())
|
||||
|| (time != null && (time >= timeRangeStart && time <= timeRangeEnd))) {
|
||||
|
||||
completeList.add(point);
|
||||
}
|
||||
}
|
||||
}
|
||||
return completeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of waypoints from the given tracks that fall into for
|
||||
* tracks that fall into the given time range. The track start time will
|
||||
* used for determining if the whole track falls into the range.
|
||||
*
|
||||
* @param timeRangeStart start timestamp of range (seconds from java epoch)
|
||||
* @param timeRangeEnd start timestamp of range (seconds from java epoch)
|
||||
* @param tracks Track list.
|
||||
*
|
||||
* @return A list of waypoints that that belong to tracks that fall into the
|
||||
* time range.
|
||||
*/
|
||||
private List<Waypoint> getTracksInRange(Long timeRangeStart, Long timeRangeEnd, List<Track> tracks) {
|
||||
List<Waypoint> completeList = new ArrayList<>();
|
||||
if (tracks != null) {
|
||||
for (Track track : tracks) {
|
||||
Long trackTime = track.getStartTime();
|
||||
|
||||
if ((trackTime == null && filters.showWaypointsWithoutTimeStamp())
|
||||
|| (trackTime != null && (trackTime >= timeRangeStart && trackTime <= timeRangeEnd))) {
|
||||
|
||||
completeList.addAll(track.getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
return completeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the latest time stamp in the given list of waypoints.
|
||||
*
|
||||
* @param points List of Waypoints, required.
|
||||
*
|
||||
* @return The latest time stamp (seconds from java epoch)
|
||||
*/
|
||||
private Long findMostRecentTimestamp(List<Waypoint> points) {
|
||||
|
||||
Long mostRecent = null;
|
||||
|
||||
for (Waypoint point : points) {
|
||||
if (mostRecent == null) {
|
||||
mostRecent = point.getTimestamp();
|
||||
} else {
|
||||
mostRecent = Math.max(mostRecent, point.getTimestamp());
|
||||
}
|
||||
}
|
||||
|
||||
return mostRecent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the latest time stamp in the given list of tracks.
|
||||
*
|
||||
* @param tracks List of Waypoints, required.
|
||||
*
|
||||
* @return The latest time stamp (seconds from java epoch)
|
||||
*/
|
||||
private Long findMostRecentTracks(List<Track> tracks) {
|
||||
Long mostRecent = null;
|
||||
|
||||
for (Track track : tracks) {
|
||||
if (mostRecent == null) {
|
||||
mostRecent = track.getStartTime();
|
||||
} else {
|
||||
mostRecent = Math.max(mostRecent, track.getStartTime());
|
||||
}
|
||||
}
|
||||
|
||||
return mostRecent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the "most recent" timestamp amount the list of waypoints and
|
||||
* track points.
|
||||
*
|
||||
* @param points List of Waypoints
|
||||
* @param tracks List of Tracks
|
||||
*
|
||||
* @return Latest time stamp (seconds from java epoch)
|
||||
*/
|
||||
private Long getMostRecent(List<Waypoint> points, List<Track> tracks) {
|
||||
Long waypointMostRecent = findMostRecentTimestamp(points);
|
||||
Long trackMostRecent = findMostRecentTracks(tracks);
|
||||
|
||||
if (waypointMostRecent != null && trackMostRecent != null) {
|
||||
return Math.max(waypointMostRecent, trackMostRecent);
|
||||
} else if (waypointMostRecent == null && trackMostRecent != null) {
|
||||
return trackMostRecent;
|
||||
} else if (waypointMostRecent != null && trackMostRecent == null) {
|
||||
return waypointMostRecent;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -67,6 +67,10 @@ final class CheckBoxListPanel<T> extends javax.swing.JPanel {
|
||||
model.removeAllElements();
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
return model.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
checkboxList.setEnabled(enabled);
|
||||
|
@ -20,14 +20,19 @@ package org.sleuthkit.autopsy.geolocation;
|
||||
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import javafx.util.Pair;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.SpinnerNumberModel;
|
||||
import javax.swing.SwingWorker;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
@ -38,12 +43,24 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
*/
|
||||
class GeoFilterPanel extends javax.swing.JPanel {
|
||||
|
||||
final static String INITPROPERTY = "FilterPanelInitCompleted";
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger logger = Logger.getLogger(GeoFilterPanel.class.getName());
|
||||
|
||||
private final SpinnerNumberModel numberModel;
|
||||
private final CheckBoxListPanel<DataSource> checkboxPanel;
|
||||
|
||||
// Make sure to update if
|
||||
private static final BlackboardArtifact.ARTIFACT_TYPE[] GPS_ARTIFACT_TYPES = {
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK,
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_LAST_KNOWN_LOCATION,
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_ROUTE,
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_SEARCH,
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACK,
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates new GeoFilterPanel
|
||||
*/
|
||||
@ -89,11 +106,8 @@ class GeoFilterPanel extends javax.swing.JPanel {
|
||||
* Update the data source list with the current data sources
|
||||
*/
|
||||
void updateDataSourceList() {
|
||||
try {
|
||||
initCheckboxList();
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "Failed to initialize the CheckboxListPane", ex); //NON-NLS
|
||||
}
|
||||
DataSourceUpdater updater = new DataSourceUpdater();
|
||||
updater.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -103,6 +117,10 @@ class GeoFilterPanel extends javax.swing.JPanel {
|
||||
checkboxPanel.clearList();
|
||||
}
|
||||
|
||||
boolean hasDataSources() {
|
||||
return !checkboxPanel.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an actionListener to listen for the filter apply action
|
||||
*
|
||||
@ -134,20 +152,6 @@ class GeoFilterPanel extends javax.swing.JPanel {
|
||||
dataSources);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the checkbox list panel
|
||||
*
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
private void initCheckboxList() throws TskCoreException {
|
||||
final SleuthkitCase sleuthkitCase = Case.getCurrentCase().getSleuthkitCase();
|
||||
|
||||
for (DataSource dataSource : sleuthkitCase.getDataSources()) {
|
||||
String dsName = sleuthkitCase.getContentById(dataSource.getId()).getName();
|
||||
checkboxPanel.addElement(dsName, dataSource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on the state of mostRecent radio button Change the state of the cnt
|
||||
* spinner and the time stamp checkbox.
|
||||
@ -376,4 +380,72 @@ class GeoFilterPanel extends javax.swing.JPanel {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SwingWorker for updating the list of valid data sources.
|
||||
*
|
||||
* doInBackground creates a list of Pair objects that contain the
|
||||
* display name of the data source and the data source object.
|
||||
*/
|
||||
final private class DataSourceUpdater extends SwingWorker<List<Pair<String, DataSource>>, Void> {
|
||||
|
||||
@Override
|
||||
protected List<Pair<String, DataSource>> doInBackground() throws Exception {
|
||||
SleuthkitCase sleuthkitCase = Case.getCurrentCase().getSleuthkitCase();
|
||||
List<Pair<String, DataSource>> validSources = new ArrayList<>();
|
||||
for (DataSource dataSource : sleuthkitCase.getDataSources()) {
|
||||
if (isGPSDataSource(sleuthkitCase, dataSource)) {
|
||||
String dsName = sleuthkitCase.getContentById(dataSource.getId()).getName();
|
||||
Pair<String, DataSource> pair = new Pair<>(dsName, dataSource);
|
||||
validSources.add(pair);
|
||||
}
|
||||
}
|
||||
|
||||
return validSources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the given data source has GPS artifacts.
|
||||
*
|
||||
* @param sleuthkitCase The current sleuthkitCase
|
||||
* @param dataSource
|
||||
*
|
||||
* @return True if the data source as at least one TSK_GPS_XXXX
|
||||
*
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
private boolean isGPSDataSource(SleuthkitCase sleuthkitCase, DataSource dataSource) throws TskCoreException {
|
||||
for (BlackboardArtifact.ARTIFACT_TYPE type : GPS_ARTIFACT_TYPES) {
|
||||
if (sleuthkitCase.getBlackboardArtifactsTypeCount(type.getTypeID(), dataSource.getId()) > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void done() {
|
||||
List<Pair<String, DataSource>> sources = null;
|
||||
try {
|
||||
sources = get();
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
Throwable cause = ex.getCause();
|
||||
if (cause != null) {
|
||||
logger.log(Level.SEVERE, cause.getMessage(), cause);
|
||||
} else {
|
||||
logger.log(Level.SEVERE, ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (sources != null) {
|
||||
for (Pair<String, DataSource> source : sources) {
|
||||
checkboxPanel.addElement(source.getKey(), source.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
GeoFilterPanel.this.firePropertyChange(INITPROPERTY, false, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,7 +28,6 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.EnumSet;
|
||||
import java.util.LinkedHashSet;
|
||||
@ -51,10 +50,6 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
||||
import org.sleuthkit.autopsy.geolocation.GeoFilterPanel.GeoFilter;
|
||||
import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationDataException;
|
||||
import org.sleuthkit.autopsy.geolocation.datamodel.Track;
|
||||
import org.sleuthkit.autopsy.geolocation.datamodel.Waypoint;
|
||||
import org.sleuthkit.autopsy.geolocation.datamodel.WaypointBuilder;
|
||||
import org.sleuthkit.autopsy.geolocation.datamodel.WaypointBuilder.WaypointFilterQueryCallBack;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import static org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent.DATA_ADDED;
|
||||
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
||||
@ -93,7 +88,9 @@ public final class GeolocationTopComponent extends TopComponent {
|
||||
|
||||
@Messages({
|
||||
"GLTopComponent_name=Geolocation",
|
||||
"GLTopComponent_initilzation_error=An error occurred during waypoint initilization. Geolocation data maybe incomplete."
|
||||
"GLTopComponent_initilzation_error=An error occurred during waypoint initilization. Geolocation data maybe incomplete.",
|
||||
"GLTopComponent_No_dataSource_message=There are no data sources with Geolocation artifacts found.",
|
||||
"GLTopComponent_No_dataSource_Title=No Geolocation artifacts found"
|
||||
})
|
||||
|
||||
/**
|
||||
@ -143,7 +140,6 @@ public final class GeolocationTopComponent extends TopComponent {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
geoFilterPanel.updateDataSourceList();
|
||||
mapPanel.clearWaypoints();
|
||||
updateWaypoints();
|
||||
showRefreshPanel(false);
|
||||
}
|
||||
});
|
||||
@ -157,6 +153,24 @@ public final class GeolocationTopComponent extends TopComponent {
|
||||
}
|
||||
});
|
||||
|
||||
geoFilterPanel.addPropertyChangeListener(GeoFilterPanel.INITPROPERTY, new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
if (geoFilterPanel.hasDataSources()) {
|
||||
updateWaypoints();
|
||||
} else {
|
||||
geoFilterPanel.setEnabled(false);
|
||||
setWaypointLoading(false);
|
||||
JOptionPane.showMessageDialog(GeolocationTopComponent.this,
|
||||
Bundle.GLTopComponent_No_dataSource_message(),
|
||||
Bundle.GLTopComponent_No_dataSource_Title(),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
mapPanel.addPropertyChangeListener(MapPanel.CURRENT_MOUSE_GEOPOSITION, new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
@ -200,9 +214,6 @@ public final class GeolocationTopComponent extends TopComponent {
|
||||
@Override
|
||||
public void open() {
|
||||
super.open();
|
||||
mapPanel.clearWaypoints();
|
||||
geoFilterPanel.clearDataSourceList();
|
||||
geoFilterPanel.updateDataSourceList();
|
||||
|
||||
// Let's make sure we only do this on the first open
|
||||
if (!mapInitalized) {
|
||||
@ -221,8 +232,12 @@ public final class GeolocationTopComponent extends TopComponent {
|
||||
return; // Doen't set the waypoints.
|
||||
}
|
||||
}
|
||||
|
||||
mapPanel.clearWaypoints();
|
||||
geoFilterPanel.clearDataSourceList();
|
||||
geoFilterPanel.updateDataSourceList();
|
||||
mapPanel.setWaypoints(new LinkedHashSet<>());
|
||||
updateWaypoints();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -236,8 +251,8 @@ public final class GeolocationTopComponent extends TopComponent {
|
||||
public void run() {
|
||||
boolean isShowing = false;
|
||||
Component[] comps = mapPanel.getComponents();
|
||||
for(Component comp: comps) {
|
||||
if(comp.equals(refreshPanel)) {
|
||||
for (Component comp : comps) {
|
||||
if (comp.equals(refreshPanel)) {
|
||||
isShowing = true;
|
||||
break;
|
||||
}
|
||||
@ -245,7 +260,7 @@ public final class GeolocationTopComponent extends TopComponent {
|
||||
if (show && !isShowing) {
|
||||
mapPanel.add(refreshPanel, BorderLayout.NORTH);
|
||||
mapPanel.revalidate();
|
||||
} else if(!show && isShowing){
|
||||
} else if (!show && isShowing) {
|
||||
mapPanel.remove(refreshPanel);
|
||||
mapPanel.revalidate();
|
||||
}
|
||||
@ -283,10 +298,61 @@ public final class GeolocationTopComponent extends TopComponent {
|
||||
setWaypointLoading(true);
|
||||
geoFilterPanel.setEnabled(false);
|
||||
|
||||
Thread thread = new Thread(new WaypointRunner(filters));
|
||||
Thread thread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
(new WaypointFetcher(filters)).getWaypoints();
|
||||
} catch (GeoLocationDataException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to filter waypoints.", ex);
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
JOptionPane.showMessageDialog(GeolocationTopComponent.this,
|
||||
Bundle.GeoTopComponent_filter_exception_Title(),
|
||||
Bundle.GeoTopComponent_filter_exception_msg(),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
|
||||
setWaypointLoading(false);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
thread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the filtered set of waypoints to the map and set the various window
|
||||
* components to their proper state.
|
||||
*
|
||||
* @param waypointList
|
||||
*/
|
||||
void addWaypointsToMap(Set<MapWaypoint> waypointList) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// If the list is empty, tell the user
|
||||
if (waypointList == null || waypointList.isEmpty()) {
|
||||
mapPanel.clearWaypoints();
|
||||
JOptionPane.showMessageDialog(GeolocationTopComponent.this,
|
||||
Bundle.GeoTopComponent_no_waypoints_returned_Title(),
|
||||
Bundle.GeoTopComponent_no_waypoints_returned_mgs(),
|
||||
JOptionPane.INFORMATION_MESSAGE);
|
||||
setWaypointLoading(false);
|
||||
geoFilterPanel.setEnabled(true);
|
||||
return;
|
||||
}
|
||||
mapPanel.clearWaypoints();
|
||||
mapPanel.setWaypoints(waypointList);
|
||||
setWaypointLoading(false);
|
||||
geoFilterPanel.setEnabled(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show or hide the waypoint loading progress bar.
|
||||
*
|
||||
@ -423,244 +489,18 @@ public final class GeolocationTopComponent extends TopComponent {
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
/**
|
||||
* A runnable class for getting waypoints based on the current filters.
|
||||
* Extends AbstractWaypointFetcher to handle the returning of
|
||||
* the filters set of MapWaypoints.
|
||||
*/
|
||||
private class WaypointRunner implements Runnable, WaypointFilterQueryCallBack {
|
||||
final private class WaypointFetcher extends AbstractWaypointFetcher {
|
||||
|
||||
private final GeoFilter filters;
|
||||
|
||||
/**
|
||||
* Constructs the Waypoint Runner
|
||||
*
|
||||
* @param filters
|
||||
*/
|
||||
WaypointRunner(GeoFilter filters) {
|
||||
this.filters = filters;
|
||||
WaypointFetcher(GeoFilter filters) {
|
||||
super(filters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Case currentCase = Case.getCurrentCase();
|
||||
try {
|
||||
WaypointBuilder.getAllWaypoints(currentCase.getSleuthkitCase(),
|
||||
filters.getDataSources(),
|
||||
filters.showAllWaypoints(),
|
||||
filters.getMostRecentNumDays(),
|
||||
filters.showWaypointsWithoutTimeStamp(),
|
||||
this);
|
||||
|
||||
} catch (GeoLocationDataException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to filter waypoints.", ex);
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
JOptionPane.showMessageDialog(GeolocationTopComponent.this,
|
||||
Bundle.GeoTopComponent_filter_exception_Title(),
|
||||
Bundle.GeoTopComponent_filter_exception_msg(),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
|
||||
setWaypointLoading(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(List<Waypoint> waypoints) {
|
||||
|
||||
List<Track> tracks = null;
|
||||
try {
|
||||
tracks = Track.getTracks(Case.getCurrentCase().getSleuthkitCase(), filters.getDataSources());
|
||||
} catch (GeoLocationDataException ex) {
|
||||
logger.log(Level.WARNING, "Exception thrown while retrieving list of Tracks", ex);
|
||||
}
|
||||
|
||||
List<Waypoint> completeList = createWaypointList(waypoints, tracks);
|
||||
final Set<MapWaypoint> pointSet = MapWaypoint.getWaypoints(completeList);
|
||||
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// If the list is empty, tell the user and do not change
|
||||
// the visible waypoints.
|
||||
if (completeList == null || completeList.isEmpty()) {
|
||||
mapPanel.clearWaypoints();
|
||||
JOptionPane.showMessageDialog(GeolocationTopComponent.this,
|
||||
Bundle.GeoTopComponent_no_waypoints_returned_Title(),
|
||||
Bundle.GeoTopComponent_no_waypoints_returned_mgs(),
|
||||
JOptionPane.INFORMATION_MESSAGE);
|
||||
setWaypointLoading(false);
|
||||
geoFilterPanel.setEnabled(true);
|
||||
return;
|
||||
}
|
||||
mapPanel.clearWaypoints();
|
||||
mapPanel.setWaypoints(pointSet);
|
||||
setWaypointLoading(false);
|
||||
geoFilterPanel.setEnabled(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a complete list of waypoints including the tracks. Takes into
|
||||
* account the current filters and includes waypoints as approprate.
|
||||
*
|
||||
* @param waypoints List of waypoints
|
||||
* @param tracks List of tracks
|
||||
*
|
||||
* @return A list of waypoints including the tracks based on the current
|
||||
* filters.
|
||||
*/
|
||||
private List<Waypoint> createWaypointList(List<Waypoint> waypoints, List<Track> tracks) {
|
||||
final List<Waypoint> completeList = new ArrayList<>();
|
||||
|
||||
if (tracks != null) {
|
||||
Long timeRangeEnd;
|
||||
Long timeRangeStart;
|
||||
if (!filters.showAllWaypoints()) {
|
||||
// Figure out what the most recent time is given the filtered
|
||||
// waypoints and the tracks.
|
||||
timeRangeEnd = getMostRecent(waypoints, tracks);
|
||||
timeRangeStart = timeRangeEnd - (86400 * filters.getMostRecentNumDays());
|
||||
|
||||
completeList.addAll(getWaypointsInRange(timeRangeStart, timeRangeEnd, waypoints));
|
||||
completeList.addAll(getTracksInRange(timeRangeStart, timeRangeEnd, tracks));
|
||||
|
||||
} else {
|
||||
completeList.addAll(waypoints);
|
||||
for (Track track : tracks) {
|
||||
completeList.addAll(track.getPath());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
completeList.addAll(waypoints);
|
||||
}
|
||||
|
||||
return completeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of waypoints that fall into the given time range.
|
||||
*
|
||||
* @param timeRangeStart start timestamp of range (seconds from java
|
||||
* epoch)
|
||||
* @param timeRangeEnd start timestamp of range (seconds from java
|
||||
* epoch)
|
||||
* @param waypoints List of waypoints to filter.
|
||||
*
|
||||
* @return A list of waypoints that fall into the time range.
|
||||
*/
|
||||
private List<Waypoint> getWaypointsInRange(Long timeRangeStart, Long timeRangeEnd, List<Waypoint> waypoints) {
|
||||
List<Waypoint> completeList = new ArrayList<>();
|
||||
// Add all of the waypoints that fix into the time range.
|
||||
if (waypoints != null) {
|
||||
for (Waypoint point : waypoints) {
|
||||
Long time = point.getTimestamp();
|
||||
if ((time == null && filters.showWaypointsWithoutTimeStamp())
|
||||
|| (time != null && (time >= timeRangeStart && time <= timeRangeEnd))) {
|
||||
|
||||
completeList.add(point);
|
||||
}
|
||||
}
|
||||
}
|
||||
return completeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of waypoints from the given tracks that fall into for
|
||||
* tracks that fall into the given time range. The track start time will
|
||||
* used for determining if the whole track falls into the range.
|
||||
*
|
||||
* @param timeRangeStart start timestamp of range (seconds from java
|
||||
* epoch)
|
||||
* @param timeRangeEnd start timestamp of range (seconds from java
|
||||
* epoch)
|
||||
* @param tracks Track list.
|
||||
*
|
||||
* @return A list of waypoints that that belong to tracks that fall into
|
||||
* the time range.
|
||||
*/
|
||||
private List<Waypoint> getTracksInRange(Long timeRangeStart, Long timeRangeEnd, List<Track> tracks) {
|
||||
List<Waypoint> completeList = new ArrayList<>();
|
||||
if (tracks != null) {
|
||||
for (Track track : tracks) {
|
||||
Long trackTime = track.getStartTime();
|
||||
|
||||
if ((trackTime == null && filters.showWaypointsWithoutTimeStamp())
|
||||
|| (trackTime != null && (trackTime >= timeRangeStart && trackTime <= timeRangeEnd))) {
|
||||
|
||||
completeList.addAll(track.getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
return completeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the latest time stamp in the given list of waypoints.
|
||||
*
|
||||
* @param points List of Waypoints, required.
|
||||
*
|
||||
* @return The latest time stamp (seconds from java epoch)
|
||||
*/
|
||||
private Long findMostRecentTimestamp(List<Waypoint> points) {
|
||||
|
||||
Long mostRecent = null;
|
||||
|
||||
for (Waypoint point : points) {
|
||||
if (mostRecent == null) {
|
||||
mostRecent = point.getTimestamp();
|
||||
} else {
|
||||
mostRecent = Math.max(mostRecent, point.getTimestamp());
|
||||
}
|
||||
}
|
||||
|
||||
return mostRecent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the latest time stamp in the given list of tracks.
|
||||
*
|
||||
* @param tracks List of Waypoints, required.
|
||||
*
|
||||
* @return The latest time stamp (seconds from java epoch)
|
||||
*/
|
||||
private Long findMostRecentTracks(List<Track> tracks) {
|
||||
Long mostRecent = null;
|
||||
|
||||
for (Track track : tracks) {
|
||||
if (mostRecent == null) {
|
||||
mostRecent = track.getStartTime();
|
||||
} else {
|
||||
mostRecent = Math.max(mostRecent, track.getStartTime());
|
||||
}
|
||||
}
|
||||
|
||||
return mostRecent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the "most recent" timestamp amount the list of waypoints and
|
||||
* track points.
|
||||
*
|
||||
* @param points List of Waypoints
|
||||
* @param tracks List of Tracks
|
||||
*
|
||||
* @return Latest time stamp (seconds from java epoch)
|
||||
*/
|
||||
private Long getMostRecent(List<Waypoint> points, List<Track> tracks) {
|
||||
Long waypointMostRecent = findMostRecentTimestamp(points);
|
||||
Long trackMostRecent = findMostRecentTracks(tracks);
|
||||
|
||||
if (waypointMostRecent != null && trackMostRecent != null) {
|
||||
return Math.max(waypointMostRecent, trackMostRecent);
|
||||
} else if (waypointMostRecent == null && trackMostRecent != null) {
|
||||
return trackMostRecent;
|
||||
} else if (waypointMostRecent != null && trackMostRecent == null) {
|
||||
return waypointMostRecent;
|
||||
}
|
||||
|
||||
return null;
|
||||
void handleFilteredWaypointSet(Set<MapWaypoint> mapWaypoints) {
|
||||
addWaypointsToMap(mapWaypoints);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,6 @@ import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
@ -58,7 +57,6 @@ import org.jxmapviewer.viewer.DefaultTileFactory;
|
||||
import org.jxmapviewer.viewer.GeoPosition;
|
||||
import org.jxmapviewer.viewer.TileFactory;
|
||||
import org.jxmapviewer.viewer.TileFactoryInfo;
|
||||
import org.jxmapviewer.viewer.Waypoint;
|
||||
import org.jxmapviewer.viewer.WaypointPainter;
|
||||
import org.jxmapviewer.viewer.WaypointRenderer;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
@ -69,7 +67,6 @@ import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationDataException;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.jxmapviewer.viewer.DefaultWaypointRenderer;
|
||||
|
||||
/**
|
||||
* The map panel. This panel contains the jxmapviewer MapViewer
|
||||
|
Loading…
x
Reference in New Issue
Block a user