Merge pull request #1341 from millmanorama/GroupPane_realted_bug_fixes

Group pane realted bug fixes
This commit is contained in:
Richard Cordovano 2015-06-11 13:54:21 -04:00
commit e090ff7a5a
8 changed files with 149 additions and 140 deletions

View File

@ -70,7 +70,11 @@ public class FileIDSelectionModel {
public void clearAndSelectAll(Long... ids) {
selected.clear();
selected.addAll(Arrays.asList(ids));
if (ids.length > 0) {
setLastSelected(ids[ids.length - 1]);
} else {
setLastSelected(null);
}
}
public void clearAndSelect(Long id) {

View File

@ -78,7 +78,7 @@ public class DrawableTile extends DrawableViewBase implements TagUtils.TagListen
globalSelectionModel.lastSelectedProperty().addListener((observable, oldValue, newValue) -> {
try {
setEffect(Objects.equals(newValue, fileID) ? LAST_SELECTED_EFFECT : null);
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");
}
@ -86,9 +86,8 @@ public class DrawableTile extends DrawableViewBase implements TagUtils.TagListen
}
public DrawableTile(GroupPane gp) {
super();
super(gp);
FXMLConstructor.construct(this, "DrawableTile.fxml");
groupPane = gp;
}
@Override
@ -103,7 +102,7 @@ public class DrawableTile extends DrawableViewBase implements TagUtils.TagListen
@Override
protected void updateSelectionState() {
super.updateSelectionState();
final boolean lastSelected = Objects.equals(globalSelectionModel.lastSelectedProperty().get(), fileID);
final boolean lastSelected = Objects.equals(globalSelectionModel.lastSelectedProperty().get(), getFileID());
Platform.runLater(() -> {
setEffect(lastSelected ? LAST_SELECTED_EFFECT : null);
});
@ -111,7 +110,7 @@ public class DrawableTile extends DrawableViewBase implements TagUtils.TagListen
@Override
protected Runnable getContentUpdateRunnable() {
Image image = file.getThumbnail();
Image image = getFile().getThumbnail();
return () -> {
imageView.setImage(image);
@ -119,8 +118,7 @@ public class DrawableTile extends DrawableViewBase implements TagUtils.TagListen
}
@Override
@ThreadConfined(type = ThreadType.UI)
protected String getLabelText() {
return file.getName();
protected String getTextForLabel() {
return getFile().getName();
}
}

View File

@ -48,7 +48,7 @@ public interface DrawableView extends TagUtils.TagListener {
static final Border CAT0_BORDER = new Border(new BorderStroke(Category.ZERO.getColor(), BorderStrokeStyle.SOLID, CAT_CORNER_RADII, CAT_BORDER_WIDTHS));
Region getBorderable();
Region getCategoryBorderRegion();
DrawableFile<?> getFile();
@ -83,8 +83,6 @@ public interface DrawableView extends TagUtils.TagListener {
static Border getCategoryBorder(Category category) {
switch (category) {
case ZERO:
return CAT0_BORDER;
case ONE:
return CAT1_BORDER;
case TWO:
@ -94,8 +92,11 @@ public interface DrawableView extends TagUtils.TagListener {
case FOUR:
return CAT4_BORDER;
case FIVE:
default:
return CAT5_BORDER;
case ZERO:
default:
return CAT0_BORDER;
}
}
@ -104,10 +105,11 @@ public interface DrawableView extends TagUtils.TagListener {
final Category category = getFile().getCategory();
final Border border = hasHashHit() && (category == Category.ZERO)
? HASH_BORDER
: DrawableView.getCategoryBorder(category);
: getCategoryBorder(category);
Platform.runLater(() -> {
getBorderable().setBorder(border);
getCategoryBorderRegion().setBorder(border);
getCategoryBorderRegion().requestLayout();
});
return category;
}

View File

@ -50,7 +50,6 @@ import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javax.swing.Action;
import javax.swing.SwingUtilities;
import org.openide.util.Exceptions;
import org.openide.util.Lookup;
import org.openide.util.actions.Presenter;
import org.openide.windows.TopComponent;
@ -137,17 +136,22 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie
static private ContextMenu contextMenu;
protected DrawableFile<?> file;
private DrawableFile<?> file;
protected Long fileID;
private Long fileID;
/**
* the groupPane this {@link DrawableViewBase} is embedded in
*/
protected GroupPane groupPane;
final private GroupPane groupPane;
private boolean registered = false;
protected DrawableViewBase() {
GroupPane getGroupPane() {
return groupPane;
}
protected DrawableViewBase(GroupPane groupPane) {
this.groupPane = groupPane;
globalSelectionModel.getSelected().addListener((Observable observable) -> {
updateSelectionState();
});
@ -254,11 +258,12 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie
protected abstract Runnable getContentUpdateRunnable();
protected abstract String getLabelText();
protected abstract String getTextForLabel();
@SuppressWarnings("deprecation")
protected void initialize() {
followUpToggle.setOnAction((ActionEvent t) -> {
if (followUpToggle.isSelected() == true) {
globalSelectionModel.clearAndSelect(fileID);
try {
@ -273,7 +278,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie
// remove file from old category group
controller.getGroupManager().removeFromGroup(new GroupKey<TagName>(DrawableAttribute.TAGS, TagUtils.getFollowUpTagName()), fileID);
List<ContentTag> contentTagsByContent = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(getFile());
List<ContentTag> contentTagsByContent = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(file);
for (ContentTag ct : contentTagsByContent) {
if (ct.getName().getDisplayName().equals(TagUtils.getFollowUpTagName().getDisplayName())) {
Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(ct);
@ -285,6 +290,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie
LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex);
}
}
});
}
@ -311,36 +317,19 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie
return tagNames.stream().anyMatch((tn) -> tn.getDisplayName().equals(followUpTagName));
}
protected void updateUI(final boolean isVideo, final boolean hasHashSetHits, final String text) {
if (isVideo) {
fileTypeImageView.setImage(videoIcon);
} else {
fileTypeImageView.setImage(null);
}
if (hasHashSetHits) {
hashHitImageView.setImage(hashHitIcon);
} else {
hashHitImageView.setImage(null);
}
nameLabel.setText(text);
nameLabel.setTooltip(new Tooltip(text));
}
@Override
public Long getFileID() {
synchronized public Long getFileID() {
return fileID;
}
@Override
public void handleTagsChanged(Collection<Long> ids) {
synchronized public void handleTagsChanged(Collection<Long> ids) {
if (fileID != null && ids.contains(fileID)) {
updateFollowUpIcon();
}
}
protected void updateFollowUpIcon() {
synchronized protected void updateFollowUpIcon() {
if (file != null) {
try {
boolean hasFollowUp = hasFollowUp();
@ -349,63 +338,77 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie
followUpToggle.setSelected(hasFollowUp);
});
} catch (TskCoreException ex) {
Exceptions.printStackTrace(ex);
LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex);
}
}
}
@Override
public void setFile(final Long fileID) {
synchronized public void setFile(final Long fileID) {
if (Objects.equals(fileID, this.fileID) == false) {
this.fileID = fileID;
disposeContent();
if (this.fileID == null || Case.isCaseOpen() == false) {
if (registered == true) {
ImageGalleryController.getDefault().getCategoryManager().unregisterListener(this);
TagUtils.unregisterListener(this);
registered = false;
}
file = null;
Platform.runLater(() -> {
clearContent();
});
} else {
if (registered == false) {
ImageGalleryController.getDefault().getCategoryManager().registerListener(this);
TagUtils.registerListener(this);
registered = true;
}
file = null;
getFile();
updateSelectionState();
updateCategoryBorder();
updateFollowUpIcon();
final String text = getLabelText();
final boolean isVideo = file.isVideo();
final boolean hasHashSetHits = hasHashHit();
Platform.runLater(() -> {
updateUI(isVideo, hasHashSetHits, text);
});
updateUI();
Platform.runLater(getContentUpdateRunnable());
}
}
}
private void updateUI() {
final boolean isVideo = getFile().isVideo();
final boolean hasHashSetHits = hasHashHit();
final String text = getTextForLabel();
Platform.runLater(() -> {
fileTypeImageView.setImage(isVideo ? videoIcon : null);
hashHitImageView.setImage(hasHashSetHits ? hashHitIcon : null);
nameLabel.setText(text);
nameLabel.setTooltip(new Tooltip(text));
});
}
/**
* update the visual representation of the selection state of this
* DrawableView
*/
protected void updateSelectionState() {
final boolean selected = globalSelectionModel.isSelected(fileID);
synchronized protected void updateSelectionState() {
final boolean selected = globalSelectionModel.isSelected(getFileID());
Platform.runLater(() -> {
setBorder(selected ? SELECTED_BORDER : UNSELECTED_BORDER);
});
}
@Override
public Region getBorderable() {
public Region getCategoryBorderRegion() {
return imageBorder;
}
@Subscribe
@Override
public void handleCategoryChanged(CategoryChangeEvent evt) {
if (evt.getIds().contains(fileID)) {
synchronized public void handleCategoryChanged(CategoryChangeEvent evt) {
if (evt.getIds().contains(getFileID())) {
updateCategoryBorder();
}
}

View File

@ -143,6 +143,8 @@ public class GroupPane extends BorderPane implements GroupView {
);
private static final FileIDSelectionModel globalSelectionModel = FileIDSelectionModel.getInstance();
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);
private final Back backAction;
@ -232,7 +234,8 @@ public class GroupPane extends BorderPane implements GroupView {
FXMLConstructor.construct(this, "GroupPane.fxml");
}
public void activateSlideShowViewer(Long slideShowFileId) {
@ThreadConfined(type = ThreadType.JFX)
public void activateSlideShowViewer(Long slideShowFileID) {
groupViewMode.set(GroupViewMode.SLIDE_SHOW);
//make a new slideShowPane if necessary
@ -241,13 +244,14 @@ public class GroupPane extends BorderPane implements GroupView {
}
//assign last selected file or if none first file in group
if (slideShowFileId == null || grouping.get().fileIds().contains(slideShowFileId) == false) {
slideShowPane.setFile(grouping.get().fileIds().get(0));
if (slideShowFileID == null || getGrouping().fileIds().contains(slideShowFileID) == false) {
slideShowPane.setFile(getGrouping().fileIds().get(0));
} else {
slideShowPane.setFile(slideShowFileId);
slideShowPane.setFile(slideShowFileID);
}
setCenter(slideShowPane);
slideShowPane.requestFocus();
}
public void activateTileViewer() {
@ -258,6 +262,7 @@ public class GroupPane extends BorderPane implements GroupView {
if (slideShowPane != null) {
slideShowPane.disposeContent();
}
slideShowPane = null;
this.scrollToFileID(globalSelectionModel.lastSelectedProperty().get());
}
@ -456,12 +461,14 @@ public class GroupPane extends BorderPane implements GroupView {
if (t.getClickCount() == 1) {
selectAllFiles();
}
if (globalSelectionModel.getSelected().isEmpty() == false) {
if (contextMenu == null) {
contextMenu = buildContextMenu();
}
contextMenu.hide();
contextMenu.show(GroupPane.this, t.getScreenX(), t.getScreenY());
}
t.consume();
break;
}
@ -574,15 +581,15 @@ public class GroupPane extends BorderPane implements GroupView {
if (isNull(viewState) || isNull(viewState.getGroup())) {
this.grouping.set(null);
final List<Long> fileIds = Collections.emptyList();
final String header = "";
gridView.getItems().setAll(Collections.emptyList());
Platform.runLater(() -> {
setCenter(null);
gridView.getItems().setAll(fileIds);
groupLabel.setText(header);
groupLabel.setText("");
resetScrollBar();
if (false == Case.isCaseOpen()) {
cellMap.values().stream().forEach(DrawableCell::resetItem);
cellMap.clear();
}
});
@ -593,9 +600,9 @@ public class GroupPane extends BorderPane implements GroupView {
this.getGrouping().fileIds().addListener(filesSyncListener);
final String header = getHeaderString();
final ObservableList<Long> fileIds = getGrouping().fileIds();
gridView.getItems().setAll(getGrouping().fileIds());
Platform.runLater(() -> {
gridView.getItems().setAll(fileIds);
groupLabel.setText(header);
resetScrollBar();
if (viewState.getMode() == GroupViewMode.TILE) {
@ -615,6 +622,31 @@ public class GroupPane extends BorderPane implements GroupView {
});
}
@ThreadConfined(type = ThreadType.JFX)
private Optional<ScrollBar> getScrollBar() {
if (gridView == null || gridView.getSkin() == null) {
return Optional.empty();
}
return Optional.ofNullable((ScrollBar) gridView.getSkin().getNode().lookup(".scroll-bar"));
}
void makeSelection(Boolean shiftDown, Long newFileID) {
if (shiftDown) {
//TODO: do more hear to implement slicker multiselect
int endIndex = grouping.get().fileIds().indexOf(newFileID);
int startIndex = IntStream.of(grouping.get().fileIds().size(), selectionAnchorIndex, endIndex).min().getAsInt();
endIndex = IntStream.of(0, selectionAnchorIndex, endIndex).max().getAsInt();
List<Long> subList = grouping.get().fileIds().subList(Math.max(0, startIndex), Math.min(endIndex, grouping.get().fileIds().size()) + 1);
globalSelectionModel.clearAndSelectAll(subList.toArray(new Long[subList.size()]));
globalSelectionModel.select(newFileID);
} else {
selectionAnchorIndex = null;
globalSelectionModel.clearAndSelect(newFileID);
}
}
private class DrawableCell extends GridCell<Long> {
private final DrawableTile tile = new DrawableTile(GroupPane.this);
@ -648,14 +680,11 @@ public class GroupPane extends BorderPane implements GroupView {
}
void resetItem() {
updateItem(null, true);
// updateItem(null, true);
tile.setFile(null);
}
}
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);
/**
* implements the key handler for tile navigation ( up, down , left, right
* arrows)
@ -772,29 +801,4 @@ public class GroupPane extends BorderPane implements GroupView {
}
}
@ThreadConfined(type = ThreadType.JFX)
private Optional<ScrollBar> getScrollBar() {
if (gridView == null || gridView.getSkin() == null) {
return Optional.empty();
}
return Optional.ofNullable((ScrollBar) gridView.getSkin().getNode().lookup(".scroll-bar"));
}
void makeSelection(Boolean shiftDown, Long newFileID) {
if (shiftDown) {
//TODO: do more hear to implement slicker multiselect
int endIndex = grouping.get().fileIds().indexOf(newFileID);
int startIndex = IntStream.of(grouping.get().fileIds().size(), selectionAnchorIndex, endIndex).min().getAsInt();
endIndex = IntStream.of(0, selectionAnchorIndex, endIndex).max().getAsInt();
List<Long> subList = grouping.get().fileIds().subList(Math.max(0, startIndex), Math.min(endIndex, grouping.get().fileIds().size()) + 1);
globalSelectionModel.clearAndSelectAll(subList.toArray(new Long[subList.size()]));
globalSelectionModel.select(newFileID);
} else {
selectionAnchorIndex = null;
globalSelectionModel.clearAndSelect(newFileID);
}
}
}

View File

@ -176,7 +176,7 @@ public class MetaDataPane extends AnchorPane implements TagUtils.TagListener, Dr
Platform.runLater(() -> {
imageView.setImage(null);
tableView.getItems().clear();
getBorderable().setBorder(null);
getCategoryBorderRegion().setBorder(null);
});
} else {
@ -216,7 +216,7 @@ public class MetaDataPane extends AnchorPane implements TagUtils.TagListener, Dr
}
@Override
public Region getBorderable() {
public Region getCategoryBorderRegion() {
return imageBorder;
}

View File

@ -7,7 +7,6 @@
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<?import org.controlsfx.control.*?>
<?scenebuilder-stylesheet GroupPane.css?>
<fx:root type="AnchorPane" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
@ -66,9 +65,7 @@
<Region prefHeight="-1.0" prefWidth="5.0" />
</children>
<stylesheets>
<URL value="@GroupPane.css" />
</stylesheets>
</HBox>
</items>
</ToolBar>

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Copyright 2013-15 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -56,6 +56,8 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.Category;
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute;
import org.sleuthkit.autopsy.imagegallery.datamodel.ImageFile;
import org.sleuthkit.autopsy.imagegallery.datamodel.VideoFile;
import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.HASH_BORDER;
import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.getCategoryBorder;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
@ -191,10 +193,10 @@ public class SlideShowView extends DrawableViewBase implements TagUtils.TagListe
syncButtonVisibility();
groupPane.grouping().addListener((Observable observable) -> {
getGroupPane().grouping().addListener((Observable observable) -> {
syncButtonVisibility();
if (groupPane.getGrouping() != null) {
groupPane.getGrouping().fileIds().addListener((Observable observable1) -> {
if (getGroupPane().getGrouping() != null) {
getGroupPane().getGrouping().fileIds().addListener((Observable observable1) -> {
syncButtonVisibility();
});
}
@ -204,7 +206,7 @@ public class SlideShowView extends DrawableViewBase implements TagUtils.TagListe
@ThreadConfined(type = ThreadType.ANY)
private void syncButtonVisibility() {
try {
final boolean hasMultipleFiles = groupPane.getGrouping().fileIds().size() > 1;
final boolean hasMultipleFiles = getGroupPane().getGrouping().fileIds().size() > 1;
Platform.runLater(() -> {
rightButton.setVisible(hasMultipleFiles);
leftButton.setVisible(hasMultipleFiles);
@ -218,8 +220,7 @@ public class SlideShowView extends DrawableViewBase implements TagUtils.TagListe
}
SlideShowView(GroupPane gp) {
super();
groupPane = gp;
super(gp);
FXMLConstructor.construct(this, "SlideShow.fxml");
}
@ -232,10 +233,10 @@ public class SlideShowView extends DrawableViewBase implements TagUtils.TagListe
}
@Override
public void setFile(final Long fileID) {
synchronized public void setFile(final Long fileID) {
super.setFile(fileID);
if (this.fileID != null) {
groupPane.makeSelection(false, this.fileID);
if (this.getFileID() != null) {
getGroupPane().makeSelection(false, this.getFileID());
}
}
@ -253,12 +254,12 @@ public class SlideShowView extends DrawableViewBase implements TagUtils.TagListe
@Override
protected Runnable getContentUpdateRunnable() {
if (file.isVideo()) {
if (getFile().isVideo()) {
return () -> {
imageBorder.setCenter(MediaControl.create((VideoFile<?>) file));
imageBorder.setCenter(MediaControl.create((VideoFile<?>) getFile()));
};
} else {
ImageView imageView = new ImageView(((ImageFile<?>) file).getFullSizeImage());
ImageView imageView = new ImageView(((ImageFile<?>) getFile()).getFullSizeImage());
imageView.setPreserveRatio(true);
imageView.fitWidthProperty().bind(imageBorder.widthProperty().subtract(CAT_BORDER_WIDTH * 2));
imageView.fitHeightProperty().bind(this.heightProperty().subtract(CAT_BORDER_WIDTH * 4).subtract(footer.heightProperty()).subtract(toolBar.heightProperty()));
@ -269,23 +270,24 @@ public class SlideShowView extends DrawableViewBase implements TagUtils.TagListe
}
@Override
protected String getLabelText() {
return file.getName() + " " + getSupplementalText();
protected String getTextForLabel() {
return getFile().getName() + " " + getSupplementalText();
}
@ThreadConfined(type = ThreadType.JFX)
private void cycleSlideShowImage(int d) {
stopVideo();
if (fileID != null) {
int index = groupPane.getGrouping().fileIds().indexOf(fileID);
final int size = groupPane.getGrouping().fileIds().size();
if (getFileID() != null) {
int index = getGroupPane().getGrouping().fileIds().indexOf(getFileID());
final int size = getGroupPane().getGrouping().fileIds().size();
index = (index + d) % size;
if (index < 0) {
index += size;
}
setFile(groupPane.getGrouping().fileIds().get(index));
setFile(getGroupPane().getGrouping().fileIds().get(index));
} else {
setFile(groupPane.getGrouping().fileIds().get(0));
setFile(getGroupPane().getGrouping().fileIds().get(0));
}
}
@ -294,23 +296,22 @@ public class SlideShowView extends DrawableViewBase implements TagUtils.TagListe
* of y"
*/
private String getSupplementalText() {
return " ( " + (groupPane.getGrouping().fileIds().indexOf(fileID) + 1) + " of " + groupPane.getGrouping().fileIds().size() + " in group )";
return " ( " + (getGroupPane().getGrouping().fileIds().indexOf(getFileID()) + 1) + " of " + getGroupPane().getGrouping().fileIds().size() + " in group )";
}
@Override
@ThreadConfined(type = ThreadType.ANY)
public Category updateCategoryBorder() {
final Category category = super.updateCategoryBorder();
final Category category = getFile().getCategory();
final Border border = hasHashHit() && (category == Category.ZERO)
? HASH_BORDER
: getCategoryBorder(category);
ToggleButton toggleForCategory = getToggleForCategory(category);
Runnable r = () -> {
Platform.runLater(() -> {
getCategoryBorderRegion().setBorder(border);
toggleForCategory.setSelected(true);
};
if (Platform.isFxApplicationThread()) {
r.run();
} else {
Platform.runLater(r);
}
});
return category;
}
@ -345,7 +346,7 @@ public class SlideShowView extends DrawableViewBase implements TagUtils.TagListe
@Override
public void changed(ObservableValue<? extends Boolean> ov, Boolean t, Boolean t1) {
if (t1) {
FileIDSelectionModel.getInstance().clearAndSelect(fileID);
FileIDSelectionModel.getInstance().clearAndSelect(getFileID());
new CategorizeAction().addTag(cat.getTagName(), "");
}
}