From b04fa81b53c959b33efbcdd536e48828670ca50b Mon Sep 17 00:00:00 2001 From: jmillman Date: Wed, 27 May 2015 13:30:25 -0400 Subject: [PATCH] fix categorization ui update errors - remove old listeners when updating treecell item. cleanup GroupTreeCell - invalidateHashSetHitsCount before adding/removing files to make sure it is seen during listner involation - cleanup GroupTreeItem and NavPanel - add comment to GroupManager --- .../imagegallery/grouping/DrawableGroup.java | 20 ++- .../imagegallery/grouping/GroupManager.java | 66 ++++----- .../gui/navpanel/GroupTreeCell.java | 132 ++++++++++-------- .../gui/navpanel/GroupTreeItem.java | 87 +++++------- .../imagegallery/gui/navpanel/NavPanel.java | 119 ++++++++-------- 5 files changed, 208 insertions(+), 216 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java index d9cfdb70a4..457f1a07e7 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java @@ -25,14 +25,12 @@ import javafx.collections.FXCollections; import javafx.collections.ObservableList; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.TskCoreException; /** * Represents a set of image/video files in a group. The UI listens to changes * to the group membership and updates itself accordingly. */ -public class DrawableGroup implements Comparable{ +public class DrawableGroup implements Comparable { private static final Logger LOGGER = Logger.getLogger(DrawableGroup.class.getName()); @@ -69,18 +67,18 @@ public class DrawableGroup implements Comparable{ * Call to indicate that an image has been added or removed from the group, * so the hash counts may not longer be accurate. */ - synchronized public void invalidateHashSetHitsCount(){ + synchronized public void invalidateHashSetHitsCount() { filesWithHashSetHitsCount = -1; } - - synchronized public int getFilesWithHashSetHitsCount() { + + synchronized public int getFilesWithHashSetHitsCount() { //TODO: use the drawable db for this ? -jm if (filesWithHashSetHitsCount < 0) { filesWithHashSetHitsCount = 0; for (Long fileID : fileIds()) { try { - if(ImageGalleryController.getDefault().getDatabase().isInHashSet(fileID)){ + if (ImageGalleryController.getDefault().getDatabase().isInHashSet(fileID)) { filesWithHashSetHitsCount++; } } catch (IllegalStateException | NullPointerException ex) { @@ -117,20 +115,20 @@ public class DrawableGroup implements Comparable{ } synchronized public void addFile(Long f) { + invalidateHashSetHitsCount(); if (fileIDs.contains(f) == false) { fileIDs.add(f); } - invalidateHashSetHitsCount(); } synchronized public void removeFile(Long f) { - fileIDs.removeAll(f); invalidateHashSetHitsCount(); + fileIDs.removeAll(f); } - + // By default, sort by group key name @Override - public int compareTo(DrawableGroup other){ + public int compareTo(DrawableGroup other) { return this.groupKey.getValueDisplayName().compareTo(other.groupKey.getValueDisplayName()); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index 3bda6a2410..72c288b817 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -281,9 +281,11 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { final DrawableGroup group = getGroupForKey(groupKey); if (group != null) { group.removeFile(fileID); - + // If we're grouping by category, we don't want to remove empty groups. - if(! group.groupKey.getValueDisplayName().startsWith("CAT-")){ + if (group.groupKey.getValueDisplayName().startsWith("CAT-")) { + return; + } else { if (group.fileIds().isEmpty()) { synchronized (groupMap) { groupMap.remove(groupKey, group); @@ -320,13 +322,13 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * was still running) */ if (task == null || (task.isCancelled() == false)) { DrawableGroup g = makeGroup(groupKey, filesInGroup); - + populateAnalyzedGroup(g, task); } } - + private synchronized > void populateAnalyzedGroup(final DrawableGroup g, ReGroupTask task) { - + if (task == null || (task.isCancelled() == false)) { final boolean groupSeen = db.isGroupSeen(g.groupKey); Platform.runLater(() -> { @@ -430,7 +432,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * @return */ @SuppressWarnings({"unchecked"}) - public > List findValuesForAttribute(DrawableAttribute groupBy) { + public > List findValuesForAttribute(DrawableAttribute groupBy) { List values; try { switch (groupBy.attrName) { @@ -456,12 +458,12 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } return values; - } catch(TskCoreException ex){ + } catch (TskCoreException ex) { LOGGER.log(Level.WARNING, "TSK error getting list of type " + groupBy.getDisplayName()); return new ArrayList(); } - - } + + } public List getFileIDsInGroup(GroupKey groupKey) throws TskCoreException { switch (groupKey.getAttribute().attrName) { @@ -515,14 +517,17 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { throw ex; } } - + /** * Count the number of files with the given category. * This is faster than getFileIDsWithCategory and should be used if only the * counts are needed and not the file IDs. + * * @param category Category to match against + * * @return Number of files with the given category - * @throws TskCoreException + * + * @throws TskCoreException */ public int countFilesWithCategory(Category category) throws TskCoreException { return db.getCategoryCount(category); @@ -581,10 +586,10 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { */ public > void regroup(final DrawableAttribute groupBy, final GroupSortBy sortBy, final SortOrder sortOrder, Boolean force) { - if(! Case.isCaseOpen()){ + if (!Case.isCaseOpen()) { return; } - + //only re-query the db if the group by attribute changed or it is forced if (groupBy != getGroupBy() || force == true) { setGroupBy(groupBy); @@ -613,15 +618,11 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } } - - /** * an executor to submit async ui related background tasks to. */ final ExecutorService regroupExecutor = Executors.newSingleThreadExecutor(new BasicThreadFactory.Builder().namingPattern("ui task -%d").build()); - - public ReadOnlyDoubleProperty regroupProgress() { return regroupProgress.getReadOnlyProperty(); } @@ -630,6 +631,8 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * handle {@link FileUpdateEvent} sent from Db when files are * inserted/updated * + * TODO: why isn't this just two methods! + * * @param evt */ @Override @@ -643,10 +646,10 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { for (GroupKey gk : groupsForFile) { removeFromGroup(gk, fileId); - + DrawableGroup g = getGroupForKey(gk); - if (g == null){ + if (g == null) { // It may be that this was the last unanalyzed file in the group, so test // whether the group is now fully analyzed. //TODO: use method in groupmanager ? @@ -654,8 +657,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { if (checkAnalyzed != null) { // => the group is analyzed, so add it to the ui populateAnalyzedGroup(gk, checkAnalyzed); } - } - else{ + } else { g.invalidateHashSetHitsCount(); } } @@ -676,7 +678,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * innertask? -jm */ for (final long fileId : fileIDs) { - + db.updateHashSetsForFile(fileId); //get grouping(s) this file would be in @@ -698,13 +700,13 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } } } - - Category.fireChange(fileIDs); + if (evt.getChangedAttribute() == DrawableAttribute.CATEGORY) { + Category.fireChange(fileIDs); + } if (evt.getChangedAttribute() == DrawableAttribute.TAGS) { TagUtils.fireChange(fileIDs); } break; - } } @@ -753,10 +755,10 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { synchronized (groupMap) { groupMap.clear(); } - + // Get the list of group keys final List vals = findValuesForAttribute(groupBy); - + // Make a list of each group final List groups = new ArrayList<>(); @@ -777,22 +779,22 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { List checkAnalyzed = checkAnalyzed(groupKey); if (checkAnalyzed != null) { // != null => the group is analyzed, so add it to the ui - + // makeGroup will create the group and add it to the map groupMap, but does not // update anything else DrawableGroup g = makeGroup(groupKey, checkAnalyzed); groups.add(g); } } - + // Sort the group list Collections.sort(groups, sortBy.getGrpComparator(sortOrder)); - + // Officially add all groups in order - for(DrawableGroup g:groups){ + for (DrawableGroup g : groups) { populateAnalyzedGroup(g, ReGroupTask.this); } - + updateProgress(1, 1); return null; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeCell.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeCell.java index f5e2b138dc..2f34aec2e1 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeCell.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeCell.java @@ -1,8 +1,28 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013-15 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.navpanel; +import static java.util.Objects.isNull; +import java.util.Optional; import javafx.application.Platform; +import javafx.beans.InvalidationListener; import javafx.beans.Observable; -import javafx.scene.Node; import javafx.scene.control.OverrunStyle; import javafx.scene.control.Tooltip; import javafx.scene.control.TreeCell; @@ -13,103 +33,95 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.grouping.DrawableGroup; /** - * A {@link Node} in the tree that listens to its associated group. Manages - * visual representation of TreeNode in Tree. Listens to properties of group - * that don't impact hierarchy and updates ui to reflect them + * A cell in the NavPanel tree that listens to its associated group's fileids. + * Manages visual representation of TreeNode in Tree. Listens to properties of + * group that don't impact hierarchy and updates ui to reflect them */ class GroupTreeCell extends TreeCell { /** * icon to use if this cell's TreeNode doesn't represent a group but just a - * folder(with no DrawableFiles) in the hierarchy. + * folder(with no DrawableFiles) in the file system hierarchy. */ private static final Image EMPTY_FOLDER_ICON = new Image("org/sleuthkit/autopsy/imagegallery/images/folder.png"); + /** + * reference to listener that allows us to remove it from a group when a new + * group is assigned to this Cell + */ + private InvalidationListener listener; + public GroupTreeCell() { + //TODO: move this to .css file //adjust indent, default is 10 which uses up a lot of space. setStyle("-fx-indent:5;"); //since end of path is probably more interesting put ellipsis at front setTextOverrun(OverrunStyle.LEADING_ELLIPSIS); + Platform.runLater(() -> { + prefWidthProperty().bind(getTreeView().widthProperty().subtract(15)); + }); + } @Override - synchronized protected void updateItem(final TreeNode tNode, boolean empty) { - super.updateItem(tNode, empty); - prefWidthProperty().bind(getTreeView().widthProperty().subtract(15)); + protected synchronized void updateItem(final TreeNode tNode, boolean empty) { + //if there was a previous group, remove the listener + Optional.ofNullable(getItem()) + .map(TreeNode::getGroup) + .ifPresent((DrawableGroup t) -> { + t.fileIds().removeListener(listener); + }); - if (tNode == null || empty) { + super.updateItem(tNode, empty); + + if (isNull(tNode) || empty) { Platform.runLater(() -> { setTooltip(null); setText(null); setGraphic(null); }); } else { - final String name = StringUtils.defaultIfBlank(tNode.getPath(), DrawableGroup.UNKNOWN); - Platform.runLater(() -> { - setTooltip(new Tooltip(name)); - }); - + final String groupName = StringUtils.defaultIfBlank(tNode.getPath(), DrawableGroup.UNKNOWN); - if (tNode.getGroup() == null) { + if (isNull(tNode.getGroup())) { + //"dummy" group in file system tree <=> a folder with no drawables Platform.runLater(() -> { - setText(name); + setTooltip(new Tooltip(groupName)); + setText(groupName); setGraphic(new ImageView(EMPTY_FOLDER_ICON)); }); } else { - //if number of files in this group changes (eg file is recategorized), update counts - tNode.getGroup().fileIds().addListener((Observable o) -> { + listener = (Observable o) -> { + final String countsText = getCountsText(); Platform.runLater(() -> { - - String groupName; // The "name" variable set earlier is generally not correct at this point - if((getItem() == null) || (getItem().getGroup() == null) || - (getItem().getGroup().groupKey == null)){ - groupName = ""; - } - else{ - groupName = getItem().getGroup().groupKey.getValueDisplayName(); - } - - setText(groupName + " (" + getNumerator() + getDenominator() + ")"); + setText(groupName + countsText); }); - }); + }; + //if number of files in this group changes (eg file is recategorized), update counts via listener + tNode.getGroup().fileIds().addListener(listener); + //... and use icon corresponding to group type + final Image icon = tNode.getGroup().groupKey.getAttribute().getIcon(); + final String countsText = getCountsText(); Platform.runLater(() -> { - //this TreeNode has a group so append counts to name ... - setText(name + " (" + getNumerator() + getDenominator() + ")"); - //... and use icon corresponding to group type - setGraphic(new ImageView(tNode.getGroup().groupKey.getAttribute().getIcon())); + setTooltip(new Tooltip(groupName)); + setGraphic(new ImageView(icon)); + setText(groupName + countsText); }); - } } } - /** - * @return the Numerator of the count to append to the group name = number - * of hashset hits + "/" - */ - synchronized private String getNumerator() { - try { - final String numerator = (getItem().getGroup().groupKey.getAttribute() != DrawableAttribute.HASHSET) - ? getItem().getGroup().getFilesWithHashSetHitsCount() + "/" - : ""; - return numerator; - } catch (NullPointerException e) { - //instead of this try catch block, remove the listener when assigned a null treeitem / group - return ""; - } - } + private synchronized String getCountsText() { + final String counts = Optional.ofNullable(getItem()) + .map(TreeNode::getGroup) + .map((DrawableGroup t) -> { + return " (" + ((t.groupKey.getAttribute() == DrawableAttribute.HASHSET) + ? Integer.toString(t.getSize()) + : t.getFilesWithHashSetHitsCount() + "/" + t.getSize()) + ")"; + }).orElse(""); //if item is null or group is null - /** - * @return the Denominator of the count to append to the group name = number - * of files in group - */ - synchronized private Integer getDenominator() { - try { - return getItem().getGroup().getSize(); - } catch (NullPointerException ex) { - return 0; - } + return counts; } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeItem.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeItem.java index 2c6b2d3666..37925b47bb 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeItem.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeItem.java @@ -37,10 +37,28 @@ import org.sleuthkit.autopsy.imagegallery.grouping.DrawableGroup; */ class GroupTreeItem extends TreeItem implements Comparable { + static GroupTreeItem getTreeItemForGroup(GroupTreeItem root, DrawableGroup grouping) { + if (Objects.equals(root.getValue().getGroup(), grouping)) { + return root; + } else { + synchronized (root.getChildren()) { + for (TreeItem child : root.getChildren()) { + final GroupTreeItem childGTI = (GroupTreeItem) child; + + GroupTreeItem val = getTreeItemForGroup(childGTI, grouping); + if (val != null) { + return val; + } + } + } + } + return null; + } + /** * maps a path segment to the child item of this item with that path segment */ - private Map childMap = new HashMap<>(); + private final Map childMap = new HashMap<>(); /** * the comparator if any used to sort the children of this item */ @@ -68,7 +86,7 @@ class GroupTreeItem extends TreeItem implements Comparable implements Comparable { + synchronized (getChildren()) { + getChildren().add(newTreeItem); } }); @@ -109,14 +124,11 @@ class GroupTreeItem extends TreeItem implements Comparable { + synchronized (getChildren()) { + getChildren().add(newTreeItem); + if (comp != null) { + FXCollections.sort(getChildren(), comp); } } }); @@ -129,7 +141,7 @@ class GroupTreeItem extends TreeItem implements Comparable path, DrawableGroup g, Boolean tree) { @@ -147,12 +159,9 @@ class GroupTreeItem extends TreeItem implements Comparable { + synchronized (getChildren()) { + getChildren().add(newTreeItem); } }); @@ -169,14 +178,11 @@ class GroupTreeItem extends TreeItem implements Comparable { + synchronized (getChildren()) { + getChildren().add(newTreeItem); + if (comp != null) { + FXCollections.sort(getChildren(), comp); } } }); @@ -189,24 +195,6 @@ class GroupTreeItem extends TreeItem implements Comparable child : root.getChildren()) { - final GroupTreeItem childGTI = (GroupTreeItem) child; - - GroupTreeItem val = getTreeItemForGroup(childGTI, grouping); - if (val != null) { - return val; - } - } - } - } - return null; - } - GroupTreeItem getTreeItemForPath(List path) { // end of recursion if (path.isEmpty()) { @@ -253,4 +241,5 @@ class GroupTreeItem extends TreeItem implements Comparable sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.imagegallery.gui.navpanel; import java.net.URL; import java.util.Arrays; -import java.util.Collection; import java.util.List; import java.util.ResourceBundle; import javafx.application.Platform; @@ -41,23 +40,21 @@ import javafx.scene.control.TreeView; import javafx.scene.layout.Priority; import javafx.scene.layout.VBox; import org.apache.commons.lang3.StringUtils; -import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.grouping.DrawableGroup; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupSortBy; import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewState; -import org.sleuthkit.datamodel.TskCoreException; /** * Display two trees. one shows all folders (groups) and calls out folders with * images. the user can select folders with images to see them in the main * GroupPane The other shows folders with hash set hits. + * + * //TODO: there is too much code duplication between the navTree and the + * hashTree. Extract the common code to some new class. */ public class NavPanel extends TabPane { @@ -170,24 +167,15 @@ public class NavPanel extends TabPane { removeFromNavTree(g); removeFromHashTree(g); } - if(change.wasPermutated()){ + if (change.wasPermutated()) { // Handle this afterward wasPermuted = true; } } - - if(wasPermuted){ - // Remove everything and add it again in the new order - for(DrawableGroup g:controller.getGroupManager().getAnalyzedGroups()){ - removeFromNavTree(g); - removeFromHashTree(g); - } - for(DrawableGroup g:controller.getGroupManager().getAnalyzedGroups()){ - insertIntoNavTree(g); - if (g.getFilesWithHashSetHitsCount() > 0) { - insertIntoHashTree(g); - } - } + + if (wasPermuted) { + rebuildTrees(); + } }); @@ -205,6 +193,27 @@ public class NavPanel extends TabPane { }); } + private void rebuildTrees() { + navTreeRoot = new GroupTreeItem("", null, sortByBox.getSelectionModel().selectedItemProperty().get()); + hashTreeRoot = new GroupTreeItem("", null, sortByBox.getSelectionModel().selectedItemProperty().get()); + + ObservableList groups = controller.getGroupManager().getAnalyzedGroups(); + + for (DrawableGroup g : groups) { + insertIntoNavTree(g); + if (g.getFilesWithHashSetHitsCount() > 0) { + insertIntoHashTree(g); + } + } + + Platform.runLater(() -> { + navTree.setRoot(navTreeRoot); + navTreeRoot.setExpanded(true); + hashTree.setRoot(hashTreeRoot); + hashTreeRoot.setExpanded(true); + }); + } + private void updateControllersGroup() { final TreeItem selectedItem = activeTreeProperty.get().getSelectionModel().getSelectedItem(); if (selectedItem != null && selectedItem.getValue() != null && selectedItem.getValue().getGroup() != null) { @@ -216,11 +225,6 @@ public class NavPanel extends TabPane { hashTreeRoot.resortChildren(sortByBox.getSelectionModel().getSelectedItem()); } - private void insertIntoHashTree(DrawableGroup g) { - initHashTree(); - hashTreeRoot.insert(g.groupKey.getValueDisplayName(), g, false); - } - /** * Set the tree to the passed in group * @@ -234,27 +238,29 @@ public class NavPanel extends TabPane { final GroupTreeItem treeItemForGroup = ((GroupTreeItem) activeTreeProperty.get().getRoot()).getTreeItemForPath(path); if (treeItemForGroup != null) { - /* When we used to run the below code on the FX thread, it would - * get into infinite loops when the next group button was pressed quickly - * because the udpates became out of order and History could not keep - * track of what was current. Currently (4/2/15), this method is - * already on the FX thread, so it is OK. */ + /* When we used to run the below code on the FX thread, it would + * get into infinite loops when the next group button was pressed + * quickly because the udpates became out of order and History could + * not + * keep track of what was current. + * + * Currently (4/2/15), this method is already on the FX thread, so + * it is OK. */ //Platform.runLater(() -> { - TreeItem ti = treeItemForGroup; - while (ti != null) { - ti.setExpanded(true); - ti = ti.getParent(); - } - int row = activeTreeProperty.get().getRow(treeItemForGroup); - if (row != -1) { - activeTreeProperty.get().getSelectionModel().select(treeItemForGroup); - activeTreeProperty.get().scrollTo(row); - } - //}); + TreeItem ti = treeItemForGroup; + while (ti != null) { + ti.setExpanded(true); + ti = ti.getParent(); + } + int row = activeTreeProperty.get().getRow(treeItemForGroup); + if (row != -1) { + activeTreeProperty.get().getSelectionModel().select(treeItemForGroup); + activeTreeProperty.get().scrollTo(row); + } + //}); //end Platform.runLater } } - @SuppressWarnings("fallthrough") private static List groupingToPath(DrawableGroup g) { if (g.groupKey.getAttribute() == DrawableAttribute.PATH) { @@ -269,11 +275,14 @@ public class NavPanel extends TabPane { } } + private void insertIntoHashTree(DrawableGroup g) { + initHashTree(); + hashTreeRoot.insert(groupingToPath(g), g, false); + } + private void insertIntoNavTree(DrawableGroup g) { initNavTree(); - List path = groupingToPath(g); - - navTreeRoot.insert(path, g, true); + navTreeRoot.insert(groupingToPath(g), g, true); } private void removeFromNavTree(DrawableGroup g) { @@ -313,22 +322,4 @@ public class NavPanel extends TabPane { }); } } - - //these are not used anymore, but could be usefull at some point - //TODO: remove them or find a use and undeprecate - @Deprecated - private void rebuildNavTree() { - navTreeRoot = new GroupTreeItem("", null, sortByBox.getSelectionModel().selectedItemProperty().get()); - - ObservableList groups = controller.getGroupManager().getAnalyzedGroups(); - - for (DrawableGroup g : groups) { - insertIntoNavTree(g); - } - - Platform.runLater(() -> { - navTree.setRoot(navTreeRoot); - navTreeRoot.setExpanded(true); - }); - } }