Merge pull request #1944 from millmanorama/IG-follow-up-flag-image

add follow up flag image to follow up action and in group list , impr…
This commit is contained in:
Richard Cordovano 2016-02-05 11:59:58 -05:00
commit 7f3396a261
13 changed files with 187 additions and 93 deletions

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2015 Basis Technology Corp. * Copyright 2015-16 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");
@ -20,10 +20,8 @@ package org.sleuthkit.autopsy.imagegallery.actions;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import java.util.Set; import java.util.Set;
import javafx.scene.image.ImageView;
import org.controlsfx.control.action.Action; import org.controlsfx.control.action.Action;
import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController;
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute;
import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TagName;
/** /**
@ -36,6 +34,6 @@ public class TagGroupAction extends Action {
Set<Long> fileIdSet = ImmutableSet.copyOf(controller.viewState().get().getGroup().getFileIDs()); Set<Long> fileIdSet = ImmutableSet.copyOf(controller.viewState().get().getGroup().getFileIDs());
new AddDrawableTagAction(controller).addTagsToFiles(tagName, "", fileIdSet); new AddDrawableTagAction(controller).addTagsToFiles(tagName, "", fileIdSet);
}); });
setGraphic(new ImageView(DrawableAttribute.TAGS.getIcon())); setGraphic(controller.getTagsManager().getGraphic(tagName));
} }
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2015 Basis Technology Corp. * Copyright 2015-16 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");
@ -18,10 +18,8 @@
*/ */
package org.sleuthkit.autopsy.imagegallery.actions; package org.sleuthkit.autopsy.imagegallery.actions;
import javafx.scene.image.ImageView;
import org.controlsfx.control.action.Action; import org.controlsfx.control.action.Action;
import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController;
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute;
import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TagName;
/** /**
@ -31,6 +29,6 @@ public class TagSelectedFilesAction extends Action {
public TagSelectedFilesAction(final TagName tagName, ImageGalleryController controller) { public TagSelectedFilesAction(final TagName tagName, ImageGalleryController controller) {
super(tagName.getDisplayName(), actionEvent -> new AddDrawableTagAction(controller).addTag(tagName, "")); super(tagName.getDisplayName(), actionEvent -> new AddDrawableTagAction(controller).addTag(tagName, ""));
setGraphic(new ImageView(DrawableAttribute.TAGS.getIcon())); setGraphic(controller.getTagsManager().getGraphic(tagName));
} }
} }

View File

@ -23,9 +23,17 @@ import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import javafx.geometry.Insets;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.Border;
import javafx.scene.layout.BorderStroke;
import javafx.scene.layout.BorderStrokeStyle;
import javafx.scene.layout.BorderWidths;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
/** /**
@ -51,6 +59,9 @@ public enum Category {
FIVE(Color.GREEN, 5, Bundle.Category_five()), FIVE(Color.GREEN, 5, Bundle.Category_five()),
ZERO(Color.LIGHTGREY, 0, Bundle.Category_zero()); ZERO(Color.LIGHTGREY, 0, Bundle.Category_zero());
private static final BorderWidths BORDER_WIDTHS_2 = new BorderWidths(2);
private static final CornerRadii CORNER_RADII_4 = new CornerRadii(4);
public static ImmutableList<Category> getNonZeroCategories() { public static ImmutableList<Category> getNonZeroCategories() {
return nonZeroCategories; return nonZeroCategories;
} }
@ -108,9 +119,10 @@ public enum Category {
} }
public Node getGraphic() { public Node getGraphic() {
Rectangle rectangle = new Rectangle(16d, 16d, getColor()); Region region = new Region();
rectangle.setArcHeight(8); region.setBackground(new Background(new BackgroundFill(getColor(), CORNER_RADII_4, Insets.EMPTY)));
rectangle.setArcWidth(8); region.setPrefSize(16, 16);
return rectangle; region.setBorder(new Border(new BorderStroke(getColor().darker(), BorderStrokeStyle.SOLID, CORNER_RADII_4, BORDER_WIDTHS_2)));
return region;
} }
} }

View File

@ -25,7 +25,9 @@ import java.util.List;
import java.util.function.Function; import java.util.function.Function;
import javafx.beans.property.ReadOnlyStringWrapper; import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.beans.property.StringProperty; import javafx.beans.property.StringProperty;
import javafx.scene.Node;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.autopsy.datamodel.ContentUtils;
@ -39,20 +41,20 @@ import org.sleuthkit.datamodel.TagName;
* of type paramaters and multivalued attributes * of type paramaters and multivalued attributes
*/ */
@NbBundle.Messages({"DrawableAttribute.md5hash=MD5 Hash", @NbBundle.Messages({"DrawableAttribute.md5hash=MD5 Hash",
"DrawableAttribute.name=Name", "DrawableAttribute.name=Name",
"DrawableAttribute.analyzed=Analyzed", "DrawableAttribute.analyzed=Analyzed",
"DrawableAttribute.category=Category", "DrawableAttribute.category=Category",
"DrawableAttribute.tags=Tags", "DrawableAttribute.tags=Tags",
"DrawableAttribute.path=Path", "DrawableAttribute.path=Path",
"DrawableAttribute.createdTime=Created Time", "DrawableAttribute.createdTime=Created Time",
"DrawableAttribute.modifiedTime=Modified Time", "DrawableAttribute.modifiedTime=Modified Time",
"DrawableAttribute.cameraMake=Camera Make", "DrawableAttribute.cameraMake=Camera Make",
"DrawableAttribute.cameraModel=Camera Model", "DrawableAttribute.cameraModel=Camera Model",
"DrawableAttribute.hashSet=Hashset", "DrawableAttribute.hashSet=Hashset",
"DrawableAttribute.intObjID=Internal Object ID", "DrawableAttribute.intObjID=Internal Object ID",
"DrawableAttribute.width=Width", "DrawableAttribute.width=Width",
"DrawableAttribute.height=Height", "DrawableAttribute.height=Height",
"DrawableAttribute.mimeType=MIME type"}) "DrawableAttribute.mimeType=MIME type"})
public class DrawableAttribute<T extends Comparable<T>> { public class DrawableAttribute<T extends Comparable<T>> {
public final static DrawableAttribute<String> MD5_HASH = public final static DrawableAttribute<String> MD5_HASH =
@ -82,10 +84,16 @@ public class DrawableAttribute<T extends Comparable<T>> {
* advantage. move categories into DrawableDB? * advantage. move categories into DrawableDB?
*/ */
public final static DrawableAttribute<Category> CATEGORY = public final static DrawableAttribute<Category> CATEGORY =
new DrawableAttribute<>(AttributeName.CATEGORY, Bundle.DrawableAttribute_category(), new DrawableAttribute<Category>(AttributeName.CATEGORY, Bundle.DrawableAttribute_category(),
false, false,
"category-icon.png", //NON-NLS "category-icon.png", //NON-NLS
f -> Collections.singleton(f.getCategory())); f -> Collections.singleton(f.getCategory())) {
@Override
public Node getGraphicForValue(Category val) {
return val.getGraphic();
}
};
public final static DrawableAttribute<TagName> TAGS = public final static DrawableAttribute<TagName> TAGS =
new DrawableAttribute<>(AttributeName.TAGS, Bundle.DrawableAttribute_tags(), new DrawableAttribute<>(AttributeName.TAGS, Bundle.DrawableAttribute_tags(),
@ -195,8 +203,8 @@ public class DrawableAttribute<T extends Comparable<T>> {
* TODO: override this to load per value icons form some attributes like * TODO: override this to load per value icons form some attributes like
* mime-type and category * mime-type and category
*/ */
public Image getIconForValue(T val) { public Node getGraphicForValue(T val) {
return getIcon(); return new ImageView(getIcon());
} }
public static List<DrawableAttribute<?>> getGroupableAttrs() { public static List<DrawableAttribute<?>> getGroupableAttrs() {

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2013-15 Basis Technology Corp. * Copyright 2013-16 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");
@ -26,6 +26,9 @@ import java.util.Objects;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javafx.scene.Node;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
@ -40,7 +43,7 @@ import org.sleuthkit.datamodel.TskCoreException;
/** /**
* Manages Tags, Tagging, and the relationship between Categories and Tags in * Manages Tags, Tagging, and the relationship between Categories and Tags in
* the autopsy Db. delegates some, work to the backing {@link TagsManager}. * the autopsy Db. Delegates some work to the backing {@link TagsManager}.
*/ */
@NbBundle.Messages({"DrawableTagsManager.followUp=Follow Up"}) @NbBundle.Messages({"DrawableTagsManager.followUp=Follow Up"})
public class DrawableTagsManager { public class DrawableTagsManager {
@ -48,11 +51,14 @@ public class DrawableTagsManager {
private static final Logger LOGGER = Logger.getLogger(DrawableTagsManager.class.getName()); private static final Logger LOGGER = Logger.getLogger(DrawableTagsManager.class.getName());
private static final String FOLLOW_UP = Bundle.DrawableTagsManager_followUp(); private static final String FOLLOW_UP = Bundle.DrawableTagsManager_followUp();
private static Image FOLLOW_UP_IMAGE;
final private Object autopsyTagsManagerLock = new Object(); final private Object autopsyTagsManagerLock = new Object();
private TagsManager autopsyTagsManager; private TagsManager autopsyTagsManager;
/** Used to distribute {@link TagsChangeEvent}s */ /**
* Used to distribute {@link TagsChangeEvent}s
*/
private final EventBus tagsEventBus = new AsyncEventBus( private final EventBus tagsEventBus = new AsyncEventBus(
Executors.newSingleThreadExecutor( Executors.newSingleThreadExecutor(
new BasicThreadFactory.Builder().namingPattern("Tags Event Bus").uncaughtExceptionHandler((Thread t, Throwable e) -> { //NON-NLS new BasicThreadFactory.Builder().namingPattern("Tags Event Bus").uncaughtExceptionHandler((Thread t, Throwable e) -> { //NON-NLS
@ -60,7 +66,9 @@ public class DrawableTagsManager {
}).build() }).build()
)); ));
/** The tag name corresponding to the "built-in" tag "Follow Up" */ /**
* The tag name corresponding to the "built-in" tag "Follow Up"
*/
private TagName followUpTagName; private TagName followUpTagName;
public DrawableTagsManager(TagsManager autopsyTagsManager) { public DrawableTagsManager(TagsManager autopsyTagsManager) {
@ -137,8 +145,8 @@ public class DrawableTagsManager {
* get all the TagNames that are not categories * get all the TagNames that are not categories
* *
* @return all the TagNames that are not categories, in alphabetical order * @return all the TagNames that are not categories, in alphabetical order
* by displayName, or, an empty set if there was an exception looking them * by displayName, or, an empty set if there was an exception
* up from the db. * looking them up from the db.
*/ */
@Nonnull @Nonnull
public List<TagName> getNonCategoryTagNames() { public List<TagName> getNonCategoryTagNames() {
@ -228,4 +236,22 @@ public class DrawableTagsManager {
autopsyTagsManager.deleteContentTag(ct); autopsyTagsManager.deleteContentTag(ct);
} }
} }
public Node getGraphic(TagName tagname) {
try {
if (tagname.equals(getFollowUpTagName())) {
return new ImageView(getFollowUpImage());
}
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Failed to get \"Follow Up\" tag name from db.", ex);
}
return DrawableAttribute.TAGS.getGraphicForValue(tagname);
}
synchronized private static Image getFollowUpImage() {
if (FOLLOW_UP_IMAGE == null) {
FOLLOW_UP_IMAGE = new Image("/org/sleuthkit/autopsy/imagegallery/images/flag_red.png");
}
return FOLLOW_UP_IMAGE;
}
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2013 Basis Technology Corp. * Copyright 2013-16 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");
@ -20,7 +20,7 @@ package org.sleuthkit.autopsy.imagegallery.datamodel.grouping;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import javafx.scene.image.Image; import javafx.scene.Node;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute;
import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TagName;
@ -89,7 +89,7 @@ public class GroupKey<T extends Comparable<T>> implements Comparable<GroupKey<T>
return val.compareTo(o.val); return val.compareTo(o.val);
} }
public Image getIcon() { public Node getGraphic() {
return attr.getIconForValue(val); return attr.getGraphicForValue(val);
} }
} }

View File

@ -1,11 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?> <?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.*?> <?import javafx.scene.control.Label?>
<?import javafx.scene.image.*?> <?import javafx.scene.control.MenuItem?>
<?import javafx.scene.layout.*?> <?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.Slider?>
<?import javafx.scene.control.SplitMenuButton?>
<?import javafx.scene.control.ToggleGroup?>
<?import javafx.scene.control.ToolBar?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Region?>
<?import javafx.scene.layout.VBox?>
<fx:root minWidth="-1.0" orientation="HORIZONTAL" prefWidth="-1.0" type="javafx.scene.control.ToolBar" xmlns="http://javafx.com/javafx/8.0.40" 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.65" xmlns:fx="http://javafx.com/fxml/1">
<items> <items>
<Label text="Group By:"> <Label text="Group By:">
<labelFor> <labelFor>
@ -13,7 +23,7 @@
</labelFor> </labelFor>
</Label> </Label>
<fx:reference source="groupByBox" /> <fx:reference source="groupByBox" />
<Region prefHeight="-1.0" prefWidth="20.0" /> <Region prefHeight="-1.0" prefWidth="10.0" />
<Label text="Sort By:"> <Label text="Sort By:">
<labelFor> <labelFor>
<ComboBox fx:id="sortByBox" /> <ComboBox fx:id="sortByBox" />
@ -50,26 +60,54 @@
</children> </children>
</HBox> </HBox>
<Separator orientation="VERTICAL" prefHeight="-1.0" prefWidth="20.0" /> <Separator orientation="VERTICAL" prefHeight="-1.0" prefWidth="20.0" />
<CheckBox fx:id="onlyAnalyzedCheckBox" allowIndeterminate="false" indeterminate="false" mnemonicParsing="false" prefWidth="16.0" selected="true" text="only analyzed groups" underline="false" visible="false" /> <HBox alignment="CENTER" spacing="5.0">
<Label contentDisplay="RIGHT" text="Apply to Group:" textOverrun="ELLIPSIS" /> <children>
<SplitMenuButton id="tagSplitMenu" fx:id="tagGroupMenuButton" disable="true" mnemonicParsing="false" text="Follow Up" textOverrun="ELLIPSIS"> <Label text="Tag Group's Files:">
<items> <graphic>
<MenuItem mnemonicParsing="false" text="Action 1" /> <ImageView fitHeight="16.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true">
<MenuItem mnemonicParsing="false" text="Action 2" /> <image>
</items> <Image url="@../images/tag_red.png" />
</SplitMenuButton> </image>
<SplitMenuButton id="catSplitMenu" fx:id="catGroupMenuButton" disable="true" mnemonicParsing="false" text="Cat-0"> </ImageView>
<items> </graphic>
<MenuItem mnemonicParsing="false" text="Action 1" /> </Label>
<MenuItem mnemonicParsing="false" text="Action 2" /> <SplitMenuButton id="tagSplitMenu" fx:id="tagGroupMenuButton" disable="true" mnemonicParsing="false" text="Follow Up" textOverrun="ELLIPSIS">
</items> <items>
</SplitMenuButton> <MenuItem mnemonicParsing="false" text="Action 1" />
<MenuItem mnemonicParsing="false" text="Action 2" />
</items>
</SplitMenuButton>
</children>
</HBox>
<HBox alignment="CENTER" spacing="5.0">
<children>
<Label text="Categorize Group's Files:">
<graphic>
<ImageView fitHeight="16.0" fitWidth="16.0" mouseTransparent="true" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../images/category-icon.png" />
</image>
</ImageView>
</graphic>
</Label>
<SplitMenuButton id="catSplitMenu" fx:id="catGroupMenuButton" disable="true" mnemonicParsing="false" text="Cat-0">
<items>
<MenuItem mnemonicParsing="false" text="Action 1" />
<MenuItem mnemonicParsing="false" text="Action 2" />
</items>
</SplitMenuButton>
</children>
</HBox>
<Separator orientation="VERTICAL" prefHeight="-1.0" prefWidth="20.0" /> <Separator orientation="VERTICAL" prefHeight="-1.0" prefWidth="20.0" />
<Label text="Thumbnail Size (px):"> <HBox alignment="CENTER" spacing="5.0">
<labelFor> <children>
<Slider fx:id="sizeSlider" blockIncrement="100.0" majorTickUnit="100.0" max="300.0" min="100.0" minorTickCount="0" orientation="HORIZONTAL" prefHeight="-1.0" showTickLabels="true" showTickMarks="true" snapToTicks="true" value="100.0" /> <Label text="Thumbnail Size (px):">
</labelFor> <labelFor>
</Label> <Slider fx:id="sizeSlider" blockIncrement="100.0" majorTickUnit="100.0" max="300.0" min="100.0" minorTickCount="0" orientation="HORIZONTAL" prefHeight="-1.0" showTickLabels="true" showTickMarks="true" snapToTicks="true" value="100.0" />
<fx:reference source="sizeSlider" /> </labelFor>
</Label>
<fx:reference source="sizeSlider" />
</children>
</HBox>
</items> </items>
</fx:root> </fx:root>

View File

@ -29,7 +29,6 @@ import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox; import javafx.scene.control.ComboBox;
import javafx.scene.control.MenuItem; import javafx.scene.control.MenuItem;
import javafx.scene.control.RadioButton; import javafx.scene.control.RadioButton;
@ -62,9 +61,6 @@ public class Toolbar extends ToolBar {
@FXML @FXML
private ComboBox<DrawableAttribute<?>> groupByBox; private ComboBox<DrawableAttribute<?>> groupByBox;
@FXML
private CheckBox onlyAnalyzedCheckBox;
@FXML @FXML
private Slider sizeSlider; private Slider sizeSlider;
@ -125,7 +121,7 @@ public class Toolbar extends ToolBar {
assert catGroupMenuButton != null : "fx:id=\"catSelectedMenubutton\" was not injected: check your FXML file 'Toolbar.fxml'."; assert catGroupMenuButton != null : "fx:id=\"catSelectedMenubutton\" was not injected: check your FXML file 'Toolbar.fxml'.";
assert descRadio != null : "fx:id=\"descRadio\" was not injected: check your FXML file 'Toolbar.fxml'."; assert descRadio != null : "fx:id=\"descRadio\" 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 onlyAnalyzedCheckBox != null : "fx:id=\"onlyAnalyzedCheckBox\" was not injected: check your FXML file 'Toolbar.fxml'.";
assert orderGroup != null : "fx:id=\"orderGroup\" was not injected: check your FXML file 'Toolbar.fxml'."; assert orderGroup != null : "fx:id=\"orderGroup\" 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 sortByBox != null : "fx:id=\"sortByBox\" was not injected: check your FXML file 'Toolbar.fxml'."; assert sortByBox != null : "fx:id=\"sortByBox\" was not injected: check your FXML file 'Toolbar.fxml'.";

View File

@ -145,6 +145,8 @@ import org.sleuthkit.datamodel.TskCoreException;
public class GroupPane extends BorderPane { public class GroupPane extends BorderPane {
private static final Logger LOGGER = Logger.getLogger(GroupPane.class.getName()); private static final Logger LOGGER = Logger.getLogger(GroupPane.class.getName());
private static final BorderWidths BORDER_WIDTHS_2 = new BorderWidths(2);
private static final CornerRadii CORNER_RADII_2 = new CornerRadii(2);
private static final DropShadow DROP_SHADOW = new DropShadow(10, Color.BLUE); private static final DropShadow DROP_SHADOW = new DropShadow(10, Color.BLUE);
@ -383,10 +385,11 @@ public class GroupPane extends BorderPane {
assert tileToggle != null : "fx:id=\"tileToggle\" was not injected: check your FXML file 'GroupHeader.fxml'."; assert tileToggle != null : "fx:id=\"tileToggle\" was not injected: check your FXML file 'GroupHeader.fxml'.";
for (Category cat : Category.values()) { for (Category cat : Category.values()) {
getToggleForCategory(cat).setBorder(new Border(new BorderStroke(cat.getColor(), BorderStrokeStyle.SOLID, new CornerRadii(1), new BorderWidths(1)))); ToggleButton toggleForCategory = getToggleForCategory(cat);
getToggleForCategory(cat).getStyleClass().remove("radio-button"); toggleForCategory.setBorder(new Border(new BorderStroke(cat.getColor(), BorderStrokeStyle.SOLID, CORNER_RADII_2, BORDER_WIDTHS_2)));
getToggleForCategory(cat).getStyleClass().add("toggle-button"); toggleForCategory.getStyleClass().remove("radio-button");
getToggleForCategory(cat).selectedProperty().addListener((ov, wasSelected, toggleSelected) -> { toggleForCategory.getStyleClass().add("toggle-button");
toggleForCategory.selectedProperty().addListener((ov, wasSelected, toggleSelected) -> {
if (toggleSelected && slideShowPane != null) { if (toggleSelected && slideShowPane != null) {
slideShowPane.getFileID().ifPresent((fileID) -> { slideShowPane.getFileID().ifPresent((fileID) -> {
selectionModel.clearAndSelect(fileID); selectionModel.clearAndSelect(fileID);

View File

@ -24,13 +24,17 @@ import javafx.application.Platform;
import javafx.beans.InvalidationListener; import javafx.beans.InvalidationListener;
import javafx.beans.Observable; import javafx.beans.Observable;
import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.scene.Node;
import javafx.scene.control.ListCell; import javafx.scene.control.ListCell;
import javafx.scene.control.OverrunStyle; import javafx.scene.control.OverrunStyle;
import javafx.scene.control.Tooltip; import javafx.scene.control.Tooltip;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import org.sleuthkit.autopsy.imagegallery.ImageGalleryController;
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.datamodel.TagName;
/** /**
* *
@ -66,9 +70,10 @@ class GroupListCell extends ListCell<DrawableGroup> {
}; };
private final ReadOnlyObjectProperty<GroupComparators<?>> sortOrder; private final ReadOnlyObjectProperty<GroupComparators<?>> sortOrder;
private final ImageGalleryController controller;
GroupListCell(ReadOnlyObjectProperty<GroupComparators<?>> sortOrderProperty) { GroupListCell(ImageGalleryController controller, ReadOnlyObjectProperty<GroupComparators<?>> sortOrderProperty) {
this.controller = controller;
this.sortOrder = sortOrderProperty; this.sortOrder = sortOrderProperty;
getStylesheets().add(GroupTreeCell.class.getResource("GroupTreeCell.css").toExternalForm()); //NON-NLS getStylesheets().add(GroupTreeCell.class.getResource("GroupTreeCell.css").toExternalForm()); //NON-NLS
getStyleClass().add("groupTreeCell"); //reduce indent to 5, default is 10 which uses up a lot of space. NON-NLS getStyleClass().add("groupTreeCell"); //reduce indent to 5, default is 10 which uses up a lot of space. NON-NLS
@ -102,10 +107,10 @@ class GroupListCell extends ListCell<DrawableGroup> {
} else { } else {
final String text = getGroupName() + getCountsText(); final String text = getGroupName() + getCountsText();
String style; String style;
Image icon; Node icon;
if (isNull(group)) { if (isNull(group)) {
//"dummy" group in file system tree <=> a folder with no drawables //"dummy" group in file system tree <=> a folder with no drawables
icon = EMPTY_FOLDER_ICON; icon = new ImageView(EMPTY_FOLDER_ICON);
style = ""; style = "";
} else { } else {
//if number of files in this group changes (eg a file is recategorized), update counts via listener //if number of files in this group changes (eg a file is recategorized), update counts via listener
@ -117,13 +122,15 @@ class GroupListCell extends ListCell<DrawableGroup> {
group.seenProperty().addListener(seenListener); group.seenProperty().addListener(seenListener);
//and use icon corresponding to group type //and use icon corresponding to group type
icon = group.getGroupKey().getIcon(); icon = (group.getGroupByAttribute() == DrawableAttribute.TAGS)
? controller.getTagsManager().getGraphic((TagName) group.getGroupByValue())
: group.getGroupKey().getGraphic();
style = getSeenStyleClass(); style = getSeenStyleClass();
} }
Platform.runLater(() -> { Platform.runLater(() -> {
setTooltip(new Tooltip(text)); setTooltip(new Tooltip(text));
setGraphic(new ImageView(icon)); setGraphic(icon);
setText(text); setText(text);
setStyle(style); setStyle(style);
}); });

View File

@ -32,7 +32,6 @@ import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView; import javafx.scene.control.TreeView;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.poi.util.Beta;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined;
import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor;
@ -73,7 +72,7 @@ final public class GroupTree extends NavPanel<TreeItem<GroupTreeNode>> {
getToolBar().visibleProperty().bind(groupedByPath.not()); getToolBar().visibleProperty().bind(groupedByPath.not());
getToolBar().managedProperty().bind(groupedByPath.not()); getToolBar().managedProperty().bind(groupedByPath.not());
groupTree.setCellFactory(treeView -> new GroupTreeCell(getSortByBox().getSelectionModel().selectedItemProperty())); groupTree.setCellFactory(treeView -> new GroupTreeCell(getController(), getSortByBox().getSelectionModel().selectedItemProperty()));
groupTree.setShowRoot(false); groupTree.setShowRoot(false);
getGroupManager().getAnalyzedGroups().addListener((ListChangeListener.Change<? extends DrawableGroup> change) -> { getGroupManager().getAnalyzedGroups().addListener((ListChangeListener.Change<? extends DrawableGroup> change) -> {

View File

@ -24,6 +24,7 @@ import javafx.application.Platform;
import javafx.beans.InvalidationListener; import javafx.beans.InvalidationListener;
import javafx.beans.Observable; import javafx.beans.Observable;
import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.scene.Node;
import javafx.scene.control.OverrunStyle; import javafx.scene.control.OverrunStyle;
import javafx.scene.control.Tooltip; import javafx.scene.control.Tooltip;
import javafx.scene.control.TreeCell; import javafx.scene.control.TreeCell;
@ -31,7 +32,10 @@ import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.sleuthkit.autopsy.imagegallery.ImageGalleryController;
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.datamodel.TagName;
/** /**
* A cell in the NavPanel tree that listens to its associated group's fileids * A cell in the NavPanel tree that listens to its associated group's fileids
@ -72,8 +76,10 @@ class GroupTreeCell extends TreeCell<GroupTreeNode> {
}); });
}; };
private final ReadOnlyObjectProperty<GroupComparators<?>> sortOrder; private final ReadOnlyObjectProperty<GroupComparators<?>> sortOrder;
private final ImageGalleryController controller;
GroupTreeCell(ReadOnlyObjectProperty<GroupComparators<?>> sortOrderProperty) { GroupTreeCell(ImageGalleryController controller, ReadOnlyObjectProperty<GroupComparators<?>> sortOrderProperty) {
this.controller = controller;
this.sortOrder = sortOrderProperty; this.sortOrder = sortOrderProperty;
getStylesheets().add(GroupTreeCell.class.getResource("GroupTreeCell.css").toExternalForm()); //NON-NLS getStylesheets().add(GroupTreeCell.class.getResource("GroupTreeCell.css").toExternalForm()); //NON-NLS
getStyleClass().add("groupTreeCell"); //reduce indent to 5, default is 10 which uses up a lot of space. NON-NLS getStyleClass().add("groupTreeCell"); //reduce indent to 5, default is 10 which uses up a lot of space. NON-NLS
@ -112,7 +118,8 @@ class GroupTreeCell extends TreeCell<GroupTreeNode> {
setStyle(""); setStyle("");
}); });
} else { } else {
if (isNull(treeNode.getGroup())) { DrawableGroup group = treeNode.getGroup();
if (isNull(group)) {
final String text = getGroupName(); final String text = getGroupName();
//"dummy" group in file system tree <=> a folder with no drawables //"dummy" group in file system tree <=> a folder with no drawables
Platform.runLater(() -> { Platform.runLater(() -> {
@ -124,20 +131,22 @@ class GroupTreeCell extends TreeCell<GroupTreeNode> {
} else { } else {
//if number of files in this group changes (eg a file is recategorized), update counts via listener //if number of files in this group changes (eg a file is recategorized), update counts via listener
treeNode.getGroup().getFileIDs().addListener(fileCountListener); group.getFileIDs().addListener(fileCountListener);
treeNode.getGroup().uncatCountProperty().addListener(fileCountListener); group.uncatCountProperty().addListener(fileCountListener);
treeNode.getGroup().hashSetHitsCountProperty().addListener(fileCountListener); group.hashSetHitsCountProperty().addListener(fileCountListener);
sortOrder.addListener(fileCountListener); sortOrder.addListener(fileCountListener);
//if the seen state of this group changes update its style //if the seen state of this group changes update its style
treeNode.getGroup().seenProperty().addListener(seenListener); group.seenProperty().addListener(seenListener);
//and use icon corresponding to group type //and use icon corresponding to group type
final Image icon = treeNode.getGroup().getGroupKey().getIcon(); Node icon = (group.getGroupByAttribute() == DrawableAttribute.TAGS)
? controller.getTagsManager().getGraphic((TagName) group.getGroupByValue())
: group.getGroupKey().getGraphic();
final String text = getGroupName() + getCountsText(); final String text = getGroupName() + getCountsText();
final String style = getSeenStyleClass(); final String style = getSeenStyleClass();
Platform.runLater(() -> { Platform.runLater(() -> {
setTooltip(new Tooltip(text)); setTooltip(new Tooltip(text));
setGraphic(new ImageView(icon)); setGraphic(icon);
setText(text); setText(text);
setStyle(style); setStyle(style);
}); });

View File

@ -79,7 +79,7 @@ final public class HashHitGroupList extends NavPanel<DrawableGroup> {
getBorderPane().setCenter(groupList); getBorderPane().setCenter(groupList);
sorted = getController().getGroupManager().getAnalyzedGroups().filtered((DrawableGroup t) -> t.getHashSetHitsCount() > 0).sorted(getDefaultComparator()); sorted = getController().getGroupManager().getAnalyzedGroups().filtered((DrawableGroup t) -> t.getHashSetHitsCount() > 0).sorted(getDefaultComparator());
groupList.setCellFactory(treeView -> new GroupListCell(getSortByBox().getSelectionModel().selectedItemProperty())); groupList.setCellFactory(treeView -> new GroupListCell(getController(), getSortByBox().getSelectionModel().selectedItemProperty()));
groupList.setItems(sorted); groupList.setItems(sorted);
} }