mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-17 18:17:43 +00:00
simplify locking in DrawableTagsManager.java by making the backing tagsManager final
This commit is contained in:
parent
31903d04d8
commit
a37b8dc743
@ -60,6 +60,7 @@ import javax.swing.JOptionPane;
|
|||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import org.netbeans.api.progress.ProgressHandle;
|
import org.netbeans.api.progress.ProgressHandle;
|
||||||
import org.openide.util.Cancellable;
|
import org.openide.util.Cancellable;
|
||||||
|
import org.openide.util.Exceptions;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case.CaseType;
|
import org.sleuthkit.autopsy.casemodule.Case.CaseType;
|
||||||
@ -123,7 +124,7 @@ public final class ImageGalleryController {
|
|||||||
private final GroupManager groupManager = new GroupManager(this);
|
private final GroupManager groupManager = new GroupManager(this);
|
||||||
private final HashSetManager hashSetManager = new HashSetManager();
|
private final HashSetManager hashSetManager = new HashSetManager();
|
||||||
private final CategoryManager categoryManager = new CategoryManager(this);
|
private final CategoryManager categoryManager = new CategoryManager(this);
|
||||||
private final DrawableTagsManager tagsManager = new DrawableTagsManager(null);
|
private DrawableTagsManager tagsManager;
|
||||||
|
|
||||||
private Runnable showTree;
|
private Runnable showTree;
|
||||||
private Toolbar toolbar;
|
private Toolbar toolbar;
|
||||||
@ -144,7 +145,11 @@ public final class ImageGalleryController {
|
|||||||
|
|
||||||
public static synchronized ImageGalleryController getDefault() {
|
public static synchronized ImageGalleryController getDefault() {
|
||||||
if (instance == null) {
|
if (instance == null) {
|
||||||
instance = new ImageGalleryController();
|
try {
|
||||||
|
instance = new ImageGalleryController();
|
||||||
|
} catch (NoClassDefFoundError error) {
|
||||||
|
Exceptions.printStackTrace(error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
@ -232,12 +237,7 @@ public final class ImageGalleryController {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
groupManager.getAnalyzedGroups().addListener((Observable o) -> {
|
groupManager.getAnalyzedGroups().addListener((Observable o) -> checkForGroups());
|
||||||
//analyzed groups is confined to JFX thread
|
|
||||||
if (Case.isCaseOpen()) {
|
|
||||||
checkForGroups();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
viewState().addListener((Observable observable) -> {
|
viewState().addListener((Observable observable) -> {
|
||||||
//when the viewed group changes, clear the selection and the undo/redo history
|
//when the viewed group changes, clear the selection and the undo/redo history
|
||||||
@ -291,7 +291,6 @@ public final class ImageGalleryController {
|
|||||||
* GroupManager and remove blocking progress spinners if there are. If there
|
* GroupManager and remove blocking progress spinners if there are. If there
|
||||||
* aren't, add a blocking progress spinner with appropriate message.
|
* aren't, add a blocking progress spinner with appropriate message.
|
||||||
*/
|
*/
|
||||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
|
||||||
@NbBundle.Messages({"ImageGalleryController.noGroupsDlg.msg1=No groups are fully analyzed; but listening to ingest is disabled. "
|
@NbBundle.Messages({"ImageGalleryController.noGroupsDlg.msg1=No groups are fully analyzed; but listening to ingest is disabled. "
|
||||||
+ " No groups will be available until ingest is finished and listening is re-enabled.",
|
+ " No groups will be available until ingest is finished and listening is re-enabled.",
|
||||||
"ImageGalleryController.noGroupsDlg.msg2=No groups are fully analyzed yet, but ingest is still ongoing. Please Wait.",
|
"ImageGalleryController.noGroupsDlg.msg2=No groups are fully analyzed yet, but ingest is still ongoing. Please Wait.",
|
||||||
@ -303,45 +302,46 @@ public final class ImageGalleryController {
|
|||||||
+ " the current Group By setting resulted in no groups, "
|
+ " the current Group By setting resulted in no groups, "
|
||||||
+ "or no groups are fully analyzed but ingest is not running."})
|
+ "or no groups are fully analyzed but ingest is not running."})
|
||||||
synchronized private void checkForGroups() {
|
synchronized private void checkForGroups() {
|
||||||
if (groupManager.getAnalyzedGroups().isEmpty()) {
|
if (Case.isCaseOpen()) {
|
||||||
if (IngestManager.getInstance().isIngestRunning()) {
|
if (groupManager.getAnalyzedGroups().isEmpty()) {
|
||||||
if (listeningEnabled.not().get()) {
|
if (IngestManager.getInstance().isIngestRunning()) {
|
||||||
replaceNotification(fullUIStackPane,
|
if (listeningEnabled.get()) {
|
||||||
new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg1()));
|
replaceNotification(centralStackPane,
|
||||||
} else {
|
new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg2(),
|
||||||
replaceNotification(fullUIStackPane,
|
new ProgressIndicator()));
|
||||||
new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg2(),
|
} else {
|
||||||
new ProgressIndicator()));
|
replaceNotification(fullUIStackPane,
|
||||||
}
|
new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg1()));
|
||||||
|
|
||||||
} else if (dbTaskQueueSize.get() > 0) {
|
|
||||||
replaceNotification(fullUIStackPane,
|
|
||||||
new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg3(),
|
|
||||||
new ProgressIndicator()));
|
|
||||||
} else if (db != null) {
|
|
||||||
try {
|
|
||||||
if (db.countAllFiles() <= 0) {
|
|
||||||
|
|
||||||
// there are no files in db
|
|
||||||
if (listeningEnabled.not().get()) {
|
|
||||||
replaceNotification(fullUIStackPane,
|
|
||||||
new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg4()));
|
|
||||||
} else {
|
|
||||||
replaceNotification(fullUIStackPane,
|
|
||||||
new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg5()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Error counting files in drawable db.", ex);
|
} else if (dbTaskQueueSize.get() > 0) {
|
||||||
|
replaceNotification(fullUIStackPane,
|
||||||
|
new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg3(),
|
||||||
|
new ProgressIndicator()));
|
||||||
|
} else if (db != null) {
|
||||||
|
try {
|
||||||
|
if (db.countAllFiles() <= 0) {
|
||||||
|
// there are no files in db
|
||||||
|
if (listeningEnabled.get()) {
|
||||||
|
replaceNotification(fullUIStackPane,
|
||||||
|
new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg5()));
|
||||||
|
} else {
|
||||||
|
replaceNotification(fullUIStackPane,
|
||||||
|
new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg4()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
logger.log(Level.SEVERE, "Error counting files in drawable db.", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (false == groupManager.isRegrouping()) {
|
||||||
|
replaceNotification(centralStackPane,
|
||||||
|
new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg6()));
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (!groupManager.isRegrouping()) {
|
} else {
|
||||||
replaceNotification(centralStackPane,
|
Platform.runLater(this::clearNotification);
|
||||||
new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg6()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
clearNotification();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,22 +357,25 @@ public final class ImageGalleryController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
|
||||||
private void replaceNotification(StackPane stackPane, Node newNode) {
|
private void replaceNotification(StackPane stackPane, Node newNode) {
|
||||||
clearNotification();
|
Platform.runLater(() -> {
|
||||||
|
clearNotification();
|
||||||
|
|
||||||
infoOverlay = new StackPane(infoOverLayBackground, newNode);
|
infoOverlay = new StackPane(infoOverLayBackground, newNode);
|
||||||
if (stackPane != null) {
|
if (stackPane != null) {
|
||||||
stackPane.getChildren().add(infoOverlay);
|
stackPane.getChildren().add(infoOverlay);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* configure the controller for a specific case.
|
* configure the controller for a specific case.
|
||||||
*
|
*
|
||||||
* @param theNewCase the case to configure the controller for
|
* @param theNewCase the case to configure the controller for
|
||||||
|
*
|
||||||
|
* @throws org.sleuthkit.datamodel.TskCoreException
|
||||||
*/
|
*/
|
||||||
public synchronized void setCase(Case theNewCase) {
|
public synchronized void setCase(Case theNewCase) throws TskCoreException {
|
||||||
if (null == theNewCase) {
|
if (null == theNewCase) {
|
||||||
reset();
|
reset();
|
||||||
} else {
|
} else {
|
||||||
@ -385,10 +388,15 @@ public final class ImageGalleryController {
|
|||||||
// if we add this line icons are made as files are analyzed rather than on demand.
|
// if we add this line icons are made as files are analyzed rather than on demand.
|
||||||
// db.addUpdatedFileListener(IconCache.getDefault());
|
// db.addUpdatedFileListener(IconCache.getDefault());
|
||||||
historyManager.clear();
|
historyManager.clear();
|
||||||
groupManager.setDB(db);
|
groupManager.reset();
|
||||||
hashSetManager.setDb(db);
|
hashSetManager.setDb(db);
|
||||||
categoryManager.setDb(db);
|
categoryManager.setDb(db);
|
||||||
tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager());
|
|
||||||
|
if (tagsManager != null) {
|
||||||
|
tagsManager.unregisterListener(groupManager);
|
||||||
|
tagsManager.unregisterListener(categoryManager);
|
||||||
|
}
|
||||||
|
tagsManager = new DrawableTagsManager(theNewCase.getServices().getTagsManager());
|
||||||
tagsManager.registerListener(groupManager);
|
tagsManager.registerListener(groupManager);
|
||||||
tagsManager.registerListener(categoryManager);
|
tagsManager.registerListener(categoryManager);
|
||||||
shutDownDBExecutor();
|
shutDownDBExecutor();
|
||||||
@ -416,10 +424,11 @@ public final class ImageGalleryController {
|
|||||||
setListeningEnabled(false);
|
setListeningEnabled(false);
|
||||||
ThumbnailCache.getDefault().clearCache();
|
ThumbnailCache.getDefault().clearCache();
|
||||||
historyManager.clear();
|
historyManager.clear();
|
||||||
groupManager.clear();
|
groupManager.reset();
|
||||||
tagsManager.clearFollowUpTagName();
|
|
||||||
tagsManager.unregisterListener(groupManager);
|
tagsManager.unregisterListener(groupManager);
|
||||||
tagsManager.unregisterListener(categoryManager);
|
tagsManager.unregisterListener(categoryManager);
|
||||||
|
tagsManager = null;
|
||||||
shutDownDBExecutor();
|
shutDownDBExecutor();
|
||||||
|
|
||||||
if (toolbar != null) {
|
if (toolbar != null) {
|
||||||
@ -854,6 +863,9 @@ public final class ImageGalleryController {
|
|||||||
taskDB.commitTransaction(drawableDbTransaction, true);
|
taskDB.commitTransaction(drawableDbTransaction, true);
|
||||||
|
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
|
if (null != drawableDbTransaction) {
|
||||||
|
taskDB.rollbackTransaction(drawableDbTransaction);
|
||||||
|
}
|
||||||
if (null != caseDbTransaction) {
|
if (null != caseDbTransaction) {
|
||||||
try {
|
try {
|
||||||
caseDbTransaction.rollback();
|
caseDbTransaction.rollback();
|
||||||
@ -861,9 +873,6 @@ public final class ImageGalleryController {
|
|||||||
logger.log(Level.SEVERE, "Error in trying to rollback transaction", ex2); //NON-NLS
|
logger.log(Level.SEVERE, "Error in trying to rollback transaction", ex2); //NON-NLS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (null != drawableDbTransaction) {
|
|
||||||
taskDB.rollbackTransaction(drawableDbTransaction);
|
|
||||||
}
|
|
||||||
|
|
||||||
progressHandle.progress(Bundle.BulkTask_stopCopy_status());
|
progressHandle.progress(Bundle.BulkTask_stopCopy_status());
|
||||||
logger.log(Level.WARNING, "Stopping copy to drawable db task. Failed to transfer all database contents", ex); //NON-NLS
|
logger.log(Level.WARNING, "Stopping copy to drawable db task. Failed to transfer all database contents", ex); //NON-NLS
|
||||||
@ -1065,8 +1074,13 @@ public final class ImageGalleryController {
|
|||||||
//close window, reset everything
|
//close window, reset everything
|
||||||
SwingUtilities.invokeLater(ImageGalleryTopComponent::closeTopComponent);
|
SwingUtilities.invokeLater(ImageGalleryTopComponent::closeTopComponent);
|
||||||
reset();
|
reset();
|
||||||
} else { // a new case has been opened
|
} else {
|
||||||
setCase(newCase); //connect db, groupmanager, start worker thread
|
try {
|
||||||
|
// a new case has been opened
|
||||||
|
setCase(newCase); //connect db, groupmanager, start worker thread
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
logger.log(Level.SEVERE, "Error changing case in ImageGallery.", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DATA_SOURCE_ADDED:
|
case DATA_SOURCE_ADDED:
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2013-16 Basis Technology Corp.
|
* Copyright 2013-18 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -18,25 +18,24 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.imagegallery.datamodel;
|
package org.sleuthkit.autopsy.imagegallery.datamodel;
|
||||||
|
|
||||||
import org.sleuthkit.autopsy.datamodel.DhsImageCategory;
|
|
||||||
import com.google.common.eventbus.AsyncEventBus;
|
import com.google.common.eventbus.AsyncEventBus;
|
||||||
import com.google.common.eventbus.EventBus;
|
import com.google.common.eventbus.EventBus;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
|
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
|
||||||
|
import org.openide.util.Exceptions;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
|
import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
|
||||||
import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
|
import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
|
||||||
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.DhsImageCategory;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
import org.sleuthkit.datamodel.ContentTag;
|
import org.sleuthkit.datamodel.ContentTag;
|
||||||
import org.sleuthkit.datamodel.TagName;
|
import org.sleuthkit.datamodel.TagName;
|
||||||
@ -44,39 +43,40 @@ import org.sleuthkit.datamodel.TskCoreException;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages Tags, Tagging, and the relationship between Categories and Tags in
|
* Manages Tags, Tagging, and the relationship between Categories and Tags in
|
||||||
* the autopsy Db. Delegates some work to the backing {@link TagsManager}.
|
* the autopsy Db. Delegates some work to the backing autopsy TagsManager.
|
||||||
*/
|
*/
|
||||||
@NbBundle.Messages({"DrawableTagsManager.followUp=Follow Up",
|
@NbBundle.Messages({"DrawableTagsManager.followUp=Follow Up",
|
||||||
"DrawableTagsManager.bookMark=Bookmark"})
|
"DrawableTagsManager.bookMark=Bookmark"})
|
||||||
public class DrawableTagsManager {
|
public final class DrawableTagsManager {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(DrawableTagsManager.class.getName());
|
private static final Logger logger = Logger.getLogger(DrawableTagsManager.class.getName());
|
||||||
|
|
||||||
private static Image FOLLOW_UP_IMAGE;
|
private static final Image FOLLOW_UP_IMAGE = new Image("/org/sleuthkit/autopsy/imagegallery/images/flag_red.png");
|
||||||
private static Image BOOKMARK_IMAGE;
|
private static final Image BOOKMARK_IMAGE = new Image("/org/sleuthkit/autopsy/images/star-bookmark-icon-16.png");
|
||||||
|
|
||||||
final private Object autopsyTagsManagerLock = new Object();
|
private final TagsManager autopsyTagsManager;
|
||||||
private TagsManager autopsyTagsManager;
|
|
||||||
|
/** The tag name corresponding to the "built-in" tag "Follow Up" */
|
||||||
|
private final TagName followUpTagName;
|
||||||
|
private final TagName bookmarkTagName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to distribute {@link TagsChangeEvent}s
|
* Used to distribute {@link TagsChangeEvent}s
|
||||||
*/
|
*/
|
||||||
private final EventBus tagsEventBus = new AsyncEventBus(
|
private final EventBus tagsEventBus
|
||||||
Executors.newSingleThreadExecutor(
|
= new AsyncEventBus(
|
||||||
new BasicThreadFactory.Builder().namingPattern("Tags Event Bus").uncaughtExceptionHandler((Thread t, Throwable e) -> { //NON-NLS
|
Executors.newSingleThreadExecutor(
|
||||||
LOGGER.log(Level.SEVERE, "uncaught exception in event bus handler", e); //NON-NLS
|
new BasicThreadFactory.Builder()
|
||||||
}).build()
|
.namingPattern("Tags Event Bus")//NON-NLS
|
||||||
));
|
.uncaughtExceptionHandler((Thread t, Throwable e) -> {
|
||||||
|
logger.log(Level.SEVERE, "Uncaught exception in DrawableTagsManager event bus handler.", e); //NON-NLS
|
||||||
|
})
|
||||||
|
.build()));
|
||||||
|
|
||||||
/**
|
public DrawableTagsManager(TagsManager autopsyTagsManager) throws TskCoreException {
|
||||||
* The tag name corresponding to the "built-in" tag "Follow Up"
|
|
||||||
*/
|
|
||||||
private TagName followUpTagName;
|
|
||||||
private TagName bookmarkTagName;
|
|
||||||
|
|
||||||
public DrawableTagsManager(TagsManager autopsyTagsManager) {
|
|
||||||
this.autopsyTagsManager = autopsyTagsManager;
|
this.autopsyTagsManager = autopsyTagsManager;
|
||||||
|
followUpTagName = getTagName(NbBundle.getMessage(DrawableTagsManager.class, "DrawableTagsManager.followUp"));
|
||||||
|
bookmarkTagName = getTagName(NbBundle.getMessage(DrawableTagsManager.class, "DrawableTagsManager.bookMark"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -106,72 +106,37 @@ public class DrawableTagsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* assign a new TagsManager to back this one, ie when the current case
|
* Get the follow up TagName.
|
||||||
* changes
|
|
||||||
*
|
*
|
||||||
* @param autopsyTagsManager
|
* @return The follow up TagName.
|
||||||
*/
|
*/
|
||||||
public void setAutopsyTagsManager(TagsManager autopsyTagsManager) {
|
public TagName getFollowUpTagName() {
|
||||||
synchronized (autopsyTagsManagerLock) {
|
return followUpTagName;
|
||||||
this.autopsyTagsManager = autopsyTagsManager;
|
|
||||||
clearFollowUpTagName();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use when closing a case to make sure everything is re-initialized in the
|
* Get the bookmark TagName.
|
||||||
* next case.
|
*
|
||||||
|
* @return The bookmark TagName.
|
||||||
*/
|
*/
|
||||||
public void clearFollowUpTagName() {
|
private TagName getBookmarkTagName() throws TskCoreException {
|
||||||
synchronized (autopsyTagsManagerLock) {
|
return bookmarkTagName;
|
||||||
followUpTagName = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get the (cached) follow up TagName
|
* Get all the TagNames that are not categories
|
||||||
*
|
*
|
||||||
* @return
|
* @return All the TagNames that are not categories, in alphabetical order
|
||||||
*
|
|
||||||
* @throws TskCoreException
|
|
||||||
*/
|
|
||||||
public TagName getFollowUpTagName() throws TskCoreException {
|
|
||||||
synchronized (autopsyTagsManagerLock) {
|
|
||||||
if (Objects.isNull(followUpTagName)) {
|
|
||||||
followUpTagName = getTagName(NbBundle.getMessage(DrawableTagsManager.class, "DrawableTagsManager.followUp"));
|
|
||||||
}
|
|
||||||
return followUpTagName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Object getBookmarkTagName() throws TskCoreException {
|
|
||||||
synchronized (autopsyTagsManagerLock) {
|
|
||||||
if (Objects.isNull(bookmarkTagName)) {
|
|
||||||
bookmarkTagName = getTagName(NbBundle.getMessage(DrawableTagsManager.class, "DrawableTagsManager.bookMark"));
|
|
||||||
}
|
|
||||||
return bookmarkTagName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get all the TagNames that are not categories
|
|
||||||
*
|
|
||||||
* @return all the TagNames that are not categories, in alphabetical order
|
|
||||||
* by displayName, or, an empty set if there was an exception
|
* by displayName, or, an empty set if there was an exception
|
||||||
* looking them up from the db.
|
* looking them up from the db.
|
||||||
*/
|
*/
|
||||||
@Nonnull
|
|
||||||
public List<TagName> getNonCategoryTagNames() {
|
public List<TagName> getNonCategoryTagNames() {
|
||||||
synchronized (autopsyTagsManagerLock) {
|
try {
|
||||||
try {
|
return autopsyTagsManager.getAllTagNames().stream()
|
||||||
return autopsyTagsManager.getAllTagNames().stream()
|
.filter(CategoryManager::isNotCategoryTagName)
|
||||||
.filter(CategoryManager::isNotCategoryTagName)
|
.distinct().sorted()
|
||||||
.distinct().sorted()
|
.collect(Collectors.toList());
|
||||||
.collect(Collectors.toList());
|
} catch (TskCoreException tskCoreException) {
|
||||||
} catch (TskCoreException | IllegalStateException ex) {
|
|
||||||
LOGGER.log(Level.WARNING, "couldn't access case", ex); //NON-NLS
|
|
||||||
}
|
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -187,9 +152,7 @@ public class DrawableTagsManager {
|
|||||||
* @throws TskCoreException if there was an error reading from the db
|
* @throws TskCoreException if there was an error reading from the db
|
||||||
*/
|
*/
|
||||||
public List<ContentTag> getContentTags(Content content) throws TskCoreException {
|
public List<ContentTag> getContentTags(Content content) throws TskCoreException {
|
||||||
synchronized (autopsyTagsManagerLock) {
|
return autopsyTagsManager.getContentTagsByContent(content);
|
||||||
return autopsyTagsManager.getContentTagsByContent(content);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -207,25 +170,23 @@ public class DrawableTagsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public TagName getTagName(String displayName) throws TskCoreException {
|
public TagName getTagName(String displayName) throws TskCoreException {
|
||||||
synchronized (autopsyTagsManagerLock) {
|
try {
|
||||||
|
TagName returnTagName = autopsyTagsManager.getDisplayNamesToTagNamesMap().get(displayName);
|
||||||
|
if (returnTagName != null) {
|
||||||
|
return returnTagName;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
TagName returnTagName = autopsyTagsManager.getDisplayNamesToTagNamesMap().get(displayName);
|
return autopsyTagsManager.addTagName(displayName);
|
||||||
|
} catch (TagsManager.TagNameAlreadyExistsException ex) {
|
||||||
|
returnTagName = autopsyTagsManager.getDisplayNamesToTagNamesMap().get(displayName);
|
||||||
if (returnTagName != null) {
|
if (returnTagName != null) {
|
||||||
return returnTagName;
|
return returnTagName;
|
||||||
}
|
}
|
||||||
try {
|
throw new TskCoreException("Tag name exists but an error occured in retrieving it", ex);
|
||||||
return autopsyTagsManager.addTagName(displayName);
|
|
||||||
} catch (TagsManager.TagNameAlreadyExistsException ex) {
|
|
||||||
returnTagName = autopsyTagsManager.getDisplayNamesToTagNamesMap().get(displayName);
|
|
||||||
if (returnTagName != null) {
|
|
||||||
return returnTagName;
|
|
||||||
}
|
|
||||||
throw new TskCoreException("Tag name exists but an error occured in retrieving it", ex);
|
|
||||||
}
|
|
||||||
} catch (NullPointerException | IllegalStateException ex) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Case was closed out from underneath", ex); //NON-NLS
|
|
||||||
throw new TskCoreException("Case was closed out from underneath", ex);
|
|
||||||
}
|
}
|
||||||
|
} catch (NullPointerException | IllegalStateException ex) {
|
||||||
|
logger.log(Level.SEVERE, "Case was closed out from underneath", ex); //NON-NLS
|
||||||
|
throw new TskCoreException("Case was closed out from underneath", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,65 +194,41 @@ public class DrawableTagsManager {
|
|||||||
try {
|
try {
|
||||||
return getTagName(cat.getDisplayName());
|
return getTagName(cat.getDisplayName());
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
|
logger.log(Level.SEVERE, "Error getting tag for Category: " + cat.getDisplayName(), ex);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ContentTag addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException {
|
public ContentTag addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException {
|
||||||
synchronized (autopsyTagsManagerLock) {
|
return autopsyTagsManager.addContentTag(file.getAbstractFile(), tagName, comment);
|
||||||
return autopsyTagsManager.addContentTag(file.getAbstractFile(), tagName, comment);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ContentTag> getContentTagsByTagName(TagName t) throws TskCoreException {
|
public List<ContentTag> getContentTagsByTagName(TagName t) throws TskCoreException {
|
||||||
synchronized (autopsyTagsManagerLock) {
|
return autopsyTagsManager.getContentTagsByTagName(t);
|
||||||
return autopsyTagsManager.getContentTagsByTagName(t);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<TagName> getAllTagNames() throws TskCoreException {
|
public List<TagName> getAllTagNames() throws TskCoreException {
|
||||||
synchronized (autopsyTagsManagerLock) {
|
return autopsyTagsManager.getAllTagNames();
|
||||||
return autopsyTagsManager.getAllTagNames();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<TagName> getTagNamesInUse() throws TskCoreException {
|
public List<TagName> getTagNamesInUse() throws TskCoreException {
|
||||||
synchronized (autopsyTagsManagerLock) {
|
return autopsyTagsManager.getTagNamesInUse();
|
||||||
return autopsyTagsManager.getTagNamesInUse();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteContentTag(ContentTag ct) throws TskCoreException {
|
public void deleteContentTag(ContentTag ct) throws TskCoreException {
|
||||||
synchronized (autopsyTagsManagerLock) {
|
autopsyTagsManager.deleteContentTag(ct);
|
||||||
autopsyTagsManager.deleteContentTag(ct);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Node getGraphic(TagName tagname) {
|
public Node getGraphic(TagName tagname) {
|
||||||
try {
|
try {
|
||||||
if (tagname.equals(getFollowUpTagName())) {
|
if (tagname.equals(getFollowUpTagName())) {
|
||||||
return new ImageView(getFollowUpImage());
|
return new ImageView(FOLLOW_UP_IMAGE);
|
||||||
} else if (tagname.equals(getBookmarkTagName())) {
|
} else if (tagname.equals(getBookmarkTagName())) {
|
||||||
return new ImageView(getBookmarkImage());
|
return new ImageView(BOOKMARK_IMAGE);
|
||||||
}
|
}
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
LOGGER.log(Level.SEVERE, "Failed to get \"Follow Up\" or \"Bookmark\"tag name from db.", ex);
|
logger.log(Level.SEVERE, "Failed to get \"Follow Up\" or \"Bookmark\"tag name from db.", ex);
|
||||||
}
|
}
|
||||||
return DrawableAttribute.TAGS.getGraphicForValue(tagname);
|
return DrawableAttribute.TAGS.getGraphicForValue(tagname);
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized private static Image getFollowUpImage() {
|
|
||||||
if (FOLLOW_UP_IMAGE == null) {
|
|
||||||
FOLLOW_UP_IMAGE = new Image("/org/sleuthkit/autopsy/imagegallery/images/flag_red.png");
|
|
||||||
}
|
|
||||||
return FOLLOW_UP_IMAGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized private static Image getBookmarkImage() {
|
|
||||||
if (BOOKMARK_IMAGE == null) {
|
|
||||||
BOOKMARK_IMAGE = new Image("/org/sleuthkit/autopsy/images/star-bookmark-icon-16.png");
|
|
||||||
}
|
|
||||||
return BOOKMARK_IMAGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -231,7 +231,7 @@ public class GroupManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized public void clear() {
|
synchronized public void reset() {
|
||||||
|
|
||||||
if (groupByTask != null) {
|
if (groupByTask != null) {
|
||||||
groupByTask.cancel(true);
|
groupByTask.cancel(true);
|
||||||
|
@ -188,9 +188,9 @@ public abstract class DrawableTileBase extends DrawableUIBase {
|
|||||||
|
|
||||||
menuItems.add(CategorizeAction.getCategoriesMenu(getController()));
|
menuItems.add(CategorizeAction.getCategoriesMenu(getController()));
|
||||||
menuItems.add(AddTagAction.getTagMenu(getController()));
|
menuItems.add(AddTagAction.getTagMenu(getController()));
|
||||||
|
|
||||||
final Collection<AbstractFile> selectedFilesList = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
final Collection<AbstractFile> selectedFilesList = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||||
if(selectedFilesList.size() == 1) {
|
if (selectedFilesList.size() == 1) {
|
||||||
menuItems.add(DeleteTagAction.getTagMenu(getController()));
|
menuItems.add(DeleteTagAction.getTagMenu(getController()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,32 +243,24 @@ public abstract class DrawableTileBase extends DrawableUIBase {
|
|||||||
protected abstract String getTextForLabel();
|
protected abstract String getTextForLabel();
|
||||||
|
|
||||||
protected void initialize() {
|
protected void initialize() {
|
||||||
followUpToggle.setOnAction(actionEvent -> {
|
followUpToggle.setOnAction(
|
||||||
getFile().ifPresent(file -> {
|
actionEvent -> getFile().ifPresent(
|
||||||
if (followUpToggle.isSelected() == true) {
|
file -> {
|
||||||
try {
|
if (followUpToggle.isSelected() == true) {
|
||||||
selectionModel.clearAndSelect(file.getId());
|
selectionModel.clearAndSelect(file.getId());
|
||||||
new AddTagAction(getController(), getController().getTagsManager().getFollowUpTagName(), selectionModel.getSelected()).handle(actionEvent);
|
new AddTagAction(getController(), getController().getTagsManager().getFollowUpTagName(), selectionModel.getSelected()).handle(actionEvent);
|
||||||
} catch (TskCoreException ex) {
|
} else {
|
||||||
LOGGER.log(Level.SEVERE, "Failed to add Follow Up tag. Could not load TagName.", ex); //NON-NLS
|
new DeleteFollowUpTagAction(getController(), file).handle(actionEvent);
|
||||||
}
|
}
|
||||||
} else {
|
})
|
||||||
new DeleteFollowUpTagAction(getController(), file).handle(actionEvent);
|
);
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean hasFollowUp() {
|
protected boolean hasFollowUp() {
|
||||||
if (getFileID().isPresent()) {
|
if (getFileID().isPresent()) {
|
||||||
try {
|
TagName followUpTagName = getController().getTagsManager().getFollowUpTagName(); //NON-NLS
|
||||||
TagName followUpTagName = getController().getTagsManager().getFollowUpTagName();
|
return DrawableAttribute.TAGS.getValue(getFile().get()).stream()
|
||||||
return DrawableAttribute.TAGS.getValue(getFile().get()).stream()
|
.anyMatch(followUpTagName::equals);
|
||||||
.anyMatch(followUpTagName::equals);
|
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
LOGGER.log(Level.WARNING, "failed to get follow up tag name ", ex); //NON-NLS
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -342,18 +334,14 @@ public abstract class DrawableTileBase extends DrawableUIBase {
|
|||||||
@Override
|
@Override
|
||||||
public void handleTagAdded(ContentTagAddedEvent evt) {
|
public void handleTagAdded(ContentTagAddedEvent evt) {
|
||||||
getFileID().ifPresent(fileID -> {
|
getFileID().ifPresent(fileID -> {
|
||||||
try {
|
final TagName followUpTagName = getController().getTagsManager().getFollowUpTagName(); //NON-NLS
|
||||||
final TagName followUpTagName = getController().getTagsManager().getFollowUpTagName();
|
final ContentTag addedTag = evt.getAddedTag();
|
||||||
final ContentTag addedTag = evt.getAddedTag();
|
if (fileID == addedTag.getContent().getId()
|
||||||
if (fileID == addedTag.getContent().getId()
|
&& addedTag.getName().equals(followUpTagName)) {
|
||||||
&& addedTag.getName().equals(followUpTagName)) {
|
Platform.runLater(() -> {
|
||||||
Platform.runLater(() -> {
|
followUpImageView.setImage(followUpIcon);
|
||||||
followUpImageView.setImage(followUpIcon);
|
followUpToggle.setSelected(true);
|
||||||
followUpToggle.setSelected(true);
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Failed to get followup tag name. Unable to update follow up status for file. ", ex); //NON-NLS
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -362,15 +350,11 @@ public abstract class DrawableTileBase extends DrawableUIBase {
|
|||||||
@Override
|
@Override
|
||||||
public void handleTagDeleted(ContentTagDeletedEvent evt) {
|
public void handleTagDeleted(ContentTagDeletedEvent evt) {
|
||||||
getFileID().ifPresent(fileID -> {
|
getFileID().ifPresent(fileID -> {
|
||||||
try {
|
final TagName followUpTagName = getController().getTagsManager().getFollowUpTagName(); //NON-NLS
|
||||||
final TagName followUpTagName = getController().getTagsManager().getFollowUpTagName();
|
final ContentTagDeletedEvent.DeletedContentTagInfo deletedTagInfo = evt.getDeletedTagInfo();
|
||||||
final ContentTagDeletedEvent.DeletedContentTagInfo deletedTagInfo = evt.getDeletedTagInfo();
|
if (fileID == deletedTagInfo.getContentID()
|
||||||
if (fileID == deletedTagInfo.getContentID()
|
&& deletedTagInfo.getName().equals(followUpTagName)) {
|
||||||
&& deletedTagInfo.getName().equals(followUpTagName)) {
|
updateFollowUpIcon();
|
||||||
updateFollowUpIcon();
|
|
||||||
}
|
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Failed to get followup tag name. Unable to update follow up status for file. ", ex); //NON-NLS
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -144,39 +144,39 @@ import org.sleuthkit.datamodel.TskCoreException;
|
|||||||
* https://bitbucket.org/controlsfx/controlsfx/issue/4/add-a-multipleselectionmodel-to-gridview
|
* https://bitbucket.org/controlsfx/controlsfx/issue/4/add-a-multipleselectionmodel-to-gridview
|
||||||
*/
|
*/
|
||||||
public class GroupPane extends BorderPane {
|
public class GroupPane extends BorderPane {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(GroupPane.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(GroupPane.class.getName());
|
||||||
private static final BorderWidths BORDER_WIDTHS_2 = new BorderWidths(2);
|
private static final BorderWidths BORDER_WIDTHS_2 = new BorderWidths(2);
|
||||||
private static final CornerRadii CORNER_RADII_2 = new CornerRadii(2);
|
private static final CornerRadii CORNER_RADII_2 = new CornerRadii(2);
|
||||||
|
|
||||||
private static final DropShadow DROP_SHADOW = new DropShadow(10, Color.BLUE);
|
private static final DropShadow DROP_SHADOW = new DropShadow(10, Color.BLUE);
|
||||||
|
|
||||||
private static final Timeline flashAnimation = new Timeline(new KeyFrame(Duration.millis(400), new KeyValue(DROP_SHADOW.radiusProperty(), 1, Interpolator.LINEAR)),
|
private static final Timeline flashAnimation = new Timeline(new KeyFrame(Duration.millis(400), new KeyValue(DROP_SHADOW.radiusProperty(), 1, Interpolator.LINEAR)),
|
||||||
new KeyFrame(Duration.millis(400), new KeyValue(DROP_SHADOW.radiusProperty(), 15, Interpolator.LINEAR))
|
new KeyFrame(Duration.millis(400), new KeyValue(DROP_SHADOW.radiusProperty(), 15, Interpolator.LINEAR))
|
||||||
);
|
);
|
||||||
|
|
||||||
private final FileIDSelectionModel selectionModel;
|
private final FileIDSelectionModel selectionModel;
|
||||||
private static final List<KeyCode> categoryKeyCodes = Arrays.asList(KeyCode.NUMPAD0, KeyCode.NUMPAD1, KeyCode.NUMPAD2, KeyCode.NUMPAD3, KeyCode.NUMPAD4, KeyCode.NUMPAD5,
|
private static final List<KeyCode> categoryKeyCodes = Arrays.asList(KeyCode.NUMPAD0, KeyCode.NUMPAD1, KeyCode.NUMPAD2, KeyCode.NUMPAD3, KeyCode.NUMPAD4, KeyCode.NUMPAD5,
|
||||||
KeyCode.DIGIT0, KeyCode.DIGIT1, KeyCode.DIGIT2, KeyCode.DIGIT3, KeyCode.DIGIT4, KeyCode.DIGIT5);
|
KeyCode.DIGIT0, KeyCode.DIGIT1, KeyCode.DIGIT2, KeyCode.DIGIT3, KeyCode.DIGIT4, KeyCode.DIGIT5);
|
||||||
|
|
||||||
private final Back backAction;
|
private final Back backAction;
|
||||||
|
|
||||||
private final Forward forwardAction;
|
private final Forward forwardAction;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private Button undoButton;
|
private Button undoButton;
|
||||||
@FXML
|
@FXML
|
||||||
private Button redoButton;
|
private Button redoButton;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private SplitMenuButton catSelectedSplitMenu;
|
private SplitMenuButton catSelectedSplitMenu;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private SplitMenuButton tagSelectedSplitMenu;
|
private SplitMenuButton tagSelectedSplitMenu;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private ToolBar headerToolBar;
|
private ToolBar headerToolBar;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private ToggleButton cat0Toggle;
|
private ToggleButton cat0Toggle;
|
||||||
@FXML
|
@FXML
|
||||||
@ -189,30 +189,30 @@ public class GroupPane extends BorderPane {
|
|||||||
private ToggleButton cat4Toggle;
|
private ToggleButton cat4Toggle;
|
||||||
@FXML
|
@FXML
|
||||||
private ToggleButton cat5Toggle;
|
private ToggleButton cat5Toggle;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private SegmentedButton segButton;
|
private SegmentedButton segButton;
|
||||||
|
|
||||||
private SlideShowView slideShowPane;
|
private SlideShowView slideShowPane;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private ToggleButton slideShowToggle;
|
private ToggleButton slideShowToggle;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private GridView<Long> gridView;
|
private GridView<Long> gridView;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private ToggleButton tileToggle;
|
private ToggleButton tileToggle;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private Button nextButton;
|
private Button nextButton;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private Button backButton;
|
private Button backButton;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private Button forwardButton;
|
private Button forwardButton;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private Label groupLabel;
|
private Label groupLabel;
|
||||||
@FXML
|
@FXML
|
||||||
@ -223,24 +223,24 @@ public class GroupPane extends BorderPane {
|
|||||||
private Label catContainerLabel;
|
private Label catContainerLabel;
|
||||||
@FXML
|
@FXML
|
||||||
private Label catHeadingLabel;
|
private Label catHeadingLabel;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private HBox catSegmentedContainer;
|
private HBox catSegmentedContainer;
|
||||||
@FXML
|
@FXML
|
||||||
private HBox catSplitMenuContainer;
|
private HBox catSplitMenuContainer;
|
||||||
|
|
||||||
private final KeyboardHandler tileKeyboardNavigationHandler = new KeyboardHandler();
|
private final KeyboardHandler tileKeyboardNavigationHandler = new KeyboardHandler();
|
||||||
|
|
||||||
private final NextUnseenGroup nextGroupAction;
|
private final NextUnseenGroup nextGroupAction;
|
||||||
|
|
||||||
private final ImageGalleryController controller;
|
private final ImageGalleryController controller;
|
||||||
|
|
||||||
private ContextMenu contextMenu;
|
private ContextMenu contextMenu;
|
||||||
|
|
||||||
private Integer selectionAnchorIndex;
|
private Integer selectionAnchorIndex;
|
||||||
private final UndoAction undoAction;
|
private final UndoAction undoAction;
|
||||||
private final RedoAction redoAction;
|
private final RedoAction redoAction;
|
||||||
|
|
||||||
GroupViewMode getGroupViewMode() {
|
GroupViewMode getGroupViewMode() {
|
||||||
return groupViewMode.get();
|
return groupViewMode.get();
|
||||||
}
|
}
|
||||||
@ -263,7 +263,7 @@ public class GroupPane extends BorderPane {
|
|||||||
*/
|
*/
|
||||||
@ThreadConfined(type = ThreadType.JFX)
|
@ThreadConfined(type = ThreadType.JFX)
|
||||||
private final Map<Long, DrawableCell> cellMap = new HashMap<>();
|
private final Map<Long, DrawableCell> cellMap = new HashMap<>();
|
||||||
|
|
||||||
private final InvalidationListener filesSyncListener = (observable) -> {
|
private final InvalidationListener filesSyncListener = (observable) -> {
|
||||||
final String header = getHeaderString();
|
final String header = getHeaderString();
|
||||||
final List<Long> fileIds = getGroup().getFileIDs();
|
final List<Long> fileIds = getGroup().getFileIDs();
|
||||||
@ -273,7 +273,7 @@ public class GroupPane extends BorderPane {
|
|||||||
groupLabel.setText(header);
|
groupLabel.setText(header);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
public GroupPane(ImageGalleryController controller) {
|
public GroupPane(ImageGalleryController controller) {
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
this.selectionModel = controller.getSelectionModel();
|
this.selectionModel = controller.getSelectionModel();
|
||||||
@ -282,10 +282,10 @@ public class GroupPane extends BorderPane {
|
|||||||
forwardAction = new Forward(controller);
|
forwardAction = new Forward(controller);
|
||||||
undoAction = new UndoAction(controller);
|
undoAction = new UndoAction(controller);
|
||||||
redoAction = new RedoAction(controller);
|
redoAction = new RedoAction(controller);
|
||||||
|
|
||||||
FXMLConstructor.construct(this, "GroupPane.fxml"); //NON-NLS
|
FXMLConstructor.construct(this, "GroupPane.fxml"); //NON-NLS
|
||||||
}
|
}
|
||||||
|
|
||||||
@ThreadConfined(type = ThreadType.JFX)
|
@ThreadConfined(type = ThreadType.JFX)
|
||||||
public void activateSlideShowViewer(Long slideShowFileID) {
|
public void activateSlideShowViewer(Long slideShowFileID) {
|
||||||
groupViewMode.set(GroupViewMode.SLIDE_SHOW);
|
groupViewMode.set(GroupViewMode.SLIDE_SHOW);
|
||||||
@ -301,16 +301,16 @@ public class GroupPane extends BorderPane {
|
|||||||
} else {
|
} else {
|
||||||
slideShowPane.setFile(slideShowFileID);
|
slideShowPane.setFile(slideShowFileID);
|
||||||
}
|
}
|
||||||
|
|
||||||
setCenter(slideShowPane);
|
setCenter(slideShowPane);
|
||||||
slideShowPane.requestFocus();
|
slideShowPane.requestFocus();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void syncCatToggle(DrawableFile file) {
|
void syncCatToggle(DrawableFile file) {
|
||||||
getToggleForCategory(file.getCategory()).setSelected(true);
|
getToggleForCategory(file.getCategory()).setSelected(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void activateTileViewer() {
|
public void activateTileViewer() {
|
||||||
groupViewMode.set(GroupViewMode.TILE);
|
groupViewMode.set(GroupViewMode.TILE);
|
||||||
tileToggle.setSelected(true);
|
tileToggle.setSelected(true);
|
||||||
@ -322,11 +322,11 @@ public class GroupPane extends BorderPane {
|
|||||||
slideShowPane = null;
|
slideShowPane = null;
|
||||||
this.scrollToFileID(selectionModel.lastSelectedProperty().get());
|
this.scrollToFileID(selectionModel.lastSelectedProperty().get());
|
||||||
}
|
}
|
||||||
|
|
||||||
public DrawableGroup getGroup() {
|
public DrawableGroup getGroup() {
|
||||||
return grouping.get();
|
return grouping.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void selectAllFiles() {
|
private void selectAllFiles() {
|
||||||
selectionModel.clearAndSelectAll(getGroup().getFileIDs());
|
selectionModel.clearAndSelectAll(getGroup().getFileIDs());
|
||||||
}
|
}
|
||||||
@ -343,15 +343,15 @@ public class GroupPane extends BorderPane {
|
|||||||
: Bundle.GroupPane_headerString(StringUtils.defaultIfBlank(getGroup().getGroupByValueDislpayName(), DrawableGroup.getBlankGroupName()),
|
: Bundle.GroupPane_headerString(StringUtils.defaultIfBlank(getGroup().getGroupByValueDislpayName(), DrawableGroup.getBlankGroupName()),
|
||||||
getGroup().getHashSetHitsCount(), getGroup().getSize());
|
getGroup().getHashSetHitsCount(), getGroup().getSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
ContextMenu getContextMenu() {
|
ContextMenu getContextMenu() {
|
||||||
return contextMenu;
|
return contextMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadOnlyObjectProperty<DrawableGroup> grouping() {
|
ReadOnlyObjectProperty<DrawableGroup> grouping() {
|
||||||
return grouping.getReadOnlyProperty();
|
return grouping.getReadOnlyProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ToggleButton getToggleForCategory(DhsImageCategory category) {
|
private ToggleButton getToggleForCategory(DhsImageCategory category) {
|
||||||
switch (category) {
|
switch (category) {
|
||||||
case ZERO:
|
case ZERO:
|
||||||
@ -396,7 +396,7 @@ public class GroupPane extends BorderPane {
|
|||||||
assert segButton != null : "fx:id=\"previewList\" was not injected: check your FXML file 'GroupHeader.fxml'.";
|
assert segButton != null : "fx:id=\"previewList\" was not injected: check your FXML file 'GroupHeader.fxml'.";
|
||||||
assert slideShowToggle != null : "fx:id=\"segButton\" was not injected: check your FXML file 'GroupHeader.fxml'.";
|
assert slideShowToggle != null : "fx:id=\"segButton\" was not injected: check your FXML file 'GroupHeader.fxml'.";
|
||||||
assert tileToggle != null : "fx:id=\"tileToggle\" was not injected: check your FXML file 'GroupHeader.fxml'.";
|
assert tileToggle != null : "fx:id=\"tileToggle\" was not injected: check your FXML file 'GroupHeader.fxml'.";
|
||||||
|
|
||||||
for (DhsImageCategory cat : DhsImageCategory.values()) {
|
for (DhsImageCategory cat : DhsImageCategory.values()) {
|
||||||
ToggleButton toggleForCategory = getToggleForCategory(cat);
|
ToggleButton toggleForCategory = getToggleForCategory(cat);
|
||||||
toggleForCategory.setBorder(new Border(new BorderStroke(cat.getColor(), BorderStrokeStyle.SOLID, CORNER_RADII_2, BORDER_WIDTHS_2)));
|
toggleForCategory.setBorder(new Border(new BorderStroke(cat.getColor(), BorderStrokeStyle.SOLID, CORNER_RADII_2, BORDER_WIDTHS_2)));
|
||||||
@ -421,20 +421,16 @@ public class GroupPane extends BorderPane {
|
|||||||
gridView.cellHeightProperty().bind(cellSize);
|
gridView.cellHeightProperty().bind(cellSize);
|
||||||
gridView.cellWidthProperty().bind(cellSize);
|
gridView.cellWidthProperty().bind(cellSize);
|
||||||
gridView.setCellFactory((GridView<Long> param) -> new DrawableCell());
|
gridView.setCellFactory((GridView<Long> param) -> new DrawableCell());
|
||||||
|
|
||||||
BooleanBinding isSelectionEmpty = Bindings.isEmpty(selectionModel.getSelected());
|
BooleanBinding isSelectionEmpty = Bindings.isEmpty(selectionModel.getSelected());
|
||||||
catSelectedSplitMenu.disableProperty().bind(isSelectionEmpty);
|
catSelectedSplitMenu.disableProperty().bind(isSelectionEmpty);
|
||||||
tagSelectedSplitMenu.disableProperty().bind(isSelectionEmpty);
|
tagSelectedSplitMenu.disableProperty().bind(isSelectionEmpty);
|
||||||
|
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
try {
|
TagSelectedFilesAction followUpSelectedACtion = new TagSelectedFilesAction(controller.getTagsManager().getFollowUpTagName(), controller); //NON-NLS
|
||||||
TagSelectedFilesAction followUpSelectedACtion = new TagSelectedFilesAction(controller.getTagsManager().getFollowUpTagName(), controller);
|
tagSelectedSplitMenu.setText(followUpSelectedACtion.getText());
|
||||||
tagSelectedSplitMenu.setText(followUpSelectedACtion.getText());
|
tagSelectedSplitMenu.setGraphic(followUpSelectedACtion.getGraphic());
|
||||||
tagSelectedSplitMenu.setGraphic(followUpSelectedACtion.getGraphic());
|
tagSelectedSplitMenu.setOnAction(followUpSelectedACtion);
|
||||||
tagSelectedSplitMenu.setOnAction(followUpSelectedACtion);
|
|
||||||
} catch (TskCoreException tskCoreException) {
|
|
||||||
LOGGER.log(Level.WARNING, "failed to load FollowUpTagName", tskCoreException); //NON-NLS
|
|
||||||
}
|
|
||||||
tagSelectedSplitMenu.showingProperty().addListener(showing -> {
|
tagSelectedSplitMenu.showingProperty().addListener(showing -> {
|
||||||
if (tagSelectedSplitMenu.isShowing()) {
|
if (tagSelectedSplitMenu.isShowing()) {
|
||||||
List<MenuItem> selTagMenues = Lists.transform(controller.getTagsManager().getNonCategoryTagNames(),
|
List<MenuItem> selTagMenues = Lists.transform(controller.getTagsManager().getNonCategoryTagNames(),
|
||||||
@ -442,9 +438,9 @@ public class GroupPane extends BorderPane {
|
|||||||
tagSelectedSplitMenu.getItems().setAll(selTagMenues);
|
tagSelectedSplitMenu.getItems().setAll(selTagMenues);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
CategorizeSelectedFilesAction cat5SelectedAction = new CategorizeSelectedFilesAction(DhsImageCategory.FIVE, controller);
|
CategorizeSelectedFilesAction cat5SelectedAction = new CategorizeSelectedFilesAction(DhsImageCategory.FIVE, controller);
|
||||||
catSelectedSplitMenu.setOnAction(cat5SelectedAction);
|
catSelectedSplitMenu.setOnAction(cat5SelectedAction);
|
||||||
catSelectedSplitMenu.setText(cat5SelectedAction.getText());
|
catSelectedSplitMenu.setText(cat5SelectedAction.getText());
|
||||||
@ -456,12 +452,12 @@ public class GroupPane extends BorderPane {
|
|||||||
catSelectedSplitMenu.getItems().setAll(categoryMenues);
|
catSelectedSplitMenu.getItems().setAll(categoryMenues);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
slideShowToggle.getStyleClass().remove("radio-button");
|
slideShowToggle.getStyleClass().remove("radio-button");
|
||||||
slideShowToggle.getStyleClass().add("toggle-button");
|
slideShowToggle.getStyleClass().add("toggle-button");
|
||||||
tileToggle.getStyleClass().remove("radio-button");
|
tileToggle.getStyleClass().remove("radio-button");
|
||||||
tileToggle.getStyleClass().add("toggle-button");
|
tileToggle.getStyleClass().add("toggle-button");
|
||||||
|
|
||||||
bottomLabel.setText(Bundle.GroupPane_bottomLabel_displayText());
|
bottomLabel.setText(Bundle.GroupPane_bottomLabel_displayText());
|
||||||
headerLabel.setText(Bundle.GroupPane_hederLabel_displayText());
|
headerLabel.setText(Bundle.GroupPane_hederLabel_displayText());
|
||||||
catContainerLabel.setText(Bundle.GroupPane_catContainerLabel_displayText());
|
catContainerLabel.setText(Bundle.GroupPane_catContainerLabel_displayText());
|
||||||
@ -481,12 +477,12 @@ public class GroupPane extends BorderPane {
|
|||||||
//listen to toggles and update view state
|
//listen to toggles and update view state
|
||||||
slideShowToggle.setOnAction(onAction -> activateSlideShowViewer(selectionModel.lastSelectedProperty().get()));
|
slideShowToggle.setOnAction(onAction -> activateSlideShowViewer(selectionModel.lastSelectedProperty().get()));
|
||||||
tileToggle.setOnAction(onAction -> activateTileViewer());
|
tileToggle.setOnAction(onAction -> activateTileViewer());
|
||||||
|
|
||||||
controller.viewState().addListener((observable, oldViewState, newViewState) -> setViewState(newViewState));
|
controller.viewState().addListener((observable, oldViewState, newViewState) -> setViewState(newViewState));
|
||||||
|
|
||||||
addEventFilter(KeyEvent.KEY_PRESSED, tileKeyboardNavigationHandler);
|
addEventFilter(KeyEvent.KEY_PRESSED, tileKeyboardNavigationHandler);
|
||||||
gridView.addEventHandler(MouseEvent.MOUSE_CLICKED, new MouseHandler());
|
gridView.addEventHandler(MouseEvent.MOUSE_CLICKED, new MouseHandler());
|
||||||
|
|
||||||
ActionUtils.configureButton(undoAction, undoButton);
|
ActionUtils.configureButton(undoAction, undoButton);
|
||||||
ActionUtils.configureButton(redoAction, redoButton);
|
ActionUtils.configureButton(redoAction, redoButton);
|
||||||
ActionUtils.configureButton(forwardAction, forwardButton);
|
ActionUtils.configureButton(forwardAction, forwardButton);
|
||||||
@ -502,7 +498,7 @@ public class GroupPane extends BorderPane {
|
|||||||
nextButton.setEffect(null);
|
nextButton.setEffect(null);
|
||||||
onAction.handle(actionEvent);
|
onAction.handle(actionEvent);
|
||||||
});
|
});
|
||||||
|
|
||||||
nextGroupAction.disabledProperty().addListener((Observable observable) -> {
|
nextGroupAction.disabledProperty().addListener((Observable observable) -> {
|
||||||
boolean newValue = nextGroupAction.isDisabled();
|
boolean newValue = nextGroupAction.isDisabled();
|
||||||
nextButton.setEffect(newValue ? null : DROP_SHADOW);
|
nextButton.setEffect(newValue ? null : DROP_SHADOW);
|
||||||
@ -516,13 +512,13 @@ public class GroupPane extends BorderPane {
|
|||||||
//listen to tile selection and make sure it is visible in scroll area
|
//listen to tile selection and make sure it is visible in scroll area
|
||||||
selectionModel.lastSelectedProperty().addListener((observable, oldFileID, newFileId) -> {
|
selectionModel.lastSelectedProperty().addListener((observable, oldFileID, newFileId) -> {
|
||||||
if (groupViewMode.get() == GroupViewMode.SLIDE_SHOW
|
if (groupViewMode.get() == GroupViewMode.SLIDE_SHOW
|
||||||
&& slideShowPane != null) {
|
&& slideShowPane != null) {
|
||||||
slideShowPane.setFile(newFileId);
|
slideShowPane.setFile(newFileId);
|
||||||
} else {
|
} else {
|
||||||
scrollToFileID(newFileId);
|
scrollToFileID(newFileId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setViewState(controller.viewState().get());
|
setViewState(controller.viewState().get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -532,16 +528,16 @@ public class GroupPane extends BorderPane {
|
|||||||
if (newFileID == null) {
|
if (newFileID == null) {
|
||||||
return; //scrolling to no file doesn't make sense, so abort.
|
return; //scrolling to no file doesn't make sense, so abort.
|
||||||
}
|
}
|
||||||
|
|
||||||
final ObservableList<Long> fileIds = gridView.getItems();
|
final ObservableList<Long> fileIds = gridView.getItems();
|
||||||
|
|
||||||
int selectedIndex = fileIds.indexOf(newFileID);
|
int selectedIndex = fileIds.indexOf(newFileID);
|
||||||
if (selectedIndex == -1) {
|
if (selectedIndex == -1) {
|
||||||
//somehow we got passed a file id that isn't in the curent group.
|
//somehow we got passed a file id that isn't in the curent group.
|
||||||
//this should never happen, but if it does everything is going to fail, so abort.
|
//this should never happen, but if it does everything is going to fail, so abort.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
getScrollBar().ifPresent(scrollBar -> {
|
getScrollBar().ifPresent(scrollBar -> {
|
||||||
DrawableCell cell = cellMap.get(newFileID);
|
DrawableCell cell = cellMap.get(newFileID);
|
||||||
|
|
||||||
@ -568,14 +564,14 @@ public class GroupPane extends BorderPane {
|
|||||||
}
|
}
|
||||||
cell = cellMap.get(newFileID);
|
cell = cellMap.get(newFileID);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Bounds gridViewBounds = gridView.localToScene(gridView.getBoundsInLocal());
|
final Bounds gridViewBounds = gridView.localToScene(gridView.getBoundsInLocal());
|
||||||
Bounds tileBounds = cell.localToScene(cell.getBoundsInLocal());
|
Bounds tileBounds = cell.localToScene(cell.getBoundsInLocal());
|
||||||
|
|
||||||
//while the cell is not within the visisble bounds of the gridview, scroll based on screen coordinates
|
//while the cell is not within the visisble bounds of the gridview, scroll based on screen coordinates
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (gridViewBounds.contains(tileBounds) == false && (i++ < 100)) {
|
while (gridViewBounds.contains(tileBounds) == false && (i++ < 100)) {
|
||||||
|
|
||||||
if (tileBounds.getMinY() < gridViewBounds.getMinY()) {
|
if (tileBounds.getMinY() < gridViewBounds.getMinY()) {
|
||||||
scrollBar.decrement();
|
scrollBar.decrement();
|
||||||
} else if (tileBounds.getMaxY() > gridViewBounds.getMaxY()) {
|
} else if (tileBounds.getMaxY() > gridViewBounds.getMaxY()) {
|
||||||
@ -593,13 +589,13 @@ public class GroupPane extends BorderPane {
|
|||||||
* @param grouping the new grouping assigned to this group
|
* @param grouping the new grouping assigned to this group
|
||||||
*/
|
*/
|
||||||
void setViewState(GroupViewState viewState) {
|
void setViewState(GroupViewState viewState) {
|
||||||
|
|
||||||
if (isNull(viewState) || isNull(viewState.getGroup())) {
|
if (isNull(viewState) || isNull(viewState.getGroup())) {
|
||||||
if (nonNull(getGroup())) {
|
if (nonNull(getGroup())) {
|
||||||
getGroup().getFileIDs().removeListener(filesSyncListener);
|
getGroup().getFileIDs().removeListener(filesSyncListener);
|
||||||
}
|
}
|
||||||
this.grouping.set(null);
|
this.grouping.set(null);
|
||||||
|
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
gridView.getItems().setAll(Collections.emptyList());
|
gridView.getItems().setAll(Collections.emptyList());
|
||||||
setCenter(null);
|
setCenter(null);
|
||||||
@ -611,18 +607,18 @@ public class GroupPane extends BorderPane {
|
|||||||
cellMap.clear();
|
cellMap.clear();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (getGroup() != viewState.getGroup()) {
|
if (getGroup() != viewState.getGroup()) {
|
||||||
if (nonNull(getGroup())) {
|
if (nonNull(getGroup())) {
|
||||||
getGroup().getFileIDs().removeListener(filesSyncListener);
|
getGroup().getFileIDs().removeListener(filesSyncListener);
|
||||||
}
|
}
|
||||||
this.grouping.set(viewState.getGroup());
|
this.grouping.set(viewState.getGroup());
|
||||||
|
|
||||||
getGroup().getFileIDs().addListener(filesSyncListener);
|
getGroup().getFileIDs().addListener(filesSyncListener);
|
||||||
|
|
||||||
final String header = getHeaderString();
|
final String header = getHeaderString();
|
||||||
|
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
gridView.getItems().setAll(getGroup().getFileIDs());
|
gridView.getItems().setAll(getGroup().getFileIDs());
|
||||||
slideShowToggle.setDisable(gridView.getItems().isEmpty());
|
slideShowToggle.setDisable(gridView.getItems().isEmpty());
|
||||||
@ -637,14 +633,14 @@ public class GroupPane extends BorderPane {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ThreadConfined(type = ThreadType.JFX)
|
@ThreadConfined(type = ThreadType.JFX)
|
||||||
private void resetScrollBar() {
|
private void resetScrollBar() {
|
||||||
getScrollBar().ifPresent((scrollBar) -> {
|
getScrollBar().ifPresent((scrollBar) -> {
|
||||||
scrollBar.setValue(0);
|
scrollBar.setValue(0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ThreadConfined(type = ThreadType.JFX)
|
@ThreadConfined(type = ThreadType.JFX)
|
||||||
private Optional<ScrollBar> getScrollBar() {
|
private Optional<ScrollBar> getScrollBar() {
|
||||||
if (gridView == null || gridView.getSkin() == null) {
|
if (gridView == null || gridView.getSkin() == null) {
|
||||||
@ -652,16 +648,16 @@ public class GroupPane extends BorderPane {
|
|||||||
}
|
}
|
||||||
return Optional.ofNullable((ScrollBar) gridView.getSkin().getNode().lookup(".scroll-bar")); //NON-NLS
|
return Optional.ofNullable((ScrollBar) gridView.getSkin().getNode().lookup(".scroll-bar")); //NON-NLS
|
||||||
}
|
}
|
||||||
|
|
||||||
void makeSelection(Boolean shiftDown, Long newFileID) {
|
void makeSelection(Boolean shiftDown, Long newFileID) {
|
||||||
|
|
||||||
if (shiftDown) {
|
if (shiftDown) {
|
||||||
//TODO: do more hear to implement slicker multiselect
|
//TODO: do more hear to implement slicker multiselect
|
||||||
int endIndex = grouping.get().getFileIDs().indexOf(newFileID);
|
int endIndex = grouping.get().getFileIDs().indexOf(newFileID);
|
||||||
int startIndex = IntStream.of(grouping.get().getFileIDs().size(), selectionAnchorIndex, endIndex).min().getAsInt();
|
int startIndex = IntStream.of(grouping.get().getFileIDs().size(), selectionAnchorIndex, endIndex).min().getAsInt();
|
||||||
endIndex = IntStream.of(0, selectionAnchorIndex, endIndex).max().getAsInt();
|
endIndex = IntStream.of(0, selectionAnchorIndex, endIndex).max().getAsInt();
|
||||||
List<Long> subList = grouping.get().getFileIDs().subList(Math.max(0, startIndex), Math.min(endIndex, grouping.get().getFileIDs().size()) + 1);
|
List<Long> subList = grouping.get().getFileIDs().subList(Math.max(0, startIndex), Math.min(endIndex, grouping.get().getFileIDs().size()) + 1);
|
||||||
|
|
||||||
selectionModel.clearAndSelectAll(subList.toArray(new Long[subList.size()]));
|
selectionModel.clearAndSelectAll(subList.toArray(new Long[subList.size()]));
|
||||||
selectionModel.select(newFileID);
|
selectionModel.select(newFileID);
|
||||||
} else {
|
} else {
|
||||||
@ -669,11 +665,11 @@ public class GroupPane extends BorderPane {
|
|||||||
selectionModel.clearAndSelect(newFileID);
|
selectionModel.clearAndSelect(newFileID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DrawableCell extends GridCell<Long> {
|
private class DrawableCell extends GridCell<Long> {
|
||||||
|
|
||||||
private final DrawableTile tile = new DrawableTile(GroupPane.this, controller);
|
private final DrawableTile tile = new DrawableTile(GroupPane.this, controller);
|
||||||
|
|
||||||
DrawableCell() {
|
DrawableCell() {
|
||||||
itemProperty().addListener((ObservableValue<? extends Long> observable, Long oldValue, Long newValue) -> {
|
itemProperty().addListener((ObservableValue<? extends Long> observable, Long oldValue, Long newValue) -> {
|
||||||
if (oldValue != null) {
|
if (oldValue != null) {
|
||||||
@ -689,19 +685,19 @@ public class GroupPane extends BorderPane {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
cellMap.put(newValue, DrawableCell.this);
|
cellMap.put(newValue, DrawableCell.this);
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setGraphic(tile);
|
setGraphic(tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void updateItem(Long item, boolean empty) {
|
protected void updateItem(Long item, boolean empty) {
|
||||||
super.updateItem(item, empty);
|
super.updateItem(item, empty);
|
||||||
tile.setFile(item);
|
tile.setFile(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetItem() {
|
void resetItem() {
|
||||||
tile.setFile(null);
|
tile.setFile(null);
|
||||||
}
|
}
|
||||||
@ -712,10 +708,10 @@ public class GroupPane extends BorderPane {
|
|||||||
* arrows)
|
* arrows)
|
||||||
*/
|
*/
|
||||||
private class KeyboardHandler implements EventHandler<KeyEvent> {
|
private class KeyboardHandler implements EventHandler<KeyEvent> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(KeyEvent t) {
|
public void handle(KeyEvent t) {
|
||||||
|
|
||||||
if (t.getEventType() == KeyEvent.KEY_PRESSED) {
|
if (t.getEventType() == KeyEvent.KEY_PRESSED) {
|
||||||
switch (t.getCode()) {
|
switch (t.getCode()) {
|
||||||
case SHIFT:
|
case SHIFT:
|
||||||
@ -758,7 +754,7 @@ public class GroupPane extends BorderPane {
|
|||||||
t.consume();
|
t.consume();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (groupViewMode.get() == GroupViewMode.TILE && categoryKeyCodes.contains(t.getCode()) && t.isAltDown()) {
|
if (groupViewMode.get() == GroupViewMode.TILE && categoryKeyCodes.contains(t.getCode()) && t.isAltDown()) {
|
||||||
selectAllFiles();
|
selectAllFiles();
|
||||||
t.consume();
|
t.consume();
|
||||||
@ -772,7 +768,7 @@ public class GroupPane extends BorderPane {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private DhsImageCategory keyCodeToCat(KeyCode t) {
|
private DhsImageCategory keyCodeToCat(KeyCode t) {
|
||||||
if (t != null) {
|
if (t != null) {
|
||||||
switch (t) {
|
switch (t) {
|
||||||
@ -798,16 +794,16 @@ public class GroupPane extends BorderPane {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleArrows(KeyEvent t) {
|
private void handleArrows(KeyEvent t) {
|
||||||
Long lastSelectFileId = selectionModel.lastSelectedProperty().get();
|
Long lastSelectFileId = selectionModel.lastSelectedProperty().get();
|
||||||
|
|
||||||
int lastSelectedIndex = lastSelectFileId != null
|
int lastSelectedIndex = lastSelectFileId != null
|
||||||
? grouping.get().getFileIDs().indexOf(lastSelectFileId)
|
? grouping.get().getFileIDs().indexOf(lastSelectFileId)
|
||||||
: Optional.ofNullable(selectionAnchorIndex).orElse(0);
|
: Optional.ofNullable(selectionAnchorIndex).orElse(0);
|
||||||
|
|
||||||
final int columns = Math.max((int) Math.floor((gridView.getWidth() - 18) / (gridView.getCellWidth() + gridView.getHorizontalCellSpacing() * 2)), 1);
|
final int columns = Math.max((int) Math.floor((gridView.getWidth() - 18) / (gridView.getCellWidth() + gridView.getHorizontalCellSpacing() * 2)), 1);
|
||||||
|
|
||||||
final Map<KeyCode, Integer> tileIndexMap = ImmutableMap.of(UP, -columns, DOWN, columns, LEFT, -1, RIGHT, 1);
|
final Map<KeyCode, Integer> tileIndexMap = ImmutableMap.of(UP, -columns, DOWN, columns, LEFT, -1, RIGHT, 1);
|
||||||
|
|
||||||
// implement proper keyboard based multiselect
|
// implement proper keyboard based multiselect
|
||||||
@ -826,19 +822,17 @@ public class GroupPane extends BorderPane {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MouseHandler implements EventHandler<MouseEvent> {
|
private class MouseHandler implements EventHandler<MouseEvent> {
|
||||||
|
|
||||||
private ContextMenu buildContextMenu() {
|
private ContextMenu buildContextMenu() {
|
||||||
ArrayList<MenuItem> menuItems = new ArrayList<>();
|
ArrayList<MenuItem> menuItems = new ArrayList<>();
|
||||||
|
|
||||||
|
|
||||||
menuItems.add(CategorizeAction.getCategoriesMenu(controller));
|
menuItems.add(CategorizeAction.getCategoriesMenu(controller));
|
||||||
menuItems.add(AddTagAction.getTagMenu(controller));
|
menuItems.add(AddTagAction.getTagMenu(controller));
|
||||||
|
|
||||||
|
|
||||||
Collection<? extends ContextMenuActionsProvider> menuProviders = Lookup.getDefault().lookupAll(ContextMenuActionsProvider.class);
|
Collection<? extends ContextMenuActionsProvider> menuProviders = Lookup.getDefault().lookupAll(ContextMenuActionsProvider.class);
|
||||||
|
|
||||||
for (ContextMenuActionsProvider provider : menuProviders) {
|
for (ContextMenuActionsProvider provider : menuProviders) {
|
||||||
for (final Action act : provider.getActions()) {
|
for (final Action act : provider.getActions()) {
|
||||||
if (act instanceof Presenter.Popup) {
|
if (act instanceof Presenter.Popup) {
|
||||||
@ -855,12 +849,12 @@ public class GroupPane extends BorderPane {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
menuItems.add(extractMenuItem);
|
menuItems.add(extractMenuItem);
|
||||||
|
|
||||||
ContextMenu contextMenu = new ContextMenu(menuItems.toArray(new MenuItem[]{}));
|
ContextMenu contextMenu = new ContextMenu(menuItems.toArray(new MenuItem[]{}));
|
||||||
contextMenu.setAutoHide(true);
|
contextMenu.setAutoHide(true);
|
||||||
return contextMenu;
|
return contextMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(MouseEvent t) {
|
public void handle(MouseEvent t) {
|
||||||
switch (t.getButton()) {
|
switch (t.getButton()) {
|
||||||
@ -881,7 +875,7 @@ public class GroupPane extends BorderPane {
|
|||||||
if (contextMenu == null) {
|
if (contextMenu == null) {
|
||||||
contextMenu = buildContextMenu();
|
contextMenu = buildContextMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
contextMenu.hide();
|
contextMenu.hide();
|
||||||
contextMenu.show(GroupPane.this, t.getScreenX(), t.getScreenY());
|
contextMenu.show(GroupPane.this, t.getScreenX(), t.getScreenY());
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user