Cleaned up geolocation threading

This commit is contained in:
Kelly Kelly 2020-01-27 17:20:59 -05:00
parent 767397bcb4
commit a1d95a9fc9
5 changed files with 441 additions and 277 deletions

View 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;
}
}

View File

@ -67,6 +67,10 @@ final class CheckBoxListPanel<T> extends javax.swing.JPanel {
model.removeAllElements(); model.removeAllElements();
} }
boolean isEmpty() {
return model.isEmpty();
}
@Override @Override
public void setEnabled(boolean enabled) { public void setEnabled(boolean enabled) {
checkboxList.setEnabled(enabled); checkboxList.setEnabled(enabled);

View File

@ -20,14 +20,19 @@ package org.sleuthkit.autopsy.geolocation;
import java.awt.GridBagConstraints; import java.awt.GridBagConstraints;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level; import java.util.logging.Level;
import javafx.util.Pair;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
import javax.swing.SpinnerNumberModel; import javax.swing.SpinnerNumberModel;
import javax.swing.SwingWorker;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
@ -38,12 +43,24 @@ import org.sleuthkit.datamodel.TskCoreException;
*/ */
class GeoFilterPanel extends javax.swing.JPanel { class GeoFilterPanel extends javax.swing.JPanel {
final static String INITPROPERTY = "FilterPanelInitCompleted";
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(GeoFilterPanel.class.getName()); private static final Logger logger = Logger.getLogger(GeoFilterPanel.class.getName());
private final SpinnerNumberModel numberModel; private final SpinnerNumberModel numberModel;
private final CheckBoxListPanel<DataSource> checkboxPanel; 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 * Creates new GeoFilterPanel
*/ */
@ -89,11 +106,8 @@ class GeoFilterPanel extends javax.swing.JPanel {
* Update the data source list with the current data sources * Update the data source list with the current data sources
*/ */
void updateDataSourceList() { void updateDataSourceList() {
try { DataSourceUpdater updater = new DataSourceUpdater();
initCheckboxList(); updater.execute();
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Failed to initialize the CheckboxListPane", ex); //NON-NLS
}
} }
/** /**
@ -103,6 +117,10 @@ class GeoFilterPanel extends javax.swing.JPanel {
checkboxPanel.clearList(); checkboxPanel.clearList();
} }
boolean hasDataSources() {
return !checkboxPanel.isEmpty();
}
/** /**
* Adds an actionListener to listen for the filter apply action * Adds an actionListener to listen for the filter apply action
* *
@ -134,20 +152,6 @@ class GeoFilterPanel extends javax.swing.JPanel {
dataSources); 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 * Based on the state of mostRecent radio button Change the state of the cnt
* spinner and the time stamp checkbox. * 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);
}
}
} }

View File

@ -28,7 +28,6 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
@ -51,10 +50,6 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined;
import org.sleuthkit.autopsy.geolocation.GeoFilterPanel.GeoFilter; import org.sleuthkit.autopsy.geolocation.GeoFilterPanel.GeoFilter;
import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationDataException; 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 org.sleuthkit.autopsy.ingest.IngestManager;
import static org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent.DATA_ADDED; import static org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent.DATA_ADDED;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
@ -93,7 +88,9 @@ public final class GeolocationTopComponent extends TopComponent {
@Messages({ @Messages({
"GLTopComponent_name=Geolocation", "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) { public void actionPerformed(ActionEvent e) {
geoFilterPanel.updateDataSourceList(); geoFilterPanel.updateDataSourceList();
mapPanel.clearWaypoints(); mapPanel.clearWaypoints();
updateWaypoints();
showRefreshPanel(false); 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() { mapPanel.addPropertyChangeListener(MapPanel.CURRENT_MOUSE_GEOPOSITION, new PropertyChangeListener() {
@Override @Override
public void propertyChange(PropertyChangeEvent evt) { public void propertyChange(PropertyChangeEvent evt) {
@ -200,9 +214,6 @@ public final class GeolocationTopComponent extends TopComponent {
@Override @Override
public void open() { public void open() {
super.open(); super.open();
mapPanel.clearWaypoints();
geoFilterPanel.clearDataSourceList();
geoFilterPanel.updateDataSourceList();
// Let's make sure we only do this on the first open // Let's make sure we only do this on the first open
if (!mapInitalized) { if (!mapInitalized) {
@ -221,8 +232,12 @@ public final class GeolocationTopComponent extends TopComponent {
return; // Doen't set the waypoints. return; // Doen't set the waypoints.
} }
} }
mapPanel.clearWaypoints();
geoFilterPanel.clearDataSourceList();
geoFilterPanel.updateDataSourceList();
mapPanel.setWaypoints(new LinkedHashSet<>()); mapPanel.setWaypoints(new LinkedHashSet<>());
updateWaypoints();
} }
/** /**
@ -283,10 +298,61 @@ public final class GeolocationTopComponent extends TopComponent {
setWaypointLoading(true); setWaypointLoading(true);
geoFilterPanel.setEnabled(false); 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(); 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. * 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 // 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; WaypointFetcher(GeoFilter filters) {
super(filters);
/**
* Constructs the Waypoint Runner
*
* @param filters
*/
WaypointRunner(GeoFilter filters) {
this.filters = filters;
} }
@Override @Override
public void run() { void handleFilteredWaypointSet(Set<MapWaypoint> mapWaypoints) {
Case currentCase = Case.getCurrentCase(); addWaypointsToMap(mapWaypoints);
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;
} }
} }
} }

View File

@ -35,7 +35,6 @@ import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
@ -58,7 +57,6 @@ import org.jxmapviewer.viewer.DefaultTileFactory;
import org.jxmapviewer.viewer.GeoPosition; import org.jxmapviewer.viewer.GeoPosition;
import org.jxmapviewer.viewer.TileFactory; import org.jxmapviewer.viewer.TileFactory;
import org.jxmapviewer.viewer.TileFactoryInfo; import org.jxmapviewer.viewer.TileFactoryInfo;
import org.jxmapviewer.viewer.Waypoint;
import org.jxmapviewer.viewer.WaypointPainter; import org.jxmapviewer.viewer.WaypointPainter;
import org.jxmapviewer.viewer.WaypointRenderer; import org.jxmapviewer.viewer.WaypointRenderer;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
@ -69,7 +67,6 @@ import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationDataException;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import org.jxmapviewer.viewer.DefaultWaypointRenderer;
/** /**
* The map panel. This panel contains the jxmapviewer MapViewer * The map panel. This panel contains the jxmapviewer MapViewer