Merge pull request #4054 from millmanorama/data-source-filter-UI

add Data Source chooser to Toolbar
This commit is contained in:
Richard Cordovano 2018-08-21 15:36:47 -04:00 committed by GitHub
commit 043a96e47e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 99 additions and 41 deletions

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.ComboBox?> <?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Label?> <?import javafx.scene.control.Label?>
<?import javafx.scene.control.MenuItem?> <?import javafx.scene.control.MenuItem?>
@ -12,19 +13,31 @@
<?import javafx.scene.image.ImageView?> <?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.HBox?> <?import javafx.scene.layout.HBox?>
<fx:root minWidth="-1.0" orientation="HORIZONTAL" prefWidth="-1.0" type="javafx.scene.control.ToolBar" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1"> <fx:root minWidth="-1.0" orientation="HORIZONTAL" prefWidth="-1.0" type="javafx.scene.control.ToolBar" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1">
<items> <items>
<HBox alignment="CENTER" spacing="5.0"> <HBox alignment="CENTER" spacing="5.0">
<children> <children>
<Label fx:id="groupByLabel" text="Group By:"> <Label mnemonicParsing="false" text=" Data Source: ">
<labelFor> <graphic>
<ComboBox fx:id="groupByBox" editable="false" /> <ImageView fitHeight="16.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true">
</labelFor> <image>
<Image url="@../images/datasource.png" />
</image>
</ImageView>
</graphic>
</Label> </Label>
<fx:reference source="groupByBox" /> <ComboBox fx:id="dataSourceComboBox" editable="false" />
</children> </children>
</HBox> </HBox>
<HBox alignment="CENTER" spacing="5.0">
<children>
<Label fx:id="groupByLabel" text="Group By:">
</Label>
<ComboBox fx:id="groupByBox" prefWidth="100.0" />
</children>
</HBox>
<ImageView fx:id="sortHelpImageView" fitHeight="16.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true"> <ImageView fx:id="sortHelpImageView" fitHeight="16.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true">
<image> <image>
<Image url="@../images/question-frame.png" /> <Image url="@../images/question-frame.png" />
@ -34,7 +47,7 @@
<Separator orientation="VERTICAL" prefHeight="-1.0" prefWidth="10.0" /> <Separator orientation="VERTICAL" prefHeight="-1.0" prefWidth="20.0" />
<HBox alignment="CENTER" spacing="5.0"> <HBox alignment="CENTER" spacing="5.0">
<children> <children>
<Label fx:id="tagImageViewLabel" text="Tag Group's Files:"> <Label fx:id="tagImageViewLabel" text="Tag Group's Files:">
@ -76,7 +89,7 @@
<Insets left="5.0" /> <Insets left="5.0" />
</padding> </padding>
</HBox> </HBox>
<Separator orientation="VERTICAL" prefHeight="-1.0" prefWidth="10.0" /> <Separator orientation="VERTICAL" prefHeight="-1.0" prefWidth="20.0" />
<HBox alignment="CENTER" spacing="5.0"> <HBox alignment="CENTER" spacing="5.0">
<children> <children>
<Label fx:id="thumbnailSizeLabel" text="Thumbnail Size (px):"> <Label fx:id="thumbnailSizeLabel" text="Thumbnail Size (px):">

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2013-16 Basis Technology Corp. * Copyright 2013-18 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -21,18 +21,21 @@ package org.sleuthkit.autopsy.imagegallery.gui;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.logging.Level; import java.util.logging.Level;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.InvalidationListener; import javafx.beans.InvalidationListener;
import javafx.beans.Observable; import javafx.beans.Observable;
import javafx.beans.property.DoubleProperty; import javafx.beans.property.DoubleProperty;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.scene.Cursor; import javafx.scene.Cursor;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.control.ComboBox; import javafx.scene.control.ComboBox;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.MenuItem; import javafx.scene.control.MenuItem;
import javafx.scene.control.Slider; import javafx.scene.control.Slider;
import javafx.scene.control.SplitMenuButton; import javafx.scene.control.SplitMenuButton;
@ -46,15 +49,16 @@ import org.controlsfx.control.PopOver;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.DhsImageCategory;
import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor;
import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController;
import org.sleuthkit.autopsy.imagegallery.actions.CategorizeGroupAction; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeGroupAction;
import org.sleuthkit.autopsy.imagegallery.actions.TagGroupAction; import org.sleuthkit.autopsy.imagegallery.actions.TagGroupAction;
import org.sleuthkit.autopsy.datamodel.DhsImageCategory;
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute;
import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup;
import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupSortBy; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupSortBy;
import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
/** /**
@ -66,39 +70,37 @@ public class Toolbar extends ToolBar {
private static final int SIZE_SLIDER_DEFAULT = 100; private static final int SIZE_SLIDER_DEFAULT = 100;
@FXML
private ComboBox<Optional<DataSource>> dataSourceComboBox;
@FXML @FXML
private ImageView sortHelpImageView; private ImageView sortHelpImageView;
@FXML @FXML
private ComboBox<DrawableAttribute<?>> groupByBox; private ComboBox<DrawableAttribute<?>> groupByBox;
@FXML @FXML
private Slider sizeSlider; private Slider sizeSlider;
@FXML @FXML
private SplitMenuButton catGroupMenuButton; private SplitMenuButton catGroupMenuButton;
@FXML @FXML
private SplitMenuButton tagGroupMenuButton; private SplitMenuButton tagGroupMenuButton;
@FXML @FXML
private Label groupByLabel; private Label groupByLabel;
@FXML @FXML
private Label tagImageViewLabel; private Label tagImageViewLabel;
@FXML @FXML
private Label categoryImageViewLabel; private Label categoryImageViewLabel;
@FXML @FXML
private Label thumbnailSizeLabel; private Label thumbnailSizeLabel;
private final ImageGalleryController controller;
private SortChooser<DrawableGroup, GroupSortBy> sortChooser; private SortChooser<DrawableGroup, GroupSortBy> sortChooser;
private final ImageGalleryController controller;
private final ObservableList<Optional<DataSource>> dataSources = FXCollections.observableArrayList();
private final InvalidationListener queryInvalidationListener = new InvalidationListener() { private final InvalidationListener queryInvalidationListener = new InvalidationListener() {
public void invalidated(Observable o) { @Override
public void invalidated(Observable invalidated) {
controller.getGroupManager().regroup( controller.getGroupManager().regroup(
//dataSourceComboBox.getSelectionModel().getSelectedItem(), TODO-1010/7: incorporate the selected datasource into this call.
groupByBox.getSelectionModel().getSelectedItem(), groupByBox.getSelectionModel().getSelectedItem(),
sortChooser.getComparator(), sortChooser.getComparator(),
sortChooser.getSortOrder(), sortChooser.getSortOrder(),
@ -106,10 +108,6 @@ public class Toolbar extends ToolBar {
} }
}; };
public DoubleProperty thumbnailSizeProperty() {
return sizeSlider.valueProperty();
}
@FXML @FXML
@NbBundle.Messages({"Toolbar.groupByLabel=Group By:", @NbBundle.Messages({"Toolbar.groupByLabel=Group By:",
"Toolbar.sortByLabel=Sort By:", "Toolbar.sortByLabel=Sort By:",
@ -121,21 +119,41 @@ public class Toolbar extends ToolBar {
"Toolbar.sortHelp=The sort direction (ascending/descending) affects the queue of unseen groups that Image Gallery maintains, but changes to this queue aren't apparent until the \"Next Unseen Group\" button is pressed.", "Toolbar.sortHelp=The sort direction (ascending/descending) affects the queue of unseen groups that Image Gallery maintains, but changes to this queue aren't apparent until the \"Next Unseen Group\" button is pressed.",
"Toolbar.sortHelpTitle=Group Sorting",}) "Toolbar.sortHelpTitle=Group Sorting",})
void initialize() { void initialize() {
assert catGroupMenuButton != null : "fx:id=\"catSelectedMenubutton\" was not injected: check your FXML file 'Toolbar.fxml'.";
assert groupByBox != null : "fx:id=\"groupByBox\" was not injected: check your FXML file 'Toolbar.fxml'."; assert groupByBox != null : "fx:id=\"groupByBox\" was not injected: check your FXML file 'Toolbar.fxml'.";
assert dataSourceComboBox != null : "fx:id=\"dataSourceComboBox\" was not injected: check your FXML file 'Toolbar.fxml'.";
assert sortHelpImageView != null : "fx:id=\"sortHelpImageView\" was not injected: check your FXML file 'Toolbar.fxml'.";
assert tagImageViewLabel != null : "fx:id=\"tagImageViewLabel\" was not injected: check your FXML file 'Toolbar.fxml'.";
assert tagGroupMenuButton != null : "fx:id=\"tagGroupMenuButton\" was not injected: check your FXML file 'Toolbar.fxml'.";
assert categoryImageViewLabel != null : "fx:id=\"categoryImageViewLabel\" was not injected: check your FXML file 'Toolbar.fxml'.";
assert catGroupMenuButton != null : "fx:id=\"catGroupMenuButton\" was not injected: check your FXML file 'Toolbar.fxml'.";
assert thumbnailSizeLabel != null : "fx:id=\"thumbnailSizeLabel\" was not injected: check your FXML file 'Toolbar.fxml'.";
assert sizeSlider != null : "fx:id=\"sizeSlider\" was not injected: check your FXML file 'Toolbar.fxml'."; assert sizeSlider != null : "fx:id=\"sizeSlider\" was not injected: check your FXML file 'Toolbar.fxml'.";
assert tagGroupMenuButton != null : "fx:id=\"tagSelectedMenubutton\" was not injected: check your FXML file 'Toolbar.fxml'.";
controller.viewState().addListener((observable, oldViewState, newViewState) -> { controller.viewState().addListener((observable, oldViewState, newViewState) -> {
Platform.runLater(() -> syncGroupControlsEnabledState(newViewState)); Platform.runLater(() -> syncGroupControlsEnabledState(newViewState));
}); });
syncGroupControlsEnabledState(controller.viewState().get()); syncGroupControlsEnabledState(controller.viewState().get());
dataSourceComboBox.setCellFactory(param -> new DataSourceCell());
dataSourceComboBox.setButtonCell(new DataSourceCell());
dataSourceComboBox.setItems(dataSources);
try { try {
/*
* TODO-1005: Getting the datasources and the tagnames are Db
* querries. We should probably push them off to a BG thread.
*/
dataSources.add(Optional.empty());
controller.getSleuthKitCase().getDataSources()
.forEach(dataSource -> dataSources.add(Optional.of(dataSource)));
/* TODO: 1010/7 push data source selected in dialog into UI */
dataSourceComboBox.getSelectionModel().selectFirst();
TagGroupAction followUpGroupAction = new TagGroupAction(controller.getTagsManager().getFollowUpTagName(), controller); TagGroupAction followUpGroupAction = new TagGroupAction(controller.getTagsManager().getFollowUpTagName(), controller);
tagGroupMenuButton.setOnAction(followUpGroupAction); tagGroupMenuButton.setOnAction(followUpGroupAction);
tagGroupMenuButton.setText(followUpGroupAction.getText()); tagGroupMenuButton.setText(followUpGroupAction.getText());
tagGroupMenuButton.setGraphic(followUpGroupAction.getGraphic()); tagGroupMenuButton.setGraphic(followUpGroupAction.getGraphic());
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
/* /*
* The problem appears to be a timing issue where a case is closed * The problem appears to be a timing issue where a case is closed
@ -147,8 +165,7 @@ public class Toolbar extends ToolBar {
*/ */
if (Case.isCaseOpen()) { if (Case.isCaseOpen()) {
LOGGER.log(Level.WARNING, "Could not create Follow Up tag menu item", ex); //NON-NLS LOGGER.log(Level.WARNING, "Could not create Follow Up tag menu item", ex); //NON-NLS
} } else {
else {
// don't add stack trace to log because it makes looking for real errors harder // don't add stack trace to log because it makes looking for real errors harder
LOGGER.log(Level.INFO, "Unable to get tag name. Case is closed."); //NON-NLS LOGGER.log(Level.INFO, "Unable to get tag name. Case is closed."); //NON-NLS
} }
@ -156,7 +173,7 @@ public class Toolbar extends ToolBar {
tagGroupMenuButton.showingProperty().addListener(showing -> { tagGroupMenuButton.showingProperty().addListener(showing -> {
if (tagGroupMenuButton.isShowing()) { if (tagGroupMenuButton.isShowing()) {
List<MenuItem> selTagMenues = Lists.transform(controller.getTagsManager().getNonCategoryTagNames(), List<MenuItem> selTagMenues = Lists.transform(controller.getTagsManager().getNonCategoryTagNames(),
tn -> GuiUtils.createAutoAssigningMenuItem(tagGroupMenuButton, new TagGroupAction(tn, controller))); tagName -> GuiUtils.createAutoAssigningMenuItem(tagGroupMenuButton, new TagGroupAction(tagName, controller)));
tagGroupMenuButton.getItems().setAll(selTagMenues); tagGroupMenuButton.getItems().setAll(selTagMenues);
} }
}); });
@ -180,7 +197,7 @@ public class Toolbar extends ToolBar {
groupByBox.setItems(FXCollections.observableList(DrawableAttribute.getGroupableAttrs())); groupByBox.setItems(FXCollections.observableList(DrawableAttribute.getGroupableAttrs()));
groupByBox.getSelectionModel().select(DrawableAttribute.PATH); groupByBox.getSelectionModel().select(DrawableAttribute.PATH);
groupByBox.getSelectionModel().selectedItemProperty().addListener(queryInvalidationListener);
groupByBox.disableProperty().bind(ImageGalleryController.getDefault().regroupDisabled()); groupByBox.disableProperty().bind(ImageGalleryController.getDefault().regroupDisabled());
groupByBox.setCellFactory(listView -> new AttributeListCell()); groupByBox.setCellFactory(listView -> new AttributeListCell());
groupByBox.setButtonCell(new AttributeListCell()); groupByBox.setButtonCell(new AttributeListCell());
@ -195,9 +212,8 @@ public class Toolbar extends ToolBar {
queryInvalidationListener.invalidated(observable); queryInvalidationListener.invalidated(observable);
}); });
sortChooser.sortOrderProperty().addListener(queryInvalidationListener);
sortChooser.setComparator(controller.getGroupManager().getSortBy()); sortChooser.setComparator(controller.getGroupManager().getSortBy());
getItems().add(1, sortChooser); getItems().add(2, sortChooser);
sortHelpImageView.setCursor(Cursor.HAND); sortHelpImageView.setCursor(Cursor.HAND);
sortHelpImageView.setOnMouseClicked(clicked -> { sortHelpImageView.setOnMouseClicked(clicked -> {
@ -208,6 +224,13 @@ public class Toolbar extends ToolBar {
sortHelpImageView.getImage(), text); sortHelpImageView.getImage(), text);
}); });
dataSourceComboBox.getSelectionModel().selectedItemProperty().addListener(queryInvalidationListener);
groupByBox.getSelectionModel().selectedItemProperty().addListener(queryInvalidationListener);
sortChooser.sortOrderProperty().addListener(queryInvalidationListener);
}
public DoubleProperty thumbnailSizeProperty() {
return sizeSlider.valueProperty();
} }
/** /**
@ -237,10 +260,16 @@ public class Toolbar extends ToolBar {
popOver.show(owner); popOver.show(owner);
} }
/**
* Disable the tag and catagory controls if and only if there is no group
* selected.
*
* @param newViewState The GroupViewState to use as a source of the
* selection.
*/
private void syncGroupControlsEnabledState(GroupViewState newViewState) { private void syncGroupControlsEnabledState(GroupViewState newViewState) {
boolean noGroupSelected = newViewState == null boolean noGroupSelected = (null == newViewState)
? true || (null == newViewState.getGroup());
: newViewState.getGroup() == null;
tagGroupMenuButton.setDisable(noGroupSelected); tagGroupMenuButton.setDisable(noGroupSelected);
catGroupMenuButton.setDisable(noGroupSelected); catGroupMenuButton.setDisable(noGroupSelected);
@ -257,4 +286,20 @@ public class Toolbar extends ToolBar {
this.controller = controller; this.controller = controller;
FXMLConstructor.construct(this, "Toolbar.fxml"); //NON-NLS FXMLConstructor.construct(this, "Toolbar.fxml"); //NON-NLS
} }
/**
* Cell used to represent a DataSource in the dataSourceComboBoc
*/
static private class DataSourceCell extends ListCell<Optional<DataSource>> {
@Override
protected void updateItem(Optional<DataSource> item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText("");
} else {
setText(item.map(DataSource::getName).orElse("All"));
}
}
}
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB