diff --git a/Core/src/org/sleuthkit/autopsy/communications/AbstractCVTAction.java b/Core/src/org/sleuthkit/autopsy/communications/AbstractCVTAction.java index ef751d262c..95c2d43bbb 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/AbstractCVTAction.java +++ b/Core/src/org/sleuthkit/autopsy/communications/AbstractCVTAction.java @@ -19,11 +19,13 @@ package org.sleuthkit.autopsy.communications; import java.util.Collection; +import java.util.stream.Collectors; import javax.swing.AbstractAction; import javax.swing.ImageIcon; import javax.swing.JMenuItem; import org.openide.util.Utilities; import org.openide.util.actions.Presenter; +import org.sleuthkit.datamodel.AccountDeviceInstance; /** * Base class for actions that act on the selected AccountDeviceInstanceKeys. @@ -37,8 +39,11 @@ abstract class AbstractCVTAction extends AbstractAction implements Presenter.Pop * * @return The selected accounts */ - Collection getSelectedAccounts() { - return Utilities.actionsGlobalContext().lookupAll(AccountDeviceInstanceKey.class); + Collection getSelectedAccounts() { + return Utilities.actionsGlobalContext().lookupAll(AccountDeviceInstanceKey.class) + .stream() + .map((adiKey -> adiKey.getAccountDeviceInstance())) + .collect(Collectors.toSet()); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/communications/CVTEvents.java b/Core/src/org/sleuthkit/autopsy/communications/CVTEvents.java index ee7224b673..ae3735e30f 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/CVTEvents.java +++ b/Core/src/org/sleuthkit/autopsy/communications/CVTEvents.java @@ -24,6 +24,7 @@ import java.util.Collection; import org.sleuthkit.autopsy.communications.FiltersPanel.DateControlState; import org.sleuthkit.datamodel.CommunicationsFilter; import org.sleuthkit.autopsy.communications.StateManager.CommunicationsState; +import org.sleuthkit.datamodel.AccountDeviceInstance; /** * Provide the singleton EventBus. @@ -73,19 +74,19 @@ final class CVTEvents { */ static final class PinAccountsEvent { - private final ImmutableSet accountDeviceInstances; + private final ImmutableSet accounInstances; private final boolean replace; public boolean isReplace() { return replace; } - ImmutableSet getAccountDeviceInstances() { - return accountDeviceInstances; + ImmutableSet getAccountDeviceInstances() { + return accounInstances; } - PinAccountsEvent(Collection accountDeviceInstances, boolean replace) { - this.accountDeviceInstances = ImmutableSet.copyOf(accountDeviceInstances); + PinAccountsEvent(Collection accountDeviceInstances, boolean replace) { + this.accounInstances = ImmutableSet.copyOf(accountDeviceInstances); this.replace = replace; } } @@ -95,14 +96,14 @@ final class CVTEvents { */ static final class UnpinAccountsEvent { - private final ImmutableSet accountDeviceInstances; + private final ImmutableSet accountInstances; - public ImmutableSet getAccountDeviceInstances() { - return accountDeviceInstances; + public ImmutableSet getAccountDeviceInstances() { + return accountInstances; } - UnpinAccountsEvent(Collection accountDeviceInstances) { - this.accountDeviceInstances = ImmutableSet.copyOf(accountDeviceInstances); + UnpinAccountsEvent(Collection accountDeviceInstances) { + this.accountInstances = ImmutableSet.copyOf(accountDeviceInstances); } } diff --git a/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java b/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java index 716d00656c..f07d4d52ab 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java +++ b/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java @@ -32,6 +32,7 @@ import java.io.InputStreamReader; import java.io.StringWriter; import java.net.URL; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -147,7 +148,7 @@ final class CommunicationsGraph extends mxGraph { scopes.put("accountName", adiKey.getAccountDeviceInstance().getAccount().getTypeSpecificID()); scopes.put("size", Math.round(Math.log(adiKey.getMessageCount()) + 5)); scopes.put("iconFileName", CommunicationsGraph.class.getResource(Utils.getIconFilePath(adiKey.getAccountDeviceInstance().getAccount().getAccountType()))); - scopes.put("pinned", pinnedAccountModel.isAccountPinned(adiKey)); + scopes.put("pinned", pinnedAccountModel.isAccountPinned(adiKey.getAccountDeviceInstance())); scopes.put("MARKER_PIN_URL", MARKER_PIN_URL); scopes.put("locked", lockedVertexModel.isVertexLocked((mxCell) cell)); scopes.put("LOCK_URL", LOCK_URL); @@ -172,7 +173,7 @@ final class CommunicationsGraph extends mxGraph { scopes.put("accountName", adiKey.getAccountDeviceInstance().getAccount().getTypeSpecificID()); scopes.put("relationships", 12);// Math.round(Math.log(adiKey.getMessageCount()) + 5)); scopes.put("iconFileName", CommunicationsGraph.class.getResource(Utils.getIconFilePath(adiKey.getAccountDeviceInstance().getAccount().getAccountType()))); - scopes.put("pinned", pinnedAccountModel.isAccountPinned(adiKey)); + scopes.put("pinned", pinnedAccountModel.isAccountPinned(adiKey.getAccountDeviceInstance())); scopes.put("MARKER_PIN_URL", MARKER_PIN_URL); scopes.put("locked", lockedVertexModel.isVertexLocked((mxCell) cell)); scopes.put("LOCK_URL", LOCK_URL); @@ -199,16 +200,24 @@ final class CommunicationsGraph extends mxGraph { lockedVertexModel.clear(); } - private mxCell getOrCreateVertex(AccountDeviceInstanceKey accountDeviceInstanceKey) { - final AccountDeviceInstance accountDeviceInstance = accountDeviceInstanceKey.getAccountDeviceInstance(); + private mxCell getOrCreateVertex(AccountDeviceInstance adi, CommunicationsManager commsManager, CommunicationsFilter currentFilter) { + final AccountDeviceInstance accountDeviceInstance = adi; final String name = accountDeviceInstance.getAccount().getTypeSpecificID(); final mxCell vertex = nodeMap.computeIfAbsent(name + accountDeviceInstance.getDeviceId(), vertexName -> { - double size = Math.sqrt(accountDeviceInstanceKey.getMessageCount()) + 10; - + long adiRelationshipsCount = 1; + try { + adiRelationshipsCount = commsManager.getRelationshipSourcesCount(accountDeviceInstance, currentFilter); + } catch (TskCoreException tskCoreException) { + logger.log(Level.SEVERE, "There was an error fetching relationships for the node: " + accountDeviceInstance, tskCoreException); + } + + double size = Math.sqrt(adiRelationshipsCount) + 10; + AccountDeviceInstanceKey adiKey = new AccountDeviceInstanceKey(adi, currentFilter, adiRelationshipsCount); + mxCell newVertex = (mxCell) insertVertex( getDefaultParent(), - name, accountDeviceInstanceKey, + name, adiKey, Math.random() * 400, Math.random() * 400, size, @@ -219,9 +228,11 @@ final class CommunicationsGraph extends mxGraph { } @SuppressWarnings("unchecked") - private mxCell addOrUpdateEdge(long relSources, AccountDeviceInstanceKey account1, AccountDeviceInstanceKey account2) { - mxCell vertex1 = getOrCreateVertex(account1); - mxCell vertex2 = getOrCreateVertex(account2); + private mxCell addOrUpdateEdge(long relSources, + AccountDeviceInstance account1, AccountDeviceInstance account2, + CommunicationsManager commsManager, CommunicationsFilter currentFilter) { + mxCell vertex1 = getOrCreateVertex(account1, commsManager, currentFilter); + mxCell vertex2 = getOrCreateVertex(account2, commsManager, currentFilter); Object[] edgesBetween = getEdgesBetween(vertex1, vertex2); mxCell edge; if (edgesBetween.length == 0) { @@ -260,28 +271,24 @@ final class CommunicationsGraph extends mxGraph { /** * set to keep track of accounts related to pinned accounts */ - final Map relatedAccounts = new HashMap<>(); - for (final AccountDeviceInstanceKey adiKey : pinnedAccountModel.getPinnedAccounts()) { + final Set relatedAccounts = new HashSet<>(); + for (final AccountDeviceInstance adi : pinnedAccountModel.getPinnedAccounts()) { if (isCancelled()) { break; } //get accounts related to pinned account final List relatedAccountDeviceInstances - = commsManager.getRelatedAccountDeviceInstances(adiKey.getAccountDeviceInstance(), currentFilter); - relatedAccounts.put(adiKey.getAccountDeviceInstance(), adiKey); - getOrCreateVertex(adiKey); + = commsManager.getRelatedAccountDeviceInstances(adi, currentFilter); + relatedAccounts.add(adi); + getOrCreateVertex(adi, commsManager, currentFilter); + + for (final AccountDeviceInstance relatedADI : relatedAccountDeviceInstances) + relatedAccounts.add(relatedADI); - for (final AccountDeviceInstance relatedADI : relatedAccountDeviceInstances) { - final long adiRelationshipsCount = commsManager.getRelationshipSourcesCount(relatedADI, currentFilter); - final AccountDeviceInstanceKey relatedADIKey = new AccountDeviceInstanceKey(relatedADI, currentFilter, adiRelationshipsCount); - relatedAccounts.put(relatedADI, relatedADIKey); //store related accounts - } progressIndicator.progress(++progressCounter); } - Set accounts = relatedAccounts.keySet(); - - Map relationshipCounts = commsManager.getRelationshipCountsPairwise(accounts, currentFilter); + Map relationshipCounts = commsManager.getRelationshipCountsPairwise(relatedAccounts, currentFilter); int total = relationshipCounts.size(); int progress = 0; @@ -290,12 +297,12 @@ final class CommunicationsGraph extends mxGraph { for (Map.Entry entry : relationshipCounts.entrySet()) { Long count = entry.getValue(); AccountPair relationshipKey = entry.getKey(); - AccountDeviceInstanceKey account1 = relatedAccounts.get(relationshipKey.getFirst()); - AccountDeviceInstanceKey account2 = relatedAccounts.get(relationshipKey.getSecond()); + AccountDeviceInstance account1 = relationshipKey.getFirst(); + AccountDeviceInstance account2 = relationshipKey.getSecond(); if (pinnedAccountModel.isAccountPinned(account1) || pinnedAccountModel.isAccountPinned(account2)) { - mxCell addEdge = addOrUpdateEdge(count, account1, account2); + mxCell addEdge = addOrUpdateEdge(count, account1, account2, commsManager, currentFilter); progressText = addEdge.getId(); } progressIndicator.progress(progressText, progress++); diff --git a/Core/src/org/sleuthkit/autopsy/communications/PinnedAccountModel.java b/Core/src/org/sleuthkit/autopsy/communications/PinnedAccountModel.java index c9fe899c3f..9221a487cb 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/PinnedAccountModel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/PinnedAccountModel.java @@ -22,6 +22,7 @@ import com.google.common.collect.ImmutableSet; import com.google.common.eventbus.EventBus; import java.util.HashSet; import java.util.Set; +import org.sleuthkit.datamodel.AccountDeviceInstance; /** * Model of what accounts are pinned to a visualization. @@ -34,7 +35,7 @@ class PinnedAccountModel { * to pinned accounts and pass the filters are show. Pinning accounts is the * primary way to populate the graph. */ - private final Set pinnedAccountDevices = new HashSet<>(); + private final Set pinnedAccountDevices = new HashSet<>(); private final EventBus eventBus = new EventBus(); @@ -46,7 +47,7 @@ class PinnedAccountModel { eventBus.unregister(handler); } - boolean isAccountPinned(AccountDeviceInstanceKey account) { + boolean isAccountPinned(AccountDeviceInstance account) { return pinnedAccountDevices.contains(account); } @@ -57,7 +58,7 @@ class PinnedAccountModel { * * @param accountDeviceInstances The accounts to unpin. */ - void unpinAccount(Set accountDeviceInstances) { + void unpinAccount(Set accountDeviceInstances) { pinnedAccountDevices.removeAll(accountDeviceInstances); } @@ -68,7 +69,7 @@ class PinnedAccountModel { * * @param accountDeviceInstances The accounts to pin. */ - void pinAccount(Set accountDeviceInstances) { + void pinAccount(Set accountDeviceInstances) { pinnedAccountDevices.addAll(accountDeviceInstances); } @@ -86,7 +87,7 @@ class PinnedAccountModel { pinnedAccountDevices.clear(); } - ImmutableSet getPinnedAccounts() { + ImmutableSet getPinnedAccounts() { return ImmutableSet.copyOf(pinnedAccountDevices); } diff --git a/Core/src/org/sleuthkit/autopsy/communications/StateManager.java b/Core/src/org/sleuthkit/autopsy/communications/StateManager.java index c84a5beb79..3f24a98764 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/StateManager.java +++ b/Core/src/org/sleuthkit/autopsy/communications/StateManager.java @@ -23,6 +23,7 @@ import java.util.HashSet; import java.util.Set; import org.sleuthkit.autopsy.communications.FiltersPanel.DateControlState; import org.sleuthkit.autopsy.coreutils.History; +import org.sleuthkit.datamodel.AccountDeviceInstance; import org.sleuthkit.datamodel.CommunicationsFilter; /** @@ -51,11 +52,11 @@ final class StateManager { @Subscribe void pinAccount(CVTEvents.PinAccountsEvent pinEvent) { if(pinEvent.isReplace()){ - HashSet pinnedList = new HashSet<>(); + HashSet pinnedList = new HashSet<>(); pinnedList.addAll(pinEvent.getAccountDeviceInstances()); historyManager.advance(new CommunicationsState(comFilter, pinnedList, -1, currentStartState, currentEndState)); } else { - HashSet pinnedList = new HashSet<>(); + HashSet pinnedList = new HashSet<>(); pinnedList.addAll(pinEvent.getAccountDeviceInstances()); pinnedList.addAll(pinModel.getPinnedAccounts()); @@ -74,7 +75,7 @@ final class StateManager { @Subscribe void unpinAccounts(CVTEvents.UnpinAccountsEvent pinEvent) { - HashSet pinnedList = new HashSet<>(); + HashSet pinnedList = new HashSet<>(); pinnedList.addAll(pinModel.getPinnedAccounts()); pinnedList.removeAll(pinEvent.getAccountDeviceInstances()); @@ -135,7 +136,7 @@ final class StateManager { */ final class CommunicationsState{ private final CommunicationsFilter communcationFilter; - private final Set pinnedList; + private final Set pinnedList; private final double zoomValue; private final DateControlState startDateState; private final DateControlState endDateState; @@ -149,7 +150,7 @@ final class StateManager { * @param zoomValue Double value of the current graph scale */ protected CommunicationsState(CommunicationsFilter communcationFilter, - Set pinnedList, double zoomValue, + Set pinnedList, double zoomValue, DateControlState startDateState, DateControlState endDateState){ this.pinnedList = pinnedList; this.communcationFilter = communcationFilter; @@ -172,7 +173,7 @@ final class StateManager { * * @return Set of AccountDeviceInstanceKey */ - public Set getPinnedList(){ + public Set getPinnedList(){ return pinnedList; } diff --git a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java index 1799ebcb8d..51005878ec 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java @@ -1100,7 +1100,7 @@ final public class VisualizationPanel extends JPanel { } else { jPopupMenu.add(new JMenuItem(new LockAction(selectedVertices))); } - if (pinnedAccountModel.isAccountPinned(adiKey)) { + if (pinnedAccountModel.isAccountPinned(adiKey.getAccountDeviceInstance())) { jPopupMenu.add(UnpinAccountsAction.getInstance().getPopupPresenter()); } else { jPopupMenu.add(PinAccountsAction.getInstance().getPopupPresenter()); diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java b/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java index f9d8fca38e..d8121e68a1 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java @@ -23,6 +23,8 @@ import java.awt.Graphics; import java.awt.GridBagConstraints; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; +import java.sql.ResultSet; +import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -38,9 +40,9 @@ import javax.swing.SwingWorker; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datamodel.utils.IconsUtil; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; +import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; @@ -482,6 +484,54 @@ class GeoFilterPanel extends javax.swing.JPanel { return new Sources(validSources, atCountsTotal); } + /** + * Get a count of artifacts of the given type containing GPS data for + * the given data case and source. Does not include rejected artifacts. + * + * @param sleuthkitCase + * @param dataSource + * @param artifactType + * + * @return The artifacts count that match the criteria + * + * @throws TskCoreException + */ + private long getGPSDataCount(SleuthkitCase sleuthkitCase, + DataSource dataSource, BlackboardArtifact.ARTIFACT_TYPE artifactType) throws TskCoreException { + long count = 0; + String queryStr + = "SELECT count(DISTINCT artifact_id) AS count FROM" + + " (" + + " SELECT * FROM blackboard_artifacts as arts" + + " INNER JOIN blackboard_attributes as attrs" + + " ON attrs.artifact_id = arts.artifact_id" + + " WHERE arts.artifact_type_id = " + artifactType.getTypeID() + + " AND arts.data_source_obj_id = " + dataSource.getId() + + " AND arts.review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID() + + " AND" + + " (" + + "attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID() + + " or attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID() + + " or attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_TRACKPOINTS.getTypeID() + + " or attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_WAYPOINTS.getTypeID() + + " )" + + " )"; + try (SleuthkitCase.CaseDbQuery queryResult = sleuthkitCase.executeQuery(queryStr); + ResultSet resultSet = queryResult.getResultSet()) { + if (resultSet.next()) { + count = resultSet.getLong("count"); + } + } catch (SQLException ex) { + Throwable cause = ex.getCause(); + if (cause != null) { + logger.log(Level.SEVERE, cause.getMessage(), cause); + } else { + logger.log(Level.SEVERE, ex.getMessage(), ex); + } + } + return count; + } + /** * Returns a Map representing the number of sources found for each * artifact type. If no data was found, an empty map is returned. @@ -496,7 +546,7 @@ class GeoFilterPanel extends javax.swing.JPanel { private Map getGPSDataSources(SleuthkitCase sleuthkitCase, DataSource dataSource) throws TskCoreException { HashMap ret = new HashMap<>(); for (BlackboardArtifact.ARTIFACT_TYPE type : GPS_ARTIFACT_TYPES) { - long count = sleuthkitCase.getBlackboardArtifactsTypeCount(type.getTypeID(), dataSource.getId()); + long count = getGPSDataCount(sleuthkitCase, dataSource, type); if (count > 0) { ret.put(type, count); } diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/MapPanel.java b/Core/src/org/sleuthkit/autopsy/geolocation/MapPanel.java index 44de21ff81..242d8e81d6 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/MapPanel.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/MapPanel.java @@ -39,6 +39,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -83,9 +84,13 @@ import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; final public class MapPanel extends javax.swing.JPanel { static final String CURRENT_MOUSE_GEOPOSITION = "CURRENT_MOUSE_GEOPOSITION"; + private static final Logger logger = Logger.getLogger(MapPanel.class.getName()); private static final long serialVersionUID = 1L; + private static final Set DOT_WAYPOINT_TYPES = new HashSet<>(); + private static final int DOT_SIZE = 12; + private boolean zoomChanging; private KdTree waypointTree; private Set waypointSet; @@ -104,6 +109,12 @@ final public class MapPanel extends javax.swing.JPanel { private MapWaypoint currentlySelectedWaypoint; private Set currentlySelectedTrack; + static { + DOT_WAYPOINT_TYPES.add(ARTIFACT_TYPE.TSK_GPS_TRACKPOINT.getTypeID()); + DOT_WAYPOINT_TYPES.add(ARTIFACT_TYPE.TSK_GPS_TRACK.getTypeID()); + DOT_WAYPOINT_TYPES.add(ARTIFACT_TYPE.TSK_GPS_ROUTE.getTypeID()); + } + /** * Creates new form MapPanel */ @@ -486,14 +497,30 @@ final public class MapPanel extends javax.swing.JPanel { Iterator iterator = waypoints.iterator(); - // These maybe the points closest to lat/log was clicked but - // that doesn't mean they are close in terms of pixles. + // These may be the points closest to the lat/lon location that was + // clicked, but that doesn't mean they are close in terms of pixles. List closestPoints = new ArrayList<>(); while (iterator.hasNext()) { MapWaypoint nextWaypoint = iterator.next(); - Point2D point = mapViewer.convertGeoPositionToPoint(nextWaypoint.getPosition()); - Rectangle rect = new Rectangle((int) point.getX() - (whiteWaypointImage.getWidth() / 2), (int) point.getY() - whiteWaypointImage.getHeight(), whiteWaypointImage.getWidth(), whiteWaypointImage.getHeight()); + int pointX = (int) point.getX(); + int pointY = (int) point.getY(); + Rectangle rect; + if (DOT_WAYPOINT_TYPES.contains(nextWaypoint.getArtifactTypeID())) { + rect = new Rectangle( + pointX - (DOT_SIZE / 2), + pointY - (DOT_SIZE / 2), + DOT_SIZE, + DOT_SIZE + ); + } else { + rect = new Rectangle( + pointX - (whiteWaypointImage.getWidth() / 2), + pointY - whiteWaypointImage.getHeight(), + whiteWaypointImage.getWidth(), + whiteWaypointImage.getHeight() + ); + } if (rect.contains(clickPoint)) { closestPoints.add(nextWaypoint); @@ -689,6 +716,7 @@ final public class MapPanel extends javax.swing.JPanel { if (waypoints.size() > 0) { MapWaypoint selection = waypoints.get(0); currentlySelectedWaypoint = selection; + currentlySelectedTrack = null; for (Set track : tracks) { if (track.contains(selection)) { currentlySelectedTrack = track; @@ -751,17 +779,16 @@ final public class MapPanel extends javax.swing.JPanel { * @return the new dot image */ private BufferedImage createTrackDotImage(Color color) { - int w = 10; - int h = 10; + int s = DOT_SIZE; - BufferedImage ret = new BufferedImage(w + 2, h + 2, BufferedImage.TYPE_INT_ARGB); + BufferedImage ret = new BufferedImage(s, s, BufferedImage.TYPE_INT_ARGB); Graphics2D g = ret.createGraphics(); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setColor(color); - g.fillOval(1, 1, w, h); + g.fillOval(1, 1, s - 2, s - 2); g.setColor(Color.BLACK); g.setStroke(new BasicStroke(1)); - g.drawOval(1, 1, w, h); + g.drawOval(1, 1, s - 2, s - 2); g.dispose(); return ret; } @@ -794,14 +821,11 @@ final public class MapPanel extends javax.swing.JPanel { public void paintWaypoint(Graphics2D g, JXMapViewer map, MapWaypoint waypoint) { Color color = getColor(waypoint); BufferedImage image; - int artifactType = waypoint.getArtifactTypeID(); Point2D point = map.getTileFactory().geoToPixel(waypoint.getPosition(), map.getZoom()); int x = (int) point.getX(); int y = (int) point.getY(); - if (artifactType == ARTIFACT_TYPE.TSK_GPS_TRACKPOINT.getTypeID() - || artifactType == ARTIFACT_TYPE.TSK_GPS_TRACK.getTypeID() - || artifactType == ARTIFACT_TYPE.TSK_GPS_ROUTE.getTypeID()) { + if (DOT_WAYPOINT_TYPES.contains(waypoint.getArtifactTypeID())) { image = dotImageCache.computeIfAbsent(color, k -> { return createTrackDotImage(color); }); diff --git a/Running_Linux_OSX.txt b/Running_Linux_OSX.txt index 60b81bc50a..0427c003b4 100644 --- a/Running_Linux_OSX.txt +++ b/Running_Linux_OSX.txt @@ -42,11 +42,10 @@ The following need to be done at least once. They do not need to be repeated for Autopsy depends on a specific version of The Sleuth Kit. You need the Java libraries of The Sleuth Kit installed, which is not part of all packages. -- Linux: Install the sleuthkit-java.deb file that you can download from github.com/sleuthkit/sleuthkit/releases. This will install libewf, etc. --- % sudo apt install ./sleuthkit-java_4.7.0-1_amd64.deb +- Linux: Install the sleuthkit-java.deb file that you can download from github.com/sleuthkit/sleuthkit/releases. This will install libewf, etc. For example: +-- % sudo apt install ./sleuthkit-java_4.8.0-1_amd64.deb -- OS X: Install The Sleuth Kit from brew. --- % brew install sleuthkit +- OS X: Build The Sleuth Kit from source. See https://github.com/sleuthkit/sleuthkit/blob/develop/INSTALL.txt for details. * Install Autopsy *