mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-12 07:56:16 +00:00
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:
parent
02c4336aaf
commit
5ba21cf3c3
@ -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
|
||||
|
||||
String orderByClause = "";
|
||||
switch (sortBy) {
|
||||
case GROUP_BY_VALUE:
|
||||
orderByClause = " ORDER BY " + groupBy.attrName.toString(); //NON-NLS
|
||||
break;
|
||||
case FILE_COUNT:
|
||||
orderByClause = " ORDER BY COUNT(*)"; //NON-NLS
|
||||
break;
|
||||
case NONE:
|
||||
// case PRIORITY:
|
||||
break;
|
||||
|
||||
if (sortBy == GROUP_BY_VALUE) {
|
||||
orderByClause = " ORDER BY " + groupBy.attrName.toString();
|
||||
} else if (sortBy == GroupSortBy.FILE_COUNT) {
|
||||
orderByClause = " ORDER BY COUNT(*)";
|
||||
}
|
||||
|
||||
query.append(orderByClause);
|
||||
|
@ -25,6 +25,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@ -126,7 +127,7 @@ public class GroupManager {
|
||||
private volatile DrawableAttribute<?> groupBy = DrawableAttribute.PATH;
|
||||
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<SortOrder> sortOrderProp = new ReadOnlyObjectWrapper<>(sortOrder);
|
||||
|
||||
@ -274,7 +275,7 @@ public class GroupManager {
|
||||
} else if (unSeenGroups.contains(group) == false) {
|
||||
unSeenGroups.add(group);
|
||||
}
|
||||
FXCollections.sort(unSeenGroups, sortBy.getGrpComparator(sortOrder));
|
||||
FXCollections.sort(unSeenGroups, applySortOrder(sortOrder, sortBy));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -299,11 +300,11 @@ public class GroupManager {
|
||||
Platform.runLater(() -> {
|
||||
if (analyzedGroups.contains(group)) {
|
||||
analyzedGroups.remove(group);
|
||||
FXCollections.sort(analyzedGroups, sortBy.getGrpComparator(sortOrder));
|
||||
FXCollections.sort(analyzedGroups, applySortOrder(sortOrder, sortBy));
|
||||
}
|
||||
if (unSeenGroups.contains(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;
|
||||
}
|
||||
|
||||
@ -459,7 +460,7 @@ public class GroupManager {
|
||||
Platform.runLater(() -> sortByProp.set(sortBy));
|
||||
}
|
||||
|
||||
public ReadOnlyObjectProperty<GroupSortBy> getSortByProperty() {
|
||||
public ReadOnlyObjectProperty< Comparator<DrawableGroup>> getSortByProperty() {
|
||||
return sortByProp.getReadOnlyProperty();
|
||||
}
|
||||
|
||||
@ -523,8 +524,8 @@ public class GroupManager {
|
||||
setSortBy(sortBy);
|
||||
setSortOrder(sortOrder);
|
||||
Platform.runLater(() -> {
|
||||
FXCollections.sort(analyzedGroups, sortBy.getGrpComparator(sortOrder));
|
||||
FXCollections.sort(unSeenGroups, sortBy.getGrpComparator(sortOrder));
|
||||
FXCollections.sort(analyzedGroups, applySortOrder(sortOrder, sortBy));
|
||||
FXCollections.sort(unSeenGroups, applySortOrder(sortOrder, sortBy));
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -675,7 +676,7 @@ public class GroupManager {
|
||||
if (analyzedGroups.contains(group) == false) {
|
||||
analyzedGroups.add(group);
|
||||
if (Objects.isNull(task)) {
|
||||
FXCollections.sort(analyzedGroups, sortBy.getGrpComparator(sortOrder));
|
||||
FXCollections.sort(analyzedGroups, applySortOrder(sortOrder, sortBy));
|
||||
}
|
||||
}
|
||||
markGroupSeen(group, groupSeen);
|
||||
@ -735,8 +736,8 @@ public class GroupManager {
|
||||
|
||||
private final SortOrder sortOrder;
|
||||
|
||||
public ReGroupTask(DrawableAttribute<A> groupBy, GroupSortBy sortBy, SortOrder sortOrder) {
|
||||
super(Bundle.ReGroupTask_displayTitle(groupBy.attrName.toString(), sortBy.name(), sortOrder.toString()), true);
|
||||
ReGroupTask(DrawableAttribute<A> groupBy, GroupSortBy sortBy, SortOrder sortOrder) {
|
||||
super(Bundle.ReGroupTask_displayTitle(groupBy.attrName.toString(), sortBy.getDisplayName(), sortOrder.toString()), true);
|
||||
|
||||
this.groupBy = groupBy;
|
||||
this.sortBy = sortBy;
|
||||
@ -755,7 +756,7 @@ public class GroupManager {
|
||||
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(() -> {
|
||||
analyzedGroups.clear();
|
||||
unSeenGroups.clear();
|
||||
@ -778,7 +779,7 @@ public class GroupManager {
|
||||
groupProgress.progress(Bundle.ReGroupTask_progressUpdate(groupBy.attrName.toString(), val), p);
|
||||
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);
|
||||
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<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,89 +18,50 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.imagegallery.datamodel.grouping;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
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.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
|
||||
* down in Toolbar as well as each enum value having the stategy
|
||||
* ({@link Comparator}) for sorting the groups
|
||||
* Pseudo enum of possible properties to sort groups by.
|
||||
*/
|
||||
@NbBundle.Messages({"GroupSortBy.groupSize=Group Size",
|
||||
"GroupSortBy.groupName=Group Name",
|
||||
"GroupSortBy.none=None",
|
||||
"GroupSortBy.priority=Priority"})
|
||||
public enum GroupSortBy implements ComparatorProvider {
|
||||
"GroupSortBy.groupName=Group Name",
|
||||
"GroupSortBy.none=None",
|
||||
"GroupSortBy.priority=Priority"})
|
||||
public class GroupSortBy implements Comparator<DrawableGroup> {
|
||||
|
||||
/**
|
||||
* sort the groups by the number of files in each sort the groups by the
|
||||
* number of files in each
|
||||
* sort the groups by the number of files in each
|
||||
*/
|
||||
FILE_COUNT(Bundle.GroupSortBy_groupSize(), true, "folder-open-image.png") { //NON-NLS
|
||||
@Override
|
||||
public Comparator<DrawableGroup> getGrpComparator(final SortOrder sortOrder) {
|
||||
return applySortOrder(sortOrder, Comparator.comparingInt(DrawableGroup::getSize));
|
||||
}
|
||||
public final static GroupSortBy FILE_COUNT = new GroupSortBy(Bundle.GroupSortBy_groupSize(), "folder-open-image.png", Comparator.comparing(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
|
||||
* them by path alphabetically )
|
||||
*/
|
||||
GROUP_BY_VALUE(Bundle.GroupSortBy_groupName(), true, "folder-rename.png") { //NON-NLS
|
||||
@Override
|
||||
public Comparator<DrawableGroup> getGrpComparator(final SortOrder sortOrder) {
|
||||
return applySortOrder(sortOrder, Comparator.comparing(t -> t.getGroupByValueDislpayName()));
|
||||
}
|
||||
public final static GroupSortBy GROUP_BY_VALUE = new GroupSortBy(Bundle.GroupSortBy_groupName(), "folder-rename.png", Comparator.comparing(DrawableGroup::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
|
||||
* order)
|
||||
*/
|
||||
NONE(Bundle.GroupSortBy_none(), false, "prohibition.png") { //NON-NLS
|
||||
@Override
|
||||
public Comparator<DrawableGroup> getGrpComparator(SortOrder sortOrder) {
|
||||
return new NoOpComparator<>();
|
||||
}
|
||||
public final static GroupSortBy NONE = new GroupSortBy(Bundle.GroupSortBy_none(), "prohibition.png", new AllEqualComparator<>());
|
||||
|
||||
@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
|
||||
*/
|
||||
PRIORITY(Bundle.GroupSortBy_priority(), false, "hashset_hits.png") { //NON-NLS
|
||||
@Override
|
||||
public Comparator<DrawableGroup> getGrpComparator(SortOrder sortOrder) {
|
||||
return Comparator.nullsLast(Comparator.comparingDouble(DrawableGroup::getHashHitDensity).thenComparingInt(DrawableGroup::getSize).reversed());
|
||||
}
|
||||
public final static GroupSortBy PRIORITY = new GroupSortBy(Bundle.GroupSortBy_priority(), "hashset_hits.png", Comparator.comparing(DrawableGroup::getHashHitDensity).thenComparing(Comparator.comparing(DrawableGroup::getUncategorizedCount)));
|
||||
|
||||
@Override
|
||||
public <A extends Comparable<A>> Comparator<A> getValueComparator(DrawableAttribute<A> attr, SortOrder sortOrder) {
|
||||
return getDefaultValueComparator(attr, sortOrder);
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public int compare(DrawableGroup o1, DrawableGroup o2) {
|
||||
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
|
||||
@ -108,8 +69,7 @@ public enum GroupSortBy implements ComparatorProvider {
|
||||
* @return
|
||||
*/
|
||||
public static ObservableList<GroupSortBy> getValues() {
|
||||
return FXCollections.observableArrayList(Arrays.asList(values()));
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
final private String displayName;
|
||||
@ -118,12 +78,12 @@ public enum GroupSortBy implements ComparatorProvider {
|
||||
|
||||
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.sortOrderEnabled = sortOrderEnabled;
|
||||
this.imageName = imagePath;
|
||||
this.delegate = internalComparator;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
@ -139,49 +99,11 @@ public enum GroupSortBy implements ComparatorProvider {
|
||||
return icon;
|
||||
}
|
||||
|
||||
public Boolean isSortOrderEnabled() {
|
||||
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> {
|
||||
static class AllEqualComparator<A> implements Comparator<A> {
|
||||
|
||||
@Override
|
||||
public int compare(A o1, A o2) {
|
||||
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);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -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>
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,113 +1,86 @@
|
||||
<?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.MenuItem?>
|
||||
<?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.65" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<items>
|
||||
<Label fx:id="groupByLabel" text="Group By:">
|
||||
<labelFor>
|
||||
<ComboBox fx:id="groupByBox" editable="false" />
|
||||
</labelFor>
|
||||
</Label>
|
||||
<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>
|
||||
</HBox>
|
||||
<Separator orientation="VERTICAL" prefHeight="-1.0" prefWidth="20.0" />
|
||||
<HBox alignment="CENTER" spacing="5.0">
|
||||
<children>
|
||||
<Label fx:id="tagImageViewLabel" text="Tag Group's Files:">
|
||||
<graphic>
|
||||
<ImageView fitHeight="16.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true">
|
||||
<image>
|
||||
<Image url="@../images/tag_red.png" />
|
||||
</image>
|
||||
</ImageView>
|
||||
</graphic>
|
||||
</Label>
|
||||
<SplitMenuButton id="tagSplitMenu" fx:id="tagGroupMenuButton" disable="true" mnemonicParsing="false" text="Follow Up" textOverrun="ELLIPSIS">
|
||||
<items>
|
||||
<MenuItem mnemonicParsing="false" text="Action 1" />
|
||||
<MenuItem mnemonicParsing="false" text="Action 2" />
|
||||
</items>
|
||||
</SplitMenuButton>
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox alignment="CENTER" spacing="5.0">
|
||||
<children>
|
||||
<Label fx:id="categoryImageViewLabel" 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" />
|
||||
<HBox alignment="CENTER" spacing="5.0">
|
||||
<children>
|
||||
<Label fx:id="thumbnailSizeLabel" text="Thumbnail Size (px):">
|
||||
<labelFor>
|
||||
<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" />
|
||||
</labelFor>
|
||||
</Label>
|
||||
<fx:reference source="sizeSlider" />
|
||||
</children>
|
||||
</HBox>
|
||||
</items>
|
||||
<items>
|
||||
<HBox alignment="CENTER" spacing="5.0">
|
||||
<children>
|
||||
<Label fx:id="groupByLabel" text="Group By:">
|
||||
<labelFor>
|
||||
<ComboBox fx:id="groupByBox" editable="false" />
|
||||
</labelFor>
|
||||
</Label>
|
||||
<fx:reference source="groupByBox" />
|
||||
|
||||
</children>
|
||||
</HBox>
|
||||
|
||||
|
||||
|
||||
|
||||
<Separator orientation="VERTICAL" prefHeight="-1.0" prefWidth="10.0" />
|
||||
<HBox alignment="CENTER" spacing="5.0">
|
||||
<children>
|
||||
<Label fx:id="tagImageViewLabel" text="Tag Group's Files:">
|
||||
<graphic>
|
||||
<ImageView fitHeight="16.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true">
|
||||
<image>
|
||||
<Image url="@../images/tag_red.png" />
|
||||
</image>
|
||||
</ImageView>
|
||||
</graphic>
|
||||
</Label>
|
||||
<SplitMenuButton id="tagSplitMenu" fx:id="tagGroupMenuButton" disable="true" mnemonicParsing="false" text="Follow Up" textOverrun="ELLIPSIS">
|
||||
<items>
|
||||
<MenuItem mnemonicParsing="false" text="Action 1" />
|
||||
<MenuItem mnemonicParsing="false" text="Action 2" />
|
||||
</items>
|
||||
</SplitMenuButton>
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox alignment="CENTER" spacing="5.0">
|
||||
<children>
|
||||
<Label fx:id="categoryImageViewLabel" 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>
|
||||
<padding>
|
||||
<Insets left="5.0" />
|
||||
</padding>
|
||||
</HBox>
|
||||
<Separator orientation="VERTICAL" prefHeight="-1.0" prefWidth="10.0" />
|
||||
<HBox alignment="CENTER" spacing="5.0">
|
||||
<children>
|
||||
<Label fx:id="thumbnailSizeLabel" text="Thumbnail Size (px):">
|
||||
<labelFor>
|
||||
<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" />
|
||||
</labelFor>
|
||||
</Label>
|
||||
<fx:reference source="sizeSlider" />
|
||||
</children>
|
||||
</HBox>
|
||||
</items>
|
||||
</fx:root>
|
||||
|
@ -32,12 +32,9 @@ import javafx.fxml.FXML;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.MenuItem;
|
||||
import javafx.scene.control.RadioButton;
|
||||
import javafx.scene.control.Slider;
|
||||
import javafx.scene.control.SplitMenuButton;
|
||||
import javafx.scene.control.ToggleGroup;
|
||||
import javafx.scene.control.ToolBar;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javax.swing.SortOrder;
|
||||
|
||||
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.datamodel.Category;
|
||||
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.GroupViewState;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
@ -67,21 +65,6 @@ public class Toolbar extends ToolBar {
|
||||
@FXML
|
||||
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
|
||||
private SplitMenuButton catGroupMenuButton;
|
||||
|
||||
@ -91,8 +74,7 @@ public class Toolbar extends ToolBar {
|
||||
@FXML
|
||||
private Label groupByLabel;
|
||||
|
||||
@FXML
|
||||
private Label sortByLabel;
|
||||
|
||||
|
||||
@FXML
|
||||
private Label tagImageViewLabel;
|
||||
@ -107,20 +89,18 @@ public class Toolbar extends ToolBar {
|
||||
|
||||
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 SortChooser<DrawableGroup, GroupSortBy> sortChooser;
|
||||
|
||||
synchronized public SortOrder getSortOrder() {
|
||||
return orderProperty.get();
|
||||
}
|
||||
private final InvalidationListener queryInvalidationListener = new InvalidationListener() {
|
||||
public void invalidated(Observable o) {
|
||||
controller.getGroupManager().regroup(
|
||||
groupByBox.getSelectionModel().getSelectedItem(),
|
||||
sortChooser.getComparator(),
|
||||
sortChooser.getSortOrder(),
|
||||
false);
|
||||
}
|
||||
};
|
||||
|
||||
public DoubleProperty sizeSliderValue() {
|
||||
return sizeSlider.valueProperty();
|
||||
@ -142,15 +122,9 @@ public class Toolbar extends ToolBar {
|
||||
"Toolbar.categoryImageViewLabel=Categorize Group's Files:",
|
||||
"Toolbar.thumbnailSizeLabel=Thumbnail Size (px):"})
|
||||
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 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 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 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'.";
|
||||
|
||||
controller.viewState().addListener((observable, oldViewState, newViewState) -> {
|
||||
@ -175,9 +149,6 @@ public class Toolbar extends ToolBar {
|
||||
});
|
||||
|
||||
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());
|
||||
categoryImageViewLabel.setText(Bundle.Toolbar_categoryImageViewLabel());
|
||||
thumbnailSizeLabel.setText(Bundle.Toolbar_thumbnailSizeLabel());
|
||||
@ -201,21 +172,22 @@ public class Toolbar extends ToolBar {
|
||||
groupByBox.setCellFactory(listView -> new AttributeListCell());
|
||||
groupByBox.setButtonCell(new AttributeListCell());
|
||||
|
||||
sortByBox.setCellFactory(listView -> new SortByListCell());
|
||||
sortByBox.setButtonCell(new SortByListCell());
|
||||
sortByBox.setItems(GroupSortBy.getValues());
|
||||
|
||||
sortByBox.getSelectionModel().selectedItemProperty().addListener(queryInvalidationListener);
|
||||
|
||||
sortByBox.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
|
||||
sortChooser = new SortChooser<>(GroupSortBy.getValues());
|
||||
sortChooser.comparatorProperty().addListener((observable, oldValue, newValue) -> {
|
||||
final boolean orderEnabled = newValue == GroupSortBy.NONE || newValue == GroupSortBy.PRIORITY;
|
||||
ascRadio.setDisable(orderEnabled);
|
||||
descRadio.setDisable(orderEnabled);
|
||||
sortChooser.setSortOrderDisabled(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) {
|
||||
@ -230,8 +202,8 @@ public class Toolbar extends ToolBar {
|
||||
public void reset() {
|
||||
Platform.runLater(() -> {
|
||||
groupByBox.getSelectionModel().select(DrawableAttribute.PATH);
|
||||
sortByBox.getSelectionModel().select(GroupSortBy.NONE);
|
||||
orderGroup.selectToggle(ascRadio);
|
||||
// sortByBox.getSelectionModel().select(GroupSortBy.NONE);
|
||||
// orderGroup.selectToggle(ascRadio);
|
||||
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 |
Loading…
x
Reference in New Issue
Block a user