Java tutorial
/* * Autopsy Forensic Browser * * Copyright 2013 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.imageanalyzer.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; import javafx.beans.Observable; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ObservableValue; import javafx.collections.FXCollections; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.scene.control.ComboBox; import javafx.scene.control.ListView; import javafx.scene.control.SelectionMode; import javafx.scene.control.Tab; import javafx.scene.control.TabPane; import javafx.scene.control.TreeItem; 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.imageanalyzer.FXMLConstructor; import org.sleuthkit.autopsy.imageanalyzer.ImageAnalyzerController; import org.sleuthkit.autopsy.imageanalyzer.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imageanalyzer.datamodel.DrawableFile; import org.sleuthkit.autopsy.imageanalyzer.grouping.DrawableGroup; import org.sleuthkit.autopsy.imageanalyzer.grouping.GroupKey; import org.sleuthkit.autopsy.imageanalyzer.grouping.GroupSortBy; import org.sleuthkit.autopsy.imageanalyzer.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. */ public class NavPanel extends TabPane { @FXML private ResourceBundle resources; @FXML private URL location; /** * TreeView for folders with hash hits */ @FXML private TreeView<TreeNode> hashTree; @FXML private TabPane navTabPane; /** * TreeView for all folders */ @FXML private TreeView<TreeNode> navTree; @FXML private Tab hashTab; @FXML private Tab navTab; @FXML private ComboBox<TreeNodeComparators> sortByBox; /** * contains the 'active tree' */ private final SimpleObjectProperty<TreeView<TreeNode>> activeTreeProperty = new SimpleObjectProperty<>(); private GroupTreeItem navTreeRoot; private GroupTreeItem hashTreeRoot; private final ImageAnalyzerController controller; public NavPanel(ImageAnalyzerController controller) { this.controller = controller; FXMLConstructor.construct(this, "NavPanel.fxml"); } @FXML void initialize() { assert hashTab != null : "fx:id=\"hashTab\" was not injected: check your FXML file 'NavPanel.fxml'."; assert hashTree != null : "fx:id=\"hashTree\" was not injected: check your FXML file 'NavPanel.fxml'."; assert navTab != null : "fx:id=\"navTab\" was not injected: check your FXML file 'NavPanel.fxml'."; assert navTabPane != null : "fx:id=\"navTabPane\" was not injected: check your FXML file 'NavPanel.fxml'."; assert navTree != null : "fx:id=\"navTree\" was not injected: check your FXML file 'NavPanel.fxml'."; assert sortByBox != null : "fx:id=\"sortByBox\" was not injected: check your FXML file 'NavPanel.fxml'."; VBox.setVgrow(this, Priority.ALWAYS); navTree.setShowRoot(false); hashTree.setShowRoot(false); navTree.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); hashTree.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); sortByBox.setCellFactory((ListView<TreeNodeComparators> p) -> new TreeNodeComparators.ComparatorListCell()); sortByBox.setButtonCell(new TreeNodeComparators.ComparatorListCell()); sortByBox.setItems( FXCollections.observableArrayList(FXCollections.observableArrayList(TreeNodeComparators.values()))); sortByBox.getSelectionModel().select(TreeNodeComparators.HIT_COUNT); sortByBox.getSelectionModel().selectedItemProperty().addListener((Observable o) -> { resortHashTree(); }); navTree.setCellFactory((TreeView<TreeNode> p) -> new GroupTreeCell()); hashTree.setCellFactory((TreeView<TreeNode> p) -> new GroupTreeCell()); activeTreeProperty.addListener((Observable o) -> { updateControllersGroup(); activeTreeProperty.get().getSelectionModel().selectedItemProperty().addListener((Observable o1) -> { updateControllersGroup(); }); }); this.activeTreeProperty.set(navTree); navTabPane.getSelectionModel().selectedItemProperty() .addListener((ObservableValue<? extends Tab> ov, Tab t, Tab t1) -> { if (t1 == hashTab) { activeTreeProperty.set(hashTree); } else if (t1 == navTab) { activeTreeProperty.set(navTree); } }); initHashTree(); initNavTree(); controller.getGroupManager().getAnalyzedGroups() .addListener((ListChangeListener.Change<? extends DrawableGroup> change) -> { while (change.next()) { for (DrawableGroup g : change.getAddedSubList()) { insertIntoNavTree(g); if (g.getFilesWithHashSetHitsCount() > 0) { insertIntoHashTree(g); } } for (DrawableGroup g : change.getRemoved()) { removeFromNavTree(g); removeFromHashTree(g); } } }); for (DrawableGroup g : controller.getGroupManager().getAnalyzedGroups()) { insertIntoNavTree(g); if (g.getFilesWithHashSetHitsCount() > 0) { insertIntoHashTree(g); } } controller.viewState().addListener((ObservableValue<? extends GroupViewState> observable, GroupViewState oldValue, GroupViewState newValue) -> { if (newValue != null && newValue.getGroup() != null) { setFocusedGroup(newValue.getGroup()); } }); } private void updateControllersGroup() { final TreeItem<TreeNode> selectedItem = activeTreeProperty.get().getSelectionModel().getSelectedItem(); if (selectedItem != null && selectedItem.getValue() != null && selectedItem.getValue().getGroup() != null) { controller.advance(GroupViewState.tile(selectedItem.getValue().getGroup())); } } private void resortHashTree() { 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 * * @param grouping */ public void setFocusedGroup(DrawableGroup grouping) { List<String> path = groupingToPath(grouping); final GroupTreeItem treeItemForGroup = ((GroupTreeItem) activeTreeProperty.get().getRoot()) .getTreeItemForPath(path); if (treeItemForGroup != null) { Platform.runLater(() -> { TreeItem<TreeNode> 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); } }); } } @SuppressWarnings("fallthrough") private static List<String> groupingToPath(DrawableGroup g) { if (g.groupKey.getAttribute() == DrawableAttribute.PATH) { String path = g.groupKey.getValueDisplayName(); String cleanPath = StringUtils.stripStart(path, "/"); String[] tokens = cleanPath.split("/"); return Arrays.asList(tokens); } else { return Arrays.asList(g.groupKey.getValueDisplayName()); } } private void insertIntoNavTree(DrawableGroup g) { initNavTree(); List<String> path = groupingToPath(g); navTreeRoot.insert(path, g, true); } private void removeFromNavTree(DrawableGroup g) { initNavTree(); final GroupTreeItem treeItemForGroup = GroupTreeItem.getTreeItemForGroup(navTreeRoot, g); if (treeItemForGroup != null) { treeItemForGroup.removeFromParent(); } } private void removeFromHashTree(DrawableGroup g) { initHashTree(); final GroupTreeItem treeItemForGroup = GroupTreeItem.getTreeItemForGroup(hashTreeRoot, g); if (treeItemForGroup != null) { treeItemForGroup.removeFromParent(); } } private void initNavTree() { if (navTreeRoot == null) { navTreeRoot = new GroupTreeItem("", null, null); Platform.runLater(() -> { navTree.setRoot(navTreeRoot); navTreeRoot.setExpanded(true); }); } } private void initHashTree() { if (hashTreeRoot == null) { hashTreeRoot = new GroupTreeItem("", null, null); Platform.runLater(() -> { hashTree.setRoot(hashTreeRoot); hashTreeRoot.setExpanded(true); }); } } //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<DrawableGroup> groups = controller.getGroupManager().getAnalyzedGroups(); for (DrawableGroup g : groups) { insertIntoNavTree(g); } Platform.runLater(() -> { navTree.setRoot(navTreeRoot); navTreeRoot.setExpanded(true); }); } @Deprecated private void rebuildHashTree() { hashTreeRoot = new GroupTreeItem("", null, sortByBox.getSelectionModel().getSelectedItem()); //TODO: can we do this as db query? List<String> hashSetNames = controller.getGroupManager().findValuesForAttribute(DrawableAttribute.HASHSET, GroupSortBy.NONE); for (String name : hashSetNames) { try { List<Long> fileIDsInGroup = controller.getGroupManager() .getFileIDsInGroup(new GroupKey<String>(DrawableAttribute.HASHSET, name)); for (Long fileId : fileIDsInGroup) { DrawableFile<?> file = controller.getFileFromId(fileId); Collection<GroupKey<?>> groupKeysForFile = controller.getGroupManager() .getGroupKeysForFile(file); for (GroupKey<?> k : groupKeysForFile) { final DrawableGroup groupForKey = controller.getGroupManager().getGroupForKey(k); if (groupForKey != null) { insertIntoHashTree(groupForKey); } } } } catch (TskCoreException ex) { Exceptions.printStackTrace(ex); } } Platform.runLater(() -> { hashTree.setRoot(hashTreeRoot); hashTreeRoot.setExpanded(true); }); } }