add new sort order buttons, add new SortChooser control, refactor GroupSortBy to implement Comparator directly, refactor ToolBar, GroupManager etc accordingly and to use new SortChooser

This commit is contained in:
jmillman 2016-01-29 15:15:19 -05:00
parent 02c4336aaf
commit 5ba21cf3c3
11 changed files with 384 additions and 274 deletions

View File

@ -903,16 +903,11 @@ public final class DrawableDB {
StringBuilder query = new StringBuilder("SELECT " + groupBy.attrName.toString() + ", COUNT(*) FROM drawable_files GROUP BY " + groupBy.attrName.toString()); //NON-NLS StringBuilder query = new StringBuilder("SELECT " + groupBy.attrName.toString() + ", COUNT(*) FROM drawable_files GROUP BY " + groupBy.attrName.toString()); //NON-NLS
String orderByClause = ""; String orderByClause = "";
switch (sortBy) {
case GROUP_BY_VALUE: if (sortBy == GROUP_BY_VALUE) {
orderByClause = " ORDER BY " + groupBy.attrName.toString(); //NON-NLS orderByClause = " ORDER BY " + groupBy.attrName.toString();
break; } else if (sortBy == GroupSortBy.FILE_COUNT) {
case FILE_COUNT: orderByClause = " ORDER BY COUNT(*)";
orderByClause = " ORDER BY COUNT(*)"; //NON-NLS
break;
case NONE:
// case PRIORITY:
break;
} }
query.append(orderByClause); query.append(orderByClause);

View File

@ -25,6 +25,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -126,7 +127,7 @@ public class GroupManager {
private volatile DrawableAttribute<?> groupBy = DrawableAttribute.PATH; private volatile DrawableAttribute<?> groupBy = DrawableAttribute.PATH;
private volatile SortOrder sortOrder = SortOrder.ASCENDING; private volatile SortOrder sortOrder = SortOrder.ASCENDING;
private final ReadOnlyObjectWrapper<GroupSortBy> sortByProp = new ReadOnlyObjectWrapper<>(sortBy); private final ReadOnlyObjectWrapper< Comparator<DrawableGroup>> sortByProp = new ReadOnlyObjectWrapper<>(sortBy);
private final ReadOnlyObjectWrapper< DrawableAttribute<?>> groupByProp = new ReadOnlyObjectWrapper<>(groupBy); private final ReadOnlyObjectWrapper< DrawableAttribute<?>> groupByProp = new ReadOnlyObjectWrapper<>(groupBy);
private final ReadOnlyObjectWrapper<SortOrder> sortOrderProp = new ReadOnlyObjectWrapper<>(sortOrder); private final ReadOnlyObjectWrapper<SortOrder> sortOrderProp = new ReadOnlyObjectWrapper<>(sortOrder);
@ -274,7 +275,7 @@ public class GroupManager {
} else if (unSeenGroups.contains(group) == false) { } else if (unSeenGroups.contains(group) == false) {
unSeenGroups.add(group); unSeenGroups.add(group);
} }
FXCollections.sort(unSeenGroups, sortBy.getGrpComparator(sortOrder)); FXCollections.sort(unSeenGroups, applySortOrder(sortOrder, sortBy));
} }
/** /**
@ -299,11 +300,11 @@ public class GroupManager {
Platform.runLater(() -> { Platform.runLater(() -> {
if (analyzedGroups.contains(group)) { if (analyzedGroups.contains(group)) {
analyzedGroups.remove(group); analyzedGroups.remove(group);
FXCollections.sort(analyzedGroups, sortBy.getGrpComparator(sortOrder)); FXCollections.sort(analyzedGroups, applySortOrder(sortOrder, sortBy));
} }
if (unSeenGroups.contains(group)) { if (unSeenGroups.contains(group)) {
unSeenGroups.remove(group); unSeenGroups.remove(group);
FXCollections.sort(unSeenGroups, sortBy.getGrpComparator(sortOrder)); FXCollections.sort(unSeenGroups, applySortOrder(sortOrder, sortBy));
} }
}); });
} }
@ -450,7 +451,7 @@ public class GroupManager {
} }
} }
public GroupSortBy getSortBy() { public Comparator<DrawableGroup> getSortBy() {
return sortBy; return sortBy;
} }
@ -459,7 +460,7 @@ public class GroupManager {
Platform.runLater(() -> sortByProp.set(sortBy)); Platform.runLater(() -> sortByProp.set(sortBy));
} }
public ReadOnlyObjectProperty<GroupSortBy> getSortByProperty() { public ReadOnlyObjectProperty< Comparator<DrawableGroup>> getSortByProperty() {
return sortByProp.getReadOnlyProperty(); return sortByProp.getReadOnlyProperty();
} }
@ -523,8 +524,8 @@ public class GroupManager {
setSortBy(sortBy); setSortBy(sortBy);
setSortOrder(sortOrder); setSortOrder(sortOrder);
Platform.runLater(() -> { Platform.runLater(() -> {
FXCollections.sort(analyzedGroups, sortBy.getGrpComparator(sortOrder)); FXCollections.sort(analyzedGroups, applySortOrder(sortOrder, sortBy));
FXCollections.sort(unSeenGroups, sortBy.getGrpComparator(sortOrder)); FXCollections.sort(unSeenGroups, applySortOrder(sortOrder, sortBy));
}); });
} }
} }
@ -675,7 +676,7 @@ public class GroupManager {
if (analyzedGroups.contains(group) == false) { if (analyzedGroups.contains(group) == false) {
analyzedGroups.add(group); analyzedGroups.add(group);
if (Objects.isNull(task)) { if (Objects.isNull(task)) {
FXCollections.sort(analyzedGroups, sortBy.getGrpComparator(sortOrder)); FXCollections.sort(analyzedGroups, applySortOrder(sortOrder, sortBy));
} }
} }
markGroupSeen(group, groupSeen); markGroupSeen(group, groupSeen);
@ -735,8 +736,8 @@ public class GroupManager {
private final SortOrder sortOrder; private final SortOrder sortOrder;
public ReGroupTask(DrawableAttribute<A> groupBy, GroupSortBy sortBy, SortOrder sortOrder) { ReGroupTask(DrawableAttribute<A> groupBy, GroupSortBy sortBy, SortOrder sortOrder) {
super(Bundle.ReGroupTask_displayTitle(groupBy.attrName.toString(), sortBy.name(), sortOrder.toString()), true); super(Bundle.ReGroupTask_displayTitle(groupBy.attrName.toString(), sortBy.getDisplayName(), sortOrder.toString()), true);
this.groupBy = groupBy; this.groupBy = groupBy;
this.sortBy = sortBy; this.sortBy = sortBy;
@ -755,7 +756,7 @@ public class GroupManager {
return null; return null;
} }
groupProgress = ProgressHandleFactory.createHandle(Bundle.ReGroupTask_displayTitle(groupBy.attrName.toString(), sortBy.name(), sortOrder.toString()), this); groupProgress = ProgressHandleFactory.createHandle(Bundle.ReGroupTask_displayTitle(groupBy.attrName.toString(), sortBy.getDisplayName(), sortOrder.toString()), this);
Platform.runLater(() -> { Platform.runLater(() -> {
analyzedGroups.clear(); analyzedGroups.clear();
unSeenGroups.clear(); unSeenGroups.clear();
@ -778,7 +779,7 @@ public class GroupManager {
groupProgress.progress(Bundle.ReGroupTask_progressUpdate(groupBy.attrName.toString(), val), p); groupProgress.progress(Bundle.ReGroupTask_progressUpdate(groupBy.attrName.toString(), val), p);
popuplateIfAnalyzed(new GroupKey<A>(groupBy, val), this); popuplateIfAnalyzed(new GroupKey<A>(groupBy, val), this);
} }
Platform.runLater(() -> FXCollections.sort(analyzedGroups, sortBy.getGrpComparator(sortOrder))); Platform.runLater(() -> FXCollections.sort(analyzedGroups, applySortOrder(sortOrder, sortBy)));
updateProgress(1, 1); updateProgress(1, 1);
return null; return null;
@ -793,4 +794,16 @@ public class GroupManager {
} }
} }
} }
private static <T> Comparator<T> applySortOrder(final SortOrder sortOrder, Comparator<T> comparator) {
switch (sortOrder) {
case ASCENDING:
return comparator;
case DESCENDING:
return comparator.reversed();
case UNSORTED:
default:
return new GroupSortBy.AllEqualComparator<>();
}
}
} }

View File

@ -18,89 +18,50 @@
*/ */
package org.sleuthkit.autopsy.imagegallery.datamodel.grouping; package org.sleuthkit.autopsy.imagegallery.datamodel.grouping;
import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javax.swing.SortOrder;
import static javax.swing.SortOrder.ASCENDING;
import static javax.swing.SortOrder.DESCENDING;
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.imagegallery.ImageGalleryController;
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute;
/** /**
* enum of possible properties to sort groups by. This is the model for the drop * Pseudo enum of possible properties to sort groups by.
* down in Toolbar as well as each enum value having the stategy
* ({@link Comparator}) for sorting the groups
*/ */
@NbBundle.Messages({"GroupSortBy.groupSize=Group Size", @NbBundle.Messages({"GroupSortBy.groupSize=Group Size",
"GroupSortBy.groupName=Group Name", "GroupSortBy.groupName=Group Name",
"GroupSortBy.none=None", "GroupSortBy.none=None",
"GroupSortBy.priority=Priority"}) "GroupSortBy.priority=Priority"})
public enum GroupSortBy implements ComparatorProvider { public class GroupSortBy implements Comparator<DrawableGroup> {
/** /**
* sort the groups by the number of files in each sort the groups by the * sort the groups by the number of files in each
* number of files in each
*/ */
FILE_COUNT(Bundle.GroupSortBy_groupSize(), true, "folder-open-image.png") { //NON-NLS public final static GroupSortBy FILE_COUNT = new GroupSortBy(Bundle.GroupSortBy_groupSize(), "folder-open-image.png", Comparator.comparing(DrawableGroup::getSize));
@Override
public Comparator<DrawableGroup> getGrpComparator(final SortOrder sortOrder) {
return applySortOrder(sortOrder, Comparator.comparingInt(DrawableGroup::getSize));
}
@Override
public <A extends Comparable<A>> Comparator<A> getValueComparator(final DrawableAttribute<A> attr, final SortOrder sortOrder) {
return getDefaultValueComparator(attr, sortOrder);
}
},
/** /**
* sort the groups by the natural order of the grouping value ( eg group * sort the groups by the natural order of the grouping value ( eg group
* them by path alphabetically ) * them by path alphabetically )
*/ */
GROUP_BY_VALUE(Bundle.GroupSortBy_groupName(), true, "folder-rename.png") { //NON-NLS public final static GroupSortBy GROUP_BY_VALUE = new GroupSortBy(Bundle.GroupSortBy_groupName(), "folder-rename.png", Comparator.comparing(DrawableGroup::getGroupByValueDislpayName));
@Override
public Comparator<DrawableGroup> getGrpComparator(final SortOrder sortOrder) {
return applySortOrder(sortOrder, Comparator.comparing(t -> t.getGroupByValueDislpayName()));
}
@Override
public <A extends Comparable<A>> Comparator<A> getValueComparator(final DrawableAttribute<A> attr, final SortOrder sortOrder) {
return applySortOrder(sortOrder, Comparator.<A>naturalOrder());
}
},
/** /**
* don't sort the groups just use what ever order they come in (ingest * don't sort the groups just use what ever order they come in (ingest
* order) * order)
*/ */
NONE(Bundle.GroupSortBy_none(), false, "prohibition.png") { //NON-NLS public final static GroupSortBy NONE = new GroupSortBy(Bundle.GroupSortBy_none(), "prohibition.png", new AllEqualComparator<>());
@Override
public Comparator<DrawableGroup> getGrpComparator(SortOrder sortOrder) {
return new NoOpComparator<>();
}
@Override
public <A extends Comparable<A>> Comparator<A> getValueComparator(DrawableAttribute<A> attr, final SortOrder sortOrder) {
return new NoOpComparator<>();
}
},
/** /**
* sort the groups by some priority metric to be determined and implemented * sort the groups by some priority metric to be determined and implemented
*/ */
PRIORITY(Bundle.GroupSortBy_priority(), false, "hashset_hits.png") { //NON-NLS public final static GroupSortBy PRIORITY = new GroupSortBy(Bundle.GroupSortBy_priority(), "hashset_hits.png", Comparator.comparing(DrawableGroup::getHashHitDensity).thenComparing(Comparator.comparing(DrawableGroup::getUncategorizedCount)));
@Override
public Comparator<DrawableGroup> getGrpComparator(SortOrder sortOrder) {
return Comparator.nullsLast(Comparator.comparingDouble(DrawableGroup::getHashHitDensity).thenComparingInt(DrawableGroup::getSize).reversed());
}
@Override @Override
public <A extends Comparable<A>> Comparator<A> getValueComparator(DrawableAttribute<A> attr, SortOrder sortOrder) { public int compare(DrawableGroup o1, DrawableGroup o2) {
return getDefaultValueComparator(attr, sortOrder); return delegate.compare(o1, o2);
} }
};
private final static ObservableList<GroupSortBy> values = FXCollections.unmodifiableObservableList(FXCollections.observableArrayList(PRIORITY, NONE, GROUP_BY_VALUE, FILE_COUNT));
/** /**
* get a list of the values of this enum * get a list of the values of this enum
@ -108,8 +69,7 @@ public enum GroupSortBy implements ComparatorProvider {
* @return * @return
*/ */
public static ObservableList<GroupSortBy> getValues() { public static ObservableList<GroupSortBy> getValues() {
return FXCollections.observableArrayList(Arrays.asList(values())); return values;
} }
final private String displayName; final private String displayName;
@ -118,12 +78,12 @@ public enum GroupSortBy implements ComparatorProvider {
private final String imageName; private final String imageName;
private final Boolean sortOrderEnabled; private final Comparator<DrawableGroup> delegate;
private GroupSortBy(String displayName, Boolean sortOrderEnabled, String imagePath) { private GroupSortBy(String displayName, String imagePath, Comparator<DrawableGroup> internalComparator) {
this.displayName = displayName; this.displayName = displayName;
this.sortOrderEnabled = sortOrderEnabled;
this.imageName = imagePath; this.imageName = imagePath;
this.delegate = internalComparator;
} }
public String getDisplayName() { public String getDisplayName() {
@ -139,49 +99,11 @@ public enum GroupSortBy implements ComparatorProvider {
return icon; return icon;
} }
public Boolean isSortOrderEnabled() { static class AllEqualComparator<A> implements Comparator<A> {
return sortOrderEnabled;
}
private static <T> Comparator<T> applySortOrder(final SortOrder sortOrder, Comparator<T> comparator) {
switch (sortOrder) {
case ASCENDING:
return comparator;
case DESCENDING:
return comparator.reversed();
case UNSORTED:
default:
return new NoOpComparator<>();
}
}
private static class NoOpComparator<A> implements Comparator<A> {
@Override @Override
public int compare(A o1, A o2) { public int compare(A o1, A o2) {
return 0; return 0;
} }
} }
}
/**
* * implementers of this interface must provide a method to compare
* ({@link Comparable}) values and Groupings based on an
* {@link DrawableAttribute} and a {@link SortOrder}
*/
interface ComparatorProvider {
<A extends Comparable<A>> Comparator<A> getValueComparator(DrawableAttribute<A> attr, SortOrder sortOrder);
Comparator<DrawableGroup> getGrpComparator(SortOrder sortOrder);
default <A extends Comparable<A>> Comparator<A> getDefaultValueComparator(DrawableAttribute<A> attr, SortOrder sortOrder) {
return (A v1, A v2) -> {
DrawableGroup g1 = ImageGalleryController.getDefault().getGroupManager().getGroupForKey(new GroupKey<>(attr, v1));
DrawableGroup g2 = ImageGalleryController.getDefault().getGroupManager().getGroupForKey(new GroupKey<>(attr, v2));
return getGrpComparator(sortOrder).compare(g1, g2);
};
}
} }

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.ToggleGroup?>
<?import javafx.scene.control.Tooltip?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.HBox?>
<?import org.controlsfx.control.SegmentedButton?>
<fx:root id="HBox" alignment="CENTER" spacing="5.0" type="HBox" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Label fx:id="label" text="Sort By:">
<labelFor>
<ComboBox fx:id="sortByBox" />
</labelFor>
</Label>
<fx:reference fx:id="sortBox" source="sortByBox" />
<SegmentedButton>
<buttons>
<RadioButton fx:id="ascRadio" contentDisplay="LEFT" mnemonicParsing="false" selected="true">
<toggleGroup>
<ToggleGroup fx:id="orderGroup" />
</toggleGroup>
<graphic>
<ImageView fitHeight="0.0" fitWidth="0.0" mouseTransparent="true" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../images/sort_ascending.png" />
</image>
</ImageView>
</graphic>
<tooltip>
<Tooltip text="Ascending" />
</tooltip>
</RadioButton>
<RadioButton fx:id="descRadio" contentDisplay="LEFT" mnemonicParsing="false" selected="false" toggleGroup="$orderGroup">
<graphic>
<ImageView fitHeight="0.0" fitWidth="0.0" mouseTransparent="true" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../images/sort_descending.png" />
</image>
</ImageView>
</graphic>
<tooltip>
<Tooltip text="Descending" />
</tooltip>
</RadioButton>
</buttons>
</SegmentedButton>
</children>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</fx:root>

View File

@ -0,0 +1,178 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2016 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.imagegallery.gui;
import java.lang.reflect.InvocationTargetException;
import java.util.Comparator;
import javafx.beans.binding.ObjectBinding;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListCell;
import javafx.scene.control.RadioButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javax.swing.SortOrder;
import org.openide.util.Exceptions;
import org.sleuthkit.autopsy.imagegallery.FXMLConstructor;
/**
*
*/
public class SortChooser<X, Y extends Comparator<X>> extends HBox {
@FXML
private RadioButton ascRadio;
@FXML
private RadioButton descRadio;
@FXML
private ToggleGroup orderGroup;
@FXML
private ComboBox<Y> sortByBox;
private final ObservableList<Y> comparators;
private final ReadOnlyObjectWrapper<SortOrder> sortOrder = new ReadOnlyObjectWrapper<>(SortOrder.ASCENDING);
private final SimpleBooleanProperty sortOrderDisabled = new SimpleBooleanProperty(false);
private final SimpleObjectProperty<ValueType> valueType = new SimpleObjectProperty<>(ValueType.NUMERIC);
private ObjectBinding<Y> comparator;
public SortChooser(ObservableList<Y> comps) {
this.comparators = comps;
FXMLConstructor.construct(this, "SortChooser.fxml");
}
public ValueType getValueType() {
return valueType.get();
}
public void setValueType(ValueType type) {
valueType.set(type);
}
public SimpleObjectProperty<ValueType> valueTypeProperty() {
return valueType;
}
@FXML
void initialize() {
assert ascRadio != null : "fx:id=\"ascRadio\" 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 orderGroup != null : "fx:id=\"orderGroup\" was not injected: check your FXML file 'Toolbar.fxml'.";
assert sortByBox != null : "fx:id=\"sortByBox\" was not injected: check your FXML file 'Toolbar.fxml'.";
ascRadio.getStyleClass().remove("radio-button");
ascRadio.getStyleClass().add("toggle-button");
descRadio.getStyleClass().remove("radio-button");
descRadio.getStyleClass().add("toggle-button");
valueType.addListener((observable, oldValue, newValue) -> {
ascRadio.setGraphic(new ImageView(newValue.getAscendingImage()));
descRadio.setGraphic(new ImageView(newValue.getDescendingImage()));
});
ascRadio.disableProperty().bind(sortOrderDisabled);
descRadio.disableProperty().bind(sortOrderDisabled);
orderGroup.selectedToggleProperty().addListener(selectedToggle -> {
sortOrder.set(orderGroup.getSelectedToggle() == ascRadio ? SortOrder.ASCENDING : SortOrder.DESCENDING);
});
sortByBox.setItems(comparators);
sortByBox.setCellFactory(listView -> new ComparatorCell());
sortByBox.setButtonCell(new ComparatorCell());
}
void setSortOrderDisabled(boolean disabled) {
sortOrderDisabled.set(disabled);
}
public boolean isSortOrderDisabled() {
return sortOrderDisabled.get();
}
SimpleBooleanProperty sortOrderDisabledProperty() {
return sortOrderDisabled;
}
SortOrder getSortOrder() {
return sortOrder.get();
}
ReadOnlyObjectProperty<SortOrder> sortOrderProperty() {
return sortOrder.getReadOnlyProperty();
}
Y getComparator() {
return sortByBox.getSelectionModel().getSelectedItem();
}
void setComparator(Y selected) {
sortByBox.getSelectionModel().select(selected);
}
ReadOnlyObjectProperty<Y> comparatorProperty() {
return sortByBox.getSelectionModel().selectedItemProperty();
}
public enum ValueType {
LEXICOGRAPHIC("sort_asc_az.png", "sort_desc_az.png"),
NUMERIC("sort_ascending.png", "sort_descending.png");
private final Image ascImage;
private final Image descImage;
private ValueType(String ascImageName, String descImageName) {
this.ascImage = new Image("/org/sleuthkit/autopsy/imagegallery/images/" + ascImageName);
this.descImage = new Image("/org/sleuthkit/autopsy/imagegallery/images/" + descImageName);
}
private Image getAscendingImage() {
return ascImage;
}
private Image getDescendingImage() {
return descImage;
}
}
private class ComparatorCell extends ListCell<Y> {
@Override
protected void updateItem(Y item, boolean empty) {
super.updateItem(item, empty); //To change body of generated methods, choose Tools | Templates.
try {
String displayName = (String) item.getClass().getMethod("getDisplayName").invoke(item);
setText(displayName);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
Exceptions.printStackTrace(ex);
setText(item.toString());
} catch (NullPointerException ex) {
setText("NPE");
}
}
}
}

View File

@ -1,65 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?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?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.Separator?> <?import javafx.scene.control.Separator?>
<?import javafx.scene.control.Slider?> <?import javafx.scene.control.Slider?>
<?import javafx.scene.control.SplitMenuButton?> <?import javafx.scene.control.SplitMenuButton?>
<?import javafx.scene.control.ToggleGroup?>
<?import javafx.scene.control.ToolBar?> <?import javafx.scene.control.ToolBar?>
<?import javafx.scene.image.Image?> <?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?> <?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.HBox?> <?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.65" 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>
<HBox alignment="CENTER" spacing="5.0">
<children>
<Label fx:id="groupByLabel" text="Group By:"> <Label fx:id="groupByLabel" text="Group By:">
<labelFor> <labelFor>
<ComboBox fx:id="groupByBox" editable="false" /> <ComboBox fx:id="groupByBox" editable="false" />
</labelFor> </labelFor>
</Label> </Label>
<fx:reference source="groupByBox" /> <fx:reference source="groupByBox" />
<Region prefHeight="-1.0" prefWidth="10.0" />
<Label fx:id="sortByLabel" text="Sort By:">
<labelFor>
<ComboBox fx:id="sortByBox" />
</labelFor>
</Label>
<HBox id="HBox" fx:id="sortControlGroup" alignment="CENTER" spacing="5.0">
<children>
<fx:reference source="sortByBox" />
<VBox alignment="CENTER_LEFT" prefHeight="-1.0" prefWidth="-1.0" spacing="2.0">
<children>
<RadioButton fx:id="ascRadio" contentDisplay="LEFT" mnemonicParsing="false" selected="true" text="Ascending">
<graphic>
<ImageView fitHeight="0.0" fitWidth="0.0" mouseTransparent="true" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../images/arrow_up.png" />
</image>
</ImageView>
</graphic>
<toggleGroup>
<ToggleGroup fx:id="orderGroup" />
</toggleGroup>
</RadioButton>
<RadioButton fx:id="descRadio" contentDisplay="LEFT" mnemonicParsing="false" selected="false" text="Descending" toggleGroup="$orderGroup">
<graphic>
<ImageView fitHeight="0.0" fitWidth="0.0" mouseTransparent="true" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../images/arrow_down.png" />
</image>
</ImageView>
</graphic>
</RadioButton>
</children>
</VBox>
</children> </children>
</HBox> </HBox>
<Separator orientation="VERTICAL" prefHeight="-1.0" prefWidth="20.0" />
<Separator orientation="VERTICAL" prefHeight="-1.0" prefWidth="10.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:">
@ -97,8 +67,11 @@
</items> </items>
</SplitMenuButton> </SplitMenuButton>
</children> </children>
<padding>
<Insets left="5.0" />
</padding>
</HBox> </HBox>
<Separator orientation="VERTICAL" prefHeight="-1.0" prefWidth="20.0" /> <Separator orientation="VERTICAL" prefHeight="-1.0" prefWidth="10.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

@ -32,12 +32,9 @@ import javafx.fxml.FXML;
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;
import javafx.scene.control.RadioButton;
import javafx.scene.control.Slider; import javafx.scene.control.Slider;
import javafx.scene.control.SplitMenuButton; import javafx.scene.control.SplitMenuButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.control.ToolBar; import javafx.scene.control.ToolBar;
import javafx.scene.layout.HBox;
import javax.swing.SortOrder; import javax.swing.SortOrder;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
@ -48,6 +45,7 @@ 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.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.Category;
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.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.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
@ -67,21 +65,6 @@ public class Toolbar extends ToolBar {
@FXML @FXML
private Slider sizeSlider; private Slider sizeSlider;
@FXML
private ComboBox<GroupSortBy> sortByBox;
@FXML
private RadioButton ascRadio;
@FXML
private RadioButton descRadio;
@FXML
private ToggleGroup orderGroup;
@FXML
private HBox sortControlGroup;
@FXML @FXML
private SplitMenuButton catGroupMenuButton; private SplitMenuButton catGroupMenuButton;
@ -91,8 +74,7 @@ public class Toolbar extends ToolBar {
@FXML @FXML
private Label groupByLabel; private Label groupByLabel;
@FXML
private Label sortByLabel;
@FXML @FXML
private Label tagImageViewLabel; private Label tagImageViewLabel;
@ -107,20 +89,18 @@ public class Toolbar extends ToolBar {
private final SimpleObjectProperty<SortOrder> orderProperty = new SimpleObjectProperty<>(SortOrder.ASCENDING); private final SimpleObjectProperty<SortOrder> orderProperty = new SimpleObjectProperty<>(SortOrder.ASCENDING);
private final InvalidationListener queryInvalidationListener = (Observable o) -> {
if (orderGroup.getSelectedToggle() == ascRadio) {
orderProperty.set(SortOrder.ASCENDING);
} else {
orderProperty.set(SortOrder.DESCENDING);
}
ImageGalleryController.getDefault().getGroupManager().regroup(groupByBox.getSelectionModel().getSelectedItem(), sortByBox.getSelectionModel().getSelectedItem(), getSortOrder(), false);
};
private final ImageGalleryController controller; private final ImageGalleryController controller;
private SortChooser<DrawableGroup, GroupSortBy> sortChooser;
synchronized public SortOrder getSortOrder() { private final InvalidationListener queryInvalidationListener = new InvalidationListener() {
return orderProperty.get(); public void invalidated(Observable o) {
controller.getGroupManager().regroup(
groupByBox.getSelectionModel().getSelectedItem(),
sortChooser.getComparator(),
sortChooser.getSortOrder(),
false);
} }
};
public DoubleProperty sizeSliderValue() { public DoubleProperty sizeSliderValue() {
return sizeSlider.valueProperty(); return sizeSlider.valueProperty();
@ -142,15 +122,9 @@ public class Toolbar extends ToolBar {
"Toolbar.categoryImageViewLabel=Categorize Group's Files:", "Toolbar.categoryImageViewLabel=Categorize Group's Files:",
"Toolbar.thumbnailSizeLabel=Thumbnail Size (px):"}) "Toolbar.thumbnailSizeLabel=Thumbnail Size (px):"})
void initialize() { void initialize() {
assert ascRadio != null : "fx:id=\"ascRadio\" 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 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 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 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 sortControlGroup != null : "fx:id=\"sortControlGroup\" was not injected: check your FXML file 'Toolbar.fxml'.";
assert tagGroupMenuButton != null : "fx:id=\"tagSelectedMenubutton\" 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) -> {
@ -175,9 +149,6 @@ public class Toolbar extends ToolBar {
}); });
groupByLabel.setText(Bundle.Toolbar_groupByLabel()); groupByLabel.setText(Bundle.Toolbar_groupByLabel());
sortByLabel.setText(Bundle.Toolbar_sortByLabel());
ascRadio.setText(Bundle.Toolbar_ascRadio());
descRadio.setText(Bundle.Toolbar_descRadio());
tagImageViewLabel.setText(Bundle.Toolbar_tagImageViewLabel()); tagImageViewLabel.setText(Bundle.Toolbar_tagImageViewLabel());
categoryImageViewLabel.setText(Bundle.Toolbar_categoryImageViewLabel()); categoryImageViewLabel.setText(Bundle.Toolbar_categoryImageViewLabel());
thumbnailSizeLabel.setText(Bundle.Toolbar_thumbnailSizeLabel()); thumbnailSizeLabel.setText(Bundle.Toolbar_thumbnailSizeLabel());
@ -201,21 +172,22 @@ public class Toolbar extends ToolBar {
groupByBox.setCellFactory(listView -> new AttributeListCell()); groupByBox.setCellFactory(listView -> new AttributeListCell());
groupByBox.setButtonCell(new AttributeListCell()); groupByBox.setButtonCell(new AttributeListCell());
sortByBox.setCellFactory(listView -> new SortByListCell()); sortChooser = new SortChooser<>(GroupSortBy.getValues());
sortByBox.setButtonCell(new SortByListCell()); sortChooser.comparatorProperty().addListener((observable, oldValue, newValue) -> {
sortByBox.setItems(GroupSortBy.getValues());
sortByBox.getSelectionModel().selectedItemProperty().addListener(queryInvalidationListener);
sortByBox.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
final boolean orderEnabled = newValue == GroupSortBy.NONE || newValue == GroupSortBy.PRIORITY; final boolean orderEnabled = newValue == GroupSortBy.NONE || newValue == GroupSortBy.PRIORITY;
ascRadio.setDisable(orderEnabled); sortChooser.setSortOrderDisabled(orderEnabled);
descRadio.setDisable(orderEnabled);
final SortChooser.ValueType valueType = newValue == GroupSortBy.GROUP_BY_VALUE ? SortChooser.ValueType.LEXICOGRAPHIC : SortChooser.ValueType.NUMERIC;
sortChooser.setValueType(valueType);
queryInvalidationListener.invalidated(observable);
}); });
sortByBox.getSelectionModel().select(GroupSortBy.PRIORITY);
orderGroup.selectedToggleProperty().addListener(queryInvalidationListener);
sortChooser.sortOrderProperty().addListener(queryInvalidationListener);
sortChooser.setComparator(GroupSortBy.PRIORITY);
getItems().add(1, sortChooser);
} }
private void syncGroupControlsEnabledState(GroupViewState newViewState) { private void syncGroupControlsEnabledState(GroupViewState newViewState) {
@ -230,8 +202,8 @@ public class Toolbar extends ToolBar {
public void reset() { public void reset() {
Platform.runLater(() -> { Platform.runLater(() -> {
groupByBox.getSelectionModel().select(DrawableAttribute.PATH); groupByBox.getSelectionModel().select(DrawableAttribute.PATH);
sortByBox.getSelectionModel().select(GroupSortBy.NONE); // sortByBox.getSelectionModel().select(GroupSortBy.NONE);
orderGroup.selectToggle(ascRadio); // orderGroup.selectToggle(ascRadio);
sizeSlider.setValue(SIZE_SLIDER_DEFAULT); sizeSlider.setValue(SIZE_SLIDER_DEFAULT);
}); });
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 699 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 768 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 714 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 707 B