diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index 034fbe3b03..cb842ed1df 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -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); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index e1f497a295..bdc659e416 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -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 sortByProp = new ReadOnlyObjectWrapper<>(sortBy); + private final ReadOnlyObjectWrapper< Comparator> sortByProp = new ReadOnlyObjectWrapper<>(sortBy); private final ReadOnlyObjectWrapper< DrawableAttribute> groupByProp = new ReadOnlyObjectWrapper<>(groupBy); private final ReadOnlyObjectWrapper 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 getSortBy() { return sortBy; } @@ -459,7 +460,7 @@ public class GroupManager { Platform.runLater(() -> sortByProp.set(sortBy)); } - public ReadOnlyObjectProperty getSortByProperty() { + public ReadOnlyObjectProperty< Comparator> 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 groupBy, GroupSortBy sortBy, SortOrder sortOrder) { - super(Bundle.ReGroupTask_displayTitle(groupBy.attrName.toString(), sortBy.name(), sortOrder.toString()), true); + ReGroupTask(DrawableAttribute 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(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 Comparator applySortOrder(final SortOrder sortOrder, Comparator comparator) { + switch (sortOrder) { + case ASCENDING: + return comparator; + case DESCENDING: + return comparator.reversed(); + case UNSORTED: + default: + return new GroupSortBy.AllEqualComparator<>(); + } + } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupSortBy.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupSortBy.java index 5d8740b343..8239837d6a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupSortBy.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupSortBy.java @@ -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 { /** - * 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 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 > Comparator getValueComparator(final DrawableAttribute 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 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 > Comparator getValueComparator(final DrawableAttribute attr, final SortOrder sortOrder) { - return applySortOrder(sortOrder, Comparator.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 getGrpComparator(SortOrder sortOrder) { - return new NoOpComparator<>(); - } + public final static GroupSortBy NONE = new GroupSortBy(Bundle.GroupSortBy_none(), "prohibition.png", new AllEqualComparator<>()); - @Override - public > Comparator getValueComparator(DrawableAttribute 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 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 > Comparator getValueComparator(DrawableAttribute attr, SortOrder sortOrder) { - return getDefaultValueComparator(attr, sortOrder); - } - }; + @Override + public int compare(DrawableGroup o1, DrawableGroup o2) { + return delegate.compare(o1, o2); + } + + private final static ObservableList 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 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 delegate; - private GroupSortBy(String displayName, Boolean sortOrderEnabled, String imagePath) { + private GroupSortBy(String displayName, String imagePath, Comparator 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 Comparator applySortOrder(final SortOrder sortOrder, Comparator comparator) { - switch (sortOrder) { - case ASCENDING: - return comparator; - case DESCENDING: - return comparator.reversed(); - case UNSORTED: - default: - return new NoOpComparator<>(); - } - } - - private static class NoOpComparator implements Comparator { + static class AllEqualComparator implements Comparator { @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 { - - > Comparator getValueComparator(DrawableAttribute attr, SortOrder sortOrder); - - Comparator getGrpComparator(SortOrder sortOrder); - - default > Comparator getDefaultValueComparator(DrawableAttribute 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); - }; - } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SortChooser.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SortChooser.fxml new file mode 100644 index 0000000000..432b47d8c7 --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SortChooser.fxml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SortChooser.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SortChooser.java new file mode 100644 index 0000000000..2486615a11 --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SortChooser.java @@ -0,0 +1,178 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2016 Basis Technology Corp. + * Contact: carrier sleuthkit 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> extends HBox { + + @FXML + private RadioButton ascRadio; + @FXML + private RadioButton descRadio; + @FXML + private ToggleGroup orderGroup; + @FXML + private ComboBox sortByBox; + + private final ObservableList comparators; + + private final ReadOnlyObjectWrapper sortOrder = new ReadOnlyObjectWrapper<>(SortOrder.ASCENDING); + private final SimpleBooleanProperty sortOrderDisabled = new SimpleBooleanProperty(false); + private final SimpleObjectProperty valueType = new SimpleObjectProperty<>(ValueType.NUMERIC); + private ObjectBinding comparator; + + public SortChooser(ObservableList 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 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 sortOrderProperty() { + return sortOrder.getReadOnlyProperty(); + } + + Y getComparator() { + return sortByBox.getSelectionModel().getSelectedItem(); + } + + void setComparator(Y selected) { + sortByBox.getSelectionModel().select(selected); + } + + ReadOnlyObjectProperty 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 { + + @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"); + } + } + } +} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.fxml index d161cc99f9..aba7982201 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.fxml +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.fxml @@ -1,113 +1,86 @@ + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java index f6ca84b3c7..cd6cda7623 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java @@ -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 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 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 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); }); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/images/sort_asc_az.png b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/images/sort_asc_az.png new file mode 100644 index 0000000000..0cac09a377 Binary files /dev/null and b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/images/sort_asc_az.png differ diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/images/sort_ascending.png b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/images/sort_ascending.png new file mode 100644 index 0000000000..5379d494bf Binary files /dev/null and b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/images/sort_ascending.png differ diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/images/sort_desc_az.png b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/images/sort_desc_az.png new file mode 100644 index 0000000000..cde15dfed8 Binary files /dev/null and b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/images/sort_desc_az.png differ diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/images/sort_descending.png b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/images/sort_descending.png new file mode 100644 index 0000000000..f63a65fb9d Binary files /dev/null and b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/images/sort_descending.png differ