Package org.sleuthkit.autopsy.imageanalyzer.gui

Source Code of org.sleuthkit.autopsy.imageanalyzer.gui.SingleDrawableViewBase

/*
* Autopsy Forensic Browser
*
* Copyright 2013-14 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.imageanalyzer.gui;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.logging.Level;
import javafx.application.Platform;
import javafx.beans.Observable;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.Tooltip;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Border;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.BorderStroke;
import javafx.scene.layout.BorderStrokeStyle;
import javafx.scene.layout.BorderWidths;
import javafx.scene.layout.CornerRadii;
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;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.corecomponentinterfaces.ContextMenuActionsProvider;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType;
import org.sleuthkit.autopsy.datamodel.FileNode;
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.imageanalyzer.FileIDSelectionModel;
import org.sleuthkit.autopsy.imageanalyzer.FileUpdateEvent;
import org.sleuthkit.autopsy.imageanalyzer.ImageAnalyzerController;
import org.sleuthkit.autopsy.imageanalyzer.ImageAnalyzerTopComponent;
import org.sleuthkit.autopsy.imageanalyzer.TagUtils;
import org.sleuthkit.autopsy.imageanalyzer.actions.AddDrawableTagAction;
import org.sleuthkit.autopsy.imageanalyzer.actions.CategorizeAction;
import org.sleuthkit.autopsy.imageanalyzer.actions.SwingMenuItemAdapter;
import org.sleuthkit.autopsy.imageanalyzer.datamodel.Category;
import org.sleuthkit.autopsy.imageanalyzer.datamodel.DrawableAttribute;
import org.sleuthkit.autopsy.imageanalyzer.datamodel.DrawableFile;
import org.sleuthkit.autopsy.imageanalyzer.grouping.GroupKey;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;

/**
* An abstract base class for {@link DrawableTile} and {@link SlideShowView},
* since they share a similar node tree and many behaviors, other implementers
* of {@link  DrawableView}s should implement the interface directly
*
*/
public abstract class SingleDrawableViewBase extends AnchorPane implements DrawableView {

    private static final Logger LOGGER = Logger.getLogger(SingleDrawableViewBase.class.getName());

    private static final Border UNSELECTED_ORDER = new Border(new BorderStroke(Color.GRAY, BorderStrokeStyle.SOLID, new CornerRadii(2), new BorderWidths(3)));

    private static final Border SELECTED_BORDER = new Border(new BorderStroke(Color.BLUE, BorderStrokeStyle.SOLID, new CornerRadii(2), new BorderWidths(3)));

    //TODO: should this stuff be done in CSS? -jm
    protected static final Image videoIcon = new Image("org/sleuthkit/autopsy/imageanalyzer/images/video-file.png");

    protected static final Image hashHitIcon = new Image("org/sleuthkit/autopsy/imageanalyzer/images/hashset_hits.png");

    protected static final Image followUpIcon = new Image("org/sleuthkit/autopsy/imageanalyzer/images/flag_red.png");

    protected static final Image followUpGray = new Image("org/sleuthkit/autopsy/imageanalyzer/images/flag_gray.png");

    protected static final FileIDSelectionModel globalSelectionModel = FileIDSelectionModel.getInstance();

    /**
     * displays the icon representing video files
     */
    @FXML
    protected ImageView fileTypeImageView;

    /**
     * displays the icon representing hash hits
     */
    @FXML
    protected ImageView hashHitImageView;

    /**
     * displays the icon representing follow up tag
     */
    @FXML
    protected ImageView followUpImageView;

    @FXML
    protected ToggleButton followUpToggle;

    /**
     * the label that shows the name of the represented file
     */
    @FXML
    protected Label nameLabel;

    @FXML
    protected BorderPane imageBorder;

    static private ContextMenu contextMenu;

    protected DrawableFile<?> file;

    protected Long fileID;

    /**
     * the groupPane this {@link SingleDrawableViewBase} is embedded in
     */
    protected GroupPane groupPane;

    protected SingleDrawableViewBase() {

        globalSelectionModel.getSelected().addListener((Observable observable) -> {
            updateSelectionState();
        });

        //set up mouse listener
        //TODO: split this between DrawableTile and SingleDrawableViewBase
        addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {

            @Override
            public void handle(MouseEvent t) {

                switch (t.getButton()) {
                    case PRIMARY:
                        if (t.getClickCount() == 1) {
                            if (t.isControlDown()) {
                                globalSelectionModel.toggleSelection(fileID);
                            } else {
                                groupPane.makeSelection(t.isShiftDown(), fileID);
                            }
                        } else if (t.getClickCount() > 1) {
                            groupPane.activateSlideShowViewer(fileID);
                        }
                        break;
                    case SECONDARY:

                        if (t.getClickCount() == 1) {
                            if (globalSelectionModel.isSelected(fileID) == false) {
                                groupPane.makeSelection(false, fileID);
                            }
                        }

                        if (contextMenu != null) {
                            contextMenu.hide();
                        }
                        final ContextMenu groupContextMenu = groupPane.getContextMenu();
                        if (groupContextMenu != null) {
                            groupContextMenu.hide();
                        }
                        contextMenu = buildContextMenu();
                        contextMenu.show(SingleDrawableViewBase.this, t.getScreenX(), t.getScreenY());

                        break;
                }
                t.consume();
            }

            private ContextMenu buildContextMenu() {
                final ArrayList<MenuItem> menuItems = new ArrayList<>();

                menuItems.add(CategorizeAction.getPopupMenu());

                menuItems.add(AddDrawableTagAction.getInstance().getPopupMenu());

                final MenuItem extractMenuItem = new MenuItem("Extract File(s)");
                extractMenuItem.setOnAction((ActionEvent t) -> {
                    SwingUtilities.invokeLater(() -> {
                        TopComponent etc = WindowManager.getDefault().findTopComponent(ImageAnalyzerTopComponent.PREFERRED_ID);
                        ExtractAction.getInstance().actionPerformed(new java.awt.event.ActionEvent(etc, 0, null));
                    });
                });
                menuItems.add(extractMenuItem);

                MenuItem contentViewer = new MenuItem("Show Content Viewer");
                contentViewer.setOnAction((ActionEvent t) -> {
                    SwingUtilities.invokeLater(() -> {
                        new NewWindowViewAction("Show Content Viewer", new FileNode(getFile().getAbstractFile())).actionPerformed(null);
                    });
                });
                menuItems.add(contentViewer);

                MenuItem externalViewer = new MenuItem("Open in External Viewer");
                final ExternalViewerAction externalViewerAction = new ExternalViewerAction("Open in External Viewer", new FileNode(getFile().getAbstractFile()));

                externalViewer.setDisable(externalViewerAction.isEnabled() == false);
                externalViewer.setOnAction((ActionEvent t) -> {
                    SwingUtilities.invokeLater(() -> {
                        externalViewerAction.actionPerformed(null);
                    });
                });
                menuItems.add(externalViewer);

                Collection<? extends ContextMenuActionsProvider> menuProviders = Lookup.getDefault().lookupAll(ContextMenuActionsProvider.class);

                for (ContextMenuActionsProvider provider : menuProviders) {
                    for (final Action act : provider.getActions()) {
                        if (act instanceof Presenter.Popup) {
                            Presenter.Popup aact = (Presenter.Popup) act;
                            menuItems.add(SwingMenuItemAdapter.create(aact.getPopupPresenter()));
                        }
                    }
                }

                ContextMenu contextMenu = new ContextMenu(menuItems.toArray(new MenuItem[]{}));
                contextMenu.setAutoHide(true);
                return contextMenu;
            }
        });
    }

    @ThreadConfined(type = ThreadType.UI)
    protected abstract void clearContent();

    protected abstract void disposeContent();

    protected abstract Runnable getContentUpdateRunnable();

    protected abstract String getLabelText();

    protected void initialize() {
        followUpToggle.setOnAction((ActionEvent t) -> {
            if (followUpToggle.isSelected() == true) {
                globalSelectionModel.clearAndSelect(fileID);
                try {
                    AddDrawableTagAction.getInstance().addTag(TagUtils.getFollowUpTagName(), "");
                } catch (TskCoreException ex) {
                    Exceptions.printStackTrace(ex);
                }
            } else {
                //TODO: convert this to an action!
                final ImageAnalyzerController controller = ImageAnalyzerController.getDefault();
                try {
                    // 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());
                    for (ContentTag ct : contentTagsByContent) {
                        if (ct.getName().getDisplayName().equals(TagUtils.getFollowUpTagName().getDisplayName())) {
                            Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(ct);
                            SwingUtilities.invokeLater(() -> DirectoryTreeTopComponent.findInstance().refreshContentTreeSafe());
                        }
                    }

                    controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS));
                } catch (TskCoreException ex) {
                    Exceptions.printStackTrace(ex);
                }
            }
        });
    }

    @Override
    public DrawableFile<?> getFile() {
        if (fileID != null) {
            if (file == null || file.getId() != fileID) {
                try {
                    file = ImageAnalyzerController.getDefault().getFileFromId(fileID);
                } catch (TskCoreException ex) {
                    LOGGER.log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileID, ex);
                    return null;
                }
            }
        } else {
            return null;
        }
        return file;
    }

    protected boolean hasFollowUp() throws TskCoreException {
        String followUpTagName = TagUtils.getFollowUpTagName().getDisplayName();
        Collection<TagName> tagNames = DrawableAttribute.TAGS.getValue(getFile());
        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() {
        return fileID;
    }

    @Override
    public void handleTagsChanged(Collection<Long> ids) {
        if (fileID != null && ids.contains(fileID)) {
            updateFollowUpIcon();
        }
    }

    protected void updateFollowUpIcon() {
        if (file != null) {
            try {
                boolean hasFollowUp = hasFollowUp();
                Platform.runLater(() -> {
                    followUpImageView.setImage(hasFollowUp ? followUpIcon : followUpGray);
                    followUpToggle.setSelected(hasFollowUp);
                });
            } catch (TskCoreException ex) {
                Exceptions.printStackTrace(ex);
            }
        }
    }

    @Override
    public void setFile(final Long fileID) {
        if (Objects.equals(fileID, this.fileID) == false) {
            this.fileID = fileID;
            disposeContent();
            if (this.fileID == null || Case.isCaseOpen() == false) {
                Category.unregisterListener(this);
                TagUtils.unregisterListener(this);
                file = null;
                Platform.runLater(() -> {
                    clearContent();
                });
            } else {
                Category.registerListener(this);
                TagUtils.registerListener(this);

                getFile();
                updateSelectionState();
                updateCategoryBorder();
                updateFollowUpIcon();
                final String text = getLabelText();
                final boolean isVideo = file.isVideo();
                final boolean hasHashSetHits = hasHashHit();
                Platform.runLater(() -> {
                    updateUI(isVideo, hasHashSetHits, text);
                });
                Platform.runLater(getContentUpdateRunnable());
            }
        }
    }

    private void updateSelectionState() {
        final boolean selected = globalSelectionModel.isSelected(fileID);
        Platform.runLater(() -> {
            SingleDrawableViewBase.this.setBorder(selected ? SELECTED_BORDER : UNSELECTED_ORDER);
        });
    }

    @Override
    public Region getBorderable() {
        return imageBorder;
    }

    @Override
    public void handleCategoryChanged(Collection<Long> ids) {
        if (ids.contains(fileID)) {
            updateCategoryBorder();
        }
    }
}
TOP

Related Classes of org.sleuthkit.autopsy.imageanalyzer.gui.SingleDrawableViewBase

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.