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();
|
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);
|
||||||
|
@ -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
|
||||||
*/
|
*/
|
||||||
@ -73,7 +90,7 @@ class GeoFilterPanel extends javax.swing.JPanel {
|
|||||||
gridBagConstraints.insets = new java.awt.Insets(0, 15, 0, 15);
|
gridBagConstraints.insets = new java.awt.Insets(0, 15, 0, 15);
|
||||||
add(checkboxPanel, gridBagConstraints);
|
add(checkboxPanel, gridBagConstraints);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setEnabled(boolean enabled) {
|
public void setEnabled(boolean enabled) {
|
||||||
applyButton.setEnabled(enabled);
|
applyButton.setEnabled(enabled);
|
||||||
@ -84,18 +101,15 @@ class GeoFilterPanel extends javax.swing.JPanel {
|
|||||||
daysLabel.setEnabled(enabled);
|
daysLabel.setEnabled(enabled);
|
||||||
daysSpinner.setEnabled(enabled);
|
daysSpinner.setEnabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the data source list.
|
* Clears the data source list.
|
||||||
*/
|
*/
|
||||||
@ -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
|
||||||
*
|
*
|
||||||
@ -128,26 +146,12 @@ class GeoFilterPanel extends javax.swing.JPanel {
|
|||||||
if (dataSources.isEmpty()) {
|
if (dataSources.isEmpty()) {
|
||||||
throw new GeoLocationUIException(Bundle.GeoFilterPanel_empty_dataSource());
|
throw new GeoLocationUIException(Bundle.GeoFilterPanel_empty_dataSource());
|
||||||
}
|
}
|
||||||
return new GeoFilter(allButton.isSelected(),
|
return new GeoFilter(allButton.isSelected(),
|
||||||
showWaypointsWOTSCheckBox.isSelected(),
|
showWaypointsWOTSCheckBox.isSelected(),
|
||||||
numberModel.getNumber().intValue(),
|
numberModel.getNumber().intValue(),
|
||||||
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -236,8 +251,8 @@ public final class GeolocationTopComponent extends TopComponent {
|
|||||||
public void run() {
|
public void run() {
|
||||||
boolean isShowing = false;
|
boolean isShowing = false;
|
||||||
Component[] comps = mapPanel.getComponents();
|
Component[] comps = mapPanel.getComponents();
|
||||||
for(Component comp: comps) {
|
for (Component comp : comps) {
|
||||||
if(comp.equals(refreshPanel)) {
|
if (comp.equals(refreshPanel)) {
|
||||||
isShowing = true;
|
isShowing = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -245,10 +260,10 @@ public final class GeolocationTopComponent extends TopComponent {
|
|||||||
if (show && !isShowing) {
|
if (show && !isShowing) {
|
||||||
mapPanel.add(refreshPanel, BorderLayout.NORTH);
|
mapPanel.add(refreshPanel, BorderLayout.NORTH);
|
||||||
mapPanel.revalidate();
|
mapPanel.revalidate();
|
||||||
} else if(!show && isShowing){
|
} else if (!show && isShowing) {
|
||||||
mapPanel.remove(refreshPanel);
|
mapPanel.remove(refreshPanel);
|
||||||
mapPanel.revalidate();
|
mapPanel.revalidate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user