Merge branch 'develop' into 6412-standardInterestingFileSetRules

This commit is contained in:
Greg DiCristofaro 2020-06-03 08:50:25 -04:00
commit c35303f71a
14 changed files with 306 additions and 61 deletions

View File

@ -43,6 +43,8 @@ import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesKey;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
@ -94,6 +96,25 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|| eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
|| eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
/**
* If a new file has been added but does not have an extension
* there is nothing to do.
*/
if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) {
if ((evt.getOldValue() instanceof ModuleContentEvent) == false) {
return;
}
ModuleContentEvent moduleContentEvent = (ModuleContentEvent) evt.getOldValue();
if ((moduleContentEvent.getSource() instanceof AbstractFile) == false) {
return;
}
AbstractFile abstractFile = (AbstractFile) moduleContentEvent.getSource();
if (abstractFile.getNameExtension().isEmpty()) {
return;
}
}
/**
* Checking for a current case is a stop gap measure until a
* different way of handling the closing of cases is worked
@ -415,7 +436,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
@Override
public void update(Observable o, Object arg) {
refresh(true);
refresh(false);
}
@Override

View File

@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.datamodel;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.List;
import java.util.Observable;
@ -252,7 +253,12 @@ public class Tags implements AutopsyVisitableItem {
? Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse(filteringDSObjId)
: Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse();
}
Collections.sort(tagNamesInUse);
Collections.sort(tagNamesInUse, new Comparator<TagName>() {
@Override
public int compare(TagName o1, TagName o2) {
return TagUtils.getDecoratedTagDisplayName(o1).compareTo(TagUtils.getDecoratedTagDisplayName(o2));
}
});
keys.addAll(tagNamesInUse);
} catch (TskCoreException | NoCurrentCaseException ex) {
Logger.getLogger(TagNameNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS

View File

@ -26,6 +26,7 @@ import javafx.util.Pair;
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.GeoLocationParseResult;
import org.sleuthkit.autopsy.geolocation.datamodel.Track;
import org.sleuthkit.autopsy.geolocation.datamodel.Waypoint;
import org.sleuthkit.autopsy.geolocation.datamodel.WaypointBuilder;
@ -70,25 +71,33 @@ abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilter
}
/**
* Called after all of the MapWaypoints are created from all of the
* TSK_GPS_XXX objects.
*
* @param mapWaypoints List of filtered MapWaypoints.
* @param tracks The tracks that were successfully parsed.
* @param wasEntirelySuccessful True if no errors occurred while processing.
*/
abstract void handleFilteredWaypointSet(Set<MapWaypoint> mapWaypoints, List<Set<MapWaypoint>> tracks);
abstract void handleFilteredWaypointSet(Set<MapWaypoint> mapWaypoints, List<Set<MapWaypoint>> tracks,
boolean wasEntirelySuccessful);
@Override
public void process(List<Waypoint> waypoints) {
List<Track> tracks = new ArrayList<>();
public void process(GeoLocationParseResult<Waypoint> waypointResults) {
GeoLocationParseResult<Track> trackResults = null;
if (filters.getArtifactTypes().contains(ARTIFACT_TYPE.TSK_GPS_TRACK)) {
try {
tracks = Track.getTracks(Case.getCurrentCase().getSleuthkitCase(), filters.getDataSources());
trackResults = Track.getTracks(Case.getCurrentCase().getSleuthkitCase(), filters.getDataSources());
} catch (GeoLocationDataException ex) {
logger.log(Level.WARNING, "Exception thrown while retrieving list of Tracks", ex);
}
}
Pair<List<Waypoint>, List<List<Waypoint>>> waypointsAndTracks = createWaypointList(waypoints, tracks);
Pair<List<Waypoint>, List<List<Waypoint>>> waypointsAndTracks = createWaypointList(
waypointResults.getItems(),
(trackResults == null) ? new ArrayList<Track>() : trackResults.getItems());
final Set<MapWaypoint> pointSet = MapWaypoint.getWaypoints(waypointsAndTracks.getKey());
final List<Set<MapWaypoint>> trackSets = new ArrayList<>();
@ -96,7 +105,9 @@ abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilter
trackSets.add(MapWaypoint.getWaypoints(t));
}
handleFilteredWaypointSet(pointSet, trackSets);
handleFilteredWaypointSet(
pointSet, trackSets,
(trackResults == null || trackResults.isSuccessfullyParsed()) && waypointResults.isSuccessfullyParsed());
}
/**

View File

@ -24,6 +24,8 @@ GeolocationTC_connection_failure_message_title=Connection Failure
GeolocationTC_empty_waypoint_message=Unable to generate KML report due to a lack of waypoints.\nPlease make sure there are waypoints visible before generating the KML report
GeolocationTC_KML_report_title=KML Report
GeolocationTC_report_progress_title=KML Report Progress
GeolocationTopComponent.WaypointFetcher.onErrorDescription=There was an error gathering some GPS Track Data. Some results have been excluded.
GeolocationTopComponent.WaypointFetcher.onErrorTitle=Error gathering GPS Track Data
GeoTopComponent_filer_data_invalid_msg=Unable to run waypoint filter.\nPlease select one or more data sources.
GeoTopComponent_filer_data_invalid_Title=Filter Failure
GeoTopComponent_filter_exception_msg=Exception occurred during waypoint filtering.

View File

@ -494,6 +494,10 @@ public final class GeolocationTopComponent extends TopComponent {
* Extends AbstractWaypointFetcher to handle the returning of
* the filters set of MapWaypoints.
*/
@Messages({
"GeolocationTopComponent.WaypointFetcher.onErrorTitle=Error gathering GPS Track Data",
"GeolocationTopComponent.WaypointFetcher.onErrorDescription=There was an error gathering some GPS Track Data. Some results have been excluded."
})
final private class WaypointFetcher extends AbstractWaypointFetcher {
WaypointFetcher(GeoFilter filters) {
@ -501,8 +505,16 @@ public final class GeolocationTopComponent extends TopComponent {
}
@Override
void handleFilteredWaypointSet(Set<MapWaypoint> mapWaypoints, List<Set<MapWaypoint>> tracks) {
void handleFilteredWaypointSet(Set<MapWaypoint> mapWaypoints, List<Set<MapWaypoint>> tracks, boolean wasEntirelySuccessful) {
addWaypointsToMap(mapWaypoints, tracks);
// if there is an error, present to the user.
if (!wasEntirelySuccessful) {
JOptionPane.showMessageDialog(GeolocationTopComponent.this,
Bundle.GeolocationTopComponent_WaypointFetcher_onErrorDescription(),
Bundle.GeolocationTopComponent_WaypointFetcher_onErrorTitle(),
JOptionPane.ERROR_MESSAGE);
}
}
}
}

View File

@ -0,0 +1,84 @@
/*
* Autopsy Forensic Browser
*
* Copyright 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.datamodel;
import java.util.ArrayList;
import java.util.List;
import org.python.google.common.collect.ImmutableList;
/**
* The result of attempting to parse GeoLocation objects.
*/
public class GeoLocationParseResult<T> {
private boolean successfullyParsed;
private final List<T> items = new ArrayList<>();
/**
* Returns a GeoLocationParseResult with no items and declared successfully
* parsed.
*/
public GeoLocationParseResult() {
successfullyParsed = true;
}
/**
* Returns a new GeoLocationParseResult.
*
* @param items The items to copy to this result (can be null).
* @param successfullyParsed Whether or not the operation was entirely
* successful.
*/
public GeoLocationParseResult(List<T> items, boolean successfullyParsed) {
this.successfullyParsed = successfullyParsed;
if (items != null) {
this.items.addAll(items);
}
}
/**
* Adds the content of the GeoLocationParseResult parameter to this. Items
* will be concatenated and this object's successfullyParsed status will be
* true if it is already true and the object is true as well.
*
* @param toAdd The GeoLocationParseResult to add.
*/
public void add(GeoLocationParseResult<T> toAdd) {
this.successfullyParsed = this.successfullyParsed && toAdd.isSuccessfullyParsed();
this.items.addAll(toAdd.getItems());
}
/**
* Whether or not the GeoLocation object has been successfully parsed.
*
* @return Whether or not the GeoLocation object has been successfully
* parsed.
*/
public boolean isSuccessfullyParsed() {
return successfullyParsed;
}
/**
* @return The successfully parsed GeoLocation objects.
*/
public List<T> getItems() {
return ImmutableList.copyOf(items);
}
}

View File

@ -31,7 +31,6 @@ import org.sleuthkit.datamodel.TskCoreException;
* Class representing a series of waypoints that form a path.
*/
public class GeoPath {
private final List<Waypoint> waypointList;
private final String pathName;
private final BlackboardArtifact artifact;
@ -74,21 +73,26 @@ public class GeoPath {
*
* @throws GeoLocationDataException
*/
static public List<Track> getTracks(SleuthkitCase skCase, List<? extends Content> sourceList) throws GeoLocationDataException {
public static GeoLocationParseResult<Track> getTracks(SleuthkitCase skCase, List<? extends Content> sourceList) throws GeoLocationDataException {
List<BlackboardArtifact> artifacts = null;
boolean allParsedSuccessfully = true;
List<Track> tracks = new ArrayList<>();
try {
artifacts = skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACK);
for (BlackboardArtifact artifact : artifacts) {
if (sourceList == null || sourceList.contains(artifact.getDataSource())) {
Track route = new Track(artifact);
tracks.add(route);
try {
tracks.add(new Track(artifact));
} catch (GeoLocationDataException e) {
allParsedSuccessfully = false;
}
}
}
} catch (TskCoreException ex) {
throw new GeoLocationDataException("Unable to get artifacts for type: TSK_GPS_BOOKMARK", ex);
}
return tracks;
return new GeoLocationParseResult<Track>(tracks, allParsedSuccessfully);
}
/**

View File

@ -22,17 +22,20 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.blackboardutils.attributes.BlackboardJsonAttrUtil;
import org.sleuthkit.datamodel.blackboardutils.attributes.BlackboardJsonAttrUtil.InvalidJsonException;
import org.sleuthkit.datamodel.blackboardutils.attributes.GeoTrackPoints;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* A GPS track with which wraps the TSK_GPS_TRACK artifact.
*/
public final class Track extends GeoPath {
private static final Logger LOGGER = Logger.getLogger(Track.class.getName());
private final Long startTimestamp;
private final Long endTimeStamp;
@ -130,15 +133,18 @@ public final class Track extends GeoPath {
*/
private GeoTrackPoints getPointsList(Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attributeMap) throws GeoLocationDataException {
BlackboardAttribute attribute = attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_TRACKPOINTS);
if (attribute != null) {
if (attribute == null) {
LOGGER.log(Level.SEVERE, "No TSK_GEO_TRACKPOINTS attribute was present on the artifact.");
throw new GeoLocationDataException("No TSK_GEO_TRACKPOINTS attribute present in attribute map to parse.");
}
try {
return BlackboardJsonAttrUtil.fromAttribute(attribute, GeoTrackPoints.class);
} catch (InvalidJsonException ex) {
LOGGER.log(Level.SEVERE, "TSK_GEO_TRACKPOINTS could not be properly parsed from TSK_GEO_TRACKPOINTS attribute.");
throw new GeoLocationDataException("Unable to parse track points in TSK_GEO_TRACKPOINTS attribute", ex);
}
}
return null;
}
/**
* A Waypoint subclass for the points of a track.

View File

@ -22,6 +22,7 @@ package org.sleuthkit.autopsy.geolocation.datamodel;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
@ -96,9 +97,10 @@ public final class WaypointBuilder {
/**
* This function will be called after the waypoints have been filtered.
*
* @param waypoints The list of waypoints.
* @param waypoints The list of waypoints and whether they were all
* successfully parsed.
*/
void process(List<Waypoint> waypoints);
void process(GeoLocationParseResult<Waypoint> waypoints);
}
/**
@ -478,7 +480,7 @@ public final class WaypointBuilder {
skCase.getCaseDbAccessManager().select(query, new CaseDbAccessManager.CaseDbAccessQueryCallback() {
@Override
public void process(ResultSet rs) {
List<Waypoint> waypoints = new ArrayList<>();
GeoLocationParseResult<Waypoint> waypointResults = new GeoLocationParseResult<>();
try {
while (rs.next()) {
int artifact_type_id = rs.getInt("artifact_type_id"); //NON-NLS
@ -486,12 +488,13 @@ public final class WaypointBuilder {
ARTIFACT_TYPE type = ARTIFACT_TYPE.fromID(artifact_type_id);
if (artifactTypes.contains(type)) {
waypoints.addAll(getWaypointForArtifact(skCase.getBlackboardArtifact(artifact_id), type));
waypointResults.add(getWaypointForArtifact(skCase.getBlackboardArtifact(artifact_id), type));
}
}
queryCallBack.process(waypoints);
} catch (GeoLocationDataException | SQLException | TskCoreException ex) {
queryCallBack.process(waypointResults);
} catch (SQLException | TskCoreException ex) {
logger.log(Level.WARNING, "Failed to filter waypoint.", ex); //NON-NLS
}
@ -522,7 +525,7 @@ public final class WaypointBuilder {
// FROM blackboard_attributes
// WHERE attribute_type_id IN (%d, %d)
return String.format(SELECT_WO_TIMESTAMP,
String.format(GEO_ARTIFACT_QUERY_ID_ONLY,TIME_TYPE_IDS),
String.format(GEO_ARTIFACT_QUERY_ID_ONLY, TIME_TYPE_IDS),
getWaypointListQuery(dataSources));
}
@ -619,6 +622,51 @@ public final class WaypointBuilder {
dataSourceList);
}
/**
* A parser that could throw a GeoLocationDataException when there is a
* parse issue.
*
* @param <T> The return type.
*/
private interface ParserWithError<T> {
T parse(BlackboardArtifact artifact) throws GeoLocationDataException;
}
/**
* Parses one waypoint.
*
* @param parser The parser to use.
* @param artifact The artifact to be parsed.
*
* @return Returns a parse result that is either successful with a parsed
* waypoint or unsuccessful with an exception.
*/
private static GeoLocationParseResult<Waypoint> parseWaypoint(ParserWithError<Waypoint> parser, BlackboardArtifact artifact) {
try {
return new GeoLocationParseResult<>(Arrays.asList(parser.parse(artifact)), true);
} catch (GeoLocationDataException ex) {
return new GeoLocationParseResult<>(null, false);
}
}
/**
* Parses a list of waypoints.
*
* @param parser The parser to use.
* @param artifact The artifact to be parsed.
*
* @return Returns a parse result that is either successful with a parsed
* waypoint or unsuccessful with an exception.
*/
private static GeoLocationParseResult<Waypoint> parseWaypoints(ParserWithError<List<Waypoint>> parser, BlackboardArtifact artifact) {
try {
return new GeoLocationParseResult<>(parser.parse(artifact), true);
} catch (GeoLocationDataException ignored) {
return new GeoLocationParseResult<>(null, false);
}
}
/**
* Create a Waypoint object for the given Blackboard artifact.
*
@ -626,37 +674,33 @@ public final class WaypointBuilder {
* @param type The type of artifact
*
* @return A new waypoint object
*
* @throws GeoLocationDataException
*/
static private List<Waypoint> getWaypointForArtifact(BlackboardArtifact artifact, ARTIFACT_TYPE type) throws GeoLocationDataException {
List<Waypoint> waypoints = new ArrayList<>();
private static GeoLocationParseResult<Waypoint> getWaypointForArtifact(BlackboardArtifact artifact, ARTIFACT_TYPE type) {
GeoLocationParseResult<Waypoint> waypoints = new GeoLocationParseResult<>();
switch (type) {
case TSK_METADATA_EXIF:
waypoints.add(new EXIFWaypoint(artifact));
waypoints.add(parseWaypoint(EXIFWaypoint::new, artifact));
break;
case TSK_GPS_BOOKMARK:
waypoints.add(new BookmarkWaypoint(artifact));
waypoints.add(parseWaypoint(BookmarkWaypoint::new, artifact));
break;
case TSK_GPS_TRACKPOINT:
waypoints.add(new TrackpointWaypoint(artifact));
waypoints.add(parseWaypoint(TrackpointWaypoint::new, artifact));
break;
case TSK_GPS_SEARCH:
waypoints.add(new SearchWaypoint(artifact));
waypoints.add(parseWaypoint(SearchWaypoint::new, artifact));
break;
case TSK_GPS_ROUTE:
Route route = new Route(artifact);
waypoints.addAll(route.getRoute());
waypoints.add(parseWaypoints((a) -> new Route(a).getRoute(), artifact));
break;
case TSK_GPS_LAST_KNOWN_LOCATION:
waypoints.add(new LastKnownWaypoint(artifact));
waypoints.add(parseWaypoint(LastKnownWaypoint::new, artifact));
break;
case TSK_GPS_TRACK:
Track track = new Track(artifact);
waypoints.addAll(track.getPath());
waypoints.add(parseWaypoints((a) -> new Track(a).getPath(), artifact));
break;
default:
waypoints.add(new CustomArtifactWaypoint(artifact));
waypoints.add(parseWaypoint(CustomArtifactWaypoint::new, artifact));
}
return waypoints;

View File

@ -2,6 +2,7 @@ KMLReport.bookmarkError=Could not extract Bookmark information.
# {0} - filePath
KMLReport.errorGeneratingReport=Error adding {0} to case as a report.
KMLReport.exifPhotoError=Could not extract photos with EXIF metadata.
KMLReport.failedToCompleteReport=Failed to complete report.
KMLReport.gpsBookmarkError=Could not get GPS Bookmarks from database.
KMLReport.gpsRouteDatabaseError=Could not get GPS Routes from database.
KMLReport.gpsRouteError=Could not extract GPS Route information.
@ -9,6 +10,7 @@ KMLReport.gpsSearchDatabaseError=Could not get GPS Searches from database.
KMLReport.kmlFileWriteError=Could not write the KML file.
KMLReport.locationDatabaseError=Could not get GPS Last Known Location from database.
KMLReport.locationError=Could not extract Last Known Location information.
KMLReport.partialFailure=There was an error creating the report. Some items were not exported.
KMLReport.stylesheetError=Error placing KML stylesheet. The .KML file will not function properly.
KMLReport.trackpointDatabaseError=Could not get GPS Trackpoints from database.
KMLReport.trackpointError=Could not extract Trackpoint information.

View File

@ -46,6 +46,7 @@ import org.openide.filesystems.FileUtil;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationDataException;
import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationParseResult;
import org.sleuthkit.autopsy.geolocation.datamodel.Waypoint;
import org.sleuthkit.autopsy.geolocation.datamodel.Route;
import org.sleuthkit.autopsy.geolocation.datamodel.Track;
@ -126,6 +127,8 @@ public final class KMLReport implements GeneralReportModule {
* @param waypointList
*/
@Messages({
"KMLReport.failedToCompleteReport=Failed to complete report.",
"KMLReport.partialFailure=There was an error creating the report. Some items were not exported.",
"KMLReport.unableToExtractPhotos=Could not extract photo information.",
"KMLReport.exifPhotoError=Could not extract photos with EXIF metadata.",
"KMLReport.bookmarkError=Could not extract Bookmark information.",
@ -208,10 +211,15 @@ public final class KMLReport implements GeneralReportModule {
try {
makeRoutes(skCase);
makeTracks(skCase);
boolean entirelySuccessful = makeTracks(skCase);
if (!entirelySuccessful) {
result = ReportProgressPanel.ReportStatus.ERROR;
errorMessage = Bundle.KMLReport_partialFailure();
}
addLocationsToReport(skCase, baseReportDir);
} catch (GeoLocationDataException | IOException | TskCoreException ex) {
errorMessage = "Failed to complete report.";
errorMessage = Bundle.KMLReport_failedToCompleteReport();
logger.log(Level.SEVERE, errorMessage, ex); //NON-NLS
result = ReportProgressPanel.ReportStatus.ERROR;
}
@ -515,14 +523,18 @@ public final class KMLReport implements GeneralReportModule {
* Add the track to the track folder in the document.
*
* @param skCase Currently open case.
* @return The operation was entirely successful.
*
* @throws TskCoreException
*/
void makeTracks(SleuthkitCase skCase) throws GeoLocationDataException, TskCoreException {
boolean makeTracks(SleuthkitCase skCase) throws GeoLocationDataException, TskCoreException {
List<Track> tracks = null;
boolean successful = true;
if (waypointList == null) {
tracks = Track.getTracks(skCase, null);
GeoLocationParseResult<Track> result = Track.getTracks(skCase, null);
tracks = result.getItems();
successful = result.isSuccessfullyParsed();
} else {
tracks = WaypointBuilder.getTracks(waypointList);
}
@ -533,6 +545,8 @@ public final class KMLReport implements GeneralReportModule {
}
addTrackToReport(track);
}
return successful;
}
/**

View File

@ -82,6 +82,12 @@ public class CategorizeAction extends Action {
this.tagName = tagName;
setGraphic(getGraphic(tagName));
setEventHandler(actionEvent -> addCatToFiles(selectedFileIDs));
int rank = tagName.getRank();
// Only map to a key if the rank is less than 10
if(rank < 10) {
setAccelerator(new KeyCodeCombination(KeyCode.getKeyCode(Integer.toString(rank))));
}
}
static public Menu getCategoriesMenu(ImageGalleryController controller) {

View File

@ -21,12 +21,19 @@ package org.sleuthkit.autopsy.imagegallery.gui;
import java.io.IOException;
import java.net.URL;
import java.util.logging.Level;
import javafx.geometry.HPos;
import javafx.geometry.Pos;
import javafx.scene.control.ButtonBase;
import javafx.scene.control.CustomMenuItem;
import javafx.scene.control.Dialog;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.image.Image;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import org.controlsfx.control.action.Action;
import org.controlsfx.control.action.ActionUtils;
@ -67,7 +74,31 @@ public final class GuiUtils {
* @return
*/
public static MenuItem createAutoAssigningMenuItem(ButtonBase button, Action action) {
MenuItem menuItem = new CustomMenuItem(new Label(action.getText(), action.getGraphic()));
Label mainLabel = new Label(action.getText(), action.getGraphic());
String hkDisplayText = action.getAccelerator() != null ? action.getAccelerator().getDisplayText() : "";
Label hotKeyLabel = new Label(hkDisplayText);
hotKeyLabel.setMaxWidth(100);
GridPane grid = new GridPane();
grid.setAlignment(Pos.CENTER);
grid.setHgap(10);
ColumnConstraints column1 = new ColumnConstraints();
column1.setHalignment(HPos.LEFT);
grid.getColumnConstraints().add(column1);
ColumnConstraints column2 = new ColumnConstraints();
column2.setHalignment(HPos.RIGHT);
column2.setMaxWidth(Double.MAX_VALUE);
grid.getColumnConstraints().add(column2);
grid.add(mainLabel, 0, 0);
grid.add(hotKeyLabel, 1, 0);
grid.setMaxWidth(Double.MAX_VALUE);
MenuItem menuItem = new CustomMenuItem(grid);
ActionUtils.configureMenuItem(action, menuItem);
menuItem.setOnAction(actionEvent -> {
action.handle(actionEvent);

View File

@ -183,6 +183,7 @@ class GPXParserFileIngestModule(FileIngestModule):
point.latitude, point.longitude, elevation, None, 0, 0, 0, timeStamp))
try:
if not geoPointList.isEmpty():
geoArtifactHelper.addTrack("Track", geoPointList, None)
except Blackboard.BlackboardException as e:
self.log(Level.SEVERE, "Error posting GPS track artifact for " +
@ -236,6 +237,7 @@ class GPXParserFileIngestModule(FileIngestModule):
Waypoint(point.latitude, point.longitude, point.elevation, point.name))
try:
if not geoWaypoints.isEmpty():
geoArtifactHelper.addRoute(None, None, geoWaypoints, None)
except Blackboard.BlackboardException as e:
self.log("Error posting GPS route artifact for " + file.getUniquePath() +