Merge pull request #5294 from rcordovano/timeline-public-api-improvements

5413 Improve and document public API for timeline data
This commit is contained in:
Richard Cordovano 2019-10-02 17:20:18 -04:00 committed by GitHub
commit 97147f285d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 175 additions and 175 deletions

View File

@ -66,7 +66,6 @@ import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.Tag;
import org.sleuthkit.datamodel.TimelineManager; import org.sleuthkit.datamodel.TimelineManager;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TimelineEvent; import org.sleuthkit.datamodel.TimelineEvent;
@ -81,6 +80,7 @@ import org.sleuthkit.datamodel.TimelineFilter.HideKnownFilter;
import org.sleuthkit.datamodel.TimelineFilter.RootFilter; import org.sleuthkit.datamodel.TimelineFilter.RootFilter;
import org.sleuthkit.datamodel.TimelineFilter.TagsFilter; import org.sleuthkit.datamodel.TimelineFilter.TagsFilter;
import org.sleuthkit.datamodel.TimelineFilter.TextFilter; import org.sleuthkit.datamodel.TimelineFilter.TextFilter;
import org.sleuthkit.datamodel.TimelineLevelOfDetail;
/** /**
* This class acts as the model for a TimelineView * This class acts as the model for a TimelineView
@ -112,8 +112,8 @@ public final class FilteredEventsModel {
private final ReadOnlyObjectWrapper<RootFilterState> requestedFilter = new ReadOnlyObjectWrapper<>(); private final ReadOnlyObjectWrapper<RootFilterState> requestedFilter = new ReadOnlyObjectWrapper<>();
private final ReadOnlyObjectWrapper<Interval> requestedTimeRange = new ReadOnlyObjectWrapper<>(); private final ReadOnlyObjectWrapper<Interval> requestedTimeRange = new ReadOnlyObjectWrapper<>();
private final ReadOnlyObjectWrapper<ZoomState> requestedZoomState = new ReadOnlyObjectWrapper<>(); private final ReadOnlyObjectWrapper<ZoomState> requestedZoomState = new ReadOnlyObjectWrapper<>();
private final ReadOnlyObjectWrapper< TimelineEventType.TypeLevel> requestedTypeZoom = new ReadOnlyObjectWrapper<>(TimelineEventType.TypeLevel.BASE_TYPE); private final ReadOnlyObjectWrapper<TimelineEventType.HierarchyLevel> requestedTypeZoom = new ReadOnlyObjectWrapper<>(TimelineEventType.HierarchyLevel.CATEGORY);
private final ReadOnlyObjectWrapper< TimelineEvent.DescriptionLevel> requestedLOD = new ReadOnlyObjectWrapper<>(TimelineEvent.DescriptionLevel.SHORT); private final ReadOnlyObjectWrapper<TimelineLevelOfDetail> requestedLOD = new ReadOnlyObjectWrapper<>(TimelineLevelOfDetail.LOW);
// end Filter and zoome state // end Filter and zoome state
//caches //caches
@ -121,7 +121,9 @@ public final class FilteredEventsModel {
private final LoadingCache<Object, Long> minCache; private final LoadingCache<Object, Long> minCache;
private final LoadingCache<Long, TimelineEvent> idToEventCache; private final LoadingCache<Long, TimelineEvent> idToEventCache;
private final LoadingCache<ZoomState, Map<TimelineEventType, Long>> eventCountsCache; private final LoadingCache<ZoomState, Map<TimelineEventType, Long>> eventCountsCache;
/** Map from datasource id to datasource name. */ /**
* Map from datasource id to datasource name.
*/
private final ObservableMap<Long, String> datasourcesMap = FXCollections.observableHashMap(); private final ObservableMap<Long, String> datasourcesMap = FXCollections.observableHashMap();
// end caches // end caches
@ -152,9 +154,9 @@ public final class FilteredEventsModel {
.build(new CacheLoaderImpl<>(this::countEventsByType)); .build(new CacheLoaderImpl<>(this::countEventsByType));
maxCache = CacheBuilder.newBuilder() maxCache = CacheBuilder.newBuilder()
.build(new CacheLoaderImpl<>(ignored -> eventManager.getMaxTime())); .build(new CacheLoaderImpl<>(ignored -> eventManager.getMaxEventTime()));
minCache = CacheBuilder.newBuilder() minCache = CacheBuilder.newBuilder()
.build(new CacheLoaderImpl<>(ignored -> eventManager.getMinTime())); .build(new CacheLoaderImpl<>(ignored -> eventManager.getMinEventTime()));
InvalidationListener filterSyncListener = observable -> { InvalidationListener filterSyncListener = observable -> {
RootFilterState rootFilter = filterProperty().get(); RootFilterState rootFilter = filterProperty().get();
@ -280,7 +282,7 @@ public final class FilteredEventsModel {
return requestedTimeRange.getReadOnlyProperty(); return requestedTimeRange.getReadOnlyProperty();
} }
synchronized public ReadOnlyObjectProperty<TimelineEvent.DescriptionLevel> descriptionLODProperty() { synchronized public ReadOnlyObjectProperty<TimelineLevelOfDetail> descriptionLODProperty() {
return requestedLOD.getReadOnlyProperty(); return requestedLOD.getReadOnlyProperty();
} }
@ -288,7 +290,7 @@ public final class FilteredEventsModel {
return requestedFilter.getReadOnlyProperty(); return requestedFilter.getReadOnlyProperty();
} }
synchronized public ReadOnlyObjectProperty<TimelineEventType.TypeLevel> eventTypeZoomProperty() { synchronized public ReadOnlyObjectProperty<TimelineEventType.HierarchyLevel> eventTypeZoomProperty() {
return requestedTypeZoom.getReadOnlyProperty(); return requestedTypeZoom.getReadOnlyProperty();
} }
@ -301,7 +303,7 @@ public final class FilteredEventsModel {
return getZoomState().getTimeRange(); return getZoomState().getTimeRange();
} }
synchronized public TimelineEvent.DescriptionLevel getDescriptionLOD() { synchronized public TimelineLevelOfDetail getDescriptionLOD() {
return getZoomState().getDescriptionLOD(); return getZoomState().getDescriptionLOD();
} }
@ -309,11 +311,12 @@ public final class FilteredEventsModel {
return getZoomState().getFilterState(); return getZoomState().getFilterState();
} }
synchronized public TimelineEventType.TypeLevel getEventTypeZoom() { synchronized public TimelineEventType.HierarchyLevel getEventTypeZoom() {
return getZoomState().getTypeZoomLevel(); return getZoomState().getTypeZoomLevel();
} }
/** Get the default filter used at startup. /**
* Get the default filter used at startup.
* *
* @return the default filter used at startup * @return the default filter used at startup
*/ */
@ -385,7 +388,7 @@ public final class FilteredEventsModel {
public Map<TimelineEventType, Long> getEventCounts(Interval timeRange) throws TskCoreException { public Map<TimelineEventType, Long> getEventCounts(Interval timeRange) throws TskCoreException {
final RootFilterState filter; final RootFilterState filter;
final TimelineEventType.TypeLevel typeZoom; final TimelineEventType.HierarchyLevel typeZoom;
synchronized (this) { synchronized (this) {
filter = getFilterState(); filter = getFilterState();
typeZoom = getEventTypeZoom(); typeZoom = getEventTypeZoom();
@ -453,39 +456,40 @@ public final class FilteredEventsModel {
synchronized public boolean handleContentTagAdded(ContentTagAddedEvent evt) throws TskCoreException { synchronized public boolean handleContentTagAdded(ContentTagAddedEvent evt) throws TskCoreException {
ContentTag contentTag = evt.getAddedTag(); ContentTag contentTag = evt.getAddedTag();
Content content = contentTag.getContent(); Content content = contentTag.getContent();
Set<Long> updatedEventIDs = addTag(content.getId(), null, contentTag); Set<Long> updatedEventIDs = eventManager.updateEventsForContentTagAdded(content);
if (isNotEmpty(updatedEventIDs)) {
invalidateCaches(updatedEventIDs);
}
return postTagsAdded(updatedEventIDs); return postTagsAdded(updatedEventIDs);
} }
synchronized public boolean handleArtifactTagAdded(BlackBoardArtifactTagAddedEvent evt) throws TskCoreException { synchronized public boolean handleArtifactTagAdded(BlackBoardArtifactTagAddedEvent evt) throws TskCoreException {
BlackboardArtifactTag artifactTag = evt.getAddedTag(); BlackboardArtifactTag artifactTag = evt.getAddedTag();
BlackboardArtifact artifact = artifactTag.getArtifact(); BlackboardArtifact artifact = artifactTag.getArtifact();
Set<Long> updatedEventIDs = addTag(artifact.getObjectID(), artifact.getArtifactID(), artifactTag); Set<Long> updatedEventIDs = eventManager.updateEventsForArtifactTagAdded(artifact);
if (isNotEmpty(updatedEventIDs)) {
invalidateCaches(updatedEventIDs);
}
return postTagsAdded(updatedEventIDs); return postTagsAdded(updatedEventIDs);
} }
synchronized public boolean handleContentTagDeleted(ContentTagDeletedEvent evt) throws TskCoreException { synchronized public boolean handleContentTagDeleted(ContentTagDeletedEvent evt) throws TskCoreException {
DeletedContentTagInfo deletedTagInfo = evt.getDeletedTagInfo(); DeletedContentTagInfo deletedTagInfo = evt.getDeletedTagInfo();
Content content = autoCase.getSleuthkitCase().getContentById(deletedTagInfo.getContentID()); Content content = autoCase.getSleuthkitCase().getContentById(deletedTagInfo.getContentID());
boolean isContentTagged = autoCase.getServices().getTagsManager().getContentTagsByContent(content).isEmpty() == false; Set<Long> updatedEventIDs = eventManager.updateEventsForContentTagDeleted(content);
boolean isArtifactTagged = false; if (isNotEmpty(updatedEventIDs)) {
invalidateCaches(updatedEventIDs);
if(content instanceof BlackboardArtifact) {
isArtifactTagged = autoCase.getServices().getTagsManager().getBlackboardArtifactTagsByArtifact((BlackboardArtifact)content).isEmpty() == false;
} }
Set<Long> updatedEventIDs = deleteTag(content.getId(), null, deletedTagInfo.getTagID(), isArtifactTagged || isContentTagged);
return postTagsDeleted(updatedEventIDs); return postTagsDeleted(updatedEventIDs);
} }
synchronized public boolean handleArtifactTagDeleted(BlackBoardArtifactTagDeletedEvent evt) throws TskCoreException { synchronized public boolean handleArtifactTagDeleted(BlackBoardArtifactTagDeletedEvent evt) throws TskCoreException {
DeletedBlackboardArtifactTagInfo deletedTagInfo = evt.getDeletedTagInfo(); DeletedBlackboardArtifactTagInfo deletedTagInfo = evt.getDeletedTagInfo();
BlackboardArtifact artifact = autoCase.getSleuthkitCase().getBlackboardArtifact(deletedTagInfo.getArtifactID()); BlackboardArtifact artifact = autoCase.getSleuthkitCase().getBlackboardArtifact(deletedTagInfo.getArtifactID());
boolean isArtifactTagged = autoCase.getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact).isEmpty() == false; Set<Long> updatedEventIDs = eventManager.updateEventsForArtifactTagDeleted(artifact);
boolean isContentTagged = autoCase.getServices().getTagsManager().getContentTagsByContent(artifact).isEmpty() == false; if (isNotEmpty(updatedEventIDs)) {
Set<Long> updatedEventIDs = deleteTag(artifact.getObjectID(), artifact.getArtifactID(), deletedTagInfo.getTagID(), isArtifactTagged || isContentTagged); invalidateCaches(updatedEventIDs);
}
return postTagsDeleted(updatedEventIDs); return postTagsDeleted(updatedEventIDs);
} }
@ -507,7 +511,7 @@ public final class FilteredEventsModel {
* @throws org.sleuthkit.datamodel.TskCoreException * @throws org.sleuthkit.datamodel.TskCoreException
*/ */
public Set<Long> getEventIDsForFile(AbstractFile file, boolean includeDerivedArtifacts) throws TskCoreException { public Set<Long> getEventIDsForFile(AbstractFile file, boolean includeDerivedArtifacts) throws TskCoreException {
return eventManager.getEventIDsForFile(file, includeDerivedArtifacts); return eventManager.getEventIDsForContent(file, includeDerivedArtifacts);
} }
/** /**
@ -599,26 +603,11 @@ public final class FilteredEventsModel {
return eventManager.getEventTypes(); return eventManager.getEventTypes();
} }
synchronized public Set<Long> addTag(long objID, Long artifactID, Tag tag) throws TskCoreException { synchronized public Set<Long> setHashHit(Collection<BlackboardArtifact> artifacts) throws TskCoreException {
Set<Long> updatedEventIDs = eventManager.setEventsTagged(objID, artifactID, true);
if (isNotEmpty(updatedEventIDs)) {
invalidateCaches(updatedEventIDs);
}
return updatedEventIDs;
}
synchronized public Set<Long> deleteTag(long objID, Long artifactID, long tagID, boolean tagged) throws TskCoreException {
Set<Long> updatedEventIDs = eventManager.setEventsTagged(objID, artifactID, tagged);
if (isNotEmpty(updatedEventIDs)) {
invalidateCaches(updatedEventIDs);
}
return updatedEventIDs;
}
synchronized public Set<Long> setHashHit(Collection<BlackboardArtifact> artifacts, boolean hasHashHit) throws TskCoreException {
Set<Long> updatedEventIDs = new HashSet<>(); Set<Long> updatedEventIDs = new HashSet<>();
for (BlackboardArtifact artifact : artifacts) { for (BlackboardArtifact artifact : artifacts) {
updatedEventIDs.addAll(eventManager.setEventsHashed(artifact.getObjectID(), hasHashHit)); Content content = autoCase.getSleuthkitCase().getContentById(artifact.getObjectID());
updatedEventIDs.addAll(eventManager.updateEventsForHashSetHit(content));
} }
if (isNotEmpty(updatedEventIDs)) { if (isNotEmpty(updatedEventIDs)) {
invalidateCaches(updatedEventIDs); invalidateCaches(updatedEventIDs);

View File

@ -190,7 +190,7 @@ final class ShowInTimelineDialog extends Dialog<ViewInTimelineRequestedEvent> {
typeColumn.setCellValueFactory(param -> new SimpleObjectProperty<>(param.getValue().getEventType())); typeColumn.setCellValueFactory(param -> new SimpleObjectProperty<>(param.getValue().getEventType()));
typeColumn.setCellFactory(param -> new TypeTableCell<>()); typeColumn.setCellFactory(param -> new TypeTableCell<>());
dateTimeColumn.setCellValueFactory(param -> new SimpleObjectProperty<>(param.getValue().getStartMillis())); dateTimeColumn.setCellValueFactory(param -> new SimpleObjectProperty<>(param.getValue().getEventTimeInMs()));
dateTimeColumn.setCellFactory(param -> new DateTimeTableCell<>()); dateTimeColumn.setCellFactory(param -> new DateTimeTableCell<>());
//add events to table //add events to table
@ -307,7 +307,7 @@ final class ShowInTimelineDialog extends Dialog<ViewInTimelineRequestedEvent> {
*/ */
private ViewInTimelineRequestedEvent makeEventInTimeRange(TimelineEvent selectedEvent) { private ViewInTimelineRequestedEvent makeEventInTimeRange(TimelineEvent selectedEvent) {
Duration selectedDuration = unitComboBox.getSelectionModel().getSelectedItem().getBaseUnit().getDuration().multipliedBy(amountSpinner.getValue()); Duration selectedDuration = unitComboBox.getSelectionModel().getSelectedItem().getBaseUnit().getDuration().multipliedBy(amountSpinner.getValue());
Interval range = IntervalUtils.getIntervalAround(Instant.ofEpochMilli(selectedEvent.getStartMillis()), selectedDuration); Interval range = IntervalUtils.getIntervalAround(Instant.ofEpochMilli(selectedEvent.getEventTimeInMs()), selectedDuration);
return new ViewInTimelineRequestedEvent(Collections.singleton(selectedEvent.getEventID()), range); return new ViewInTimelineRequestedEvent(Collections.singleton(selectedEvent.getEventID()), range);
} }

View File

@ -93,6 +93,7 @@ import org.sleuthkit.datamodel.TimelineEvent;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TimelineEventType; import org.sleuthkit.datamodel.TimelineEventType;
import org.sleuthkit.datamodel.TimelineFilter.EventTypeFilter; import org.sleuthkit.datamodel.TimelineFilter.EventTypeFilter;
import org.sleuthkit.datamodel.TimelineLevelOfDetail;
/** /**
* Controller in the MVC design along with FilteredEventsModel TimeLineView. * Controller in the MVC design along with FilteredEventsModel TimeLineView.
@ -296,9 +297,9 @@ public class TimeLineController {
try { try {
InitialZoomState = new ZoomState(filteredEvents.getSpanningInterval(), InitialZoomState = new ZoomState(filteredEvents.getSpanningInterval(),
TimelineEventType.TypeLevel.BASE_TYPE, TimelineEventType.HierarchyLevel.CATEGORY,
filteredEvents.filterProperty().get(), filteredEvents.filterProperty().get(),
TimelineEvent.DescriptionLevel.SHORT); TimelineLevelOfDetail.LOW);
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
throw new TskCoreException("Error getting spanning interval.", ex); throw new TskCoreException("Error getting spanning interval.", ex);
} }
@ -492,7 +493,7 @@ public class TimeLineController {
return topComponent; return topComponent;
} }
synchronized public void pushEventTypeZoom(TimelineEventType.TypeLevel typeZoomeLevel) { synchronized public void pushEventTypeZoom(TimelineEventType.HierarchyLevel typeZoomeLevel) {
ZoomState currentZoom = filteredEvents.zoomStateProperty().get(); ZoomState currentZoom = filteredEvents.zoomStateProperty().get();
if (currentZoom == null) { if (currentZoom == null) {
advance(InitialZoomState.withTypeZoomLevel(typeZoomeLevel)); advance(InitialZoomState.withTypeZoomLevel(typeZoomeLevel));
@ -554,7 +555,7 @@ public class TimeLineController {
} }
} }
synchronized public void pushDescrLOD(TimelineEvent.DescriptionLevel newLOD) { synchronized public void pushDescrLOD(TimelineLevelOfDetail newLOD) {
ZoomState currentZoom = filteredEvents.zoomStateProperty().get(); ZoomState currentZoom = filteredEvents.zoomStateProperty().get();
if (currentZoom == null) { if (currentZoom == null) {
advance(InitialZoomState.withDescrLOD(newLOD)); advance(InitialZoomState.withDescrLOD(newLOD));
@ -564,7 +565,7 @@ public class TimeLineController {
} }
@SuppressWarnings("AssignmentToMethodParameter") //clamp timerange to case @SuppressWarnings("AssignmentToMethodParameter") //clamp timerange to case
synchronized public void pushTimeAndType(Interval timeRange, TimelineEventType.TypeLevel typeZoom) throws TskCoreException { synchronized public void pushTimeAndType(Interval timeRange, TimelineEventType.HierarchyLevel typeZoom) throws TskCoreException {
Interval overlappingTimeRange = this.filteredEvents.getSpanningInterval().overlap(timeRange); Interval overlappingTimeRange = this.filteredEvents.getSpanningInterval().overlap(timeRange);
ZoomState currentZoom = filteredEvents.zoomStateProperty().get(); ZoomState currentZoom = filteredEvents.zoomStateProperty().get();
if (currentZoom == null) { if (currentZoom == null) {
@ -745,7 +746,7 @@ public class TimeLineController {
case DATA_ADDED: case DATA_ADDED:
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == TSK_HASHSET_HIT.getTypeID()) { if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == TSK_HASHSET_HIT.getTypeID()) {
logFutureException(executor.submit(() -> filteredEvents.setHashHit(eventData.getArtifacts(), true)), logFutureException(executor.submit(() -> filteredEvents.setHashHit(eventData.getArtifacts())),
"Error executing task in response to DATA_ADDED event.", "Error executing task in response to DATA_ADDED event.",
"Error executing response to new data."); "Error executing response to new data.");
} }

View File

@ -57,6 +57,7 @@ import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TimelineEventType; import org.sleuthkit.datamodel.TimelineEventType;
import org.sleuthkit.datamodel.TimelineEvent; import org.sleuthkit.datamodel.TimelineEvent;
import org.sleuthkit.datamodel.TimelineLevelOfDetail;
/** /**
* * Explorer Node for a TimelineEvent. * * Explorer Node for a TimelineEvent.
@ -113,7 +114,7 @@ public class EventNode extends DisplayableItemNode {
properties.put(new NodeProperty<>("icon", Bundle.NodeProperty_displayName_icon(), "icon", true)); // NON-NLS //gets overridden with icon properties.put(new NodeProperty<>("icon", Bundle.NodeProperty_displayName_icon(), "icon", true)); // NON-NLS //gets overridden with icon
properties.put(new TimeProperty("time", Bundle.NodeProperty_displayName_dateTime(), "time ", getDateTimeString()));// NON-NLS properties.put(new TimeProperty("time", Bundle.NodeProperty_displayName_dateTime(), "time ", getDateTimeString()));// NON-NLS
properties.put(new NodeProperty<>("description", Bundle.NodeProperty_displayName_description(), "description", event.getFullDescription())); // NON-NLS properties.put(new NodeProperty<>("description", Bundle.NodeProperty_displayName_description(), "description", event.getDescription(TimelineLevelOfDetail.HIGH))); // NON-NLS
properties.put(new NodeProperty<>("eventType", Bundle.NodeProperty_displayName_eventType(), "event type", event.getEventType().getDisplayName())); // NON-NLS properties.put(new NodeProperty<>("eventType", Bundle.NodeProperty_displayName_eventType(), "event type", event.getEventType().getDisplayName())); // NON-NLS
return sheet; return sheet;
@ -127,7 +128,7 @@ public class EventNode extends DisplayableItemNode {
* controller's time zone setting. * controller's time zone setting.
*/ */
private String getDateTimeString() { private String getDateTimeString() {
return new DateTime(event.getStartMillis(), DateTimeZone.UTC).toString(TimeLineController.getZonedFormatter()); return new DateTime(event.getEventTimeInMs(), DateTimeZone.UTC).toString(TimeLineController.getZonedFormatter());
} }
@Override @Override
@ -270,7 +271,7 @@ public class EventNode extends DisplayableItemNode {
* data in the lookup. * data in the lookup.
*/ */
final TimelineEvent eventById = eventsModel.getEventById(eventID); final TimelineEvent eventById = eventsModel.getEventById(eventID);
Content file = sleuthkitCase.getContentById(eventById.getFileObjID()); Content file = sleuthkitCase.getContentById(eventById.getContentObjID());
if (eventById.getArtifactID().isPresent()) { if (eventById.getArtifactID().isPresent()) {
BlackboardArtifact blackboardArtifact = sleuthkitCase.getBlackboardArtifact(eventById.getArtifactID().get()); BlackboardArtifact blackboardArtifact = sleuthkitCase.getBlackboardArtifact(eventById.getArtifactID().get());

View File

@ -107,15 +107,15 @@ final public class EventTypeUtils {
return Color.hsb(359, .9, .9, 0); return Color.hsb(359, .9, .9, 0);
} }
TimelineEventType superType = type.getSuperType(); TimelineEventType superType = type.getParent();
Color baseColor = getColor(superType); Color baseColor = getColor(superType);
int siblings = superType.getSiblingTypes().stream() int siblings = superType.getSiblings().stream()
.max((type1, type2) -> Integer.compare(type1.getSubTypes().size(), type2.getSubTypes().size())) .max((type1, type2) -> Integer.compare(type1.getChildren().size(), type2.getChildren().size()))
.get().getSubTypes().size() + 1; .get().getChildren().size() + 1;
int superSiblingsCount = superType.getSiblingTypes().size(); int superSiblingsCount = superType.getSiblings().size();
int ordinal = new ArrayList<>(type.getSiblingTypes()).indexOf(type); int ordinal = new ArrayList<>(type.getSiblings()).indexOf(type);
double offset = (360.0 / superSiblingsCount) / siblings; double offset = (360.0 / superSiblingsCount) / siblings;
Color deriveColor = baseColor.deriveColor(ordinal * offset, 1, 1, 1); Color deriveColor = baseColor.deriveColor(ordinal * offset, 1, 1, 1);

View File

@ -207,7 +207,7 @@ final class EventCountsChart extends StackedBarChart<String, Number> implements
final Node node = item.getNode(); final Node node = item.getNode();
if (node != null) { if (node != null) {
node.setStyle("-fx-border-width: 2; " node.setStyle("-fx-border-width: 2; "
+ " -fx-border-color: " + ColorUtilities.getRGBCode(getColor(eventType.getSuperType())) + "; " + " -fx-border-color: " + ColorUtilities.getRGBCode(getColor(eventType.getParent())) + "; "
+ " -fx-bar-fill: " + ColorUtilities.getRGBCode(getColor(eventType))); // NON-NLS + " -fx-bar-fill: " + ColorUtilities.getRGBCode(getColor(eventType))); // NON-NLS
node.setCursor(Cursor.HAND); node.setCursor(Cursor.HAND);

View File

@ -62,7 +62,7 @@ import org.sleuthkit.autopsy.timeline.ui.detailview.datamodel.DetailsViewModel;
import org.sleuthkit.autopsy.timeline.ui.detailview.datamodel.EventStripe; import org.sleuthkit.autopsy.timeline.ui.detailview.datamodel.EventStripe;
import org.sleuthkit.autopsy.timeline.utils.MappedList; import org.sleuthkit.autopsy.timeline.utils.MappedList;
import org.sleuthkit.autopsy.timeline.zooming.ZoomState; import org.sleuthkit.autopsy.timeline.zooming.ZoomState;
import org.sleuthkit.datamodel.TimelineEvent; import org.sleuthkit.datamodel.TimelineLevelOfDetail;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
/** /**
@ -192,7 +192,7 @@ final public class DetailViewPane extends AbstractTimelineChart<DateTime, EventS
* *
* @return a new Action that will unhide events with the given description. * @return a new Action that will unhide events with the given description.
*/ */
public Action newUnhideDescriptionAction(String description, TimelineEvent.DescriptionLevel descriptionLoD) { public Action newUnhideDescriptionAction(String description, TimelineLevelOfDetail descriptionLoD) {
return new UnhideDescriptionAction(description, descriptionLoD, getChart()); return new UnhideDescriptionAction(description, descriptionLoD, getChart());
} }
@ -204,7 +204,7 @@ final public class DetailViewPane extends AbstractTimelineChart<DateTime, EventS
* *
* @return a new Action that will hide events with the given description. * @return a new Action that will hide events with the given description.
*/ */
public Action newHideDescriptionAction(String description, TimelineEvent.DescriptionLevel descriptionLoD) { public Action newHideDescriptionAction(String description, TimelineLevelOfDetail descriptionLoD) {
return new HideDescriptionAction(description, descriptionLoD, getChart()); return new HideDescriptionAction(description, descriptionLoD, getChart());
} }

View File

@ -59,7 +59,7 @@ import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.SqlFilterState;
import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.DescriptionFilter; import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.DescriptionFilter;
import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.RootFilterState; import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.RootFilterState;
import org.sleuthkit.autopsy.timeline.zooming.ZoomState; import org.sleuthkit.autopsy.timeline.zooming.ZoomState;
import org.sleuthkit.datamodel.TimelineEvent; import org.sleuthkit.datamodel.TimelineLevelOfDetail;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TimelineEventType; import org.sleuthkit.datamodel.TimelineEventType;
import org.sleuthkit.datamodel.TimelineEvent; import org.sleuthkit.datamodel.TimelineEvent;
@ -181,7 +181,7 @@ final class EventClusterNode extends MultiEventNodeBase<EventCluster, EventStrip
.intersect(new SqlFilterState<>( .intersect(new SqlFilterState<>(
new EventTypeFilter(getEventType()), true)); new EventTypeFilter(getEventType()), true));
final Interval subClusterSpan = new Interval(getStartMillis(), getEndMillis() + 1000); final Interval subClusterSpan = new Interval(getStartMillis(), getEndMillis() + 1000);
final TimelineEventType.TypeLevel eventTypeZoomLevel = eventsModel.getEventTypeZoom(); final TimelineEventType.HierarchyLevel eventTypeZoomLevel = eventsModel.getEventTypeZoom();
final ZoomState zoom = new ZoomState(subClusterSpan, eventTypeZoomLevel, subClusterFilter, getDescriptionLevel()); final ZoomState zoom = new ZoomState(subClusterSpan, eventTypeZoomLevel, subClusterFilter, getDescriptionLevel());
DescriptionFilter descriptionFilter = new DescriptionFilter(getEvent().getDescriptionLevel(), getDescription()); DescriptionFilter descriptionFilter = new DescriptionFilter(getEvent().getDescriptionLevel(), getDescription());
@ -191,14 +191,14 @@ final class EventClusterNode extends MultiEventNodeBase<EventCluster, EventStrip
Task<List<EventStripe>> loggedTask; Task<List<EventStripe>> loggedTask;
loggedTask = new LoggedTask<List<EventStripe>>(Bundle.EventClusterNode_loggedTask_name(), false) { loggedTask = new LoggedTask<List<EventStripe>>(Bundle.EventClusterNode_loggedTask_name(), false) {
private volatile TimelineEvent.DescriptionLevel loadedDescriptionLevel = withRelativeDetail(getDescriptionLevel(), relativeDetail); private volatile TimelineLevelOfDetail loadedDescriptionLevel = withRelativeDetail(getDescriptionLevel(), relativeDetail);
@Override @Override
protected List<EventStripe> call() throws Exception { protected List<EventStripe> call() throws Exception {
//newly loaded substripes //newly loaded substripes
List<EventStripe> stripes; List<EventStripe> stripes;
//next LoD in diraction of given relativeDetail //next LoD in diraction of given relativeDetail
TimelineEvent.DescriptionLevel next = loadedDescriptionLevel; TimelineLevelOfDetail next = loadedDescriptionLevel;
do { do {
loadedDescriptionLevel = next; loadedDescriptionLevel = next;
if (loadedDescriptionLevel == getEvent().getDescriptionLevel()) { if (loadedDescriptionLevel == getEvent().getDescriptionLevel()) {
@ -311,7 +311,7 @@ final class EventClusterNode extends MultiEventNodeBase<EventCluster, EventStrip
}); });
//disabled if the given node is already at full description level of detail //disabled if the given node is already at full description level of detail
disabledProperty().bind(node.descriptionLoDProperty().isEqualTo(TimelineEvent.DescriptionLevel.FULL)); disabledProperty().bind(node.descriptionLoDProperty().isEqualTo(TimelineLevelOfDetail.HIGH));
} }
} }
@ -346,7 +346,7 @@ final class EventClusterNode extends MultiEventNodeBase<EventCluster, EventStrip
LESS; LESS;
} }
private static TimelineEvent.DescriptionLevel withRelativeDetail(TimelineEvent.DescriptionLevel LoD, RelativeDetail relativeDetail) { private static TimelineLevelOfDetail withRelativeDetail(TimelineLevelOfDetail LoD, RelativeDetail relativeDetail) {
switch (relativeDetail) { switch (relativeDetail) {
case EQUAL: case EQUAL:
return LoD; return LoD;

View File

@ -148,10 +148,10 @@ public abstract class EventNodeBase<Type extends DetailViewEvent> extends StackP
show(tagIV, false); show(tagIV, false);
} }
if (chartLane.getController().getEventsModel().getEventTypeZoom() == TimelineEventType.TypeLevel.SUB_TYPE) { if (chartLane.getController().getEventsModel().getEventTypeZoom() == TimelineEventType.HierarchyLevel.CATEGORY) {
evtColor = getColor(getEventType()); evtColor = getColor(getEventType());
} else { } else {
evtColor = getColor(getEventType().getBaseType()); evtColor = getColor(getEventType().getCategory());
} }
SELECTION_BORDER = new Border(new BorderStroke(evtColor.darker().desaturate(), BorderStrokeStyle.SOLID, CORNER_RADII_3, new BorderWidths(2))); SELECTION_BORDER = new Border(new BorderStroke(evtColor.darker().desaturate(), BorderStrokeStyle.SOLID, CORNER_RADII_3, new BorderWidths(2)));

View File

@ -24,7 +24,7 @@ import org.controlsfx.control.action.Action;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.DescriptionFilter; import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.DescriptionFilter;
import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.DescriptionFilterState; import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.DescriptionFilterState;
import org.sleuthkit.datamodel.TimelineEvent; import org.sleuthkit.datamodel.TimelineLevelOfDetail;
/** /**
* An Action that hides, in the given chart, events that have the given * An Action that hides, in the given chart, events that have the given
@ -36,7 +36,7 @@ class HideDescriptionAction extends Action {
private static final Image HIDE = new Image("/org/sleuthkit/autopsy/timeline/images/eye--minus.png"); // NON-NLS private static final Image HIDE = new Image("/org/sleuthkit/autopsy/timeline/images/eye--minus.png"); // NON-NLS
HideDescriptionAction(String description, TimelineEvent.DescriptionLevel descriptionLoD, DetailsChart chart) { HideDescriptionAction(String description, TimelineLevelOfDetail descriptionLoD, DetailsChart chart) {
super(Bundle.HideDescriptionAction_displayName()); super(Bundle.HideDescriptionAction_displayName());
setLongText(Bundle.HideDescriptionAction_displayMsg()); setLongText(Bundle.HideDescriptionAction_displayMsg());
setGraphic(new ImageView(HIDE)); setGraphic(new ImageView(HIDE));

View File

@ -36,7 +36,7 @@ import javafx.scene.layout.Pane;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.timeline.ui.detailview.datamodel.MultiEvent; import org.sleuthkit.autopsy.timeline.ui.detailview.datamodel.MultiEvent;
import org.sleuthkit.datamodel.TimelineEvent; import org.sleuthkit.datamodel.TimelineLevelOfDetail;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
/** /**
@ -52,7 +52,7 @@ abstract class MultiEventNodeBase< BundleType extends MultiEvent<ParentType>, Pa
final ObservableList<EventNodeBase<?>> subNodes = FXCollections.observableArrayList(); final ObservableList<EventNodeBase<?>> subNodes = FXCollections.observableArrayList();
final Pane subNodePane = new Pane(); final Pane subNodePane = new Pane();
private final ReadOnlyObjectWrapper<TimelineEvent.DescriptionLevel> descLOD = new ReadOnlyObjectWrapper<>(); private final ReadOnlyObjectWrapper<TimelineLevelOfDetail> descLOD = new ReadOnlyObjectWrapper<>();
MultiEventNodeBase(DetailsChartLane<?> chartLane, BundleType event, ParentNodeType parentNode) { MultiEventNodeBase(DetailsChartLane<?> chartLane, BundleType event, ParentNodeType parentNode) {
super(event, parentNode, chartLane); super(event, parentNode, chartLane);
@ -80,18 +80,18 @@ abstract class MultiEventNodeBase< BundleType extends MultiEvent<ParentType>, Pa
Bindings.bindContent(subNodePane.getChildren(), subNodes); Bindings.bindContent(subNodePane.getChildren(), subNodes);
} }
public ReadOnlyObjectProperty<TimelineEvent.DescriptionLevel> descriptionLoDProperty() { public ReadOnlyObjectProperty<TimelineLevelOfDetail> descriptionLoDProperty() {
return descLOD.getReadOnlyProperty(); return descLOD.getReadOnlyProperty();
} }
final TimelineEvent.DescriptionLevel getDescriptionLevel() { final TimelineLevelOfDetail getDescriptionLevel() {
return descLOD.get(); return descLOD.get();
} }
/** /**
* *
*/ */
final void setDescriptionLOD(final TimelineEvent.DescriptionLevel descriptionLoD) { final void setDescriptionLOD(final TimelineLevelOfDetail descriptionLoD) {
descLOD.set(descriptionLoD); descLOD.set(descriptionLoD);
} }

View File

@ -23,7 +23,7 @@ import javafx.scene.image.ImageView;
import org.controlsfx.control.action.Action; import org.controlsfx.control.action.Action;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.DescriptionFilter; import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.DescriptionFilter;
import org.sleuthkit.datamodel.TimelineEvent; import org.sleuthkit.datamodel.TimelineLevelOfDetail;
/** /**
* An Action that un-hides, in the given chart, events with the given * An Action that un-hides, in the given chart, events with the given
@ -34,7 +34,7 @@ class UnhideDescriptionAction extends Action {
private static final Image SHOW = new Image("/org/sleuthkit/autopsy/timeline/images/eye--plus.png"); // NON-NLS private static final Image SHOW = new Image("/org/sleuthkit/autopsy/timeline/images/eye--plus.png"); // NON-NLS
UnhideDescriptionAction(String description, TimelineEvent.DescriptionLevel descriptionLoD, DetailsChart chart) { UnhideDescriptionAction(String description, TimelineLevelOfDetail descriptionLoD, DetailsChart chart) {
super(Bundle.UnhideDescriptionAction_displayName()); super(Bundle.UnhideDescriptionAction_displayName());
setGraphic(new ImageView(SHOW)); setGraphic(new ImageView(SHOW));

View File

@ -22,7 +22,7 @@ import java.util.Comparator;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.SortedSet; import java.util.SortedSet;
import org.sleuthkit.datamodel.TimelineEvent; import org.sleuthkit.datamodel.TimelineLevelOfDetail;
import org.sleuthkit.datamodel.TimelineEventType; import org.sleuthkit.datamodel.TimelineEventType;
/** /**
@ -49,7 +49,7 @@ public interface DetailViewEvent {
* *
* @return the description level of detail of the given events * @return the description level of detail of the given events
*/ */
public TimelineEvent.DescriptionLevel getDescriptionLevel(); public TimelineLevelOfDetail getDescriptionLevel();
/** /**
* get the EventStripe (if any) that contains this event. * get the EventStripe (if any) that contains this event.

View File

@ -37,6 +37,7 @@ import java.util.SortedSet;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.ImmutablePair;
@ -57,6 +58,7 @@ import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TimelineEventType; import org.sleuthkit.datamodel.TimelineEventType;
import org.sleuthkit.datamodel.TimelineEvent; import org.sleuthkit.datamodel.TimelineEvent;
import org.sleuthkit.datamodel.TimelineFilter; import org.sleuthkit.datamodel.TimelineFilter;
import org.sleuthkit.datamodel.TimelineLevelOfDetail;
/** /**
* Model for the Details View. Uses FilteredEventsModel as underlying datamodel * Model for the Details View. Uses FilteredEventsModel as underlying datamodel
@ -115,19 +117,21 @@ final public class DetailsViewModel {
DateTimeZone timeZone = TimeLineController.getJodaTimeZone(); DateTimeZone timeZone = TimeLineController.getJodaTimeZone();
//unpack params //unpack params
Interval timeRange = zoom.getTimeRange(); Interval timeRange = zoom.getTimeRange();
TimelineEvent.DescriptionLevel descriptionLOD = zoom.getDescriptionLOD(); TimelineLevelOfDetail descriptionLOD = zoom.getDescriptionLOD();
TimelineEventType.TypeLevel typeZoomLevel = zoom.getTypeZoomLevel();
//intermediate results //intermediate results
Map<TimelineEventType, SetMultimap< String, EventCluster>> eventClusters = new HashMap<>(); Map<TimelineEventType, SetMultimap< String, EventCluster>> eventClusters = new HashMap<>();
try { try {
eventCache.get(zoom).stream() eventCache.get(zoom).stream()
.filter(uiFilter) .filter(uiFilter)
.forEach(event -> { .forEach(new Consumer<TimelineEvent>() {
TimelineEventType clusterType = event.getEventType(typeZoomLevel); @Override
eventClusters.computeIfAbsent(clusterType, eventType -> HashMultimap.create()) public void accept(TimelineEvent event) {
.put(event.getDescription(descriptionLOD), new EventCluster(event, clusterType, descriptionLOD)); TimelineEventType clusterType = event.getEventType().getCategory();
}); eventClusters.computeIfAbsent(clusterType, eventType -> HashMultimap.create())
.put(event.getDescription(descriptionLOD), new EventCluster(event, clusterType, descriptionLOD));
}
});
//get some info about the time range requested //get some info about the time range requested
TimeUnits periodSize = RangeDivision.getRangeDivision(timeRange, timeZone).getPeriodSize(); TimeUnits periodSize = RangeDivision.getRangeDivision(timeRange, timeZone).getPeriodSize();
return mergeClustersToStripes(periodSize.toUnitPeriod(), eventClusters); return mergeClustersToStripes(periodSize.toUnitPeriod(), eventClusters);

View File

@ -28,9 +28,9 @@ import java.util.Set;
import java.util.SortedSet; import java.util.SortedSet;
import org.joda.time.Interval; import org.joda.time.Interval;
import org.sleuthkit.autopsy.timeline.utils.IntervalUtils; import org.sleuthkit.autopsy.timeline.utils.IntervalUtils;
import org.sleuthkit.datamodel.TimelineEvent;
import org.sleuthkit.datamodel.TimelineEventType; import org.sleuthkit.datamodel.TimelineEventType;
import org.sleuthkit.datamodel.TimelineEvent; import org.sleuthkit.datamodel.TimelineEvent;
import org.sleuthkit.datamodel.TimelineLevelOfDetail;
/** /**
* Represents a set of other events clustered together. All the sub events * Represents a set of other events clustered together. All the sub events
@ -59,7 +59,7 @@ public class EventCluster implements MultiEvent<EventStripe> {
/** /**
* the description level of detail that the events were clustered at. * the description level of detail that the events were clustered at.
*/ */
private final TimelineEvent.DescriptionLevel lod; private final TimelineLevelOfDetail lod;
/** /**
* the set of ids of the clustered events * the set of ids of the clustered events
@ -126,7 +126,7 @@ public class EventCluster implements MultiEvent<EventStripe> {
} }
private EventCluster(Interval spanningInterval, TimelineEventType type, Set<Long> eventIDs, private EventCluster(Interval spanningInterval, TimelineEventType type, Set<Long> eventIDs,
Set<Long> hashHits, Set<Long> tagged, String description, TimelineEvent.DescriptionLevel lod, Set<Long> hashHits, Set<Long> tagged, String description, TimelineLevelOfDetail lod,
EventStripe parent) { EventStripe parent) {
this.span = spanningInterval; this.span = spanningInterval;
@ -141,19 +141,19 @@ public class EventCluster implements MultiEvent<EventStripe> {
} }
public EventCluster(Interval spanningInterval, TimelineEventType type, Set<Long> eventIDs, public EventCluster(Interval spanningInterval, TimelineEventType type, Set<Long> eventIDs,
Set<Long> hashHits, Set<Long> tagged, String description, TimelineEvent.DescriptionLevel lod) { Set<Long> hashHits, Set<Long> tagged, String description, TimelineLevelOfDetail lod) {
this(spanningInterval, type, eventIDs, hashHits, tagged, description, lod, null); this(spanningInterval, type, eventIDs, hashHits, tagged, description, lod, null);
} }
public EventCluster(TimelineEvent event, TimelineEventType type, TimelineEvent.DescriptionLevel lod) { public EventCluster(TimelineEvent event, TimelineEventType type, TimelineLevelOfDetail lod) {
this.span = new Interval(event.getStartMillis(), event.getEndMillis()); this.span = new Interval(event.getEventTimeInMs(), event.getEventTimeInMs());
this.type = type; this.type = type;
this.eventIDs = new HashSet<>(); this.eventIDs = new HashSet<>();
this.eventIDs.add(event.getEventID()); this.eventIDs.add(event.getEventID());
this.hashHits = event.isHashHit() ? new HashSet<>(eventIDs) : emptySet(); this.hashHits = event.eventSourceHasHashHits()? new HashSet<>(eventIDs) : emptySet();
this.tagged = event.isTagged() ? new HashSet<>(eventIDs) : emptySet(); this.tagged = event.eventSourceIsTagged()? new HashSet<>(eventIDs) : emptySet();
this.lod = lod; this.lod = lod;
this.description = event.getDescription(lod); this.description = event.getDescription(lod);
this.parent = null; this.parent = null;
@ -222,7 +222,7 @@ public class EventCluster implements MultiEvent<EventStripe> {
} }
@Override @Override
public TimelineEvent.DescriptionLevel getDescriptionLevel() { public TimelineLevelOfDetail getDescriptionLevel() {
return lod; return lod;
} }

View File

@ -26,7 +26,7 @@ import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.SortedSet; import java.util.SortedSet;
import org.sleuthkit.datamodel.TimelineEvent; import org.sleuthkit.datamodel.TimelineLevelOfDetail;
import org.sleuthkit.datamodel.TimelineEventType; import org.sleuthkit.datamodel.TimelineEventType;
/** /**
@ -52,7 +52,7 @@ public final class EventStripe implements MultiEvent<EventCluster> {
/** /**
* the description level of detail that the events were clustered at. * the description level of detail that the events were clustered at.
*/ */
private final TimelineEvent.DescriptionLevel lod; private final TimelineLevelOfDetail lod;
/** /**
* the set of ids of the events * the set of ids of the events
@ -88,7 +88,7 @@ public final class EventStripe implements MultiEvent<EventCluster> {
} }
private EventStripe(EventCluster parent, TimelineEventType type, String description, private EventStripe(EventCluster parent, TimelineEventType type, String description,
TimelineEvent.DescriptionLevel lod, SortedSet<EventCluster> clusters, TimelineLevelOfDetail lod, SortedSet<EventCluster> clusters,
Set<Long> eventIDs, Set<Long> tagged, Set<Long> hashHits) { Set<Long> eventIDs, Set<Long> tagged, Set<Long> hashHits) {
this.parent = parent; this.parent = parent;
this.type = type; this.type = type;
@ -151,7 +151,7 @@ public final class EventStripe implements MultiEvent<EventCluster> {
} }
@Override @Override
public TimelineEvent.DescriptionLevel getDescriptionLevel() { public TimelineLevelOfDetail getDescriptionLevel() {
return lod; return lod;
} }

View File

@ -28,6 +28,7 @@ import java.util.SortedSet;
import org.joda.time.Interval; import org.joda.time.Interval;
import org.sleuthkit.datamodel.TimelineEvent; import org.sleuthkit.datamodel.TimelineEvent;
import org.sleuthkit.datamodel.TimelineEventType; import org.sleuthkit.datamodel.TimelineEventType;
import org.sleuthkit.datamodel.TimelineLevelOfDetail;
/** /**
* A single event. * A single event.
@ -65,7 +66,7 @@ public class SingleDetailsViewEvent implements DetailViewEvent {
* The three descriptions (full, med, short) stored in a map, keyed by * The three descriptions (full, med, short) stored in a map, keyed by
* DescriptionLOD (Level of Detail) * DescriptionLOD (Level of Detail)
*/ */
private final ImmutableMap<TimelineEvent.DescriptionLevel, String> descriptions; private final ImmutableMap<TimelineLevelOfDetail, String> descriptions;
/** /**
* True if the file this event is derived from hits any of the configured * True if the file this event is derived from hits any of the configured
@ -106,9 +107,9 @@ public class SingleDetailsViewEvent implements DetailViewEvent {
this.artifactID = Long.valueOf(0).equals(artifactID) ? null : artifactID; this.artifactID = Long.valueOf(0).equals(artifactID) ? null : artifactID;
this.time = time; this.time = time;
this.type = type; this.type = type;
descriptions = ImmutableMap.<TimelineEvent.DescriptionLevel, String>of(TimelineEvent.DescriptionLevel.FULL, fullDescription, descriptions = ImmutableMap.<TimelineLevelOfDetail, String>of(TimelineLevelOfDetail.HIGH, fullDescription,
TimelineEvent.DescriptionLevel.MEDIUM, medDescription, TimelineLevelOfDetail.MEDIUM, medDescription,
TimelineEvent.DescriptionLevel.SHORT, shortDescription); TimelineLevelOfDetail.LOW, shortDescription);
this.hashHit = hashHit; this.hashHit = hashHit;
this.tagged = tagged; this.tagged = tagged;
} }
@ -116,15 +117,15 @@ public class SingleDetailsViewEvent implements DetailViewEvent {
public SingleDetailsViewEvent(TimelineEvent singleEvent) { public SingleDetailsViewEvent(TimelineEvent singleEvent) {
this(singleEvent.getEventID(), this(singleEvent.getEventID(),
singleEvent.getDataSourceObjID(), singleEvent.getDataSourceObjID(),
singleEvent.getFileObjID(), singleEvent.getContentObjID(),
singleEvent.getArtifactID().orElse(null), singleEvent.getArtifactID().orElse(null),
singleEvent.getTime(), singleEvent.getTime(),
singleEvent.getEventType(), singleEvent.getEventType(),
singleEvent.getFullDescription(), singleEvent.getDescription(TimelineLevelOfDetail.HIGH),
singleEvent.getMedDescription(), singleEvent.getDescription(TimelineLevelOfDetail.MEDIUM),
singleEvent.getShortDescription(), singleEvent.getDescription(TimelineLevelOfDetail.LOW),
singleEvent.isHashHit(), singleEvent.eventSourceHasHashHits(),
singleEvent.isTagged()); singleEvent.eventSourceIsTagged());
} }
/** /**
@ -137,7 +138,7 @@ public class SingleDetailsViewEvent implements DetailViewEvent {
* with the given parent. * with the given parent.
*/ */
public SingleDetailsViewEvent withParent(MultiEvent<?> newParent) { public SingleDetailsViewEvent withParent(MultiEvent<?> newParent) {
SingleDetailsViewEvent singleEvent = new SingleDetailsViewEvent(eventID, dataSourceObjId, fileObjId, artifactID, time, type, descriptions.get(TimelineEvent.DescriptionLevel.FULL), descriptions.get(TimelineEvent.DescriptionLevel.MEDIUM), descriptions.get(TimelineEvent.DescriptionLevel.SHORT), hashHit, tagged); SingleDetailsViewEvent singleEvent = new SingleDetailsViewEvent(eventID, dataSourceObjId, fileObjId, artifactID, time, type, descriptions.get(TimelineLevelOfDetail.HIGH), descriptions.get(TimelineLevelOfDetail.MEDIUM), descriptions.get(TimelineLevelOfDetail.LOW), hashHit, tagged);
singleEvent.parent = newParent; singleEvent.parent = newParent;
return singleEvent; return singleEvent;
} }
@ -212,7 +213,7 @@ public class SingleDetailsViewEvent implements DetailViewEvent {
* @return the full description * @return the full description
*/ */
public String getFullDescription() { public String getFullDescription() {
return getDescription(TimelineEvent.DescriptionLevel.FULL); return getDescription(TimelineLevelOfDetail.HIGH);
} }
/** /**
@ -221,7 +222,7 @@ public class SingleDetailsViewEvent implements DetailViewEvent {
* @return the medium description * @return the medium description
*/ */
public String getMedDescription() { public String getMedDescription() {
return getDescription(TimelineEvent.DescriptionLevel.MEDIUM); return getDescription(TimelineLevelOfDetail.MEDIUM);
} }
/** /**
@ -230,7 +231,7 @@ public class SingleDetailsViewEvent implements DetailViewEvent {
* @return the short description * @return the short description
*/ */
public String getShortDescription() { public String getShortDescription() {
return getDescription(TimelineEvent.DescriptionLevel.SHORT); return getDescription(TimelineLevelOfDetail.LOW);
} }
/** /**
@ -240,7 +241,7 @@ public class SingleDetailsViewEvent implements DetailViewEvent {
* *
* @return The description of this event at the given level of detail. * @return The description of this event at the given level of detail.
*/ */
public String getDescription(TimelineEvent.DescriptionLevel lod) { public String getDescription(TimelineLevelOfDetail lod) {
return descriptions.get(lod); return descriptions.get(lod);
} }
@ -299,7 +300,7 @@ public class SingleDetailsViewEvent implements DetailViewEvent {
@Override @Override
public SortedSet<EventCluster> getClusters() { public SortedSet<EventCluster> getClusters() {
EventCluster eventCluster = new EventCluster(new Interval(time * 1000, time * 1000), type, getEventIDs(), getEventIDsWithHashHits(), getEventIDsWithTags(), getFullDescription(), TimelineEvent.DescriptionLevel.FULL); EventCluster eventCluster = new EventCluster(new Interval(time * 1000, time * 1000), type, getEventIDs(), getEventIDsWithHashHits(), getEventIDsWithTags(), getFullDescription(), TimelineLevelOfDetail.HIGH);
return ImmutableSortedSet.orderedBy(Comparator.comparing(EventCluster::getStartMillis)).add(eventCluster).build(); return ImmutableSortedSet.orderedBy(Comparator.comparing(EventCluster::getStartMillis)).add(eventCluster).build();
} }
@ -309,8 +310,8 @@ public class SingleDetailsViewEvent implements DetailViewEvent {
} }
@Override @Override
public TimelineEvent.DescriptionLevel getDescriptionLevel() { public TimelineLevelOfDetail getDescriptionLevel() {
return TimelineEvent.DescriptionLevel.FULL; return TimelineLevelOfDetail.HIGH;
} }
/** /**

View File

@ -29,9 +29,9 @@ import org.sleuthkit.autopsy.timeline.ui.detailview.datamodel.DetailViewEvent;
import org.sleuthkit.datamodel.TimelineEventType; import org.sleuthkit.datamodel.TimelineEventType;
/** /**
* EventTreeItem for base event types (file system, misc, web, ...) * EventTreeItem for category event types (file system, misc, web, ...)
*/ */
class BaseTypeTreeItem extends EventTypeTreeItem { class CategoryTypeTreeItem extends EventTypeTreeItem {
/** /**
* A map of the children TreeItems, keyed by EventTypes if the children are * A map of the children TreeItems, keyed by EventTypes if the children are
@ -46,8 +46,8 @@ class BaseTypeTreeItem extends EventTypeTreeItem {
* @param comparator the initial comparator used to sort the children of * @param comparator the initial comparator used to sort the children of
* this tree item * this tree item
*/ */
BaseTypeTreeItem(DetailViewEvent event, Comparator<TreeItem<DetailViewEvent>> comparator) { CategoryTypeTreeItem(DetailViewEvent event, Comparator<TreeItem<DetailViewEvent>> comparator) {
super(event.getEventType().getBaseType(), comparator); super(event.getEventType().getCategory(), comparator);
} }
@ThreadConfined(type = ThreadConfined.ThreadType.JFX) @ThreadConfined(type = ThreadConfined.ThreadType.JFX)
@ -61,7 +61,7 @@ class BaseTypeTreeItem extends EventTypeTreeItem {
* if the stripe and this tree item have the same type, create a * if the stripe and this tree item have the same type, create a
* description tree item, else create a sub-type tree item * description tree item, else create a sub-type tree item
*/ */
if (head.getEventType().getTypeLevel() == TimelineEventType.TypeLevel.SUB_TYPE) { if (head.getEventType().getTypeHierarchyLevel() == TimelineEventType.HierarchyLevel.CATEGORY) {
descriptionKey = head.getEventType().getDisplayName(); descriptionKey = head.getEventType().getDisplayName();
treeItemConstructor = () -> configureNewTreeItem(new SubTypeTreeItem(head, getComparator())); treeItemConstructor = () -> configureNewTreeItem(new SubTypeTreeItem(head, getComparator()));
} else { } else {
@ -87,7 +87,7 @@ class BaseTypeTreeItem extends EventTypeTreeItem {
* if the stripe and this tree item have the same type, get the child * if the stripe and this tree item have the same type, get the child
* item keyed on event type, else keyed on description. * item keyed on event type, else keyed on description.
*/ */
if (head.getEventType().getTypeLevel() == TimelineEventType.TypeLevel.SUB_TYPE) { if (head.getEventType().getTypeHierarchyLevel()== TimelineEventType.HierarchyLevel.CATEGORY) {
descTreeItem = childMap.get(head.getEventType().getDisplayName()); descTreeItem = childMap.get(head.getEventType().getDisplayName());
} else { } else {
path.remove(0); //remove head of list if we are going straight to description path.remove(0); //remove head of list if we are going straight to description

View File

@ -35,7 +35,7 @@ class RootItem extends EventsTreeItem {
/** /**
* A map of the children BaseTypeTreeItems, keyed by EventType. * A map of the children BaseTypeTreeItems, keyed by EventType.
*/ */
private final Map<TimelineEventType, BaseTypeTreeItem> childMap = new HashMap<>(); private final Map<TimelineEventType, CategoryTypeTreeItem> childMap = new HashMap<>();
/** /**
* Constructor * Constructor
@ -85,7 +85,7 @@ class RootItem extends EventsTreeItem {
@Override @Override
void remove(List<DetailViewEvent> path) { void remove(List<DetailViewEvent> path) {
DetailViewEvent event = path.get(0); DetailViewEvent event = path.get(0);
BaseTypeTreeItem typeTreeItem = childMap.get(event.getEventType().getBaseType()); CategoryTypeTreeItem typeTreeItem = childMap.get(event.getEventType().getCategory());
//remove the path from the child //remove the path from the child
if (typeTreeItem != null) { if (typeTreeItem != null) {
@ -93,7 +93,7 @@ class RootItem extends EventsTreeItem {
//if the child has no children remove it also //if the child has no children remove it also
if (typeTreeItem.getChildren().isEmpty()) { if (typeTreeItem.getChildren().isEmpty()) {
childMap.remove(event.getEventType().getBaseType()); childMap.remove(event.getEventType().getCategory());
getChildren().remove(typeTreeItem); getChildren().remove(typeTreeItem);
} }
} }
@ -102,8 +102,8 @@ class RootItem extends EventsTreeItem {
@Override @Override
void insert(List<DetailViewEvent> path) { void insert(List<DetailViewEvent> path) {
DetailViewEvent event = path.get(0); DetailViewEvent event = path.get(0);
BaseTypeTreeItem treeItem = childMap.computeIfAbsent(event.getEventType().getBaseType(), CategoryTypeTreeItem treeItem = childMap.computeIfAbsent(event.getEventType().getCategory(),
baseType -> configureNewTreeItem(new BaseTypeTreeItem(event, getComparator())) baseType -> configureNewTreeItem(new CategoryTypeTreeItem(event, getComparator()))
); );
treeItem.insert(path); treeItem.insert(path);
} }

View File

@ -79,8 +79,8 @@ final class LegendCell extends TreeTableCell<FilterState<?>, FilterState<?>> {
setLegendColor(filter, rect, newZoomLevel); setLegendColor(filter, rect, newZoomLevel);
}); });
HBox hBox = new HBox(new Rectangle(filter.getEventType().getTypeLevel().ordinal() * 10, 5, CLEAR), HBox hBox = new HBox(new Rectangle(filter.getRootEventType().getTypeHierarchyLevel().ordinal() * 10, 5, CLEAR),
new ImageView(EventTypeUtils.getImagePath(filter.getEventType())), rect new ImageView(EventTypeUtils.getImagePath(filter.getRootEventType())), rect
); );
hBox.setAlignment(Pos.CENTER); hBox.setAlignment(Pos.CENTER);
Platform.runLater(() -> { Platform.runLater(() -> {
@ -92,7 +92,7 @@ final class LegendCell extends TreeTableCell<FilterState<?>, FilterState<?>> {
TextFilter filter = (TextFilter) item.getFilter(); TextFilter filter = (TextFilter) item.getFilter();
TextField textField = new TextField(); TextField textField = new TextField();
textField.setPromptText(Bundle.Timeline_ui_filtering_promptText()); textField.setPromptText(Bundle.Timeline_ui_filtering_promptText());
textField.textProperty().bindBidirectional(filter.textProperty()); textField.textProperty().bindBidirectional(filter.substringProperty());
Platform.runLater(() -> setGraphic(textField)); Platform.runLater(() -> setGraphic(textField));
} else { } else {
@ -104,12 +104,12 @@ final class LegendCell extends TreeTableCell<FilterState<?>, FilterState<?>> {
} }
} }
private void setLegendColor(EventTypeFilter filter, Rectangle rect, TimelineEventType.TypeLevel eventTypeZoom) { private void setLegendColor(EventTypeFilter filter, Rectangle rect, TimelineEventType.HierarchyLevel eventTypeZoom) {
//only show legend color if filter is of the same zoomlevel as requested in filteredEvents //only show legend color if filter is of the same zoomlevel as requested in filteredEvents
if (eventTypeZoom.equals(filter.getEventType().getTypeLevel())) { if (eventTypeZoom.equals(filter.getRootEventType().getTypeHierarchyLevel())) {
Platform.runLater(() -> { Platform.runLater(() -> {
rect.setStroke(EventTypeUtils.getColor(filter.getEventType().getSuperType())); rect.setStroke(EventTypeUtils.getColor(filter.getRootEventType().getParent()));
rect.setFill(EventTypeUtils.getColor(filter.getEventType())); rect.setFill(EventTypeUtils.getColor(filter.getRootEventType()));
}); });
} else { } else {
Platform.runLater(() -> { Platform.runLater(() -> {

View File

@ -20,23 +20,23 @@ package org.sleuthkit.autopsy.timeline.ui.filtering.datamodel;
import java.util.Objects; import java.util.Objects;
import org.sleuthkit.datamodel.TimelineEvent; import org.sleuthkit.datamodel.TimelineEvent;
import org.sleuthkit.datamodel.TimelineEvent; import org.sleuthkit.datamodel.TimelineLevelOfDetail;
/** /**
* Ui level filter for events that have the given description. * Ui level filter for events that have the given description.
*/ */
public final class DescriptionFilter implements UIFilter { public final class DescriptionFilter implements UIFilter {
private final TimelineEvent.DescriptionLevel descriptionLoD; private final TimelineLevelOfDetail descriptionLoD;
private final String description; private final String description;
public DescriptionFilter(TimelineEvent.DescriptionLevel descriptionLoD, String description) { public DescriptionFilter(TimelineLevelOfDetail descriptionLoD, String description) {
super(); super();
this.descriptionLoD = descriptionLoD; this.descriptionLoD = descriptionLoD;
this.description = description; this.description = description;
} }
public TimelineEvent.DescriptionLevel getDescriptionLevel() { public TimelineLevelOfDetail getDescriptionLevel() {
return descriptionLoD; return descriptionLoD;
} }

View File

@ -39,9 +39,9 @@ public class SqlFilterState<FilterType extends TimelineFilter> extends AbstractF
selectedProperty().addListener(selectedProperty -> { selectedProperty().addListener(selectedProperty -> {
if (filter instanceof TimelineFilter.TagsFilter) { if (filter instanceof TimelineFilter.TagsFilter) {
((TimelineFilter.TagsFilter)filter).setTagged(isSelected()); ((TimelineFilter.TagsFilter)filter).setEventSourcesAreTagged(isSelected());
} else if (filter instanceof TimelineFilter.HashHitsFilter) { } else if (filter instanceof TimelineFilter.HashHitsFilter) {
((TimelineFilter.HashHitsFilter)filter).setTagged(isSelected()); ((TimelineFilter.HashHitsFilter)filter).setEventSourcesHaveHashSetHits(isSelected());
} }
}); });

View File

@ -98,6 +98,7 @@ import static org.sleuthkit.datamodel.TimelineEventType.FILE_CREATED;
import static org.sleuthkit.datamodel.TimelineEventType.FILE_MODIFIED; import static org.sleuthkit.datamodel.TimelineEventType.FILE_MODIFIED;
import static org.sleuthkit.datamodel.TimelineEventType.FILE_SYSTEM; import static org.sleuthkit.datamodel.TimelineEventType.FILE_SYSTEM;
import org.sleuthkit.datamodel.TimelineEvent; import org.sleuthkit.datamodel.TimelineEvent;
import org.sleuthkit.datamodel.TimelineLevelOfDetail;
/** /**
* The inner component that makes up the List view. Manages the TableView. * The inner component that makes up the List view. Manages the TableView.
@ -232,11 +233,11 @@ class ListTimeline extends BorderPane {
//// set up cell and cell-value factories for columns //// set up cell and cell-value factories for columns
dateTimeColumn.setCellValueFactory(CELL_VALUE_FACTORY); dateTimeColumn.setCellValueFactory(CELL_VALUE_FACTORY);
dateTimeColumn.setCellFactory(col -> new TextEventTableCell(singleEvent dateTimeColumn.setCellFactory(col -> new TextEventTableCell(singleEvent
-> TimeLineController.getZonedFormatter().print(singleEvent.getStartMillis()))); -> TimeLineController.getZonedFormatter().print(singleEvent.getEventTimeInMs())));
descriptionColumn.setCellValueFactory(CELL_VALUE_FACTORY); descriptionColumn.setCellValueFactory(CELL_VALUE_FACTORY);
descriptionColumn.setCellFactory(col -> new TextEventTableCell(singleEvent descriptionColumn.setCellFactory(col -> new TextEventTableCell(singleEvent
-> singleEvent.getDescription(TimelineEvent.DescriptionLevel.FULL))); -> singleEvent.getDescription(TimelineLevelOfDetail.HIGH)));
typeColumn.setCellValueFactory(CELL_VALUE_FACTORY); typeColumn.setCellValueFactory(CELL_VALUE_FACTORY);
typeColumn.setCellFactory(col -> new EventTypeCell()); typeColumn.setCellFactory(col -> new EventTypeCell());
@ -409,11 +410,11 @@ class ListTimeline extends BorderPane {
setGraphic(null); setGraphic(null);
setTooltip(null); setTooltip(null);
} else { } else {
if (item.getEventTypes().stream().allMatch(TimelineEventType.FILE_SYSTEM.getSubTypes()::contains)) { if (item.getEventTypes().stream().allMatch(TimelineEventType.FILE_SYSTEM.getChildren()::contains)) {
String typeString = ""; //NON-NLS String typeString = ""; //NON-NLS
VBox toolTipVbox = new VBox(5); VBox toolTipVbox = new VBox(5);
for (TimelineEventType type : TimelineEventType.FILE_SYSTEM.getSubTypes()) { for (TimelineEventType type : TimelineEventType.FILE_SYSTEM.getChildren()) {
if (item.getEventTypes().contains(type)) { if (item.getEventTypes().contains(type)) {
if (type.equals(FILE_MODIFIED)) { if (type.equals(FILE_MODIFIED)) {
typeString += "M"; //NON-NLS typeString += "M"; //NON-NLS
@ -472,7 +473,7 @@ class ListTimeline extends BorderPane {
protected void updateItem(CombinedEvent item, boolean empty) { protected void updateItem(CombinedEvent item, boolean empty) {
super.updateItem(item, empty); super.updateItem(item, empty);
if (empty || item == null || (getEvent().isTagged() == false)) { if (empty || item == null || (getEvent().eventSourceIsTagged() == false)) {
setGraphic(null); setGraphic(null);
setTooltip(null); setTooltip(null);
} else { } else {
@ -485,13 +486,13 @@ class ListTimeline extends BorderPane {
SortedSet<String> tagNames = new TreeSet<>(); SortedSet<String> tagNames = new TreeSet<>();
try { try {
//get file tags //get file tags
Content file = sleuthkitCase.getContentById(getEvent().getFileObjID()); Content file = sleuthkitCase.getContentById(getEvent().getContentObjID());
tagsManager.getContentTagsByContent(file).stream() tagsManager.getContentTagsByContent(file).stream()
.map(tag -> tag.getName().getDisplayName()) .map(tag -> tag.getName().getDisplayName())
.forEach(tagNames::add); .forEach(tagNames::add);
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to lookup tags for obj id " + getEvent().getFileObjID(), ex); //NON-NLS logger.log(Level.SEVERE, "Failed to lookup tags for obj id " + getEvent().getContentObjID(), ex); //NON-NLS
Platform.runLater(() -> { Platform.runLater(() -> {
Notifications.create() Notifications.create()
.owner(getScene().getWindow()) .owner(getScene().getWindow())
@ -544,7 +545,7 @@ class ListTimeline extends BorderPane {
protected void updateItem(CombinedEvent item, boolean empty) { protected void updateItem(CombinedEvent item, boolean empty) {
super.updateItem(item, empty); super.updateItem(item, empty);
if (empty || item == null || (getEvent().isHashHit() == false)) { if (empty || item == null || (getEvent().eventSourceHasHashHits()== false)) {
setGraphic(null); setGraphic(null);
setTooltip(null); setTooltip(null);
} else { } else {
@ -555,12 +556,12 @@ class ListTimeline extends BorderPane {
*/ */
setGraphic(new ImageView(HASH_HIT)); setGraphic(new ImageView(HASH_HIT));
try { try {
Set<String> hashSetNames = new TreeSet<>(sleuthkitCase.getContentById(getEvent().getFileObjID()).getHashSetNames()); Set<String> hashSetNames = new TreeSet<>(sleuthkitCase.getContentById(getEvent().getContentObjID()).getHashSetNames());
Tooltip tooltip = new Tooltip(Bundle.ListTimeline_hashHitTooltip_text(String.join("\n", hashSetNames))); //NON-NLS Tooltip tooltip = new Tooltip(Bundle.ListTimeline_hashHitTooltip_text(String.join("\n", hashSetNames))); //NON-NLS
tooltip.setGraphic(new ImageView(HASH_HIT)); tooltip.setGraphic(new ImageView(HASH_HIT));
setTooltip(tooltip); setTooltip(tooltip);
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to lookup hash set names for obj id " + getEvent().getFileObjID(), ex); //NON-NLS logger.log(Level.SEVERE, "Failed to lookup hash set names for obj id " + getEvent().getContentObjID(), ex); //NON-NLS
Platform.runLater(() -> { Platform.runLater(() -> {
Notifications.create() Notifications.create()
.owner(getScene().getWindow()) .owner(getScene().getWindow())

View File

@ -35,6 +35,7 @@ import org.sleuthkit.datamodel.TimelineManager;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TimelineEvent; import org.sleuthkit.datamodel.TimelineEvent;
import org.sleuthkit.datamodel.TimelineEventType; import org.sleuthkit.datamodel.TimelineEventType;
import org.sleuthkit.datamodel.TimelineLevelOfDetail;
/** /**
* Model for the ListView. Uses FilteredEventsModel as underlying datamodel and * Model for the ListView. Uses FilteredEventsModel as underlying datamodel and
@ -88,7 +89,7 @@ public class ListViewModel {
ArrayList<CombinedEvent> combinedEvents = new ArrayList<>(); ArrayList<CombinedEvent> combinedEvents = new ArrayList<>();
Map<CombinedEventGroup, List<TimelineEvent>> groupedEventList = events.stream().collect(groupingBy(event -> new CombinedEventGroup(event.getTime(), event.getFileObjID(), event.getFullDescription()))); Map<CombinedEventGroup, List<TimelineEvent>> groupedEventList = events.stream().collect(groupingBy(event -> new CombinedEventGroup(event.getTime(), event.getContentObjID(), event.getDescription(TimelineLevelOfDetail.HIGH))));
for(Entry<CombinedEventGroup, List<TimelineEvent>> entry: groupedEventList.entrySet()){ for(Entry<CombinedEventGroup, List<TimelineEvent>> entry: groupedEventList.entrySet()){
List<TimelineEvent> groupedEvents = entry.getValue(); List<TimelineEvent> groupedEvents = entry.getValue();
@ -120,7 +121,7 @@ public class ListViewModel {
private boolean hasFileTypeEvents(Collection<TimelineEventType> eventTypes) { private boolean hasFileTypeEvents(Collection<TimelineEventType> eventTypes) {
for (TimelineEventType type: eventTypes) { for (TimelineEventType type: eventTypes) {
if (type.getBaseType() != TimelineEventType.FILE_SYSTEM) { if (type.getCategory() != TimelineEventType.FILE_SYSTEM) {
return false; return false;
} }
} }

View File

@ -41,6 +41,7 @@ import org.sleuthkit.autopsy.timeline.utils.RangeDivision;
import org.sleuthkit.datamodel.TimelineEvent; import org.sleuthkit.datamodel.TimelineEvent;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TimelineEventType; import org.sleuthkit.datamodel.TimelineEventType;
import org.sleuthkit.datamodel.TimelineLevelOfDetail;
/** /**
* A Panel that acts as a view for a given * A Panel that acts as a view for a given
@ -93,21 +94,21 @@ public class ZoomSettingsPane extends TitledPane {
zoomLabel.setText(Bundle.ZoomSettingsPane_zoomLabel_text()); zoomLabel.setText(Bundle.ZoomSettingsPane_zoomLabel_text());
typeZoomSlider.setMin(1); //don't show ROOT_TYPE typeZoomSlider.setMin(1); //don't show ROOT_TYPE
typeZoomSlider.setMax(TimelineEventType.TypeLevel.values().length - 1); typeZoomSlider.setMax(TimelineEventType.HierarchyLevel.values().length - 1);
configureSliderListeners(typeZoomSlider, configureSliderListeners(typeZoomSlider,
controller::pushEventTypeZoom, controller::pushEventTypeZoom,
filteredEvents.eventTypeZoomProperty(), filteredEvents.eventTypeZoomProperty(),
TimelineEventType.TypeLevel.class, TimelineEventType.HierarchyLevel.class,
TimelineEventType.TypeLevel::ordinal, TimelineEventType.HierarchyLevel::ordinal,
Function.identity()); Function.identity());
typeZoomLabel.setText(Bundle.ZoomSettingsPane_typeZoomLabel_text()); typeZoomLabel.setText(Bundle.ZoomSettingsPane_typeZoomLabel_text());
descrLODSlider.setMax(TimelineEvent.DescriptionLevel.values().length - 1); descrLODSlider.setMax(TimelineLevelOfDetail.values().length - 1);
configureSliderListeners(descrLODSlider, configureSliderListeners(descrLODSlider,
controller::pushDescrLOD, controller::pushDescrLOD,
filteredEvents.descriptionLODProperty(), filteredEvents.descriptionLODProperty(),
TimelineEvent.DescriptionLevel.class, TimelineLevelOfDetail.class,
TimelineEvent.DescriptionLevel::ordinal, TimelineLevelOfDetail::ordinal,
Function.identity()); Function.identity());
descrLODLabel.setText(Bundle.ZoomSettingsPane_descrLODLabel_text()); descrLODLabel.setText(Bundle.ZoomSettingsPane_descrLODLabel_text());
//the description slider is only usefull in the detail view //the description slider is only usefull in the detail view

View File

@ -23,6 +23,7 @@ import org.joda.time.Interval;
import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.RootFilterState; import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.RootFilterState;
import org.sleuthkit.datamodel.TimelineEvent; import org.sleuthkit.datamodel.TimelineEvent;
import org.sleuthkit.datamodel.TimelineEventType; import org.sleuthkit.datamodel.TimelineEventType;
import org.sleuthkit.datamodel.TimelineLevelOfDetail;
/** /**
* This class encapsulates all the zoom(and filter) parameters into one object * This class encapsulates all the zoom(and filter) parameters into one object
@ -32,17 +33,17 @@ final public class ZoomState {
private final Interval timeRange; private final Interval timeRange;
private final TimelineEventType.TypeLevel typeZoomLevel; private final TimelineEventType.HierarchyLevel typeZoomLevel;
private final RootFilterState filter; private final RootFilterState filter;
private final TimelineEvent.DescriptionLevel descrLOD; private final TimelineLevelOfDetail descrLOD;
public Interval getTimeRange() { public Interval getTimeRange() {
return timeRange; return timeRange;
} }
public TimelineEventType.TypeLevel getTypeZoomLevel() { public TimelineEventType.HierarchyLevel getTypeZoomLevel() {
return typeZoomLevel; return typeZoomLevel;
} }
@ -50,22 +51,22 @@ final public class ZoomState {
return filter; return filter;
} }
public TimelineEvent.DescriptionLevel getDescriptionLOD() { public TimelineLevelOfDetail getDescriptionLOD() {
return descrLOD; return descrLOD;
} }
public ZoomState(Interval timeRange, TimelineEventType.TypeLevel zoomLevel, RootFilterState filter, TimelineEvent.DescriptionLevel descrLOD) { public ZoomState(Interval timeRange, TimelineEventType.HierarchyLevel zoomLevel, RootFilterState filter, TimelineLevelOfDetail descrLOD) {
this.timeRange = timeRange; this.timeRange = timeRange;
this.typeZoomLevel = zoomLevel; this.typeZoomLevel = zoomLevel;
this.filter = filter; this.filter = filter;
this.descrLOD = descrLOD; this.descrLOD = descrLOD;
} }
public ZoomState withTimeAndType(Interval timeRange, TimelineEventType.TypeLevel zoomLevel) { public ZoomState withTimeAndType(Interval timeRange, TimelineEventType.HierarchyLevel zoomLevel) {
return new ZoomState(timeRange, zoomLevel, filter, descrLOD); return new ZoomState(timeRange, zoomLevel, filter, descrLOD);
} }
public ZoomState withTypeZoomLevel(TimelineEventType.TypeLevel zoomLevel) { public ZoomState withTypeZoomLevel(TimelineEventType.HierarchyLevel zoomLevel) {
return new ZoomState(timeRange, zoomLevel, filter, descrLOD); return new ZoomState(timeRange, zoomLevel, filter, descrLOD);
} }
@ -73,7 +74,7 @@ final public class ZoomState {
return new ZoomState(timeRange, typeZoomLevel, filter, descrLOD); return new ZoomState(timeRange, typeZoomLevel, filter, descrLOD);
} }
public ZoomState withDescrLOD(TimelineEvent.DescriptionLevel descrLOD) { public ZoomState withDescrLOD(TimelineLevelOfDetail descrLOD) {
return new ZoomState(timeRange, typeZoomLevel, filter, descrLOD); return new ZoomState(timeRange, typeZoomLevel, filter, descrLOD);
} }
@ -85,7 +86,7 @@ final public class ZoomState {
return this.filter.equals(filterSet); return this.filter.equals(filterSet);
} }
public boolean hasTypeZoomLevel(TimelineEventType.TypeLevel typeZoom) { public boolean hasTypeZoomLevel(TimelineEventType.HierarchyLevel typeZoom) {
return this.typeZoomLevel.equals(typeZoom); return this.typeZoomLevel.equals(typeZoom);
} }
@ -93,7 +94,7 @@ final public class ZoomState {
return this.timeRange != null && this.timeRange.equals(timeRange); return this.timeRange != null && this.timeRange.equals(timeRange);
} }
public boolean hasDescrLOD(TimelineEvent.DescriptionLevel newLOD) { public boolean hasDescrLOD(TimelineLevelOfDetail newLOD) {
return this.descrLOD.equals(newLOD); return this.descrLOD.equals(newLOD);
} }