mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-16 17:57:43 +00:00
Merge branch 'develop' of https://github.com/sleuthkit/autopsy into develop
This commit is contained in:
commit
000d56188b
@ -234,22 +234,29 @@ public class ImageUtils {
|
||||
*/
|
||||
public static boolean isGIF(AbstractFile file) {
|
||||
try {
|
||||
final FileTypeDetector fileTypeDetector = getFileTypeDetector();
|
||||
if (nonNull(fileTypeDetector)) {
|
||||
String fileType = fileTypeDetector.getFileType(file);
|
||||
final FileTypeDetector myFileTypeDetector = getFileTypeDetector();
|
||||
if (nonNull(myFileTypeDetector)) {
|
||||
String fileType = myFileTypeDetector.getFileType(file);
|
||||
return IMAGE_GIF_MIME.equalsIgnoreCase(fileType);
|
||||
}
|
||||
} catch (TskCoreException | FileTypeDetectorInitException ex) {
|
||||
LOGGER.log(Level.WARNING, "Failed to get mime type with FileTypeDetector.", ex); //NOI18N
|
||||
} catch (FileTypeDetectorInitException ex) {
|
||||
LOGGER.log(Level.WARNING, "Failed to initialize FileTypeDetector.", ex); //NOI18N
|
||||
} catch (TskCoreException ex) {
|
||||
if (ex.getMessage().contains("An SQLException was provoked by the following failure: java.lang.InterruptedException")) {
|
||||
LOGGER.log(Level.WARNING, "Mime type look up with FileTypeDetector was interupted."); //NOI18N}
|
||||
return "gif".equalsIgnoreCase(file.getNameExtension()); //NOI18N
|
||||
} else {
|
||||
LOGGER.log(Level.SEVERE, "Failed to get mime type of " + getContentPathSafe(file) + " with FileTypeDetector.", ex); //NOI18N}
|
||||
}
|
||||
}
|
||||
LOGGER.log(Level.WARNING, "Falling back on direct mime type check."); //NOI18N
|
||||
LOGGER.log(Level.WARNING, "Falling back on direct mime type check for {0}.", getContentPathSafe(file)); //NOI18N
|
||||
switch (file.isMimeType(GIF_MIME_SET)) {
|
||||
|
||||
case TRUE:
|
||||
return true;
|
||||
case UNDEFINED:
|
||||
LOGGER.log(Level.WARNING, "Falling back on extension check."); //NOI18N
|
||||
return "gif".equals(file.getNameExtension()); //NOI18N
|
||||
return "gif".equalsIgnoreCase(file.getNameExtension()); //NOI18N
|
||||
case FALSE:
|
||||
default:
|
||||
return false;
|
||||
@ -660,6 +667,9 @@ public class ImageUtils {
|
||||
if (isGIF(file)) {
|
||||
return readImage();
|
||||
}
|
||||
if (isCancelled()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// If a thumbnail file is already saved locally, just read that.
|
||||
if (cacheFile != null && cacheFile.exists()) {
|
||||
@ -673,6 +683,9 @@ public class ImageUtils {
|
||||
}
|
||||
}
|
||||
|
||||
if (isCancelled()) {
|
||||
return null;
|
||||
}
|
||||
//There was no correctly-sized cached thumbnail so make one.
|
||||
BufferedImage thumbnail = null;
|
||||
|
||||
@ -722,6 +735,11 @@ public class ImageUtils {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
if (isCancelled()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
updateProgress(-1, 1);
|
||||
|
||||
//if we got a valid thumbnail save it
|
||||
@ -810,7 +828,9 @@ public class ImageUtils {
|
||||
}
|
||||
//fall through to default image reading code if there was an error
|
||||
}
|
||||
|
||||
if (isCancelled()) {
|
||||
return null;
|
||||
}
|
||||
try (ImageInputStream input = ImageIO.createImageInputStream(inputStream)) {
|
||||
if (input == null) {
|
||||
throw new IIOException(COULD_NOT_CREATE_IMAGE_INPUT_STREAM);
|
||||
@ -834,9 +854,6 @@ public class ImageUtils {
|
||||
param.setDestination(bufferedImage);
|
||||
try {
|
||||
bufferedImage = reader.read(0, param); //should always be same bufferedImage object
|
||||
if (isCancelled()) {
|
||||
return null;
|
||||
}
|
||||
} catch (IOException iOException) {
|
||||
// Ignore this exception or display a warning or similar, for exceptions happening during decoding
|
||||
LOGGER.log(Level.WARNING, IMAGE_UTILS_COULD_NOT_READ_UNSUPPORTE_OR_CORRUPT + ": " + iOException.toString(), ImageUtils.getContentPathSafe(file)); //NOI18N
|
||||
@ -844,6 +861,9 @@ public class ImageUtils {
|
||||
reader.removeIIOReadProgressListener(this);
|
||||
reader.dispose();
|
||||
}
|
||||
if (isCancelled()) {
|
||||
return null;
|
||||
}
|
||||
return SwingFXUtils.toFXImage(bufferedImage, null);
|
||||
} else {
|
||||
throw new IIOException(NO_IMAGE_READER_FOUND_FOR_ + ImageUtils.getContentPathSafe(file));
|
||||
@ -857,6 +877,7 @@ public class ImageUtils {
|
||||
//update this task with the progress reported by ImageReader.read
|
||||
updateProgress(percentageDone, 100);
|
||||
if (isCancelled()) {
|
||||
reader.removeIIOReadProgressListener(this);
|
||||
reader.abort();
|
||||
reader.dispose();
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
@ -89,7 +91,14 @@ import org.sleuthkit.datamodel.TskData;
|
||||
* Connects different parts of ImageGallery together and is hub for flow of
|
||||
* control.
|
||||
*/
|
||||
public final class ImageGalleryController {
|
||||
public final class ImageGalleryController implements Executor {
|
||||
|
||||
private final Executor execDelegate = Executors.newSingleThreadExecutor();
|
||||
|
||||
@Override
|
||||
public void execute(Runnable command) {
|
||||
execDelegate.execute(command);
|
||||
}
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(ImageGalleryController.class.getName());
|
||||
|
||||
@ -838,7 +847,7 @@ public final class ImageGalleryController {
|
||||
/**
|
||||
* Copy files from a newly added data source into the DB. Get all
|
||||
* "drawable" files, based on extension. After ingest we use file type
|
||||
* id module and if necessary jpeg signature matching to add/remove
|
||||
* id module and if necessary jpeg/png signature matching to add/remove
|
||||
* files
|
||||
*/
|
||||
@Override
|
||||
@ -847,30 +856,28 @@ public final class ImageGalleryController {
|
||||
updateMessage("prepopulating image/video database");
|
||||
|
||||
try {
|
||||
String fsQuery = "";
|
||||
String fsQuery = "(fs_obj_id IS NULL) "; //default clause
|
||||
/*
|
||||
* NOTE: Logical files currently (Apr '15) have a null value for
|
||||
* fs_obj_id in DB. for them, we will not specify a fs_obj_id,
|
||||
* which means we will grab files from another data source, but
|
||||
* the drawable DB is smart enough to de-dupe them. For Images
|
||||
* we can do better.
|
||||
*/
|
||||
if (dataSource instanceof Image) {
|
||||
List<FileSystem> fileSystems = ((Image) dataSource).getFileSystems();
|
||||
if (fileSystems.isEmpty() == false) {
|
||||
if (fileSystems.isEmpty()) {
|
||||
/*
|
||||
* no filesystems, don't bother with the initial
|
||||
* population, just catch things on file_done
|
||||
* population, just sort things out on file_done events
|
||||
*/
|
||||
progressHandle.finish();
|
||||
return;
|
||||
}
|
||||
String internal = fileSystems.stream()
|
||||
//use this clause to only grab files from the newly added filesystems.
|
||||
fsQuery = fileSystems.stream()
|
||||
.map(fileSystem -> String.valueOf(fileSystem.getId()))
|
||||
.collect(Collectors.joining(" OR fs_obj_id = "));
|
||||
fsQuery = "(fs_obj_id = " + internal + ") "; //suffix
|
||||
} else {
|
||||
/*
|
||||
* NOTE: Logical files currently (Apr '15) have a null value
|
||||
* for fs_obj_id in DB. for them, we will not specify a
|
||||
* fs_obj_id, which means we will grab files from another
|
||||
* data source, but the drawable DB is smart enough to
|
||||
* de-dupe them.
|
||||
*/
|
||||
fsQuery = "(fs_obj_id IS NULL) ";
|
||||
.collect(Collectors.joining(" OR fs_obj_id = ", "(fs_obj_id = ", ") "));
|
||||
}
|
||||
|
||||
final List<AbstractFile> files = getSleuthKitCase().findAllFilesWhere(fsQuery + " AND " + DRAWABLE_QUERY);
|
||||
|
@ -39,11 +39,11 @@ import javafx.scene.image.Image;
|
||||
import javafx.scene.image.WritableImage;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.imageio.ImageIO;
|
||||
import org.openide.util.Exceptions;
|
||||
import org.sleuthkit.autopsy.coreutils.ImageUtils;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile;
|
||||
import org.sleuthkit.autopsy.imagegallery.gui.Toolbar;
|
||||
import org.sleuthkit.autopsy.imagegallery.utils.TaskUtils;
|
||||
import org.sleuthkit.datamodel.ReadContentInputStream;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
@ -184,12 +184,7 @@ public enum ThumbnailCache {
|
||||
public Task<Image> getThumbnailTask(DrawableFile<?> file) {
|
||||
final Image thumbnail = cache.getIfPresent(file.getId());
|
||||
if (thumbnail != null) {
|
||||
return new Task<Image>() {
|
||||
@Override
|
||||
protected Image call() throws Exception {
|
||||
return thumbnail;
|
||||
}
|
||||
};
|
||||
return TaskUtils.taskFrom(() -> thumbnail);
|
||||
}
|
||||
final Task<Image> newGetThumbnailTask = ImageUtils.newGetThumbnailTask(file.getAbstractFile(), MAX_THUMBNAIL_SIZE, false);
|
||||
newGetThumbnailTask.stateProperty().addListener((Observable observable) -> {
|
||||
@ -198,7 +193,7 @@ public enum ThumbnailCache {
|
||||
try {
|
||||
cache.put(Long.MIN_VALUE, newGetThumbnailTask.get());
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
Exceptions.printStackTrace(ex);
|
||||
LOGGER.log(Level.SEVERE, "There was an exception even though thumbnail task succedded for. This should not be possible.", ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -19,9 +19,9 @@
|
||||
package org.sleuthkit.autopsy.imagegallery.actions;
|
||||
|
||||
import java.util.Optional;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.binding.ObjectExpression;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
@ -36,10 +36,10 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState;
|
||||
*/
|
||||
public class NextUnseenGroup extends Action {
|
||||
|
||||
private static final Image END
|
||||
= new Image(NextUnseenGroup.class.getResourceAsStream("/org/sleuthkit/autopsy/imagegallery/images/control-stop.png"));
|
||||
private static final Image ADVANCE
|
||||
= new Image(NextUnseenGroup.class.getResourceAsStream("/org/sleuthkit/autopsy/imagegallery/images/control-double.png"));
|
||||
private static final Image END =
|
||||
new Image(NextUnseenGroup.class.getResourceAsStream("/org/sleuthkit/autopsy/imagegallery/images/control-stop.png"));
|
||||
private static final Image ADVANCE =
|
||||
new Image(NextUnseenGroup.class.getResourceAsStream("/org/sleuthkit/autopsy/imagegallery/images/control-double.png"));
|
||||
|
||||
private static final String MARK_GROUP_SEEN = "Mark Group Seen";
|
||||
private static final String NEXT_UNSEEN_GROUP = "Next Unseen group";
|
||||
@ -53,25 +53,36 @@ public class NextUnseenGroup extends Action {
|
||||
|
||||
//TODO: do we need both these listeners?
|
||||
controller.getGroupManager().getAnalyzedGroups().addListener((Observable observable) -> {
|
||||
Platform.runLater(this::updateButton);
|
||||
updateButton();
|
||||
|
||||
});
|
||||
controller.getGroupManager().getUnSeenGroups().addListener((Observable observable) -> {
|
||||
Platform.runLater(this::updateButton);
|
||||
|
||||
updateButton();
|
||||
});
|
||||
|
||||
setEventHandler((ActionEvent t) -> {
|
||||
//fx-thread
|
||||
//if there is a group assigned to the view, mark it as seen
|
||||
Optional.ofNullable(controller.viewState())
|
||||
.map(ObjectExpression<GroupViewState>::getValue)
|
||||
.map(GroupViewState::getGroup)
|
||||
.ifPresent(group -> controller.getGroupManager().markGroupSeen(group, true));
|
||||
controller.execute(new Task<Void>() {
|
||||
|
||||
if (false == controller.getGroupManager().getUnSeenGroups().isEmpty()) {
|
||||
controller.advance(GroupViewState.tile(controller.getGroupManager().getUnSeenGroups().get(0)), true);
|
||||
}
|
||||
updateButton();
|
||||
@Override
|
||||
protected Void call() throws Exception {
|
||||
if (false == controller.getGroupManager().getUnSeenGroups().isEmpty()) {
|
||||
controller.advance(GroupViewState.tile(controller.getGroupManager().getUnSeenGroups().get(0)), true);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void succeeded() {
|
||||
super.succeeded();
|
||||
updateButton();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
updateButton();
|
||||
|
@ -21,6 +21,8 @@ package org.sleuthkit.autopsy.imagegallery.gui.drawableviews;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Level;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.WeakChangeListener;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.CacheHint;
|
||||
@ -48,6 +50,13 @@ public class DrawableTile extends DrawableTileBase {
|
||||
private static final DropShadow LAST_SELECTED_EFFECT = new DropShadow(10, Color.BLUE);
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(DrawableTile.class.getName());
|
||||
private final ChangeListener<? super Long> lastSelectionListener = (observable, oldValue, newValue) -> {
|
||||
try {
|
||||
setEffect(Objects.equals(newValue, getFileID()) ? LAST_SELECTED_EFFECT : null);
|
||||
} catch (java.lang.IllegalStateException ex) {
|
||||
Logger.getLogger(DrawableTile.class.getName()).log(Level.WARNING, "Error displaying tile");
|
||||
}
|
||||
};
|
||||
|
||||
@FXML
|
||||
@Override
|
||||
@ -63,13 +72,7 @@ public class DrawableTile extends DrawableTileBase {
|
||||
imageView.fitHeightProperty().bind(Toolbar.getDefault(getController()).sizeSliderValue());
|
||||
imageView.fitWidthProperty().bind(Toolbar.getDefault(getController()).sizeSliderValue());
|
||||
|
||||
selectionModel.lastSelectedProperty().addListener((observable, oldValue, newValue) -> {
|
||||
try {
|
||||
setEffect(Objects.equals(newValue, getFileID()) ? LAST_SELECTED_EFFECT : null);
|
||||
} catch (java.lang.IllegalStateException ex) {
|
||||
Logger.getLogger(DrawableTile.class.getName()).log(Level.WARNING, "Error displaying tile");
|
||||
}
|
||||
});
|
||||
selectionModel.lastSelectedProperty().addListener(new WeakChangeListener<>(lastSelectionListener));
|
||||
}
|
||||
|
||||
public DrawableTile(GroupPane gp, ImageGalleryController controller) {
|
||||
@ -100,6 +103,4 @@ public class DrawableTile extends DrawableTileBase {
|
||||
return getFile().map(AbstractContent::getName).orElse("");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -25,7 +25,9 @@ import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import java.util.logging.Level;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.InvalidationListener;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.WeakInvalidationListener;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.fxml.FXML;
|
||||
@ -111,7 +113,6 @@ public abstract class DrawableTileBase extends DrawableUIBase {
|
||||
@FXML
|
||||
private ImageView hashHitImageView;
|
||||
|
||||
|
||||
/**
|
||||
* displays the icon representing follow up tag
|
||||
*/
|
||||
@ -148,7 +149,7 @@ public abstract class DrawableTileBase extends DrawableUIBase {
|
||||
super(controller);
|
||||
this.groupPane = groupPane;
|
||||
selectionModel = controller.getSelectionModel();
|
||||
selectionModel.getSelected().addListener((Observable observable) -> updateSelectionState());
|
||||
selectionModel.getSelected().addListener(new WeakInvalidationListener(selectionListener));
|
||||
|
||||
//set up mouse listener
|
||||
//TODO: split this between DrawableTile and SingleDrawableViewBase
|
||||
@ -243,6 +244,7 @@ public abstract class DrawableTileBase extends DrawableUIBase {
|
||||
}
|
||||
});
|
||||
}
|
||||
private final InvalidationListener selectionListener = (Observable observable) -> updateSelectionState();
|
||||
|
||||
GroupPane getGroupPane() {
|
||||
return groupPane;
|
||||
@ -314,7 +316,7 @@ public abstract class DrawableTileBase extends DrawableUIBase {
|
||||
getFile().ifPresent(file -> {
|
||||
final boolean isVideo = file.isVideo();
|
||||
final boolean hasHashSetHits = hasHashHit();
|
||||
|
||||
|
||||
final String text = getTextForLabel();
|
||||
|
||||
Platform.runLater(() -> {
|
||||
@ -322,7 +324,7 @@ public abstract class DrawableTileBase extends DrawableUIBase {
|
||||
fileTypeImageView.setVisible(isVideo);
|
||||
hashHitImageView.setManaged(hasHashSetHits);
|
||||
hashHitImageView.setVisible(hasHashSetHits);
|
||||
|
||||
|
||||
nameLabel.setText(text);
|
||||
nameLabel.setTooltip(new Tooltip(text));
|
||||
});
|
||||
|
@ -157,7 +157,11 @@ abstract public class DrawableUIBase extends AnchorPane implements DrawableView
|
||||
}
|
||||
});
|
||||
myTask.setOnCancelled(cancelled -> {
|
||||
disposeContent();
|
||||
synchronized (DrawableUIBase.this) {
|
||||
imageTask = null;
|
||||
}
|
||||
imageView.setImage(null);
|
||||
imageBorder.setCenter(null);
|
||||
});
|
||||
|
||||
exec.execute(myTask);
|
||||
|
@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.imagegallery.gui.navpanel;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.FXCollections;
|
||||
@ -108,32 +107,12 @@ final public class NavPanel extends TabPane {
|
||||
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) -> {
|
||||
//user action ->jfx thread
|
||||
resortHashTree();
|
||||
});
|
||||
sortByBox.getSelectionModel().selectedItemProperty().addListener(o -> resortHashTree());
|
||||
|
||||
navTree.setRoot(navTreeRoot);
|
||||
navTreeRoot.setExpanded(true);
|
||||
navTree.setCellFactory((TreeView<TreeNode> p) -> new GroupTreeCell());
|
||||
navTree.setShowRoot(false);
|
||||
navTree.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
|
||||
|
||||
hashTree.setRoot(hashTreeRoot);
|
||||
hashTreeRoot.setExpanded(true);
|
||||
hashTree.setCellFactory((TreeView<TreeNode> p) -> new GroupTreeCell());
|
||||
hashTree.setShowRoot(false);
|
||||
hashTree.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
|
||||
|
||||
activeTreeProperty.addListener((Observable o) -> {
|
||||
updateControllersGroup();
|
||||
activeTreeProperty.get().getSelectionModel().selectedItemProperty().addListener((Observable o1) -> {
|
||||
updateControllersGroup();
|
||||
});
|
||||
});
|
||||
|
||||
this.activeTreeProperty.set(navTree);
|
||||
configureTree(navTree, navTreeRoot);
|
||||
configureTree(hashTree, hashTreeRoot);
|
||||
|
||||
activeTreeProperty.set(navTree);
|
||||
navTabPane.getSelectionModel().selectedItemProperty().addListener((ObservableValue<? extends Tab> ov, Tab t, Tab t1) -> {
|
||||
if (t1 == hashTab) {
|
||||
activeTreeProperty.set(hashTree);
|
||||
@ -143,7 +122,6 @@ final public class NavPanel extends TabPane {
|
||||
});
|
||||
|
||||
controller.getGroupManager().getAnalyzedGroups().addListener((ListChangeListener.Change<? extends DrawableGroup> change) -> {
|
||||
|
||||
while (change.next()) {
|
||||
for (DrawableGroup g : change.getAddedSubList()) {
|
||||
insertIntoNavTree(g);
|
||||
@ -158,15 +136,23 @@ final public class NavPanel extends TabPane {
|
||||
}
|
||||
});
|
||||
|
||||
rebuildTrees();
|
||||
|
||||
controller.viewState().addListener((ObservableValue<? extends GroupViewState> observable, GroupViewState oldValue, GroupViewState newValue) -> {
|
||||
if (newValue != null && newValue.getGroup() != null) {
|
||||
Platform.runLater(() -> {
|
||||
setFocusedGroup(newValue.getGroup());
|
||||
});
|
||||
setFocusedGroup(newValue.getGroup());
|
||||
}
|
||||
});
|
||||
|
||||
rebuildTrees();
|
||||
}
|
||||
|
||||
@ThreadConfined(type = ThreadType.JFX)
|
||||
private void configureTree(final TreeView<TreeNode> navTree1, final GroupTreeItem navTreeRoot1) {
|
||||
navTree1.setRoot(navTreeRoot1);
|
||||
navTreeRoot1.setExpanded(true);
|
||||
navTree1.setCellFactory(treeView -> new GroupTreeCell());
|
||||
navTree1.setShowRoot(false);
|
||||
navTree1.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
|
||||
navTree1.getSelectionModel().selectedItemProperty().addListener(o -> updateControllersGroup());
|
||||
}
|
||||
|
||||
private void rebuildTrees() {
|
||||
@ -207,38 +193,28 @@ final public class NavPanel extends TabPane {
|
||||
*/
|
||||
@ThreadConfined(type = ThreadType.JFX)
|
||||
private void setFocusedGroup(DrawableGroup grouping) {
|
||||
|
||||
final GroupTreeItem treeItemForGroup = ((GroupTreeItem) activeTreeProperty.get().getRoot()).getTreeItemForPath(groupingToPath(grouping));
|
||||
|
||||
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.
|
||||
*/
|
||||
//Platform.runLater(() -> {
|
||||
activeTreeProperty.get().getSelectionModel().select(treeItemForGroup);
|
||||
int row = activeTreeProperty.get().getRow(treeItemForGroup);
|
||||
if (row != -1) {
|
||||
activeTreeProperty.get().scrollTo(row - 2); //put newly selected row 3 from the top
|
||||
}
|
||||
//}); //end Platform.runLater
|
||||
Platform.runLater(() -> {
|
||||
int row = activeTreeProperty.get().getRow(treeItemForGroup);
|
||||
if (row != -1) {
|
||||
activeTreeProperty.get().scrollTo(row - 2); //put newly selected row 3 from the top
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> groupingToPath(DrawableGroup g) {
|
||||
if (g.groupKey.getAttribute() == DrawableAttribute.PATH) {
|
||||
String path = g.groupKey.getValueDisplayName();
|
||||
|
||||
String[] cleanPathTokens = StringUtils.stripStart(path, "/").split("/");
|
||||
|
||||
return Arrays.asList(cleanPathTokens);
|
||||
private List<String> groupingToPath(DrawableGroup g) {
|
||||
if (g.groupKey.getAttribute() != DrawableAttribute.PATH
|
||||
|| activeTreeProperty.get() == hashTree) {
|
||||
String stripStart = StringUtils.strip(g.groupKey.getValueDisplayName(), "/");
|
||||
return Arrays.asList(stripStart);
|
||||
} else {
|
||||
return Arrays.asList(g.groupKey.getValueDisplayName());
|
||||
String path = g.groupKey.getValueDisplayName();
|
||||
String[] cleanPathTokens = StringUtils.stripStart(path, "/").split("/");
|
||||
return Arrays.asList(cleanPathTokens);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user