mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-17 18:17:43 +00:00
flesh out ListViewPane, keep events sorted by date
This commit is contained in:
parent
695c5c69c3
commit
2858421d46
@ -279,7 +279,7 @@ public final class FilteredEventsModel {
|
||||
return repo.getTagCountsByTagName(eventIDsWithTags);
|
||||
}
|
||||
|
||||
public Set<Long> getEventIDs(Interval timeRange, Filter filter) {
|
||||
public List<Long> getEventIDs(Interval timeRange, Filter filter) {
|
||||
final Interval overlap;
|
||||
final RootFilter intersect;
|
||||
synchronized (this) {
|
||||
@ -290,7 +290,7 @@ public final class FilteredEventsModel {
|
||||
return repo.getEventIDs(overlap, intersect);
|
||||
}
|
||||
|
||||
public Set<Long> getEventIDs() {
|
||||
public List<Long> getEventIDs() {
|
||||
return getEventIDs(requestedTimeRange.get(), requestedFilter.get());
|
||||
}
|
||||
|
||||
|
@ -343,18 +343,19 @@ public class EventDB {
|
||||
return result;
|
||||
}
|
||||
|
||||
Set<Long> getEventIDs(Interval timeRange, RootFilter filter) {
|
||||
List<Long> getEventIDs(Interval timeRange, RootFilter filter) {
|
||||
return getEventIDs(timeRange.getStartMillis() / 1000, timeRange.getEndMillis() / 1000, filter);
|
||||
}
|
||||
|
||||
Set<Long> getEventIDs(Long startTime, Long endTime, RootFilter filter) {
|
||||
List<Long> getEventIDs(Long startTime, Long endTime, RootFilter filter) {
|
||||
if (Objects.equals(startTime, endTime)) {
|
||||
endTime++;
|
||||
}
|
||||
Set<Long> resultIDs = new HashSet<>();
|
||||
ArrayList<Long> resultIDs = new ArrayList<>();
|
||||
|
||||
DBLock.lock();
|
||||
final String query = "SELECT events.event_id AS event_id FROM events" + useHashHitTablesHelper(filter) + useTagTablesHelper(filter) + " WHERE time >= " + startTime + " AND time <" + endTime + " AND " + SQLHelper.getSQLWhere(filter); // NON-NLS
|
||||
final String query = "SELECT events.event_id AS event_id FROM events" + useHashHitTablesHelper(filter) + useTagTablesHelper(filter)
|
||||
+ " WHERE time >= " + startTime + " AND time <" + endTime + " AND " + SQLHelper.getSQLWhere(filter) + " ORDER BY time ASC"; // NON-NLS
|
||||
try (Statement stmt = con.createStatement();
|
||||
ResultSet rs = stmt.executeQuery(query)) {
|
||||
while (rs.next()) {
|
||||
@ -1168,7 +1169,6 @@ public class EventDB {
|
||||
return useSubTypes ? "sub_type" : "base_type"; //NON-NLS
|
||||
}
|
||||
|
||||
|
||||
private PreparedStatement prepareStatement(String queryString) throws SQLException {
|
||||
PreparedStatement prepareStatement = con.prepareStatement(queryString);
|
||||
preparedStatements.add(prepareStatement);
|
||||
|
@ -214,7 +214,7 @@ public class EventsRepository {
|
||||
idToEventCache.invalidateAll();
|
||||
}
|
||||
|
||||
public Set<Long> getEventIDs(Interval timeRange, RootFilter filter) {
|
||||
public List<Long> getEventIDs(Interval timeRange, RootFilter filter) {
|
||||
return eventDB.getEventIDs(timeRange, filter);
|
||||
}
|
||||
|
||||
|
@ -29,15 +29,12 @@ import java.util.function.Supplier;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.InvalidationListener;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.MenuButton;
|
||||
import javafx.scene.control.TitledPane;
|
||||
import javafx.scene.control.Toggle;
|
||||
import javafx.scene.control.ToggleButton;
|
||||
import javafx.scene.control.ToolBar;
|
||||
import javafx.scene.control.Tooltip;
|
||||
@ -60,8 +57,10 @@ import javax.annotation.Nonnull;
|
||||
import javax.annotation.concurrent.GuardedBy;
|
||||
import jfxtras.scene.control.LocalDateTimePicker;
|
||||
import jfxtras.scene.control.LocalDateTimeTextField;
|
||||
import jfxtras.scene.control.ToggleGroupValue;
|
||||
import org.controlsfx.control.NotificationPane;
|
||||
import org.controlsfx.control.RangeSlider;
|
||||
import org.controlsfx.control.SegmentedButton;
|
||||
import org.controlsfx.control.action.Action;
|
||||
import org.controlsfx.control.action.ActionUtils;
|
||||
import org.joda.time.DateTime;
|
||||
@ -162,6 +161,8 @@ final public class VisualizationPanel extends BorderPane {
|
||||
@FXML
|
||||
private Label visualizationModeLabel;
|
||||
@FXML
|
||||
private SegmentedButton modeSegButton;
|
||||
@FXML
|
||||
private ToggleButton countsToggle;
|
||||
@FXML
|
||||
private ToggleButton detailsToggle;
|
||||
@ -261,6 +262,7 @@ final public class VisualizationPanel extends BorderPane {
|
||||
"VisualizationPanel.endLabel.text=End:",
|
||||
"VisualizationPanel.countsToggle.text=Counts",
|
||||
"VisualizationPanel.detailsToggle.text=Details",
|
||||
"VisualizationPanel.listToggle.text=List",
|
||||
"VisualizationPanel.zoomMenuButton.text=Zoom in/out to",
|
||||
"VisualizationPanel.tagsAddedOrDeleted=Tags have been created and/or deleted. The visualization may not be up to date."
|
||||
})
|
||||
@ -280,25 +282,18 @@ final public class VisualizationPanel extends BorderPane {
|
||||
visualizationModeLabel.setText(Bundle.VisualizationPanel_visualizationModeLabel_text());
|
||||
countsToggle.setText(Bundle.VisualizationPanel_countsToggle_text());
|
||||
detailsToggle.setText(Bundle.VisualizationPanel_detailsToggle_text());
|
||||
ChangeListener<Toggle> toggleListener = (ObservableValue<? extends Toggle> observable, Toggle oldValue, Toggle newValue) -> {
|
||||
if (newValue == null) {
|
||||
countsToggle.getToggleGroup().selectToggle(oldValue != null ? oldValue : countsToggle);
|
||||
} else if (newValue == countsToggle && oldValue != null) {
|
||||
controller.setVisualizationMode(VisualizationMode.COUNTS);
|
||||
} else if (newValue == detailsToggle && oldValue != null) {
|
||||
controller.setVisualizationMode(VisualizationMode.DETAIL);
|
||||
} else if (newValue == listToggle && oldValue != null) {
|
||||
controller.setVisualizationMode(VisualizationMode.LIST);
|
||||
}
|
||||
};
|
||||
listToggle.setText(Bundle.VisualizationPanel_listToggle_text());
|
||||
|
||||
if (countsToggle.getToggleGroup() != null) {
|
||||
countsToggle.getToggleGroup().selectedToggleProperty().addListener(toggleListener);
|
||||
} else {
|
||||
countsToggle.toggleGroupProperty().addListener((Observable toggleGroup) -> {
|
||||
countsToggle.getToggleGroup().selectedToggleProperty().addListener(toggleListener);
|
||||
});
|
||||
}
|
||||
ToggleGroupValue<VisualizationMode> visModeToggleGroup = new ToggleGroupValue<>();
|
||||
visModeToggleGroup.add(listToggle, VisualizationMode.LIST);
|
||||
visModeToggleGroup.add(detailsToggle, VisualizationMode.DETAIL);
|
||||
visModeToggleGroup.add(countsToggle, VisualizationMode.COUNTS);
|
||||
|
||||
modeSegButton.setToggleGroup(visModeToggleGroup);
|
||||
|
||||
visModeToggleGroup.valueProperty().addListener((observable, oldVisMode, newValue) -> {
|
||||
controller.setVisualizationMode(newValue != null ? newValue : (oldVisMode != null ? oldVisMode : VisualizationMode.COUNTS));
|
||||
});
|
||||
|
||||
controller.visualizationModeProperty().addListener(visualizationMode -> syncVisualizationMode());
|
||||
syncVisualizationMode();
|
||||
|
@ -7,6 +7,7 @@ package org.sleuthkit.autopsy.timeline.ui.listvew;
|
||||
|
||||
import java.util.Arrays;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.scene.Node;
|
||||
@ -14,50 +15,66 @@ import javafx.scene.chart.Axis;
|
||||
import javafx.scene.control.ContextMenu;
|
||||
import javafx.scene.control.TableCell;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableRow;
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.util.Callback;
|
||||
import org.sleuthkit.autopsy.timeline.TimeLineController;
|
||||
import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType;
|
||||
import org.sleuthkit.autopsy.timeline.datamodel.SingleEvent;
|
||||
import org.sleuthkit.autopsy.timeline.ui.IntervalSelector;
|
||||
import org.sleuthkit.autopsy.timeline.ui.TimeLineChart;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
import org.sleuthkit.autopsy.timeline.zooming.DescriptionLoD;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class ListChart extends TableView<Long> implements TimeLineChart<Long> {
|
||||
|
||||
Callback<TableColumn.CellDataFeatures<Long, Long>, ObservableValue<Long>> cellValueFactory = param -> new SimpleObjectProperty<>(param.getValue());
|
||||
|
||||
private final TimeLineController controller;
|
||||
private final TableColumn<Long, Long> idColumn = new TableColumn<>();
|
||||
private final TableColumn<Long, Long> millisColumn = new TableColumn<>();
|
||||
private final TableColumn<Long, Image> iconColumn = new TableColumn<>();
|
||||
private final TableColumn<Long, String> descriptionColumn = new TableColumn<>();
|
||||
private final TableColumn<Long, EventType> baseTypeColumn = new TableColumn<>();
|
||||
private final TableColumn<Long, EventType> subTypeColumn = new TableColumn<>();
|
||||
private final TableColumn<Long, TskData.FileKnown> knownColumn = new TableColumn<>();
|
||||
private final TableColumn<Long, Long> idColumn = new TableColumn<>("Event ID");
|
||||
private final TableColumn<Long, Long> millisColumn = new TableColumn<>("Date/Time");
|
||||
private final TableColumn<Long, Long> iconColumn = new TableColumn<>("Icon");
|
||||
private final TableColumn<Long, Long> descriptionColumn = new TableColumn<>("Description");
|
||||
private final TableColumn<Long, Long> baseTypeColumn = new TableColumn<>("Base Type");
|
||||
private final TableColumn<Long, Long> subTypeColumn = new TableColumn<>("Sub Type");
|
||||
private final TableColumn<Long, Long> knownColumn = new TableColumn<>("Known");
|
||||
|
||||
ListChart(TimeLineController controller) {
|
||||
this.controller = controller;
|
||||
getColumns().addAll(Arrays.asList(idColumn, iconColumn, millisColumn));
|
||||
setColumnResizePolicy(CONSTRAINED_RESIZE_POLICY);
|
||||
getColumns().addAll(Arrays.asList(idColumn, millisColumn, iconColumn, descriptionColumn, baseTypeColumn, subTypeColumn, knownColumn));
|
||||
|
||||
idColumn.setCellValueFactory(param -> new SimpleObjectProperty<>(param.getValue()));
|
||||
setRowFactory(tableView -> new EventRow());
|
||||
|
||||
millisColumn.setCellValueFactory(param -> {
|
||||
return new SimpleObjectProperty<>(controller.getEventsModel().getEventById(param.getValue()).getStartMillis());
|
||||
});
|
||||
idColumn.setCellValueFactory(cellValueFactory);
|
||||
idColumn.setSortable(false);
|
||||
|
||||
millisColumn.setCellValueFactory(cellValueFactory);
|
||||
millisColumn.setCellFactory(col -> new EpochMillisCell());
|
||||
iconColumn.setCellValueFactory(param -> {
|
||||
return new SimpleObjectProperty<>(controller.getEventsModel().getEventById(param.getValue()).getEventType().getFXImage());
|
||||
});
|
||||
millisColumn.setSortable(false);
|
||||
|
||||
iconColumn.setCellValueFactory(cellValueFactory);
|
||||
iconColumn.setCellFactory(col -> new ImageCell());
|
||||
iconColumn.setSortable(false);
|
||||
|
||||
millisColumn.setSortType(TableColumn.SortType.DESCENDING);
|
||||
millisColumn.setSortable(true);
|
||||
millisColumn.setComparator(Long::compare);
|
||||
getSortOrder().setAll(Arrays.asList(millisColumn));
|
||||
descriptionColumn.setCellValueFactory(cellValueFactory);
|
||||
descriptionColumn.setCellFactory(col -> new DescriptionCell());
|
||||
descriptionColumn.setSortable(false);
|
||||
|
||||
baseTypeColumn.setCellValueFactory(cellValueFactory);
|
||||
baseTypeColumn.setCellFactory(col -> new BaseTypeCell());
|
||||
baseTypeColumn.setSortable(false);
|
||||
|
||||
subTypeColumn.setCellValueFactory(cellValueFactory);
|
||||
subTypeColumn.setCellFactory(col -> new EventTypeCell());
|
||||
subTypeColumn.setSortable(false);
|
||||
|
||||
knownColumn.setCellValueFactory(cellValueFactory);
|
||||
knownColumn.setCellFactory(col -> new KnownCell());
|
||||
knownColumn.setSortable(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -105,15 +122,86 @@ class ListChart extends TableView<Long> implements TimeLineChart<Long> {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
private static class ImageCell extends TableCell<Long, Image> {
|
||||
private static class ImageCell extends TableCell<Long, Long> {
|
||||
|
||||
@Override
|
||||
protected void updateItem(Image item, boolean empty) {
|
||||
protected void updateItem(Long item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (empty || item == null) {
|
||||
setGraphic(null);
|
||||
} else {
|
||||
setGraphic(new ImageView(item));
|
||||
EventRow tableRow = (EventRow) getTableRow();
|
||||
if (tableRow != null) {
|
||||
setGraphic(new ImageView(tableRow.getEvent().getEventType().getFXImage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class DescriptionCell extends TableCell<Long, Long> {
|
||||
|
||||
@Override
|
||||
protected void updateItem(Long item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
|
||||
if (empty || item == null) {
|
||||
setText("");
|
||||
} else {
|
||||
EventRow tableRow = (EventRow) getTableRow();
|
||||
if (tableRow != null) {
|
||||
setText(tableRow.getEvent().getDescription(DescriptionLoD.FULL));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class BaseTypeCell extends TableCell<Long, Long> {
|
||||
|
||||
@Override
|
||||
protected void updateItem(Long item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
|
||||
if (empty || item == null) {
|
||||
setText("");
|
||||
} else {
|
||||
EventRow tableRow = (EventRow) getTableRow();
|
||||
if (tableRow != null) {
|
||||
setText(tableRow.getEvent().getEventType().getBaseType().getDisplayName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class EventTypeCell extends TableCell<Long, Long> {
|
||||
|
||||
@Override
|
||||
protected void updateItem(Long item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
|
||||
if (empty || item == null) {
|
||||
setText("");
|
||||
} else {
|
||||
EventRow tableRow = (EventRow) getTableRow();
|
||||
if (tableRow != null) {
|
||||
setText(tableRow.getEvent().getEventType().getDisplayName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class KnownCell extends TableCell<Long, Long> {
|
||||
|
||||
@Override
|
||||
protected void updateItem(Long item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
|
||||
if (empty || item == null) {
|
||||
setText("");
|
||||
} else {
|
||||
EventRow tableRow = (EventRow) getTableRow();
|
||||
if (tableRow != null) {
|
||||
setText(tableRow.getEvent().getKnown().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -127,9 +215,32 @@ class ListChart extends TableView<Long> implements TimeLineChart<Long> {
|
||||
if (empty || item == null) {
|
||||
setText("");
|
||||
} else {
|
||||
setText(TimeLineController.getZonedFormatter().print(item));
|
||||
|
||||
EventRow tableRow = (EventRow) getTableRow();
|
||||
if (tableRow != null) {
|
||||
setText(TimeLineController.getZonedFormatter().print(tableRow.getEvent().getStartMillis()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class EventRow extends TableRow<Long> {
|
||||
|
||||
private SingleEvent event;
|
||||
|
||||
SingleEvent getEvent() {
|
||||
return event;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateItem(Long item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
|
||||
if (empty || item == null) {
|
||||
event = null;
|
||||
} else {
|
||||
event = controller.getEventsModel().getEventById(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.timeline.ui.listvew;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.List;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.Parent;
|
||||
@ -116,7 +116,7 @@ public class ListViewPane extends AbstractVisualizationPane<Long, SingleEvent, N
|
||||
|
||||
// updateMessage(Bundle.DetailViewPane_loggedTask_queryDb());
|
||||
//get the event stripes to be displayed
|
||||
Set<Long> eventIDs = eventsModel.getEventIDs();
|
||||
List<Long> eventIDs = eventsModel.getEventIDs();
|
||||
getChart().getItems().setAll(eventIDs);
|
||||
|
||||
// updateMessage(Bundle.DetailViewPane_loggedTask_updateUI());
|
||||
|
Loading…
x
Reference in New Issue
Block a user