From 638750c7201d860a7136919b70972f1267b67a97 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Thu, 23 May 2019 11:46:47 -0400 Subject: [PATCH 001/115] Checkin of the current state of the UI, will continue to make improvements --- .../contentviewers/MediaViewImagePanel.form | 55 ++++ .../contentviewers/MediaViewImagePanel.java | 194 ++++++-------- .../imagetagging/ControlType.java | 32 +++ .../imagetagging/FocusChangeEvent.java | 49 ++++ .../imagetagging/FocusChangeListener.java | 18 ++ .../imagetagging/ImageTagCreator.java | 145 +++++++++++ .../imagetagging/StoredTag.java | 239 ++++++++++++++++++ .../imagetagging/StoredTagEvent.java | 40 +++ .../imagetagging/StoredTagListener.java | 33 +++ .../imagetagging/TopLevelTagsGroup.java | 98 +++++++ 10 files changed, 788 insertions(+), 115 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ControlType.java create mode 100755 Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/FocusChangeEvent.java create mode 100755 Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/FocusChangeListener.java create mode 100755 Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagCreator.java create mode 100755 Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTag.java create mode 100755 Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTagEvent.java create mode 100755 Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTagListener.java create mode 100755 Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/TopLevelTagsGroup.java diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.form b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.form index e057337e6f..fb17c441db 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.form @@ -1,6 +1,31 @@
+ + + + + + + + + + + + + + + + + + + + + + + + + @@ -200,6 +225,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java index 5c16dbed93..ebf7f48444 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java @@ -18,6 +18,11 @@ */ package org.sleuthkit.autopsy.contentviewers; +import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagCreator; +import org.sleuthkit.autopsy.contentviewers.imagetagging.StoredTag; +import org.sleuthkit.autopsy.contentviewers.imagetagging.StoredTagListener; +import org.sleuthkit.autopsy.contentviewers.imagetagging.TopLevelTagsGroup; +import org.sleuthkit.autopsy.contentviewers.imagetagging.StoredTagEvent; import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.util.Collections; @@ -32,6 +37,7 @@ import javafx.embed.swing.JFXPanel; import javafx.geometry.Pos; import javafx.geometry.Rectangle2D; import javafx.scene.Cursor; +import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; @@ -49,11 +55,8 @@ import javax.swing.JPanel; import org.controlsfx.control.MaskerPane; import org.openide.util.NbBundle; import org.python.google.common.collect.Lists; -import javafx.scene.Group; -import javafx.scene.input.MouseEvent; -import javafx.scene.paint.Color; -import javafx.scene.shape.Rectangle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.contentviewers.imagetagging.ControlType; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.datamodel.FileNode; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; @@ -74,9 +77,10 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan private final boolean fxInited; private JFXPanel fxPanel; - private Group imageGroup; - private ImageTaggingTool tagger; + private TopLevelTagsGroup imageGroup; + private ImageTagCreator tagger; private ImageView fxImageView; + private Node focusedNode; private ScrollPane scrollPane; private final ProgressBar progressBar = new ProgressBar(); private final MaskerPane maskerPane = new MaskerPane(); @@ -121,8 +125,18 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan // build jfx ui (we could do this in FXML?) fxImageView = new ImageView(); // will hold image - imageGroup = new Group(); - imageGroup.getChildren().add(fxImageView); + imageGroup = new TopLevelTagsGroup(fxImageView); + deleteTagButton.setEnabled(false); + imageGroup.addFocusChangeListener((event) -> { + if(event.getType() == ControlType.NOT_FOCUSED || event.getNode() == fxImageView) { + deleteTagButton.setEnabled(false); + createTagButton.setEnabled(true); + } else if (event.getType() == ControlType.FOCUSED) { + deleteTagButton.setEnabled(true); + createTagButton.setEnabled(false); + focusedNode = event.getNode(); + } + }); scrollPane = new ScrollPane(imageGroup); // scrolls and sizes imageview scrollPane.getStyleClass().add("bg"); //NOI18N scrollPane.setVbarPolicy(ScrollBarPolicy.AS_NEEDED); @@ -154,8 +168,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan Platform.runLater(() -> { fxImageView.setViewport(new Rectangle2D(0, 0, 0, 0)); fxImageView.setImage(null); - tagger.defaultSettings(); - + imageGroup.getChildren().clear(); scrollPane.setContent(null); scrollPane.setContent(imageGroup); }); @@ -205,11 +218,17 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan try { Image fxImage = readImageTask.get(); + imageGroup.getChildren().clear(); + imageGroup.getChildren().add(fxImageView); if (nonNull(fxImage)) { // We have a non-null image, so let's show it. fxImageView.setImage(fxImage); - imageGroup.getChildren().remove(tagger); - tagger = new ImageTaggingTool(fxImageView, Color.RED); + tagger = new ImageTagCreator(fxImageView); + StoredTagListener newTagListener = (StoredTagEvent evt) -> { + StoredTag tag = evt.getTag(); + imageGroup.getChildren().add(tag); + }; + tagger.addNewTagListener(newTagListener); imageGroup.getChildren().add(tagger); resetView(); scrollPane.setContent(imageGroup); @@ -293,6 +312,9 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan // //GEN-BEGIN:initComponents private void initComponents() { + jMenu1 = new javax.swing.JMenu(); + jPopupMenu1 = new javax.swing.JPopupMenu(); + jPopupMenu2 = new javax.swing.JPopupMenu(); toolbar = new javax.swing.JToolBar(); rotationTextField = new javax.swing.JTextField(); rotateLeftButton = new javax.swing.JButton(); @@ -303,6 +325,12 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan zoomInButton = new javax.swing.JButton(); jSeparator2 = new javax.swing.JToolBar.Separator(); zoomResetButton = new javax.swing.JButton(); + jSeparator3 = new javax.swing.JToolBar.Separator(); + createTagButton = new javax.swing.JButton(); + jSeparator4 = new javax.swing.JToolBar.Separator(); + deleteTagButton = new javax.swing.JButton(); + + org.openide.awt.Mnemonics.setLocalizedText(jMenu1, org.openide.util.NbBundle.getMessage(MediaViewImagePanel.class, "MediaViewImagePanel.jMenu1.text")); // NOI18N setBackground(new java.awt.Color(0, 0, 0)); addComponentListener(new java.awt.event.ComponentAdapter() { @@ -406,6 +434,30 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan } }); toolbar.add(zoomResetButton); + toolbar.add(jSeparator3); + + org.openide.awt.Mnemonics.setLocalizedText(createTagButton, org.openide.util.NbBundle.getMessage(MediaViewImagePanel.class, "MediaViewImagePanel.createTagButton.text")); // NOI18N + createTagButton.setFocusable(false); + createTagButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + createTagButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + createTagButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + createTagButtonActionPerformed(evt); + } + }); + toolbar.add(createTagButton); + toolbar.add(jSeparator4); + + org.openide.awt.Mnemonics.setLocalizedText(deleteTagButton, org.openide.util.NbBundle.getMessage(MediaViewImagePanel.class, "MediaViewImagePanel.deleteTagButton.text")); // NOI18N + deleteTagButton.setFocusable(false); + deleteTagButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + deleteTagButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + deleteTagButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + deleteTagButtonActionPerformed(evt); + } + }); + toolbar.add(deleteTagButton); add(toolbar); }// //GEN-END:initComponents @@ -450,9 +502,24 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan updateView(); }//GEN-LAST:event_formComponentResized + private void deleteTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTagButtonActionPerformed + imageGroup.deleteNode(focusedNode); + }//GEN-LAST:event_deleteTagButtonActionPerformed + + private void createTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_createTagButtonActionPerformed + + }//GEN-LAST:event_createTagButtonActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton createTagButton; + private javax.swing.JButton deleteTagButton; + private javax.swing.JMenu jMenu1; + private javax.swing.JPopupMenu jPopupMenu1; + private javax.swing.JPopupMenu jPopupMenu2; private javax.swing.JToolBar.Separator jSeparator1; private javax.swing.JToolBar.Separator jSeparator2; + private javax.swing.JToolBar.Separator jSeparator3; + private javax.swing.JToolBar.Separator jSeparator4; private javax.swing.JButton rotateLeftButton; private javax.swing.JButton rotateRightButton; private javax.swing.JTextField rotationTextField; @@ -618,107 +685,4 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan rotationTextField.setText((int) rotation + "°"); zoomTextField.setText((Math.round(zoomRatio * 100.0)) + "%"); } - - /** - * Enables users to 'tag' a region of an image by clicking and dragging a - * rectangle overtop. - */ - class ImageTaggingTool extends Rectangle { - - private final double imageWidth; - private final double imageHeight; - private final double imageOriginX; - private final double imageOriginY; - - //Origin of the drag event. - private double rectangleOriginX; - private double rectangleOriginY; - - //Rectangle lines should be 1.5% of the image. This level of thickness has - //a good balance between visual acuity and loss of selection at the borders - //of the image. - private double lineThicknessAsPercent = 1.5; - - /** - * Adds tagging support to an image, where the 'tag' rectangle will be - * the specified color. - * - * @param image Image to tag - * @param color Color of the 'tag' rectangle - */ - private ImageTaggingTool(ImageView image, Color color) { - defaultSettings(); - - imageWidth = image.getImage().getWidth(); - imageHeight = image.getImage().getHeight(); - imageOriginX = image.getX(); - imageOriginY = image.getY(); - - setStroke(color); - setFill(color.deriveColor(0, 0, 0, 0)); - - //Calculate how many pixels the stroke width should be to guarentee - //a consistent % of image consumed by the rectangle border. - double min = Math.min(imageWidth, imageHeight); - double lineThicknessPixels = min * lineThicknessAsPercent / 100.0; - setStrokeWidth(lineThicknessPixels); - setVisible(false); - - //Create a rectangle by left clicking on the image - image.setOnMousePressed((MouseEvent event) -> { - if (event.isSecondaryButtonDown()) { - return; - } - - //Reset box on new click. - defaultSettings(); - - rectangleOriginX = event.getX(); - rectangleOriginY = event.getY(); - - setX(rectangleOriginX); - setY(rectangleOriginY); - }); - - //Adjust the rectangle by dragging the left mouse button - image.setOnMouseDragged((MouseEvent event) -> { - if (event.isSecondaryButtonDown()) { - return; - } - - /** - * Ensure the rectangle is contained within image boundaries and - * that the line thickness is kept within bounds. - */ - double newX = Math.min(Math.max(event.getX(), imageOriginX) - + lineThicknessPixels / 2, imageWidth - lineThicknessPixels / 2); - double newY = Math.min(Math.max(event.getY(), imageOriginY) - + lineThicknessPixels / 2, imageHeight - lineThicknessPixels / 2); - - setVisible(true); - double offsetX = newX - rectangleOriginX; - if (offsetX < 0) { - setX(newX); - } - setWidth(Math.abs(offsetX)); - - double offsetY = newY - rectangleOriginY; - if (offsetY < 0) { - setY(newY); - } - setHeight(Math.abs(offsetY)); - }); - } - - /** - * Reset the rectangle to default dimensions. - */ - public final void defaultSettings() { - setX(0); - setY(0); - setWidth(0); - setHeight(0); - setVisible(false); - } - } } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ControlType.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ControlType.java new file mode 100755 index 0000000000..6e0c6a2493 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ControlType.java @@ -0,0 +1,32 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 Basis Technology Corp. + * Contact: carrier sleuthkit 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.contentviewers.imagetagging; + +import javafx.event.Event; +import javafx.event.EventType; + +/** + * + * @author dsmyda + */ +public class ControlType { + public static final EventType NOT_FOCUSED = new EventType<>("NOT_FOCUSED"); + public static final EventType FOCUSED = new EventType<>("FOCUSED"); + public static final EventType DELETE = new EventType<>("DELETE"); +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/FocusChangeEvent.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/FocusChangeEvent.java new file mode 100755 index 0000000000..e487e01061 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/FocusChangeEvent.java @@ -0,0 +1,49 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 Basis Technology Corp. + * Contact: carrier sleuthkit 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.contentviewers.imagetagging; + +import java.util.EventObject; +import javafx.event.Event; +import javafx.event.EventType; +import javafx.scene.Node; + +/** + * + * @author dsmyda + */ +public final class FocusChangeEvent extends EventObject{ + + private final EventType type; + private final Node focused; + + public FocusChangeEvent(Object source, EventType type, Node focused) { + super(source); + this.type = type; + this.focused = focused; + } + + public EventType getType() { + return type; + } + + public Node getNode() { + return focused; + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/FocusChangeListener.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/FocusChangeListener.java new file mode 100755 index 0000000000..6699e57002 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/FocusChangeListener.java @@ -0,0 +1,18 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.contentviewers.imagetagging; + +import java.util.EventListener; + +/** + * + * @author dsmyda + */ +@FunctionalInterface +public interface FocusChangeListener extends EventListener{ + + void focusChanged(FocusChangeEvent event); +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagCreator.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagCreator.java new file mode 100755 index 0000000000..146fbe1281 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagCreator.java @@ -0,0 +1,145 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 Basis Technology Corp. + * Contact: carrier sleuthkit 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.contentviewers.imagetagging; + +import java.util.ArrayList; +import java.util.Collection; +import javafx.scene.image.ImageView; +import javafx.scene.input.MouseEvent; +import javafx.scene.paint.Color; +import javafx.scene.shape.Rectangle; + +/** + * Creates image tags. This tool can be treated like any other JavaFX node. + */ +public final class ImageTagCreator extends Rectangle { + + //Origin of the drag event. + private double rectangleOriginX, rectangleOriginY; + + //Rectangle lines should be 1.5% of the image. This level of thickness has + //a good balance between visual acuity and loss of selection at the borders + //of the image. + private double lineThicknessAsPercent = 1.5; + private final double minArea; + private final Collection listeners; + + /** + * Adds tagging support to an image, where the 'tag' rectangle will be the + * specified color. + * + * @param image Image to tag + */ + public ImageTagCreator(ImageView image) { + listeners = new ArrayList<>(); + + setStroke(Color.RED); + setFill(Color.RED.deriveColor(0, 0, 0, 0)); + + //Calculate how many pixels the stroke width should be to guarentee + //a consistent % of image consumed by the rectangle border. + double min = Math.min(image.getImage().getWidth(), image.getImage().getHeight()); + double lineThicknessPixels = min * lineThicknessAsPercent / 100.0; + setStrokeWidth(lineThicknessPixels); + minArea = lineThicknessPixels * lineThicknessPixels; + setVisible(false); + + this.addEventHandler(ControlType.NOT_FOCUSED, (event) -> defaultSettings()); + + //Create a rectangle by left clicking on the image + image.setOnMousePressed((MouseEvent event) -> { + if (event.isSecondaryButtonDown()) { + return; + } + + //Reset box on new click. + defaultSettings(); + rectangleOriginX = event.getX(); + rectangleOriginY = event.getY(); + + setX(rectangleOriginX); + setY(rectangleOriginY); + }); + + //Adjust the rectangle by dragging the left mouse button + image.setOnMouseDragged((MouseEvent event) -> { + if (event.isSecondaryButtonDown()) { + return; + } + + double currentX = event.getX(), currentY = event.getY(); + + /** + * Ensure the rectangle is contained within image boundaries and + * that the line thickness is kept within bounds. + */ + double newX = Math.min(Math.max(currentX, image.getX()) + + lineThicknessPixels / 2, image.getImage().getWidth() - lineThicknessPixels / 2); + double newY = Math.min(Math.max(currentY, image.getY()) + + lineThicknessPixels / 2, image.getImage().getHeight() - lineThicknessPixels / 2); + + setVisible(true); + double offsetX = newX - rectangleOriginX; + if (offsetX < 0) { + setX(newX); + } + setWidth(Math.abs(offsetX)); + + double offsetY = newY - rectangleOriginY; + if (offsetY < 0) { + setY(newY); + } + setHeight(Math.abs(offsetY)); + }); + + image.setOnMouseReleased(event -> { + if ((this.getWidth() - this.getStrokeWidth()) * + (this.getHeight() - this.getStrokeWidth()) <= minArea) { + defaultSettings(); + return; + } + + //TODO - persist tag. + + //Notify listeners + StoredTagEvent newTagEvent = new StoredTagEvent(this, new StoredTag(image, this.getX(), this.getY(), + this.getX() + this.getWidth(), this.getY() + this.getHeight())); + + listeners.forEach((listener) -> { + listener.newTagEvent(newTagEvent); + }); + + defaultSettings(); + }); + } + + public void addNewTagListener(StoredTagListener listener) { + listeners.add(listener); + } + + /** + * Reset the rectangle to default dimensions. + */ + private void defaultSettings() { + setWidth(0); + setHeight(0); + setVisible(false); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTag.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTag.java new file mode 100755 index 0000000000..6670639811 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTag.java @@ -0,0 +1,239 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 Basis Technology Corp. + * Contact: carrier sleuthkit 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.contentviewers.imagetagging; + +import com.sun.javafx.event.EventDispatchChainImpl; +import javafx.collections.ListChangeListener; +import javafx.scene.Cursor; +import javafx.scene.Group; +import javafx.scene.Node; +import javafx.scene.image.ImageView; +import javafx.scene.input.MouseEvent; +import javafx.scene.paint.Color; +import javafx.scene.shape.Circle; +import javafx.scene.shape.Rectangle; + +/** + * + * @author dsmyda + */ +public final class StoredTag extends Group { + + private final EventDispatchChainImpl ALL_CHILDREN; + private final PhysicalTag physicalTag; + + public StoredTag(ImageView image, double x, double y, double x1, double y1) { + ALL_CHILDREN = new EventDispatchChainImpl(); + + this.getChildren().addListener((ListChangeListener) change -> { + change.next(); + change.getAddedSubList().forEach((node) -> ALL_CHILDREN.append(node.getEventDispatcher())); + }); + + double min = Math.min(image.getImage().getWidth(), image.getImage().getHeight()); + double lineThicknessPixels = min * 1.5 / 100.0; + physicalTag = new PhysicalTag(image); + physicalTag.setStrokeWidth(lineThicknessPixels); + + EditHandle bottomLeft = new EditHandle(); + bottomLeft.setPosition(Position.bottom(), Position.left()); + bottomLeft.setDrag(Drag.bottom(), Drag.left()); + + EditHandle bottomRight = new EditHandle(); + bottomRight.setPosition(Position.bottom(), Position.right()); + bottomRight.setDrag(Drag.bottom(), Drag.right()); + + EditHandle topLeft = new EditHandle(); + topLeft.setPosition(Position.top(), Position.left()); + topLeft.setDrag(Drag.top(), Drag.left()); + + EditHandle topRight = new EditHandle(); + topRight.setPosition(Position.top(), Position.right()); + topRight.setDrag(Drag.top(), Drag.right()); + + EditHandle bottomMiddle = new EditHandle(); + bottomMiddle.setPosition(Position.bottom(), Position.xMiddle()); + bottomMiddle.setDrag(Drag.bottom()); + + EditHandle topMiddle = new EditHandle(); + topMiddle.setPosition(Position.top(), Position.xMiddle()); + topMiddle.setDrag(Drag.top()); + + EditHandle rightMiddle = new EditHandle(); + rightMiddle.setPosition(Position.right(), Position.yMiddle()); + rightMiddle.setDrag(Drag.right()); + + EditHandle leftMiddle = new EditHandle(); + leftMiddle.setPosition(Position.left(), Position.yMiddle()); + leftMiddle.setDrag(Drag.left()); + + this.getChildren().addAll(physicalTag, bottomLeft, bottomRight, topLeft, + topRight, bottomMiddle, topMiddle, rightMiddle, leftMiddle); + + //Position the tag on the image. The edit knobs will be notified of + //the new coords and adjust themselves. + physicalTag.setX(x); + physicalTag.setY(y); + physicalTag.setWidth(x1 - x); + physicalTag.setHeight(y1 - y); + + this.addEventHandler(ControlType.NOT_FOCUSED, event -> ALL_CHILDREN.dispatchEvent(event)); + this.addEventHandler(ControlType.FOCUSED, event -> ALL_CHILDREN.dispatchEvent(event)); + this.addEventHandler(ControlType.DELETE, event -> ALL_CHILDREN.dispatchEvent(event)); + } + + class PhysicalTag extends Rectangle { + + private final ImageView image; + + public PhysicalTag(ImageView image) { + this.setStroke(Color.RED); + this.setFill(Color.RED.deriveColor(0, 0, 0, 0)); + + this.addEventHandler(ControlType.NOT_FOCUSED, event -> this.setOpacity(1)); + this.addEventHandler(ControlType.FOCUSED, event -> this.setOpacity(0.5)); + + this.addEventHandler(ControlType.DELETE, event -> { + this.setVisible(false); + //TODO - delete tag from persistent storage here. + }); + + this.image = image; + } + + private void save() { + //TODO - persist tag + } + + private ImageView getUnderlyingImage() { + return image; + } + } + + class EditHandle extends Circle { + + public EditHandle() { + super(physicalTag.getStrokeWidth(), physicalTag.getStroke()); + this.setVisible(false); + + //Manipulate the parent rectangle when this knob is dragged. + this.addEventHandler(ControlType.NOT_FOCUSED, event -> this.setVisible(false)); + this.addEventHandler(ControlType.FOCUSED, event -> this.setVisible(true)); + this.addEventHandler(ControlType.DELETE, event -> this.setVisible(false)); + this.setOnDragDetected(event -> this.getParent().setCursor(Cursor.CLOSED_HAND)); + this.setOnMouseReleased(event -> { + this.getParent().setCursor(Cursor.DEFAULT); + physicalTag.save(); + }); + } + + public void setPosition(Position... vals) { + for (Position pos : vals) { + physicalTag.widthProperty().addListener((obs, oldVal, newVal) -> pos.set(physicalTag, this)); + physicalTag.heightProperty().addListener((obs, oldVal, newVal) -> pos.set(physicalTag, this)); + } + } + + public void setDrag(Drag... vals) { + this.setOnMouseDragged((event) -> { + for (Drag drag : vals) { + drag.perform(physicalTag, event, physicalTag.getUnderlyingImage()); + } + }); + } + } + + static interface Position { + + void set(Rectangle parent, Circle knob); + + static Position left() { + return (parent, knob) -> knob.centerXProperty().bind(parent.xProperty()); + } + + static Position right() { + return (parent, knob) -> knob.centerXProperty().bind(parent.xProperty().add(parent.getWidth())); + } + + static Position top() { + return (parent, knob) -> knob.centerYProperty().bind(parent.yProperty()); + } + + static Position bottom() { + return (parent, knob) -> knob.centerYProperty().bind(parent.yProperty().add(parent.getHeight())); + } + + static Position xMiddle() { + return (parent, knob) -> knob.centerXProperty().bind(parent.xProperty().add(parent.getWidth() / 2)); + } + + static Position yMiddle() { + return (parent, knob) -> knob.centerYProperty().bind(parent.yProperty().add(parent.getHeight() / 2)); + } + } + + static interface Drag { + + void perform(Rectangle parent, MouseEvent event, ImageView image); + + static Drag bottom() { + return (parent, event, image) -> { + double deltaY = event.getY() - parent.getY(); + if (deltaY > 0 && event.getY() + < image.getY() + image.getImage().getHeight() + - parent.getStrokeWidth() / 2) { + parent.setHeight(deltaY); + } + }; + } + + static Drag top() { + return (parent, event, image) -> { + double deltaY = parent.getY() + parent.getHeight() - event.getY(); + if (deltaY < parent.getY() + parent.getHeight() && event.getY() + > image.getY() + parent.getStrokeWidth() / 2 && deltaY > 0) { + parent.setHeight(deltaY); + parent.setY(event.getY()); + } + }; + } + + static Drag left() { + return (parent, event, image) -> { + double deltaX = parent.getX() + parent.getWidth() - event.getX(); + if (deltaX < parent.getX() + parent.getWidth() + && event.getX() > image.getX() + parent.getStrokeWidth() / 2 + && deltaX > 0) { + parent.setWidth(deltaX); + parent.setX(event.getX()); + } + }; + } + + static Drag right() { + return (parent, event, image) -> { + double deltaX = event.getX() - parent.getX(); + if (deltaX > 0 && event.getX() < image.getX() + + image.getImage().getWidth() - parent.getStrokeWidth() / 2) { + parent.setWidth(deltaX); + } + }; + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTagEvent.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTagEvent.java new file mode 100755 index 0000000000..e1cba2d7f6 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTagEvent.java @@ -0,0 +1,40 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 Basis Technology Corp. + * Contact: carrier sleuthkit 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.contentviewers.imagetagging; + + +import java.util.EventObject; + +/** + * + * @author dsmyda + */ +public final class StoredTagEvent extends EventObject { + private final StoredTag tag; + + public StoredTagEvent(Object source, StoredTag tag) { + super(source); + this.tag = tag; + } + + public StoredTag getTag() { + return tag; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTagListener.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTagListener.java new file mode 100755 index 0000000000..a727cc4f53 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTagListener.java @@ -0,0 +1,33 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 Basis Technology Corp. + * Contact: carrier sleuthkit 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.contentviewers.imagetagging; + + +import java.util.EventListener; + +/** + * + * @author dsmyda + */ +@FunctionalInterface +public interface StoredTagListener extends EventListener { + + void newTagEvent(StoredTagEvent tagEvent); +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/TopLevelTagsGroup.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/TopLevelTagsGroup.java new file mode 100755 index 0000000000..6b7bca78e8 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/TopLevelTagsGroup.java @@ -0,0 +1,98 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 Basis Technology Corp. + * Contact: carrier sleuthkit 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.contentviewers.imagetagging; + +import com.sun.javafx.event.EventDispatchChainImpl; +import java.util.ArrayList; +import java.util.Collection; +import javafx.event.Event; +import javafx.scene.Group; +import javafx.scene.Node; +import javafx.scene.image.ImageView; +import javafx.scene.input.MouseEvent; + +/** + * Top level group containing Image and all existing tags. + */ +public final class TopLevelTagsGroup extends Group { + private final EventDispatchChainImpl NO_OP_CHAIN = new EventDispatchChainImpl(); + private final Collection listeners; + + private Node lastFocus; + private final ImageView baseImage; + + public TopLevelTagsGroup(ImageView image) { + super(image); + baseImage = image; + listeners = new ArrayList<>(); + + //Manage focus, such that only one child can be set at a time. + this.addEventFilter(MouseEvent.MOUSE_PRESSED, (MouseEvent e) -> { + if (!e.isPrimaryButtonDown()) { + return; + } + + Node child = getTopLevelChild(e.getPickResult().getIntersectedNode()); + if (lastFocus == child) { + return; + } else if (lastFocus != null && lastFocus != child) { + resetFocus(lastFocus); + } + + child.getEventDispatcher().dispatchEvent(new Event(ControlType.FOCUSED), NO_OP_CHAIN); + listeners.forEach((listener) -> { + listener.focusChanged(new FocusChangeEvent(this, ControlType.FOCUSED, child)); + }); + + if(child != baseImage) { + child.toFront(); + } + lastFocus = child; + }); + } + + public void addFocusChangeListener(FocusChangeListener fcl) { + listeners.add(fcl); + } + + private void resetFocus(Node n) { + n.getEventDispatcher().dispatchEvent(new Event(ControlType.NOT_FOCUSED), NO_OP_CHAIN); + listeners.forEach((listener) -> { + listener.focusChanged(new FocusChangeEvent(this, ControlType.NOT_FOCUSED, n)); + }); + } + + public void deleteNode(Node dest) { + if(lastFocus == dest) { + resetFocus(lastFocus); + lastFocus = null; + } + + dest.getEventDispatcher().dispatchEvent(new Event(ControlType.DELETE), NO_OP_CHAIN); + } + + private Node getTopLevelChild(Node selected) { + Node curr = selected; + while (!this.getChildren().contains(curr)) { + curr = curr.getParent(); + } + return curr; + } +} From 40689ae751a31020828443b03951933be30b0c87 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Tue, 28 May 2019 12:48:38 -0400 Subject: [PATCH 002/115] Continued development checkpoint, more work to be done. --- .../ApplicationTagsManager.java | 67 +++++++++++++++ .../autopsy/contentviewers/Bundle.properties | 4 + .../contentviewers/Bundle.properties-MERGED | 4 + .../contentviewers/MediaViewImagePanel.form | 21 ++++- .../contentviewers/MediaViewImagePanel.java | 82 ++++++++++++++++--- .../imagetagging/FocusChangeEvent.java | 7 +- .../imagetagging/ImageTagCreator.java | 48 +++++++---- .../imagetagging/StoredTag.java | 30 +++++++ .../imagetagging/TopLevelTagsGroup.java | 73 +++++++++-------- 9 files changed, 271 insertions(+), 65 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ApplicationTagsManager.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ApplicationTagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ApplicationTagsManager.java new file mode 100755 index 0000000000..65756d16c8 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ApplicationTagsManager.java @@ -0,0 +1,67 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 Basis Technology Corp. + * Contact: carrier sleuthkit 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.casemodule.services.applicationtags; + +import java.util.EnumSet; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.CaseDbAccessManager; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * A per case Autopsy service that manages the addition of application content + * tags to the case database. + */ +public final class ApplicationTagsManager { + + private static CaseDbAccessManager dbManager; + + private static final String TABLE_NAME = "beta_tag_app_data"; + private static final String TABLE_SCHEMA = "(app_data_id INTEGER PRIMARY KEY, " + + "content_tag_id INTEGER NOT NULL, app_data TEXT NOT NULL," + + "FOREIGN KEY(content_tag_id) REFERENCES content_tags(tag_id))"; + + private final String INSERT_OR_REPLACE_TAG_DATA = "(content_tag_id, app_data) VALUES (?, ?)"; + private final String SELECT_TAG_DATA = "* FROM " + TABLE_NAME + " WHERE content_tag_id = ?"; + private final String DELETE_TAG_DATA = "WHERE app_data_id = ?"; + + static { + Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), evt -> { + if(evt.getNewValue() != null) { + Case currentCase = (Case) evt.getNewValue(); + try { + CaseDbAccessManager caseDb = currentCase.getSleuthkitCase().getCaseDbAccessManager(); + //Create our custom application tags table, if need be. + if (!caseDb.tableExists(TABLE_NAME)) { + caseDb.createTable(TABLE_NAME, TABLE_SCHEMA); + } + + dbManager = caseDb; + } catch (TskCoreException ex) { + //Log + } + } + }); + } + + //public createTag + //public updateTag + //public getTag + //public deleteTag + +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties index 652f8781ba..631bb91273 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties @@ -89,3 +89,7 @@ MediaPlayerPanel.VolumeIcon.text=\ \ \ \ \ Volume MediaPlayerPanel.progressLabel.text=00:00:00/00:00:00 MediaPlayerPanel.playButton.text=\u25ba MediaPlayerPanel.infoLabel.text=No Errors +MediaViewImagePanel.deleteTagButton.text=Delete Tag +MediaViewImagePanel.createTagButton.text=Create Tag +MediaViewImagePanel.jMenu1.text=jMenu1 +MediaViewImagePanel.editTagButton.text=Edit Tag Info diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED index 236fddfada..b18b79580c 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED @@ -151,6 +151,10 @@ MediaPlayerPanel.VolumeIcon.text=\ \ \ \ \ Volume MediaPlayerPanel.progressLabel.text=00:00:00/00:00:00 MediaPlayerPanel.playButton.text=\u25ba MediaPlayerPanel.infoLabel.text=No Errors +MediaViewImagePanel.deleteTagButton.text=Delete Tag +MediaViewImagePanel.createTagButton.text=Create Tag +MediaViewImagePanel.jMenu1.text=jMenu1 +MediaViewImagePanel.editTagButton.text=Edit Tag Info # {0} - tableName SQLiteViewer.readTable.errorText=Error getting rows for table: {0} # {0} - tableName diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.form b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.form index fb17c441db..ccfe83b2cc 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.form @@ -44,7 +44,7 @@ - + @@ -227,12 +227,15 @@ + + + @@ -242,12 +245,28 @@ + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java index ebf7f48444..b6ec14fba1 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java @@ -52,15 +52,21 @@ import javafx.scene.transform.Scale; import javafx.scene.transform.Translate; import javax.imageio.ImageIO; import javax.swing.JPanel; +import javax.swing.SwingUtilities; import org.controlsfx.control.MaskerPane; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.python.google.common.collect.Lists; +import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog; +import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog.TagNameAndComment; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.contentviewers.imagetagging.ControlType; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.datamodel.FileNode; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.TskCoreException; /** * Image viewer part of the Media View layered pane. Uses JavaFX to display the @@ -77,10 +83,11 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan private final boolean fxInited; private JFXPanel fxPanel; + private AbstractFile file; + private StoredTag lastFocused; private TopLevelTagsGroup imageGroup; private ImageTagCreator tagger; private ImageView fxImageView; - private Node focusedNode; private ScrollPane scrollPane; private final ProgressBar progressBar = new ProgressBar(); private final MaskerPane maskerPane = new MaskerPane(); @@ -127,14 +134,17 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan fxImageView = new ImageView(); // will hold image imageGroup = new TopLevelTagsGroup(fxImageView); deleteTagButton.setEnabled(false); + editTagButton.setEnabled(false); imageGroup.addFocusChangeListener((event) -> { - if(event.getType() == ControlType.NOT_FOCUSED || event.getNode() == fxImageView) { + if (event.getType() == ControlType.NOT_FOCUSED || event.getNode().equals(fxImageView)) { deleteTagButton.setEnabled(false); createTagButton.setEnabled(true); + editTagButton.setEnabled(false); } else if (event.getType() == ControlType.FOCUSED) { deleteTagButton.setEnabled(true); + editTagButton.setEnabled(true); createTagButton.setEnabled(false); - focusedNode = event.getNode(); + lastFocused = event.getNode(); } }); scrollPane = new ScrollPane(imageGroup); // scrolls and sizes imageview @@ -220,16 +230,10 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan Image fxImage = readImageTask.get(); imageGroup.getChildren().clear(); imageGroup.getChildren().add(fxImageView); + this.file = file; if (nonNull(fxImage)) { // We have a non-null image, so let's show it. fxImageView.setImage(fxImage); - tagger = new ImageTagCreator(fxImageView); - StoredTagListener newTagListener = (StoredTagEvent evt) -> { - StoredTag tag = evt.getTag(); - imageGroup.getChildren().add(tag); - }; - tagger.addNewTagListener(newTagListener); - imageGroup.getChildren().add(tagger); resetView(); scrollPane.setContent(imageGroup); } else { @@ -326,8 +330,11 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan jSeparator2 = new javax.swing.JToolBar.Separator(); zoomResetButton = new javax.swing.JButton(); jSeparator3 = new javax.swing.JToolBar.Separator(); + filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0)); createTagButton = new javax.swing.JButton(); jSeparator4 = new javax.swing.JToolBar.Separator(); + editTagButton = new javax.swing.JButton(); + jSeparator5 = new javax.swing.JToolBar.Separator(); deleteTagButton = new javax.swing.JButton(); org.openide.awt.Mnemonics.setLocalizedText(jMenu1, org.openide.util.NbBundle.getMessage(MediaViewImagePanel.class, "MediaViewImagePanel.jMenu1.text")); // NOI18N @@ -435,9 +442,11 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan }); toolbar.add(zoomResetButton); toolbar.add(jSeparator3); + toolbar.add(filler1); org.openide.awt.Mnemonics.setLocalizedText(createTagButton, org.openide.util.NbBundle.getMessage(MediaViewImagePanel.class, "MediaViewImagePanel.createTagButton.text")); // NOI18N createTagButton.setFocusable(false); + createTagButton.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); createTagButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); createTagButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); createTagButton.addActionListener(new java.awt.event.ActionListener() { @@ -448,8 +457,21 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan toolbar.add(createTagButton); toolbar.add(jSeparator4); + org.openide.awt.Mnemonics.setLocalizedText(editTagButton, org.openide.util.NbBundle.getMessage(MediaViewImagePanel.class, "MediaViewImagePanel.editTagButton.text")); // NOI18N + editTagButton.setFocusable(false); + editTagButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + editTagButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + editTagButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + editTagButtonActionPerformed(evt); + } + }); + toolbar.add(editTagButton); + toolbar.add(jSeparator5); + org.openide.awt.Mnemonics.setLocalizedText(deleteTagButton, org.openide.util.NbBundle.getMessage(MediaViewImagePanel.class, "MediaViewImagePanel.deleteTagButton.text")); // NOI18N deleteTagButton.setFocusable(false); + deleteTagButton.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); deleteTagButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); deleteTagButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); deleteTagButton.addActionListener(new java.awt.event.ActionListener() { @@ -503,16 +525,53 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan }//GEN-LAST:event_formComponentResized private void deleteTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTagButtonActionPerformed - imageGroup.deleteNode(focusedNode); + Platform.runLater(() -> { + imageGroup.deleteNode(lastFocused); + }); + try { + Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(lastFocused.getContentTag()); + } catch (TskCoreException ex) { + + } }//GEN-LAST:event_deleteTagButtonActionPerformed private void createTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_createTagButtonActionPerformed + Platform.runLater(() -> { + tagger = new ImageTagCreator(fxImageView); + StoredTagListener newTagListener = (StoredTagEvent event) -> { + StoredTag tag = event.getTag(); + imageGroup.getChildren().add(tag); + SwingUtilities.invokeLater(() -> { + TagNameAndComment result = GetTagNameAndCommentDialog.doDialog(); + if (result != null) { + try { + ContentTag t = Case.getCurrentCase().getServices().getTagsManager().addContentTag(file, + result.getTagName(), result.getComment()); + tag.addContentTag(t); + } catch (TskCoreException ex) { + Platform.runLater(() -> imageGroup.deleteNode(tag)); + } + } else { + Platform.runLater(() -> imageGroup.deleteNode(tag)); + } + }); + imageGroup.deleteNode(tagger); + }; + tagger.addNewTagListener(newTagListener); + imageGroup.getChildren().add(tagger); + }); }//GEN-LAST:event_createTagButtonActionPerformed + private void editTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editTagButtonActionPerformed + ContentTag t = lastFocused.getContentTag(); + }//GEN-LAST:event_editTagButtonActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton createTagButton; private javax.swing.JButton deleteTagButton; + private javax.swing.JButton editTagButton; + private javax.swing.Box.Filler filler1; private javax.swing.JMenu jMenu1; private javax.swing.JPopupMenu jPopupMenu1; private javax.swing.JPopupMenu jPopupMenu2; @@ -520,6 +579,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan private javax.swing.JToolBar.Separator jSeparator2; private javax.swing.JToolBar.Separator jSeparator3; private javax.swing.JToolBar.Separator jSeparator4; + private javax.swing.JToolBar.Separator jSeparator5; private javax.swing.JButton rotateLeftButton; private javax.swing.JButton rotateRightButton; private javax.swing.JTextField rotationTextField; diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/FocusChangeEvent.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/FocusChangeEvent.java index e487e01061..f8cac1a128 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/FocusChangeEvent.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/FocusChangeEvent.java @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.contentviewers.imagetagging; import java.util.EventObject; import javafx.event.Event; import javafx.event.EventType; -import javafx.scene.Node; /** * @@ -30,9 +29,9 @@ import javafx.scene.Node; public final class FocusChangeEvent extends EventObject{ private final EventType type; - private final Node focused; + private final StoredTag focused; - public FocusChangeEvent(Object source, EventType type, Node focused) { + public FocusChangeEvent(Object source, EventType type, StoredTag focused) { super(source); this.type = type; this.focused = focused; @@ -42,7 +41,7 @@ public final class FocusChangeEvent extends EventObject{ return type; } - public Node getNode() { + public StoredTag getNode() { return focused; } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagCreator.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagCreator.java index 146fbe1281..b0c114ada5 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagCreator.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagCreator.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.contentviewers.imagetagging; import java.util.ArrayList; import java.util.Collection; +import javafx.event.EventHandler; import javafx.scene.image.ImageView; import javafx.scene.input.MouseEvent; import javafx.scene.paint.Color; @@ -40,6 +41,10 @@ public final class ImageTagCreator extends Rectangle { private double lineThicknessAsPercent = 1.5; private final double minArea; private final Collection listeners; + + private final EventHandler mousePressed; + private final EventHandler mouseDragged; + private final EventHandler mouseReleased; /** * Adds tagging support to an image, where the 'tag' rectangle will be the @@ -60,11 +65,8 @@ public final class ImageTagCreator extends Rectangle { setStrokeWidth(lineThicknessPixels); minArea = lineThicknessPixels * lineThicknessPixels; setVisible(false); - - this.addEventHandler(ControlType.NOT_FOCUSED, (event) -> defaultSettings()); - - //Create a rectangle by left clicking on the image - image.setOnMousePressed((MouseEvent event) -> { + + this.mousePressed = (MouseEvent event) -> { if (event.isSecondaryButtonDown()) { return; } @@ -76,10 +78,11 @@ public final class ImageTagCreator extends Rectangle { setX(rectangleOriginX); setY(rectangleOriginY); - }); - - //Adjust the rectangle by dragging the left mouse button - image.setOnMouseDragged((MouseEvent event) -> { + }; + + image.addEventHandler(MouseEvent.MOUSE_PRESSED, this.mousePressed); + + this.mouseDragged = (MouseEvent event) -> { if (event.isSecondaryButtonDown()) { return; } @@ -107,16 +110,16 @@ public final class ImageTagCreator extends Rectangle { setY(newY); } setHeight(Math.abs(offsetY)); - }); - - image.setOnMouseReleased(event -> { + }; + + image.addEventHandler(MouseEvent.MOUSE_DRAGGED, this.mouseDragged); + + this.mouseReleased = event -> { if ((this.getWidth() - this.getStrokeWidth()) * (this.getHeight() - this.getStrokeWidth()) <= minArea) { defaultSettings(); return; - } - - //TODO - persist tag. + } //Notify listeners StoredTagEvent newTagEvent = new StoredTagEvent(this, new StoredTag(image, this.getX(), this.getY(), @@ -127,7 +130,22 @@ public final class ImageTagCreator extends Rectangle { }); defaultSettings(); + }; + + image.addEventHandler(MouseEvent.MOUSE_RELEASED, this.mouseReleased); + this.addEventHandler(ControlType.NOT_FOCUSED, (event) -> { + defaultSettings(); + image.removeEventHandler(MouseEvent.MOUSE_RELEASED, mouseReleased); + image.removeEventHandler(MouseEvent.MOUSE_DRAGGED, mouseDragged); + image.removeEventHandler(MouseEvent.MOUSE_PRESSED, mousePressed); }); + + this.addEventHandler(ControlType.DELETE, event -> { + defaultSettings(); + image.removeEventHandler(MouseEvent.MOUSE_RELEASED, mouseReleased); + image.removeEventHandler(MouseEvent.MOUSE_DRAGGED, mouseDragged); + image.removeEventHandler(MouseEvent.MOUSE_PRESSED, mousePressed); + }); } public void addNewTagListener(StoredTagListener listener) { diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTag.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTag.java index 6670639811..1a97918dee 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTag.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTag.java @@ -28,6 +28,7 @@ import javafx.scene.input.MouseEvent; import javafx.scene.paint.Color; import javafx.scene.shape.Circle; import javafx.scene.shape.Rectangle; +import org.sleuthkit.datamodel.ContentTag; /** * @@ -92,15 +93,32 @@ public final class StoredTag extends Group { physicalTag.setY(y); physicalTag.setWidth(x1 - x); physicalTag.setHeight(y1 - y); + + this.focusedProperty().addListener((ov, oldV, newV) -> { + if(!newV) { + System.out.println("NOT FOCUSED"); + } else { + System.out.println("GAINED FOCUS"); + } + }); this.addEventHandler(ControlType.NOT_FOCUSED, event -> ALL_CHILDREN.dispatchEvent(event)); this.addEventHandler(ControlType.FOCUSED, event -> ALL_CHILDREN.dispatchEvent(event)); this.addEventHandler(ControlType.DELETE, event -> ALL_CHILDREN.dispatchEvent(event)); } + + public void addContentTag(ContentTag t) { + physicalTag.linkContentTag(t); + } + + public ContentTag getContentTag() { + return physicalTag.getContentTag(); + } class PhysicalTag extends Rectangle { private final ImageView image; + private ContentTag tag; public PhysicalTag(ImageView image) { this.setStroke(Color.RED); @@ -120,10 +138,22 @@ public final class StoredTag extends Group { private void save() { //TODO - persist tag } + + public void linkContentTag(ContentTag t) { + tag = t; + } + + public ContentTag getContentTag() { + return tag; + } private ImageView getUnderlyingImage() { return image; } + + private class ImageRegion { + + } } class EditHandle extends Circle { diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/TopLevelTagsGroup.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/TopLevelTagsGroup.java index 6b7bca78e8..2a00df6f7a 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/TopLevelTagsGroup.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/TopLevelTagsGroup.java @@ -16,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.contentviewers.imagetagging; import com.sun.javafx.event.EventDispatchChainImpl; @@ -32,6 +31,7 @@ import javafx.scene.input.MouseEvent; * Top level group containing Image and all existing tags. */ public final class TopLevelTagsGroup extends Group { + private final EventDispatchChainImpl NO_OP_CHAIN = new EventDispatchChainImpl(); private final Collection listeners; @@ -49,50 +49,55 @@ public final class TopLevelTagsGroup extends Group { return; } - Node child = getTopLevelChild(e.getPickResult().getIntersectedNode()); - if (lastFocus == child) { - return; - } else if (lastFocus != null && lastFocus != child) { - resetFocus(lastFocus); + Node topLevelChild = e.getPickResult().getIntersectedNode(); + while (!this.getChildren().contains(topLevelChild)) { + topLevelChild = topLevelChild.getParent(); } - - child.getEventDispatcher().dispatchEvent(new Event(ControlType.FOCUSED), NO_OP_CHAIN); - listeners.forEach((listener) -> { - listener.focusChanged(new FocusChangeEvent(this, ControlType.FOCUSED, child)); - }); - - if(child != baseImage) { - child.toFront(); - } - lastFocus = child; + + requestFocus(topLevelChild); }); } - + public void addFocusChangeListener(FocusChangeListener fcl) { listeners.add(fcl); } - + private void resetFocus(Node n) { n.getEventDispatcher().dispatchEvent(new Event(ControlType.NOT_FOCUSED), NO_OP_CHAIN); - listeners.forEach((listener) -> { - listener.focusChanged(new FocusChangeEvent(this, ControlType.NOT_FOCUSED, n)); - }); - } - - public void deleteNode(Node dest) { - if(lastFocus == dest) { - resetFocus(lastFocus); - lastFocus = null; + if(n instanceof StoredTag) { + listeners.forEach((listener) -> { + listener.focusChanged(new FocusChangeEvent(this, ControlType.NOT_FOCUSED, (StoredTag) n)); + }); } - - dest.getEventDispatcher().dispatchEvent(new Event(ControlType.DELETE), NO_OP_CHAIN); } - private Node getTopLevelChild(Node selected) { - Node curr = selected; - while (!this.getChildren().contains(curr)) { - curr = curr.getParent(); + public void deleteNode(Node n) { + if (lastFocus == n) { + resetFocus(n); + lastFocus = null; } - return curr; + n.getEventDispatcher().dispatchEvent(new Event(ControlType.DELETE), NO_OP_CHAIN); + this.getChildren().remove(n); + } + + public void requestFocus(Node n) { + if (lastFocus == n) { + return; + } else if (lastFocus != null && lastFocus != n) { + resetFocus(lastFocus); + } + + n.getEventDispatcher().dispatchEvent(new Event(ControlType.FOCUSED), NO_OP_CHAIN); + if(n instanceof StoredTag) { + listeners.forEach((listener) -> { + listener.focusChanged(new FocusChangeEvent(this, ControlType.FOCUSED, (StoredTag) n)); + }); + } + + if (n != baseImage) { + n.toFront(); + } + + lastFocus = n; } } From 85a3124f9d5765e5822d53092d44345131692ecd Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 28 May 2019 16:20:03 -0400 Subject: [PATCH 003/115] 5061 add initial commit of Bing translator --- Core/ivy.xml | 3 + Core/nbproject/project.properties | 4 + Core/nbproject/project.xml | 8 + .../translators/BingTranslator.java | 158 ++++++++++++++++++ .../translators/BingTranslatorTest.java | 89 ++++++++++ 5 files changed, 262 insertions(+) create mode 100644 Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java create mode 100644 Core/test/unit/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorTest.java diff --git a/Core/ivy.xml b/Core/ivy.xml index 9dfd0fcf85..54ed532feb 100644 --- a/Core/ivy.xml +++ b/Core/ivy.xml @@ -45,6 +45,9 @@ + + + diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties index cf21c9a068..74a08fd53d 100644 --- a/Core/nbproject/project.properties +++ b/Core/nbproject/project.properties @@ -111,6 +111,10 @@ file.reference.grpc-context-1.19.0.jar=release/modules/ext/grpc-context-1.19.0.j file.reference.opencensus-api-0.19.2.jar=release/modules/ext/opencensus-api-0.19.2.jar file.reference.opencensus-contrib-http-util-0.19.2.jar=release/modules/ext/opencensus-contrib-http-util-0.19.2.jar file.reference.threetenbp-1.3.3.jar=release/modules/ext/threetenbp-1.3.3.jar +file.reference.okhttp-2.7.5-javadoc.jar=release/modules/ext/okhttp-2.7.5-javadoc.jar +file.reference.okhttp-2.7.5-sources.jar=release/modules/ext/okhttp-2.7.5-sources.jar +file.reference.okhttp-2.7.5.jar=release/modules/ext/okhttp-2.7.5.jar +file.reference.okio-1.6.0.jar=release/modules/ext/okio-1.6.0.jar javac.source=1.8 javac.compilerargs=-Xlint -Xlint:-serial license.file=../LICENSE-2.0.txt diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index 2a2fcd6676..624421be48 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -773,6 +773,14 @@ ext/google-api-services-translate-v2-rev20170525-1.27.0.jar release/modules/ext/google-api-services-translate-v2-rev20170525-1.27.0.jar + + ext/okhttp-2.7.5.jar + release/modules/ext/okhttp-2.7.5.jar + + + ext/okio-1.6.0.jar + release/modules/ext/okio-1.6.0.jar + diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java new file mode 100644 index 0000000000..892ecb5ac6 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java @@ -0,0 +1,158 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 Basis Technology Corp. + * Contact: carrier sleuthkit 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.texttranslation.translators; + +import java.io.*; +import com.google.gson.*; +import com.squareup.okhttp.*; +import java.awt.Component; +import javax.swing.JLabel; +import org.openide.util.NbBundle.Messages; + +/** + * Translates text by making HTTP requests to Bing Translator. + * This requires a valid subscription key for a Microsoft Azure account. + */ +@ServiceProvider(service = TextTranslator.class) +public class BingTranslator implements TextTranslator{ + // Insert the subscription key here. + private String subscriptionKey = ""; + + //In the String below, "en" is the target language. You can include multiple target + //languages separated by commas. A full list of supported languages is here: + //https://docs.microsoft.com/en-us/azure/cognitive-services/translator/language-support + private static final String URL = "https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=en"; + + // This sends messages to Microsoft. + private final OkHttpClient CLIENT = new OkHttpClient(); + + //We might want to make this a configurable setting for anyone who has a + //paid account that's willing to pay for long documents. + private final int MAX_STRING_LENGTH = 5000; + + /** + * Converts an input test to the JSON format required by Bing Translator, + * posts it to Microsoft, and returns the JSON text response. + * + * @param string The input text to be translated. + * @return The translation response as a JSON string + * @throws IOException if the request could not be executed due to cancellation, a connectivity problem or timeout. + */ + public String postTranslationRequest(String string) throws IOException { + MediaType mediaType = MediaType.parse("application/json"); + + JsonArray jsonArray = new JsonArray(); + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("Text", string); + jsonArray.add(jsonObject); + String bodyString = jsonArray.toString(); + + RequestBody body = RequestBody.create(mediaType, + bodyString); + Request request = new Request.Builder() + .url(URL).post(body) + .addHeader("Ocp-Apim-Subscription-Key", subscriptionKey) + .addHeader("Content-type", "application/json").build(); + Response response = CLIENT.newCall(request).execute(); + return response.body().string(); + } + + @Override + public String translate(String string) throws TranslationException { + if (subscriptionKey == null || subscriptionKey.isEmpty()) { + throw new TranslationException("Bing Translator has not been configured, credentials need to be specified"); + } + + //Translates some text into English, without specifying the source langauge. + + // HTML files were producing lots of white space at the end + string = string.trim(); + + //Google Translate required us to replace (\r\n|\n) with
+ //but Bing Translator doesn not have that requirement. + + //The free account has a maximum file size. If you have a paid account, + //you probably still want to limit file size to prevent accidentally + //translating very large documents. + if (string.length() > MAX_STRING_LENGTH) { + string = string.substring(0, MAX_STRING_LENGTH); + } + + try { + String response = postTranslationRequest(string); + return parseJSONResponse(response); + } catch (Throwable e) { + throw new TranslationException(e.getMessage()); + } + } + + @Messages({"BingTranslator.name.text=Bing Translator"}) + @Override + public String getName() { + return Bundle.BingTranslator_name_text(); + } + + @Override + public Component getComponent() { + return new JLabel("There are no settings to configure for Bing Translator"); + } + + @Override + public void saveSettings() { + //There are no settings to configure for Bing Translator + //Possible settings for the future: + //source language, target language, API key, path to JSON file of API key. + //We'll need test code to make sure that exceptions are thrown in all of + //those scenarios. + return; + } + + private String parseJSONResponse(String json_text) throws TranslationException { + /* Here is an example of the text we get from Bing when input is "gato", + the Spanish word for cat: + [ + { + "detectedLanguage": { + "language": "es", + "score": 1.0 + }, + "translations": [ + { + "text": "cat", + "to": "en" + } + ] + } + ] + */ + JsonParser parser = new JsonParser(); + try { + JsonArray responses = parser.parse(json_text).getAsJsonArray(); + //As far as I know, there's always exactly one item in the array. + JsonObject response0 = responses.get(0).getAsJsonObject(); + JsonArray translations = response0.getAsJsonArray("translations"); + JsonObject translation0 = translations.get(0).getAsJsonObject(); + String text = translation0.get("text").getAsString(); + return text; + } catch (IllegalStateException | ClassCastException | NullPointerException | IndexOutOfBoundsException e) { + throw new TranslationException("JSON text does not match Bing Translator scheme: " + e); + } + } +} \ No newline at end of file diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorTest.java new file mode 100644 index 0000000000..97512faa3c --- /dev/null +++ b/Core/test/unit/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorTest.java @@ -0,0 +1,89 @@ + +/* + * Autopsy Forensic Browser + * + * Copyright 2019 Basis Technology Corp. + * Contact: carrier sleuthkit 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.texttranslation.translators; + +import java.io.IOException; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; + +public class BingTranslatorTest { + @Test + public void testTranslate() throws Exception { + BingTranslator translator = new BingTranslator(); + String input = "gato"; + String expectedTranslation = "cat"; + runTest(translator, input, expectedTranslation); + } + + @Test + public void testQuickStartSentence() throws Exception { + BingTranslator translator = new BingTranslator(); + String input = "Willkommen bei Microsoft Translator. Raten Sie mal, wie viele Sprachen ich spreche."; + String expectedTranslation = "Welcome to Microsoft Translator. Guess how many languages I speak."; + runTest(translator, input, expectedTranslation); + } + + @Test + public void testCharacterEscapes() throws Exception { + BingTranslator translator = new BingTranslator(); + String input = "\"gato\"";; + String expectedTranslation = "Cat"; + runTest(translator, input, expectedTranslation); + } + + @Test + public void testLineBreaks() throws Exception { + BingTranslator translator = new BingTranslator(); + String input = "gato\nperro";; + String expectedTranslation = "cat\nDog"; + runTest(translator, input, expectedTranslation); + } + + /** + * Test whether translator throws an error. This should not be part of our + * regular testing, because we are limited to only 2MB of free translations + * ever. + * @param translator A BingTranslator + * @param input Text to translate + * @param expectedTranslation Not used unless you uncomment those lines. + */ + public void runTest(BingTranslator translator, String input, String expectedTranslation) { + String translation; + try { + translation = translator.translate(input); + } + catch (Throwable e) { + fail("Bing translation produced an exception: " + e.getMessage()); + return; + }; + + /* + //It's unrealistic to expect the same answer every time, but sometimes + //it's helpful to have this in your debug process. + System.out.println(translation); + assertEquals(expectedTranslation, translation); + */ + } +} From 1408fd289bd3aa7d61f93e7fa50b188b91f34e42 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 28 May 2019 18:08:24 -0400 Subject: [PATCH 004/115] 5061 allow Bing Translator credentials to be set by user --- .../translators/BingTranslator.java | 44 +++-- .../translators/BingTranslatorSettings.java | 80 ++++++++ .../BingTranslatorSettingsPanel.form | 85 +++++++++ .../BingTranslatorSettingsPanel.java | 171 ++++++++++++++++++ .../translators/Bundle.properties | 1 + .../translators/Bundle.properties-MERGED | 2 + .../translators/GoogleTranslator.java | 2 +- 7 files changed, 368 insertions(+), 17 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettings.java create mode 100644 Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form create mode 100644 Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java index 892ecb5ac6..1f790d14c3 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java @@ -19,12 +19,20 @@ package org.sleuthkit.autopsy.texttranslation.translators; -import java.io.*; -import com.google.gson.*; -import com.squareup.okhttp.*; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.squareup.okhttp.MediaType; +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.RequestBody; +import com.squareup.okhttp.Response; import java.awt.Component; -import javax.swing.JLabel; +import java.io.IOException; import org.openide.util.NbBundle.Messages; +import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.texttranslation.TextTranslator; +import org.sleuthkit.autopsy.texttranslation.TranslationException; /** * Translates text by making HTTP requests to Bing Translator. @@ -32,13 +40,13 @@ import org.openide.util.NbBundle.Messages; */ @ServiceProvider(service = TextTranslator.class) public class BingTranslator implements TextTranslator{ - // Insert the subscription key here. - private String subscriptionKey = ""; - //In the String below, "en" is the target language. You can include multiple target //languages separated by commas. A full list of supported languages is here: //https://docs.microsoft.com/en-us/azure/cognitive-services/translator/language-support private static final String URL = "https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=en"; + private final BingTranslatorSettingsPanel settingsPanel; + private final BingTranslatorSettings settings = new BingTranslatorSettings(); + // This sends messages to Microsoft. private final OkHttpClient CLIENT = new OkHttpClient(); @@ -47,6 +55,15 @@ public class BingTranslator implements TextTranslator{ //paid account that's willing to pay for long documents. private final int MAX_STRING_LENGTH = 5000; + + public BingTranslator(){ + settingsPanel = new BingTranslatorSettingsPanel(settings.getCredentials()); + } + + static String getMicrosftTranlatorUrl(){ + return URL; + } + /** * Converts an input test to the JSON format required by Bing Translator, * posts it to Microsoft, and returns the JSON text response. @@ -68,7 +85,7 @@ public class BingTranslator implements TextTranslator{ bodyString); Request request = new Request.Builder() .url(URL).post(body) - .addHeader("Ocp-Apim-Subscription-Key", subscriptionKey) + .addHeader("Ocp-Apim-Subscription-Key", settings.getCredentials()) .addHeader("Content-type", "application/json").build(); Response response = CLIENT.newCall(request).execute(); return response.body().string(); @@ -76,7 +93,7 @@ public class BingTranslator implements TextTranslator{ @Override public String translate(String string) throws TranslationException { - if (subscriptionKey == null || subscriptionKey.isEmpty()) { + if (settings.getCredentials() == null || settings.getCredentials().isEmpty()) { throw new TranslationException("Bing Translator has not been configured, credentials need to be specified"); } @@ -111,17 +128,12 @@ public class BingTranslator implements TextTranslator{ @Override public Component getComponent() { - return new JLabel("There are no settings to configure for Bing Translator"); + return settingsPanel; } @Override public void saveSettings() { - //There are no settings to configure for Bing Translator - //Possible settings for the future: - //source language, target language, API key, path to JSON file of API key. - //We'll need test code to make sure that exceptions are thrown in all of - //those scenarios. - return; + settings.setCredentials(settingsPanel.getCredentials()); } private String parseJSONResponse(String json_text) throws TranslationException { diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettings.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettings.java new file mode 100644 index 0000000000..6d6ef47b39 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettings.java @@ -0,0 +1,80 @@ +/* + * Autopsy + * + * Copyright 2019 Basis Technology Corp. + * Contact: carrier sleuthkit 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.texttranslation.translators; + +import org.apache.commons.lang3.StringUtils; +import org.sleuthkit.autopsy.coreutils.ModuleSettings; + +/** + * Class to handle the settings associated with the GoogleTranslator + */ +public final class BingTranslatorSettings { + + private static final String CREDENTIALS_KEY = "Credentials"; + private static final String BING_TRANSLATE_NAME = "BingTranslate"; + private static final String DEFAULT_CREDENTIALS = ""; + private String credentials; + + /** + * Construct a new GoogleTranslatorSettingsObject + */ + BingTranslatorSettings() { + loadSettings(); + } + + /** + * Get the path to the JSON credentials file + * + * @return the path to the credentials file + */ + String getCredentials() { + return credentials; + } + + /** + * Set the path to the JSON credentials file + * + * @param path the path to the credentials file + */ + void setCredentials(String creds) { + credentials = creds; + } + + + /** + * Load the settings into memory from their on disk storage + */ + void loadSettings() { + if (!ModuleSettings.configExists(BING_TRANSLATE_NAME)) { + ModuleSettings.makeConfigFile(BING_TRANSLATE_NAME); + } + if (ModuleSettings.settingExists(BING_TRANSLATE_NAME, CREDENTIALS_KEY)) { + credentials = ModuleSettings.getConfigSetting(BING_TRANSLATE_NAME, CREDENTIALS_KEY); + } else { + credentials = DEFAULT_CREDENTIALS; + } + } + + /** + * Save the setting from memory to their location on disk + */ + void saveSettings() { + ModuleSettings.setConfigSetting(BING_TRANSLATE_NAME, CREDENTIALS_KEY, credentials); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form new file mode 100644 index 0000000000..ae87b5a187 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java new file mode 100644 index 0000000000..ae8da0adcf --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java @@ -0,0 +1,171 @@ +/* + * Autopsy + * + * Copyright 2019 Basis Technology Corp. + * Contact: carrier sleuthkit 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.texttranslation.translators; + +import com.google.gson.JsonArray; +import com.google.gson.JsonParser; +import com.google.gson.JsonObject; +import com.squareup.okhttp.MediaType; +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.RequestBody; +import com.squareup.okhttp.Response; +import java.io.IOException; +import java.util.logging.Logger; + +/** + * Settings panel for the GoogleTranslator + */ +public class BingTranslatorSettingsPanel extends javax.swing.JPanel { + + private static final Logger logger = Logger.getLogger(BingTranslatorSettingsPanel.class.getName()); + private static final long serialVersionUID = 1L; + + /** + * Creates new form GoogleTranslatorSettingsPanel + */ + public BingTranslatorSettingsPanel(String credentials) { + initComponents(); + credentialsField.setText(credentials); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + credentialsLabel = new javax.swing.JLabel(); + credentialsField = new javax.swing.JTextField(); + warningLabel = new javax.swing.JLabel(); + testButton = new javax.swing.JButton(); + + org.openide.awt.Mnemonics.setLocalizedText(credentialsLabel, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "GoogleTranslatorSettingsPanel.credentialsLabel.text")); // NOI18N + + warningLabel.setForeground(new java.awt.Color(255, 0, 0)); + org.openide.awt.Mnemonics.setLocalizedText(warningLabel, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "GoogleTranslatorSettingsPanel.warningLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(testButton, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "BingTranslatorSettingsPanel.testButton.text")); // NOI18N + testButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + testButtonActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(warningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 551, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(layout.createSequentialGroup() + .addComponent(credentialsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 86, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(credentialsField, javax.swing.GroupLayout.DEFAULT_SIZE, 463, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(testButton) + .addGap(8, 8, 8)))) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(credentialsLabel) + .addComponent(credentialsField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(testButton)) + .addGap(31, 31, 31) + .addComponent(warningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(29, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + + private void testButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_testButtonActionPerformed + if (testTranslationSetup()) { + warningLabel.setText(""); + } else { + warningLabel.setText("Invalid translation credentials"); + } + }//GEN-LAST:event_testButtonActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JTextField credentialsField; + private javax.swing.JLabel credentialsLabel; + private javax.swing.JButton testButton; + private javax.swing.JLabel warningLabel; + // End of variables declaration//GEN-END:variables + /** + * Converts an input test to the JSON format required by Bing Translator, + * posts it to Microsoft, and returns the JSON text response. + * + * @param string The input text to be translated. + * + * @return The translation response as a JSON string + * + * @throws IOException if the request could not be executed due to + * cancellation, a connectivity problem or timeout. + */ + private boolean testTranslationSetup() { + String testString = "forense"; + MediaType mediaType = MediaType.parse("application/json"); + + JsonArray jsonArray = new JsonArray(); + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("Text", testString); + jsonArray.add(jsonObject); + String bodyString = jsonArray.toString(); + + RequestBody body = RequestBody.create(mediaType, + bodyString); + Request request = new Request.Builder() + .url(BingTranslator.getMicrosftTranlatorUrl()).post(body) + .addHeader("Ocp-Apim-Subscription-Key", credentialsField.getText()) + .addHeader("Content-type", "application/json").build(); + try { + Response response = new OkHttpClient().newCall(request).execute(); + JsonParser parser = new JsonParser(); + JsonArray responses = parser.parse(response.body().string()).getAsJsonArray(); + //As far as I know, there's always exactly one item in the array. + JsonObject response0 = responses.get(0).getAsJsonObject(); + JsonArray translations = response0.getAsJsonArray("translations"); + JsonObject translation0 = translations.get(0).getAsJsonObject(); + translation0.get("text").getAsString(); + return true; + } catch (IOException | IllegalStateException | ClassCastException | NullPointerException | IndexOutOfBoundsException e) { + return false; + } + + } + + /** + * Get the currently set path to the JSON credentials file + * + * @return the path to the credentials file specified in the textarea + */ + String getCredentials() { + return credentialsField.getText(); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties index 56782cdf33..024ddfadcd 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties @@ -2,3 +2,4 @@ GoogleTranslatorSettingsPanel.browseButton.text=Browse GoogleTranslatorSettingsPanel.credentialsLabel.text=Credentials: GoogleTranslatorSettingsPanel.warningLabel.text= GoogleTranslatorSettingsPanel.targetLanguageLabel.text=Target Language: +BingTranslatorSettingsPanel.testButton.text=Test diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED index b0e30f632c..bfe84cb856 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED @@ -1,3 +1,4 @@ +BingTranslator.name.text=Bing Translator GoogleTranslator.name.text=Google Translate GoogleTranslatorSettingsPanel.browseButton.text=Browse GoogleTranslatorSettingsPanel.credentialsLabel.text=Credentials: @@ -11,3 +12,4 @@ GoogleTranslatorSettingsPanel.fileChooser.confirmButton=Select GoogleTranslatorSettingsPanel.json.description=JSON Files GoogleTranslatorSettingsPanel.warningLabel.text= GoogleTranslatorSettingsPanel.targetLanguageLabel.text=Target Language: +BingTranslatorSettingsPanel.jButton1.text=Test diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslator.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslator.java index 38506ef936..f40b2129e2 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslator.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslator.java @@ -106,7 +106,7 @@ public final class GoogleTranslator implements TextTranslator { } /** - * Load the Google Cloud Translation service give the currently saved + * Load the Google Cloud Translation service given the currently saved * settings */ private void loadTranslator() { From f4e36841b116d35ed1a1c63409a6f13c359426fa Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 28 May 2019 18:09:24 -0400 Subject: [PATCH 005/115] 5061 minor ui panel tweak --- .../translators/BingTranslatorSettingsPanel.form | 4 ++-- .../translators/BingTranslatorSettingsPanel.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form index ae87b5a187..6acf950f40 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form @@ -44,9 +44,9 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java index ae8da0adcf..b49c3645b8 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java @@ -97,9 +97,9 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { .addComponent(credentialsLabel) .addComponent(credentialsField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(testButton)) - .addGap(31, 31, 31) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(warningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(29, Short.MAX_VALUE)) + .addContainerGap(49, Short.MAX_VALUE)) ); }// //GEN-END:initComponents From 5d63ab2bb8c76a37afbb5a7ec216c24b361aedb2 Mon Sep 17 00:00:00 2001 From: Raman Date: Wed, 29 May 2019 12:41:36 -0400 Subject: [PATCH 006/115] 4963: offload computation of S C & O columns to a background task, in order to speed up the loading of Data Results View table. --- .../datamodel/AbstractAbstractFileNode.java | 44 +++++++----- .../autopsy/datamodel/GetSCOTask.java | 71 +++++++++++++++++++ .../sleuthkit/autopsy/datamodel/SCOData.java | 56 +++++++++++++++ 3 files changed, 155 insertions(+), 16 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/SCOData.java diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java index fa4529e44b..d6b589f977 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java @@ -82,7 +82,8 @@ public abstract class AbstractAbstractFileNode extends A private static final Set CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.CURRENT_CASE, Case.Events.CONTENT_TAG_ADDED, Case.Events.CONTENT_TAG_DELETED, Case.Events.CR_COMMENT_CHANGED); - private static final ExecutorService translationPool; + // pool to run long running translation and getSCO tasks in backgound + private static final ExecutorService translationSCOPool; private static final Integer MAX_POOL_SIZE = 10; /** @@ -101,7 +102,7 @@ public abstract class AbstractAbstractFileNode extends A } if (UserPreferences.displayTranslatedFileNames()) { - AbstractAbstractFileNode.translationPool.submit(new TranslationTask( + AbstractAbstractFileNode.translationSCOPool.submit(new TranslationTask( new WeakReference<>(this), weakPcl)); } @@ -113,8 +114,8 @@ public abstract class AbstractAbstractFileNode extends A static { //Initialize this pool only once! This will be used by every instance of AAFN //to do their heavy duty SCO column and translation updates. - translationPool = Executors.newFixedThreadPool(MAX_POOL_SIZE, - new ThreadFactoryBuilder().setNameFormat("translation-task-thread-%d").build()); + translationSCOPool = Executors.newFixedThreadPool(MAX_POOL_SIZE, + new ThreadFactoryBuilder().setNameFormat("translation-and-sco-task-thread-%d").build()); } /** @@ -145,6 +146,7 @@ public abstract class AbstractAbstractFileNode extends A */ enum NodeSpecificEvents { TRANSLATION_AVAILABLE, + SCO_AVAILABLE } private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> { @@ -223,6 +225,18 @@ public abstract class AbstractAbstractFileNode extends A //Set the tooltip this.setShortDescription(content.getName()); updateSheet(new NodeProperty<>(ORIGINAL_NAME.toString(), ORIGINAL_NAME.toString(), NO_DESCR, content.getName())); + } else if (eventType.equals(NodeSpecificEvents.SCO_AVAILABLE.toString())) { + SCOData scoData = (SCOData)evt.getNewValue(); + if (scoData.getScoreAndDescription() != null) { + updateSheet(new NodeProperty<>(SCORE.toString(), SCORE.toString(), scoData.getScoreAndDescription().getRight(), scoData.getScoreAndDescription().getLeft())); + } + if (scoData.getComment() != null) { + updateSheet(new NodeProperty<>(COMMENT.toString(), COMMENT.toString(), NO_DESCR, scoData.getComment())); + } + if (scoData.getCountAndDescription() != null && + !UserPreferences.hideCentralRepoCommentsAndOccurrences()) { + updateSheet(new NodeProperty<>(OCCURRENCES.toString(), OCCURRENCES.toString(), scoData.getCountAndDescription().getRight(), scoData.getCountAndDescription().getLeft())); + } } }; /** @@ -368,18 +382,16 @@ public abstract class AbstractAbstractFileNode extends A properties.add(new NodeProperty<>(ORIGINAL_NAME.toString(), ORIGINAL_NAME.toString(), NO_DESCR, "")); } - //SCO column prereq info.. - List tags = getContentTagsFromDatabase(); - CorrelationAttributeInstance attribute = getCorrelationAttributeInstance(); - - Pair scoreAndDescription = getScorePropertyAndDescription(tags); - properties.add(new NodeProperty<>(SCORE.toString(), SCORE.toString(), scoreAndDescription.getRight(), scoreAndDescription.getLeft())); - DataResultViewerTable.HasCommentStatus comment = getCommentProperty(tags, attribute); - properties.add(new NodeProperty<>(COMMENT.toString(), COMMENT.toString(), NO_DESCR, comment)); - if (!UserPreferences.hideCentralRepoCommentsAndOccurrences()) { - Pair countAndDescription = getCountPropertyAndDescription(attribute); - properties.add(new NodeProperty<>(OCCURRENCES.toString(), OCCURRENCES.toString(), countAndDescription.getRight(), countAndDescription.getLeft())); - } + // Create place holders for S C O + properties.add(new NodeProperty<>(SCORE.toString(), SCORE.toString(), NO_DESCR, "")); + properties.add(new NodeProperty<>(COMMENT.toString(), COMMENT.toString(), NO_DESCR, "")); + properties.add(new NodeProperty<>(OCCURRENCES.toString(), OCCURRENCES.toString(), NO_DESCR, "")); + + + // Get the SCO columns data in a background task + AbstractAbstractFileNode.translationSCOPool.submit(new GetSCOTask( + new WeakReference<>(this), weakPcl)); + properties.add(new NodeProperty<>(LOCATION.toString(), LOCATION.toString(), NO_DESCR, getContentPath(content))); properties.add(new NodeProperty<>(MOD_TIME.toString(), MOD_TIME.toString(), NO_DESCR, ContentUtils.getStringTime(content.getMtime(), content))); properties.add(new NodeProperty<>(CHANGED_TIME.toString(), CHANGED_TIME.toString(), NO_DESCR, ContentUtils.getStringTime(content.getCtime(), content))); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java b/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java new file mode 100644 index 0000000000..e8a7b5b1f5 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java @@ -0,0 +1,71 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 Basis Technology Corp. + * Contact: carrier sleuthkit 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.datamodel; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.lang.ref.WeakReference; +import java.util.List; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; +import org.sleuthkit.autopsy.core.UserPreferences; +import org.sleuthkit.autopsy.events.AutopsyEvent; +import org.sleuthkit.datamodel.ContentTag; + +/** + * Background task to get Score, Comment and Occurrences values for a Abstract file node. + * + */ +class GetSCOTask implements Runnable { + + private final WeakReference> weakNodeRef; + private final PropertyChangeListener listener; + + public GetSCOTask(WeakReference> weakContentRef, PropertyChangeListener listener) { + this.weakNodeRef = weakContentRef; + this.listener = listener; + } + + @Override + public void run() { + AbstractAbstractFileNode fileNode = weakNodeRef.get(); + + //Check for stale reference + if (fileNode == null) { + return; + } + + // get the SCO column values + List tags = fileNode.getContentTagsFromDatabase(); + CorrelationAttributeInstance attribute = fileNode.getCorrelationAttributeInstance(); + + SCOData scoData = new SCOData(); + scoData.setScoreAndDescription(fileNode.getScorePropertyAndDescription(tags)); + scoData.setComment(fileNode.getCommentProperty(tags, attribute)); + if (!UserPreferences.hideCentralRepoCommentsAndOccurrences()) { + scoData.setCountAndDescription(fileNode.getCountPropertyAndDescription(attribute)); + } + + if (listener != null) { + listener.propertyChange(new PropertyChangeEvent( + AutopsyEvent.SourceType.LOCAL.toString(), + AbstractAbstractFileNode.NodeSpecificEvents.SCO_AVAILABLE.toString(), + null, scoData)); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/SCOData.java b/Core/src/org/sleuthkit/autopsy/datamodel/SCOData.java new file mode 100644 index 0000000000..a9dd99369d --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/SCOData.java @@ -0,0 +1,56 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 Basis Technology Corp. + * Contact: carrier sleuthkit 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.datamodel; + +import org.apache.commons.lang3.tuple.Pair; +import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; + +/** + * Container to bag the S C & O data for an abstract file node. + * + */ +class SCOData { + + private Pair scoreAndDescription = null; + private DataResultViewerTable.HasCommentStatus comment = null; + private Pair countAndDescription = null; + + Pair getScoreAndDescription() { + return scoreAndDescription; + } + + DataResultViewerTable.HasCommentStatus getComment() { + return comment; + } + + Pair getCountAndDescription() { + return countAndDescription; + } + + void setScoreAndDescription(Pair scoreAndDescription) { + this.scoreAndDescription = scoreAndDescription; + } + void setComment(DataResultViewerTable.HasCommentStatus comment) { + this.comment = comment; + } + void setCountAndDescription(Pair countAndDescription) { + this.countAndDescription = countAndDescription; + } + +} From 5221f35fad788b85b6b2359ef756006f70196850 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 30 May 2019 11:24:04 -0400 Subject: [PATCH 007/115] 5061 disable bing tests since service won't have credentials --- ...guageWrapper.java => LanguageWrapper.java} | 0 .../translators/BingTranslatorTest.java | 117 +++++++++--------- 2 files changed, 60 insertions(+), 57 deletions(-) rename Core/src/org/sleuthkit/autopsy/texttranslation/translators/{GoogleLanguageWrapper.java => LanguageWrapper.java} (100%) diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleLanguageWrapper.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/LanguageWrapper.java similarity index 100% rename from Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleLanguageWrapper.java rename to Core/src/org/sleuthkit/autopsy/texttranslation/translators/LanguageWrapper.java diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorTest.java index 97512faa3c..48c29543d3 100644 --- a/Core/test/unit/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorTest.java @@ -1,4 +1,3 @@ - /* * Autopsy Forensic Browser * @@ -17,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.texttranslation.translators; import java.io.IOException; @@ -28,62 +26,67 @@ import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; -public class BingTranslatorTest { +/** + * Tests for the BingTranslator translation service, these tests have been + * commented out because they require credentials to perform + */ +public class BingTranslatorTest { + @Test public void testTranslate() throws Exception { - BingTranslator translator = new BingTranslator(); - String input = "gato"; - String expectedTranslation = "cat"; - runTest(translator, input, expectedTranslation); - } - - @Test - public void testQuickStartSentence() throws Exception { - BingTranslator translator = new BingTranslator(); - String input = "Willkommen bei Microsoft Translator. Raten Sie mal, wie viele Sprachen ich spreche."; - String expectedTranslation = "Welcome to Microsoft Translator. Guess how many languages I speak."; - runTest(translator, input, expectedTranslation); - } - - @Test - public void testCharacterEscapes() throws Exception { - BingTranslator translator = new BingTranslator(); - String input = "\"gato\"";; - String expectedTranslation = "Cat"; - runTest(translator, input, expectedTranslation); - } - - @Test - public void testLineBreaks() throws Exception { - BingTranslator translator = new BingTranslator(); - String input = "gato\nperro";; - String expectedTranslation = "cat\nDog"; - runTest(translator, input, expectedTranslation); - } - - /** - * Test whether translator throws an error. This should not be part of our - * regular testing, because we are limited to only 2MB of free translations - * ever. - * @param translator A BingTranslator - * @param input Text to translate - * @param expectedTranslation Not used unless you uncomment those lines. - */ - public void runTest(BingTranslator translator, String input, String expectedTranslation) { - String translation; - try { - translation = translator.translate(input); - } - catch (Throwable e) { - fail("Bing translation produced an exception: " + e.getMessage()); - return; - }; - - /* - //It's unrealistic to expect the same answer every time, but sometimes - //it's helpful to have this in your debug process. - System.out.println(translation); - assertEquals(expectedTranslation, translation); - */ +// BingTranslator translator = new BingTranslator(); +// String input = "gato"; +// String expectedTranslation = "cat"; +// runTest(translator, input, expectedTranslation); } + +// @Test +// public void testQuickStartSentence() throws Exception { +// BingTranslator translator = new BingTranslator(); +// String input = "Willkommen bei Microsoft Translator. Raten Sie mal, wie viele Sprachen ich spreche."; +// String expectedTranslation = "Welcome to Microsoft Translator. Guess how many languages I speak."; +// runTest(translator, input, expectedTranslation); +// } +// +// @Test +// public void testCharacterEscapes() throws Exception { +// BingTranslator translator = new BingTranslator(); +// String input = "\"gato\"";; +// String expectedTranslation = "Cat"; +// runTest(translator, input, expectedTranslation); +// } +// +// @Test +// public void testLineBreaks() throws Exception { +// BingTranslator translator = new BingTranslator(); +// String input = "gato\nperro";; +// String expectedTranslation = "cat\nDog"; +// runTest(translator, input, expectedTranslation); +// } +// +// /** +// * Test whether translator throws an error. This should not be part of our +// * regular testing, because we are limited to only 2MB of free translations +// * ever. +// * @param translator A BingTranslator +// * @param input Text to translate +// * @param expectedTranslation Not used unless you uncomment those lines. +// */ +// public void runTest(BingTranslator translator, String input, String expectedTranslation) { +// String translation; +// try { +// translation = translator.translate(input); +// } +// catch (Throwable e) { +// fail("Bing translation produced an exception: " + e.getMessage()); +// return; +// }; +// +// /* +// //It's unrealistic to expect the same answer every time, but sometimes +// //it's helpful to have this in your debug process. +// System.out.println(translation); +// assertEquals(expectedTranslation, translation); +// */ +// } } From 0c5ac83644ad09a3e72b1371dfb58c2a8ea2ddf4 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 30 May 2019 11:24:38 -0400 Subject: [PATCH 008/115] 5061 adjust BingTranslator to use user specified settings --- .../translators/BingTranslator.java | 20 +-- .../translators/BingTranslatorSettings.java | 33 +++- .../BingTranslatorSettingsPanel.form | 80 ++++++++- .../BingTranslatorSettingsPanel.java | 169 ++++++++++++++---- .../translators/Bundle.properties | 3 + .../translators/Bundle.properties-MERGED | 5 +- .../GoogleTranslatorSettingsPanel.form | 4 +- .../GoogleTranslatorSettingsPanel.java | 8 +- .../translators/LanguageWrapper.java | 32 +++- 9 files changed, 284 insertions(+), 70 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java index 1f790d14c3..4aaba09ee5 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java @@ -43,7 +43,7 @@ public class BingTranslator implements TextTranslator{ //In the String below, "en" is the target language. You can include multiple target //languages separated by commas. A full list of supported languages is here: //https://docs.microsoft.com/en-us/azure/cognitive-services/translator/language-support - private static final String URL = "https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=en"; + private static final String BASE_URL = "https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to="; private final BingTranslatorSettingsPanel settingsPanel; private final BingTranslatorSettings settings = new BingTranslatorSettings(); @@ -57,11 +57,11 @@ public class BingTranslator implements TextTranslator{ public BingTranslator(){ - settingsPanel = new BingTranslatorSettingsPanel(settings.getCredentials()); + settingsPanel = new BingTranslatorSettingsPanel(settings.getCredentials(), settings.getTargetLanguageCode()); } - static String getMicrosftTranlatorUrl(){ - return URL; + private String getTranlatorUrl(){ + return BASE_URL + settings.getTargetLanguageCode(); } /** @@ -84,7 +84,7 @@ public class BingTranslator implements TextTranslator{ RequestBody body = RequestBody.create(mediaType, bodyString); Request request = new Request.Builder() - .url(URL).post(body) + .url(getTranlatorUrl()).post(body) .addHeader("Ocp-Apim-Subscription-Key", settings.getCredentials()) .addHeader("Content-type", "application/json").build(); Response response = CLIENT.newCall(request).execute(); @@ -96,11 +96,10 @@ public class BingTranslator implements TextTranslator{ if (settings.getCredentials() == null || settings.getCredentials().isEmpty()) { throw new TranslationException("Bing Translator has not been configured, credentials need to be specified"); } - + String toTranslate = string.trim(); //Translates some text into English, without specifying the source langauge. // HTML files were producing lots of white space at the end - string = string.trim(); //Google Translate required us to replace (\r\n|\n) with
//but Bing Translator doesn not have that requirement. @@ -108,12 +107,12 @@ public class BingTranslator implements TextTranslator{ //The free account has a maximum file size. If you have a paid account, //you probably still want to limit file size to prevent accidentally //translating very large documents. - if (string.length() > MAX_STRING_LENGTH) { - string = string.substring(0, MAX_STRING_LENGTH); + if (toTranslate.length() > MAX_STRING_LENGTH) { + toTranslate = toTranslate.substring(0, MAX_STRING_LENGTH); } try { - String response = postTranslationRequest(string); + String response = postTranslationRequest(toTranslate); return parseJSONResponse(response); } catch (Throwable e) { throw new TranslationException(e.getMessage()); @@ -134,6 +133,7 @@ public class BingTranslator implements TextTranslator{ @Override public void saveSettings() { settings.setCredentials(settingsPanel.getCredentials()); + settings.setTargetLanguageCode(settingsPanel.getTargetLanguageCode()); } private String parseJSONResponse(String json_text) throws TranslationException { diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettings.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettings.java index 6d6ef47b39..ca68adb77c 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettings.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettings.java @@ -29,7 +29,10 @@ public final class BingTranslatorSettings { private static final String CREDENTIALS_KEY = "Credentials"; private static final String BING_TRANSLATE_NAME = "BingTranslate"; private static final String DEFAULT_CREDENTIALS = ""; + private static final String DEFAULT_TARGET_LANGUAGE = "en"; + private static final String TARGET_LANGUAGE_CODE_KEY = "TargetLanguageCode"; private String credentials; + private String targetLanguageCode; /** * Construct a new GoogleTranslatorSettingsObject @@ -56,7 +59,6 @@ public final class BingTranslatorSettings { credentials = creds; } - /** * Load the settings into memory from their on disk storage */ @@ -69,6 +71,34 @@ public final class BingTranslatorSettings { } else { credentials = DEFAULT_CREDENTIALS; } + if (ModuleSettings.settingExists(BING_TRANSLATE_NAME, TARGET_LANGUAGE_CODE_KEY)) { + targetLanguageCode = ModuleSettings.getConfigSetting(BING_TRANSLATE_NAME, TARGET_LANGUAGE_CODE_KEY); + } else { + targetLanguageCode = DEFAULT_TARGET_LANGUAGE; + } + } + + /** + * Get the target language code + * + * @return the code used to identify the target language + */ + String getTargetLanguageCode() { + return targetLanguageCode; + } + + /** + * Set the target language code. If a blank code is specified it sets the + * default code instead. + * + * @param code the target language code to set + */ + void setTargetLanguageCode(String code) { + if (StringUtils.isBlank(code)) { + targetLanguageCode = DEFAULT_TARGET_LANGUAGE; + } else { + targetLanguageCode = code; + } } /** @@ -76,5 +106,6 @@ public final class BingTranslatorSettings { */ void saveSettings() { ModuleSettings.setConfigSetting(BING_TRANSLATE_NAME, CREDENTIALS_KEY, credentials); + ModuleSettings.setConfigSetting(BING_TRANSLATE_NAME, TARGET_LANGUAGE_CODE_KEY, targetLanguageCode); } } diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form index 6acf950f40..3e7e151bbf 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form @@ -16,13 +16,9 @@ - + - - - - @@ -31,6 +27,24 @@ + + + + + + + + + + + + + + + + + + @@ -44,9 +58,20 @@ - + + + + + + + + + + + + - + @@ -81,5 +106,46 @@
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java index b49c3645b8..5488ca9c62 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.texttranslation.translators; import com.google.gson.JsonArray; +import com.google.gson.JsonElement; import com.google.gson.JsonParser; import com.google.gson.JsonObject; import com.squareup.okhttp.MediaType; @@ -27,7 +28,13 @@ import com.squareup.okhttp.Request; import com.squareup.okhttp.RequestBody; import com.squareup.okhttp.Response; import java.io.IOException; +import java.util.Iterator; +import java.util.Map.Entry; +import java.util.logging.Level; import java.util.logging.Logger; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import org.apache.commons.lang3.StringUtils; /** * Settings panel for the GoogleTranslator @@ -36,13 +43,70 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { private static final Logger logger = Logger.getLogger(BingTranslatorSettingsPanel.class.getName()); private static final long serialVersionUID = 1L; + private static final String GET_TARGET_LANGUAGES_URL = "https://api.cognitive.microsofttranslator.com/languages?api-version=3.0&scope=translation"; + private String targetLanguageCode = ""; /** * Creates new form GoogleTranslatorSettingsPanel */ - public BingTranslatorSettingsPanel(String credentials) { + public BingTranslatorSettingsPanel(String credentials, String code) { initComponents(); credentialsField.setText(credentials); + credentialsField.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void insertUpdate(DocumentEvent e) { + firePropertyChange("SettingChanged", true, false); + } + + @Override + public void removeUpdate(DocumentEvent e) { + firePropertyChange("SettingChanged", true, false); + } + + @Override + public void changedUpdate(DocumentEvent e) { + firePropertyChange("SettingChanged", true, false); + } + + }); + targetLanguageCode = code; + populateComboBox(); + selectLanguageByCode(targetLanguageCode); + } + + private void populateComboBox() { + Request get_request = new Request.Builder() + .url(GET_TARGET_LANGUAGES_URL).build(); + try { + Response response = new OkHttpClient().newCall(get_request).execute(); + JsonParser parser = new JsonParser(); + String responseBody = response.body().string(); + JsonElement elementBody = parser.parse(responseBody); + JsonObject asObject = elementBody.getAsJsonObject(); + JsonElement translationElement = asObject.get("translation"); + JsonObject responses = translationElement.getAsJsonObject(); + for (Entry entry : responses.entrySet()) { + targetLanguageComboBox.addItem(new LanguageWrapper(entry.getKey(), entry.getValue().getAsJsonObject().get("name").getAsString())); + } + } catch (IOException | IllegalStateException | ClassCastException | NullPointerException | IndexOutOfBoundsException ex) { + logger.log(Level.WARNING, "Unable to get list of target languages or parse the result that was received", ex); + } + + } + + /** + * Given a language code select the corresponding language in the combo box + * if it is present + * + * @param code language code such as "en" for English + */ + private void selectLanguageByCode(String code) { + for (int i = 0; i < targetLanguageComboBox.getModel().getSize(); i++) { + if (targetLanguageComboBox.getModel().getElementAt(i).getLanguageCode().equals(code)) { + targetLanguageComboBox.setSelectedIndex(i); + break; + } + } } /** @@ -58,6 +122,11 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { credentialsField = new javax.swing.JTextField(); warningLabel = new javax.swing.JLabel(); testButton = new javax.swing.JButton(); + jLabel1 = new javax.swing.JLabel(); + targetLanguageComboBox = new javax.swing.JComboBox<>(); + jLabel2 = new javax.swing.JLabel(); + jSpinner1 = new javax.swing.JSpinner(); + jLabel3 = new javax.swing.JLabel(); org.openide.awt.Mnemonics.setLocalizedText(credentialsLabel, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "GoogleTranslatorSettingsPanel.credentialsLabel.text")); // NOI18N @@ -71,6 +140,20 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { } }); + org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "BingTranslatorSettingsPanel.jLabel1.text")); // NOI18N + + targetLanguageComboBox.addItemListener(new java.awt.event.ItemListener() { + public void itemStateChanged(java.awt.event.ItemEvent evt) { + targetLanguageComboBoxSelected(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "BingTranslatorSettingsPanel.jLabel2.text")); // NOI18N + + jSpinner1.setModel(new javax.swing.SpinnerNumberModel(5000, 5000, 500000, 5000)); + + org.openide.awt.Mnemonics.setLocalizedText(jLabel3, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "BingTranslatorSettingsPanel.jLabel3.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -78,16 +161,27 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(warningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 551, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() .addComponent(credentialsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 86, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(credentialsField, javax.swing.GroupLayout.DEFAULT_SIZE, 463, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(testButton) - .addGap(8, 8, 8)))) + .addGap(8, 8, 8)) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(warningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 551, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(layout.createSequentialGroup() + .addComponent(jLabel1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(targetLanguageComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 192, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(jLabel2) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jSpinner1, javax.swing.GroupLayout.PREFERRED_SIZE, 77, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel3))) + .addGap(0, 0, Short.MAX_VALUE)))) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -97,9 +191,18 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { .addComponent(credentialsLabel) .addComponent(credentialsField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(testButton)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel1) + .addComponent(targetLanguageComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel2) + .addComponent(jSpinner1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel3)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(warningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(49, Short.MAX_VALUE)) + .addContainerGap()) ); }// //GEN-END:initComponents @@ -111,9 +214,22 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { } }//GEN-LAST:event_testButtonActionPerformed + private void targetLanguageComboBoxSelected(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_targetLanguageComboBoxSelected + String selectedCode = ((LanguageWrapper) targetLanguageComboBox.getSelectedItem()).getLanguageCode(); + if (!StringUtils.isBlank(selectedCode) && !selectedCode.equals(targetLanguageCode)) { + targetLanguageCode = selectedCode; + firePropertyChange("SettingChanged", true, false); + } + }//GEN-LAST:event_targetLanguageComboBoxSelected + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JTextField credentialsField; private javax.swing.JLabel credentialsLabel; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel2; + private javax.swing.JLabel jLabel3; + private javax.swing.JSpinner jSpinner1; + private javax.swing.JComboBox targetLanguageComboBox; private javax.swing.JButton testButton; private javax.swing.JLabel warningLabel; // End of variables declaration//GEN-END:variables @@ -129,35 +245,7 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { * cancellation, a connectivity problem or timeout. */ private boolean testTranslationSetup() { - String testString = "forense"; - MediaType mediaType = MediaType.parse("application/json"); - - JsonArray jsonArray = new JsonArray(); - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("Text", testString); - jsonArray.add(jsonObject); - String bodyString = jsonArray.toString(); - - RequestBody body = RequestBody.create(mediaType, - bodyString); - Request request = new Request.Builder() - .url(BingTranslator.getMicrosftTranlatorUrl()).post(body) - .addHeader("Ocp-Apim-Subscription-Key", credentialsField.getText()) - .addHeader("Content-type", "application/json").build(); - try { - Response response = new OkHttpClient().newCall(request).execute(); - JsonParser parser = new JsonParser(); - JsonArray responses = parser.parse(response.body().string()).getAsJsonArray(); - //As far as I know, there's always exactly one item in the array. - JsonObject response0 = responses.get(0).getAsJsonObject(); - JsonArray translations = response0.getAsJsonArray("translations"); - JsonObject translation0 = translations.get(0).getAsJsonObject(); - translation0.get("text").getAsString(); - return true; - } catch (IOException | IllegalStateException | ClassCastException | NullPointerException | IndexOutOfBoundsException e) { - return false; - } - + return true; } /** @@ -168,4 +256,13 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { String getCredentials() { return credentialsField.getText(); } + + /** + * Get the currently selected target language code + * + * @return the target language code of the language selected in the combobox + */ + String getTargetLanguageCode() { + return targetLanguageCode; + } } diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties index 024ddfadcd..888cb51018 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties @@ -3,3 +3,6 @@ GoogleTranslatorSettingsPanel.credentialsLabel.text=Credentials: GoogleTranslatorSettingsPanel.warningLabel.text= GoogleTranslatorSettingsPanel.targetLanguageLabel.text=Target Language: BingTranslatorSettingsPanel.testButton.text=Test +BingTranslatorSettingsPanel.jLabel1.text=Target Language: +BingTranslatorSettingsPanel.jLabel2.text=Translation Size: +BingTranslatorSettingsPanel.jLabel3.text=characters diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED index bfe84cb856..2fb4ea5ef4 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED @@ -12,4 +12,7 @@ GoogleTranslatorSettingsPanel.fileChooser.confirmButton=Select GoogleTranslatorSettingsPanel.json.description=JSON Files GoogleTranslatorSettingsPanel.warningLabel.text= GoogleTranslatorSettingsPanel.targetLanguageLabel.text=Target Language: -BingTranslatorSettingsPanel.jButton1.text=Test +BingTranslatorSettingsPanel.testButton.text=Test +BingTranslatorSettingsPanel.jLabel1.text=Target Language: +BingTranslatorSettingsPanel.jLabel2.text=Translation Size: +BingTranslatorSettingsPanel.jLabel3.text=characters diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.form index 97a10b500f..1a78f115ac 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.form @@ -98,7 +98,7 @@
- + @@ -119,4 +119,4 @@ - + \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java index fbb957413b..83ad5cf302 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java @@ -118,7 +118,7 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { targetLanguageComboBox.removeAllItems(); if (!listSupportedLanguages.isEmpty()) { listSupportedLanguages.forEach((lang) -> { - targetLanguageComboBox.addItem(new GoogleLanguageWrapper(lang)); + targetLanguageComboBox.addItem(new LanguageWrapper(lang)); }); selectLanguageByCode(targetLanguageCode); targetLanguageComboBox.addItemListener(listener); @@ -145,7 +145,7 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { */ private void selectLanguageByCode(String code) { for (int i = 0; i < targetLanguageComboBox.getModel().getSize(); i++) { - if (targetLanguageComboBox.getItemAt(i).getLanguage().getCode().equals(code)) { + if (targetLanguageComboBox.getItemAt(i).getLanguageCode().equals(code)) { targetLanguageComboBox.setSelectedIndex(i); return; } @@ -253,7 +253,7 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { private javax.swing.JButton browseButton; private javax.swing.JLabel credentialsLabel; private javax.swing.JTextField credentialsPathField; - private javax.swing.JComboBox targetLanguageComboBox; + private javax.swing.JComboBox targetLanguageComboBox; private javax.swing.JLabel targetLanguageLabel; private javax.swing.JLabel warningLabel; // End of variables declaration//GEN-END:variables @@ -284,7 +284,7 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { @Override public void itemStateChanged(java.awt.event.ItemEvent evt) { - String selectedCode = ((GoogleLanguageWrapper) targetLanguageComboBox.getSelectedItem()).getLanguage().getCode(); + String selectedCode = ((LanguageWrapper) targetLanguageComboBox.getSelectedItem()).getLanguageCode(); if (!StringUtils.isBlank(selectedCode) && !selectedCode.equals(targetLanguageCode)) { targetLanguageCode = selectedCode; populateTargetLanguageComboBox(); diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/LanguageWrapper.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/LanguageWrapper.java index c61ed1c948..3c3c048469 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/LanguageWrapper.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/LanguageWrapper.java @@ -21,19 +21,33 @@ package org.sleuthkit.autopsy.texttranslation.translators; import com.google.cloud.translate.Language; /** - * Wrapper for the Language class + * Wrapper for Language definitions used by translators */ -class GoogleLanguageWrapper { +class LanguageWrapper { - private final Language language; + private final String languageCode; + private final String languageDisplayName; /** - * Create a new GoogleLanguageWrapper + * Create a new LanguageWrapper to wrap the google language object * * @param lang the Language object to wrap */ - GoogleLanguageWrapper(Language lang) { - language = lang; + LanguageWrapper(Language language) { + languageCode = language.getCode(); + languageDisplayName = language.getName(); + } + + /** + * Create a new LanguageWrapper to wrap json elements that identify a + * language for microsofts translation service + * + * @param code the code which uniquely identifies a language + * @param name the name of the language + */ + LanguageWrapper(String code, String name) { + languageCode = code; + languageDisplayName = name; } /** @@ -41,14 +55,14 @@ class GoogleLanguageWrapper { * * @return the wrapped Language */ - Language getLanguage() { - return language; + String getLanguageCode() { + return languageCode; } @Override public String toString() { //toString overridden so that the jComboBox in the GoogleTranslatorSettingsPanel will display the name of the language - return language.getName(); + return languageDisplayName; } } From 90a002efee982071e665ac8156f44f1adaa088c7 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 30 May 2019 12:21:05 -0400 Subject: [PATCH 009/115] 5061 add test button to Bing translator settings panel --- .../translators/BingTranslator.java | 6 +- .../BingTranslatorSettingsPanel.form | 93 ++++++++++---- .../BingTranslatorSettingsPanel.java | 117 +++++++++++++----- .../translators/Bundle.properties | 9 +- .../translators/Bundle.properties-MERGED | 9 +- .../translators/LanguageWrapper.java | 2 +- 6 files changed, 175 insertions(+), 61 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java index 4aaba09ee5..1d27d8ce33 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java @@ -60,8 +60,8 @@ public class BingTranslator implements TextTranslator{ settingsPanel = new BingTranslatorSettingsPanel(settings.getCredentials(), settings.getTargetLanguageCode()); } - private String getTranlatorUrl(){ - return BASE_URL + settings.getTargetLanguageCode(); + static String getTranlatorUrl(String languageCode){ + return BASE_URL + languageCode; } /** @@ -84,7 +84,7 @@ public class BingTranslator implements TextTranslator{ RequestBody body = RequestBody.create(mediaType, bodyString); Request request = new Request.Builder() - .url(getTranlatorUrl()).post(body) + .url(getTranlatorUrl(settings.getTargetLanguageCode())).post(body) .addHeader("Ocp-Apim-Subscription-Key", settings.getCredentials()) .addHeader("Content-type", "application/json").build(); Response response = CLIENT.newCall(request).execute(); diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form index 3e7e151bbf..944cc3d124 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form @@ -23,24 +23,38 @@ - - - + - + - + - + + + + - - - + + + + + + + + + + + + + + + + @@ -56,20 +70,27 @@ - - + - - - + + + - + + + + + + + + + @@ -106,10 +127,10 @@ - + - + @@ -126,24 +147,52 @@ - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java index 5488ca9c62..4282ecbc63 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java @@ -44,6 +44,7 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { private static final Logger logger = Logger.getLogger(BingTranslatorSettingsPanel.class.getName()); private static final long serialVersionUID = 1L; private static final String GET_TARGET_LANGUAGES_URL = "https://api.cognitive.microsofttranslator.com/languages?api-version=3.0&scope=translation"; + private static final String DEFUALT_TEST_STRING = "traducción exitoso"; //spanish which should translate to something along the lines of translation successful private String targetLanguageCode = ""; /** @@ -51,6 +52,7 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { */ public BingTranslatorSettingsPanel(String credentials, String code) { initComponents(); + credentialsField.setText(credentials); credentialsField.getDocument().addDocumentListener(new DocumentListener() { @Override @@ -122,11 +124,15 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { credentialsField = new javax.swing.JTextField(); warningLabel = new javax.swing.JLabel(); testButton = new javax.swing.JButton(); - jLabel1 = new javax.swing.JLabel(); + targetLanguageLabel = new javax.swing.JLabel(); targetLanguageComboBox = new javax.swing.JComboBox<>(); - jLabel2 = new javax.swing.JLabel(); - jSpinner1 = new javax.swing.JSpinner(); - jLabel3 = new javax.swing.JLabel(); + translationSizeLabel = new javax.swing.JLabel(); + translationSizeSpinner = new javax.swing.JSpinner(); + unitsLabel = new javax.swing.JLabel(); + testUntranslatedTextField = new javax.swing.JTextField(); + untranslatedLabel = new javax.swing.JLabel(); + resultLabel = new javax.swing.JLabel(); + testResultValueLabel = new javax.swing.JLabel(); org.openide.awt.Mnemonics.setLocalizedText(credentialsLabel, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "GoogleTranslatorSettingsPanel.credentialsLabel.text")); // NOI18N @@ -140,7 +146,7 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { } }); - org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "BingTranslatorSettingsPanel.jLabel1.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(targetLanguageLabel, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "BingTranslatorSettingsPanel.targetLanguageLabel.text")); // NOI18N targetLanguageComboBox.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent evt) { @@ -148,11 +154,19 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { } }); - org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "BingTranslatorSettingsPanel.jLabel2.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(translationSizeLabel, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "BingTranslatorSettingsPanel.translationSizeLabel.text")); // NOI18N - jSpinner1.setModel(new javax.swing.SpinnerNumberModel(5000, 5000, 500000, 5000)); + translationSizeSpinner.setModel(new javax.swing.SpinnerNumberModel(5000, 5000, 500000, 5000)); - org.openide.awt.Mnemonics.setLocalizedText(jLabel3, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "BingTranslatorSettingsPanel.jLabel3.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(unitsLabel, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "BingTranslatorSettingsPanel.unitsLabel.text")); // NOI18N + + testUntranslatedTextField.setText(DEFUALT_TEST_STRING); + + org.openide.awt.Mnemonics.setLocalizedText(untranslatedLabel, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "BingTranslatorSettingsPanel.untranslatedLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(resultLabel, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "BingTranslatorSettingsPanel.resultLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(testResultValueLabel, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "BingTranslatorSettingsPanel.testResultValueLabel.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -165,22 +179,32 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { .addComponent(credentialsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 86, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(credentialsField, javax.swing.GroupLayout.DEFAULT_SIZE, 463, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(testButton) - .addGap(8, 8, 8)) + .addGap(67, 67, 67)) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addComponent(warningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 551, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(layout.createSequentialGroup() - .addComponent(jLabel1) + .addComponent(targetLanguageLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(targetLanguageComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 192, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(layout.createSequentialGroup() - .addComponent(jLabel2) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(translationSizeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(testButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jSpinner1, javax.swing.GroupLayout.PREFERRED_SIZE, 77, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jLabel3))) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(translationSizeSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, 77, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(unitsLabel)) + .addGroup(layout.createSequentialGroup() + .addComponent(untranslatedLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(testUntranslatedTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 140, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(resultLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(testResultValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))) .addGap(0, 0, Short.MAX_VALUE)))) ); layout.setVerticalGroup( @@ -189,18 +213,24 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(credentialsLabel) - .addComponent(credentialsField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(testButton)) + .addComponent(credentialsField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabel1) + .addComponent(targetLanguageLabel) .addComponent(targetLanguageComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabel2) - .addComponent(jSpinner1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jLabel3)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(translationSizeLabel) + .addComponent(translationSizeSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(unitsLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(testButton) + .addComponent(testUntranslatedTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(untranslatedLabel) + .addComponent(resultLabel) + .addComponent(testResultValueLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(warningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE) .addContainerGap()) ); @@ -225,12 +255,16 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JTextField credentialsField; private javax.swing.JLabel credentialsLabel; - private javax.swing.JLabel jLabel1; - private javax.swing.JLabel jLabel2; - private javax.swing.JLabel jLabel3; - private javax.swing.JSpinner jSpinner1; + private javax.swing.JLabel resultLabel; private javax.swing.JComboBox targetLanguageComboBox; + private javax.swing.JLabel targetLanguageLabel; private javax.swing.JButton testButton; + private javax.swing.JLabel testResultValueLabel; + private javax.swing.JTextField testUntranslatedTextField; + private javax.swing.JLabel translationSizeLabel; + private javax.swing.JSpinner translationSizeSpinner; + private javax.swing.JLabel unitsLabel; + private javax.swing.JLabel untranslatedLabel; private javax.swing.JLabel warningLabel; // End of variables declaration//GEN-END:variables /** @@ -245,7 +279,32 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { * cancellation, a connectivity problem or timeout. */ private boolean testTranslationSetup() { - return true; + MediaType mediaType = MediaType.parse("application/json"); + JsonArray jsonArray = new JsonArray(); + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("Text", testUntranslatedTextField.getText()); + jsonArray.add(jsonObject); + String bodyString = jsonArray.toString(); + + RequestBody body = RequestBody.create(mediaType, + bodyString); + Request request = new Request.Builder() + .url(BingTranslator.getTranlatorUrl(targetLanguageCode)).post(body) + .addHeader("Ocp-Apim-Subscription-Key", credentialsField.getText()) + .addHeader("Content-type", "application/json").build(); + try { + Response response = new OkHttpClient().newCall(request).execute(); + JsonParser parser = new JsonParser(); + JsonArray responses = parser.parse(response.body().string()).getAsJsonArray(); + //As far as I know, there's always exactly one item in the array. + JsonObject response0 = responses.get(0).getAsJsonObject(); + JsonArray translations = response0.getAsJsonArray("translations"); + JsonObject translation0 = translations.get(0).getAsJsonObject(); + testResultValueLabel.setText(translation0.get("text").getAsString()); + return true; + } catch (IOException | IllegalStateException | ClassCastException | NullPointerException | IndexOutOfBoundsException e) { + return false; + } } /** diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties index 888cb51018..adf27cddfa 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties @@ -3,6 +3,9 @@ GoogleTranslatorSettingsPanel.credentialsLabel.text=Credentials: GoogleTranslatorSettingsPanel.warningLabel.text= GoogleTranslatorSettingsPanel.targetLanguageLabel.text=Target Language: BingTranslatorSettingsPanel.testButton.text=Test -BingTranslatorSettingsPanel.jLabel1.text=Target Language: -BingTranslatorSettingsPanel.jLabel2.text=Translation Size: -BingTranslatorSettingsPanel.jLabel3.text=characters +BingTranslatorSettingsPanel.testResultValueLabel.text= +BingTranslatorSettingsPanel.resultLabel.text=Result: +BingTranslatorSettingsPanel.untranslatedLabel.text=Untranslated: +BingTranslatorSettingsPanel.translationSizeLabel.text=Translation Size: +BingTranslatorSettingsPanel.targetLanguageLabel.text=Target Language: +BingTranslatorSettingsPanel.unitsLabel.text=characters diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED index 2fb4ea5ef4..01c6123934 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED @@ -13,6 +13,9 @@ GoogleTranslatorSettingsPanel.json.description=JSON Files GoogleTranslatorSettingsPanel.warningLabel.text= GoogleTranslatorSettingsPanel.targetLanguageLabel.text=Target Language: BingTranslatorSettingsPanel.testButton.text=Test -BingTranslatorSettingsPanel.jLabel1.text=Target Language: -BingTranslatorSettingsPanel.jLabel2.text=Translation Size: -BingTranslatorSettingsPanel.jLabel3.text=characters +BingTranslatorSettingsPanel.testResultValueLabel.text= +BingTranslatorSettingsPanel.resultLabel.text=Result: +BingTranslatorSettingsPanel.untranslatedLabel.text=Untranslated: +BingTranslatorSettingsPanel.translationSizeLabel.text=Translation Size: +BingTranslatorSettingsPanel.targetLanguageLabel.text=Target Language: +BingTranslatorSettingsPanel.unitsLabel.text=characters diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/LanguageWrapper.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/LanguageWrapper.java index 3c3c048469..2fa308291b 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/LanguageWrapper.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/LanguageWrapper.java @@ -61,7 +61,7 @@ class LanguageWrapper { @Override public String toString() { - //toString overridden so that the jComboBox in the GoogleTranslatorSettingsPanel will display the name of the language + //toString overridden so that the jComboBox in the TranslatorSettingsPanels will display the name of the language return languageDisplayName; } From d2bf1777f293b26d1fbde974274da0d1a7889e56 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 30 May 2019 12:35:24 -0400 Subject: [PATCH 010/115] 5061 reword credentials to be authentication key for bing translator --- .../translators/BingTranslator.java | 15 ++-- .../translators/BingTranslatorSettings.java | 32 +++++---- .../BingTranslatorSettingsPanel.form | 37 ++++++---- .../BingTranslatorSettingsPanel.java | 68 ++++++++++--------- .../translators/Bundle.properties | 3 +- 5 files changed, 86 insertions(+), 69 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java index 1d27d8ce33..db17236edc 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java @@ -46,18 +46,15 @@ public class BingTranslator implements TextTranslator{ private static final String BASE_URL = "https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to="; private final BingTranslatorSettingsPanel settingsPanel; private final BingTranslatorSettings settings = new BingTranslatorSettings(); - - // This sends messages to Microsoft. - private final OkHttpClient CLIENT = new OkHttpClient(); - + private final OkHttpClient CLIENT = new OkHttpClient(); //We might want to make this a configurable setting for anyone who has a //paid account that's willing to pay for long documents. private final int MAX_STRING_LENGTH = 5000; public BingTranslator(){ - settingsPanel = new BingTranslatorSettingsPanel(settings.getCredentials(), settings.getTargetLanguageCode()); + settingsPanel = new BingTranslatorSettingsPanel(settings.getAuthenticationKey(), settings.getTargetLanguageCode()); } static String getTranlatorUrl(String languageCode){ @@ -85,7 +82,7 @@ public class BingTranslator implements TextTranslator{ bodyString); Request request = new Request.Builder() .url(getTranlatorUrl(settings.getTargetLanguageCode())).post(body) - .addHeader("Ocp-Apim-Subscription-Key", settings.getCredentials()) + .addHeader("Ocp-Apim-Subscription-Key", settings.getAuthenticationKey()) .addHeader("Content-type", "application/json").build(); Response response = CLIENT.newCall(request).execute(); return response.body().string(); @@ -93,8 +90,8 @@ public class BingTranslator implements TextTranslator{ @Override public String translate(String string) throws TranslationException { - if (settings.getCredentials() == null || settings.getCredentials().isEmpty()) { - throw new TranslationException("Bing Translator has not been configured, credentials need to be specified"); + if (settings.getAuthenticationKey() == null || settings.getAuthenticationKey().isEmpty()) { + throw new TranslationException("Bing Translator has not been configured, authentication key needs to be specified"); } String toTranslate = string.trim(); //Translates some text into English, without specifying the source langauge. @@ -132,7 +129,7 @@ public class BingTranslator implements TextTranslator{ @Override public void saveSettings() { - settings.setCredentials(settingsPanel.getCredentials()); + settings.setAuthenticationKey(settingsPanel.getAuthenticationKey()); settings.setTargetLanguageCode(settingsPanel.getTargetLanguageCode()); } diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettings.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettings.java index ca68adb77c..039c24c480 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettings.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettings.java @@ -26,12 +26,12 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings; */ public final class BingTranslatorSettings { - private static final String CREDENTIALS_KEY = "Credentials"; + private static final String AUTHENTICATION_KEY = "Credentials"; private static final String BING_TRANSLATE_NAME = "BingTranslate"; - private static final String DEFAULT_CREDENTIALS = ""; + private static final String DEFAULT_AUTHENTICATION = ""; private static final String DEFAULT_TARGET_LANGUAGE = "en"; private static final String TARGET_LANGUAGE_CODE_KEY = "TargetLanguageCode"; - private String credentials; + private String authenticationKey; private String targetLanguageCode; /** @@ -42,21 +42,23 @@ public final class BingTranslatorSettings { } /** - * Get the path to the JSON credentials file + * Get the Authentication key to be used for the Microsoft translation + * service * - * @return the path to the credentials file + * @return the Authentication key for the service */ - String getCredentials() { - return credentials; + String getAuthenticationKey() { + return authenticationKey; } /** - * Set the path to the JSON credentials file + * Set the Authentication key to be used for the Microsoft translation + * service * - * @param path the path to the credentials file + * @param authKey the Authentication key for the service */ - void setCredentials(String creds) { - credentials = creds; + void setAuthenticationKey(String authKey) { + authenticationKey = authKey; } /** @@ -66,10 +68,10 @@ public final class BingTranslatorSettings { if (!ModuleSettings.configExists(BING_TRANSLATE_NAME)) { ModuleSettings.makeConfigFile(BING_TRANSLATE_NAME); } - if (ModuleSettings.settingExists(BING_TRANSLATE_NAME, CREDENTIALS_KEY)) { - credentials = ModuleSettings.getConfigSetting(BING_TRANSLATE_NAME, CREDENTIALS_KEY); + if (ModuleSettings.settingExists(BING_TRANSLATE_NAME, AUTHENTICATION_KEY)) { + authenticationKey = ModuleSettings.getConfigSetting(BING_TRANSLATE_NAME, AUTHENTICATION_KEY); } else { - credentials = DEFAULT_CREDENTIALS; + authenticationKey = DEFAULT_AUTHENTICATION; } if (ModuleSettings.settingExists(BING_TRANSLATE_NAME, TARGET_LANGUAGE_CODE_KEY)) { targetLanguageCode = ModuleSettings.getConfigSetting(BING_TRANSLATE_NAME, TARGET_LANGUAGE_CODE_KEY); @@ -105,7 +107,7 @@ public final class BingTranslatorSettings { * Save the setting from memory to their location on disk */ void saveSettings() { - ModuleSettings.setConfigSetting(BING_TRANSLATE_NAME, CREDENTIALS_KEY, credentials); + ModuleSettings.setConfigSetting(BING_TRANSLATE_NAME, AUTHENTICATION_KEY, authenticationKey); ModuleSettings.setConfigSetting(BING_TRANSLATE_NAME, TARGET_LANGUAGE_CODE_KEY, targetLanguageCode); } } diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form index 944cc3d124..5b275b52e3 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form @@ -19,31 +19,37 @@ - - - - - - - + + + + + + + + + + + + - + + @@ -57,7 +63,7 @@ - + @@ -68,8 +74,8 @@ - - + + @@ -98,14 +104,19 @@ - + - + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java index 4282ecbc63..b95887cea1 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java @@ -28,7 +28,6 @@ import com.squareup.okhttp.Request; import com.squareup.okhttp.RequestBody; import com.squareup.okhttp.Response; import java.io.IOException; -import java.util.Iterator; import java.util.Map.Entry; import java.util.logging.Level; import java.util.logging.Logger; @@ -44,17 +43,17 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { private static final Logger logger = Logger.getLogger(BingTranslatorSettingsPanel.class.getName()); private static final long serialVersionUID = 1L; private static final String GET_TARGET_LANGUAGES_URL = "https://api.cognitive.microsofttranslator.com/languages?api-version=3.0&scope=translation"; - private static final String DEFUALT_TEST_STRING = "traducción exitoso"; //spanish which should translate to something along the lines of translation successful + private static final String DEFUALT_TEST_STRING = "traducción exitoso"; //spanish which should translate to something along the lines of "successful translation" private String targetLanguageCode = ""; /** * Creates new form GoogleTranslatorSettingsPanel */ - public BingTranslatorSettingsPanel(String credentials, String code) { + public BingTranslatorSettingsPanel(String authenticationKey, String code) { initComponents(); - - credentialsField.setText(credentials); - credentialsField.getDocument().addDocumentListener(new DocumentListener() { + + authenticationKeyField.setText(authenticationKey); + authenticationKeyField.getDocument().addDocumentListener(new DocumentListener() { @Override public void insertUpdate(DocumentEvent e) { firePropertyChange("SettingChanged", true, false); @@ -69,7 +68,7 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { public void changedUpdate(DocumentEvent e) { firePropertyChange("SettingChanged", true, false); } - + }); targetLanguageCode = code; populateComboBox(); @@ -87,9 +86,9 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { JsonObject asObject = elementBody.getAsJsonObject(); JsonElement translationElement = asObject.get("translation"); JsonObject responses = translationElement.getAsJsonObject(); - for (Entry entry : responses.entrySet()) { + responses.entrySet().forEach((entry) -> { targetLanguageComboBox.addItem(new LanguageWrapper(entry.getKey(), entry.getValue().getAsJsonObject().get("name").getAsString())); - } + }); } catch (IOException | IllegalStateException | ClassCastException | NullPointerException | IndexOutOfBoundsException ex) { logger.log(Level.WARNING, "Unable to get list of target languages or parse the result that was received", ex); } @@ -120,8 +119,8 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { // //GEN-BEGIN:initComponents private void initComponents() { - credentialsLabel = new javax.swing.JLabel(); - credentialsField = new javax.swing.JTextField(); + authenticationKeyLabel = new javax.swing.JLabel(); + authenticationKeyField = new javax.swing.JTextField(); warningLabel = new javax.swing.JLabel(); testButton = new javax.swing.JButton(); targetLanguageLabel = new javax.swing.JLabel(); @@ -134,7 +133,9 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { resultLabel = new javax.swing.JLabel(); testResultValueLabel = new javax.swing.JLabel(); - org.openide.awt.Mnemonics.setLocalizedText(credentialsLabel, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "GoogleTranslatorSettingsPanel.credentialsLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(authenticationKeyLabel, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "GoogleTranslatorSettingsPanel.credentialsLabel.text")); // NOI18N + + authenticationKeyField.setToolTipText(org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "BingTranslatorSettingsPanel.authenticationKeyField.toolTipText")); // NOI18N warningLabel.setForeground(new java.awt.Color(255, 0, 0)); org.openide.awt.Mnemonics.setLocalizedText(warningLabel, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "GoogleTranslatorSettingsPanel.warningLabel.text")); // NOI18N @@ -175,28 +176,32 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(credentialsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 86, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(credentialsField, javax.swing.GroupLayout.DEFAULT_SIZE, 463, Short.MAX_VALUE) - .addGap(67, 67, 67)) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addComponent(warningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 551, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(layout.createSequentialGroup() .addComponent(targetLanguageLabel) + .addGap(18, 18, 18) + .addComponent(targetLanguageComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 192, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(authenticationKeyLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(targetLanguageComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 192, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(authenticationKeyField, javax.swing.GroupLayout.PREFERRED_SIZE, 486, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 20, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addComponent(translationSizeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(testButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGap(25, 25, 25) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(translationSizeSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, 77, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(unitsLabel)) + .addComponent(unitsLabel) + .addGap(0, 0, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() .addComponent(untranslatedLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) @@ -205,15 +210,15 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { .addComponent(resultLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(testResultValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))) - .addGap(0, 0, Short.MAX_VALUE)))) + .addContainerGap()))) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(credentialsLabel) - .addComponent(credentialsField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(authenticationKeyLabel) + .addComponent(authenticationKeyField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(targetLanguageLabel) @@ -240,7 +245,7 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { if (testTranslationSetup()) { warningLabel.setText(""); } else { - warningLabel.setText("Invalid translation credentials"); + warningLabel.setText("Invalid translation authentication key"); } }//GEN-LAST:event_testButtonActionPerformed @@ -253,8 +258,8 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { }//GEN-LAST:event_targetLanguageComboBoxSelected // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JTextField credentialsField; - private javax.swing.JLabel credentialsLabel; + private javax.swing.JTextField authenticationKeyField; + private javax.swing.JLabel authenticationKeyLabel; private javax.swing.JLabel resultLabel; private javax.swing.JComboBox targetLanguageComboBox; private javax.swing.JLabel targetLanguageLabel; @@ -290,7 +295,7 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { bodyString); Request request = new Request.Builder() .url(BingTranslator.getTranlatorUrl(targetLanguageCode)).post(body) - .addHeader("Ocp-Apim-Subscription-Key", credentialsField.getText()) + .addHeader("Ocp-Apim-Subscription-Key", authenticationKeyField.getText()) .addHeader("Content-type", "application/json").build(); try { Response response = new OkHttpClient().newCall(request).execute(); @@ -308,12 +313,13 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { } /** - * Get the currently set path to the JSON credentials file + * Get the currently set authentication key to be used for the Microsoft + * translation service * - * @return the path to the credentials file specified in the textarea + * @return the authentication key specified in the textarea */ - String getCredentials() { - return credentialsField.getText(); + String getAuthenticationKey() { + return authenticationKeyField.getText(); } /** diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties index adf27cddfa..1d6a9318be 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties @@ -1,5 +1,5 @@ GoogleTranslatorSettingsPanel.browseButton.text=Browse -GoogleTranslatorSettingsPanel.credentialsLabel.text=Credentials: +GoogleTranslatorSettingsPanel.credentialsLabel.text=Authentication key: GoogleTranslatorSettingsPanel.warningLabel.text= GoogleTranslatorSettingsPanel.targetLanguageLabel.text=Target Language: BingTranslatorSettingsPanel.testButton.text=Test @@ -9,3 +9,4 @@ BingTranslatorSettingsPanel.untranslatedLabel.text=Untranslated: BingTranslatorSettingsPanel.translationSizeLabel.text=Translation Size: BingTranslatorSettingsPanel.targetLanguageLabel.text=Target Language: BingTranslatorSettingsPanel.unitsLabel.text=characters +BingTranslatorSettingsPanel.authenticationKeyField.toolTipText=Enter the hash for the From fd399e4cfb7c080e358ea4dfd6e47ab3fb87f2d3 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 30 May 2019 13:04:32 -0400 Subject: [PATCH 011/115] 5061 clean up loading of settings --- .../texttranslation/translators/BingTranslatorSettings.java | 6 ++++-- .../texttranslation/translators/Bundle.properties-MERGED | 3 ++- .../translators/GoogleTranslatorSettings.java | 6 ++++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettings.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettings.java index 039c24c480..dcd54fd6f9 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettings.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettings.java @@ -70,12 +70,14 @@ public final class BingTranslatorSettings { } if (ModuleSettings.settingExists(BING_TRANSLATE_NAME, AUTHENTICATION_KEY)) { authenticationKey = ModuleSettings.getConfigSetting(BING_TRANSLATE_NAME, AUTHENTICATION_KEY); - } else { + } + if (authenticationKey == null || StringUtils.isBlank(authenticationKey)) { authenticationKey = DEFAULT_AUTHENTICATION; } if (ModuleSettings.settingExists(BING_TRANSLATE_NAME, TARGET_LANGUAGE_CODE_KEY)) { targetLanguageCode = ModuleSettings.getConfigSetting(BING_TRANSLATE_NAME, TARGET_LANGUAGE_CODE_KEY); - } else { + } + if (targetLanguageCode == null || StringUtils.isBlank(targetLanguageCode)) { targetLanguageCode = DEFAULT_TARGET_LANGUAGE; } } diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED index 01c6123934..89f7d8b02a 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED @@ -1,7 +1,7 @@ BingTranslator.name.text=Bing Translator GoogleTranslator.name.text=Google Translate GoogleTranslatorSettingsPanel.browseButton.text=Browse -GoogleTranslatorSettingsPanel.credentialsLabel.text=Credentials: +GoogleTranslatorSettingsPanel.credentialsLabel.text=Authentication key: GoogleTranslatorSettingsPanel.errorMessage.fileNotFound=Credentials file not found, please set the location to be a valid JSON credentials file. GoogleTranslatorSettingsPanel.errorMessage.noFileSelected=A JSON file must be selected to provide your credentials for Google Translate. GoogleTranslatorSettingsPanel.errorMessage.unableToMakeCredentials=Unable to construct credentials object from credentials file, please set the location to be a valid JSON credentials file. @@ -19,3 +19,4 @@ BingTranslatorSettingsPanel.untranslatedLabel.text=Untranslated: BingTranslatorSettingsPanel.translationSizeLabel.text=Translation Size: BingTranslatorSettingsPanel.targetLanguageLabel.text=Target Language: BingTranslatorSettingsPanel.unitsLabel.text=characters +BingTranslatorSettingsPanel.authenticationKeyField.toolTipText=Enter the hash for the diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettings.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettings.java index 55771b8c7a..34ebfd67d4 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettings.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettings.java @@ -92,12 +92,14 @@ public final class GoogleTranslatorSettings { } if (ModuleSettings.settingExists(GOOGLE_TRANSLATE_NAME, TARGET_LANGUAGE_CODE_KEY)) { targetLanguageCode = ModuleSettings.getConfigSetting(GOOGLE_TRANSLATE_NAME, TARGET_LANGUAGE_CODE_KEY); - } else { + } + if (targetLanguageCode == null || StringUtils.isBlank(targetLanguageCode)) { targetLanguageCode = DEFAULT_TARGET_LANGUAGE; } if (ModuleSettings.settingExists(GOOGLE_TRANSLATE_NAME, CREDENTIAL_PATH_KEY)) { credentialPath = ModuleSettings.getConfigSetting(GOOGLE_TRANSLATE_NAME, CREDENTIAL_PATH_KEY); - } else { + } + if (credentialPath == null) { credentialPath = DEFAULT_CREDENTIAL_PATH; } } From e6670f34bab10ab51a7bbc82d53d35668d0c54fe Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 30 May 2019 13:46:15 -0400 Subject: [PATCH 012/115] 5061 test button added to google translate options panel --- .../translators/BingTranslator.java | 75 ++++++-------- .../BingTranslatorSettingsPanel.java | 2 +- .../translators/Bundle.properties | 6 +- .../translators/Bundle.properties-MERGED | 6 +- .../GoogleTranslatorSettingsPanel.form | 71 ++++++++++++-- .../GoogleTranslatorSettingsPanel.java | 97 +++++++++++++++---- 6 files changed, 184 insertions(+), 73 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java index db17236edc..78f1cf9afd 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java @@ -16,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.texttranslation.translators; import com.google.gson.JsonArray; @@ -35,11 +34,12 @@ import org.sleuthkit.autopsy.texttranslation.TextTranslator; import org.sleuthkit.autopsy.texttranslation.TranslationException; /** - * Translates text by making HTTP requests to Bing Translator. - * This requires a valid subscription key for a Microsoft Azure account. + * Translates text by making HTTP requests to Bing Translator. This requires a + * valid subscription key for a Microsoft Azure account. */ @ServiceProvider(service = TextTranslator.class) -public class BingTranslator implements TextTranslator{ +public class BingTranslator implements TextTranslator { + //In the String below, "en" is the target language. You can include multiple target //languages separated by commas. A full list of supported languages is here: //https://docs.microsoft.com/en-us/azure/cognitive-services/translator/language-support @@ -47,43 +47,45 @@ public class BingTranslator implements TextTranslator{ private final BingTranslatorSettingsPanel settingsPanel; private final BingTranslatorSettings settings = new BingTranslatorSettings(); // This sends messages to Microsoft. - private final OkHttpClient CLIENT = new OkHttpClient(); + private final OkHttpClient CLIENT = new OkHttpClient(); //We might want to make this a configurable setting for anyone who has a //paid account that's willing to pay for long documents. private final int MAX_STRING_LENGTH = 5000; - - - public BingTranslator(){ + + public BingTranslator() { settingsPanel = new BingTranslatorSettingsPanel(settings.getAuthenticationKey(), settings.getTargetLanguageCode()); } - - static String getTranlatorUrl(String languageCode){ + + static String getTranlatorUrl(String languageCode) { return BASE_URL + languageCode; } - + /** * Converts an input test to the JSON format required by Bing Translator, * posts it to Microsoft, and returns the JSON text response. - * + * * @param string The input text to be translated. + * * @return The translation response as a JSON string - * @throws IOException if the request could not be executed due to cancellation, a connectivity problem or timeout. + * + * @throws IOException if the request could not be executed due to + * cancellation, a connectivity problem or timeout. */ public String postTranslationRequest(String string) throws IOException { MediaType mediaType = MediaType.parse("application/json"); - + JsonArray jsonArray = new JsonArray(); JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("Text", string); jsonArray.add(jsonObject); String bodyString = jsonArray.toString(); - + RequestBody body = RequestBody.create(mediaType, - bodyString); + bodyString); Request request = new Request.Builder() - .url(getTranlatorUrl(settings.getTargetLanguageCode())).post(body) - .addHeader("Ocp-Apim-Subscription-Key", settings.getAuthenticationKey()) - .addHeader("Content-type", "application/json").build(); + .url(getTranlatorUrl(settings.getTargetLanguageCode())).post(body) + .addHeader("Ocp-Apim-Subscription-Key", settings.getAuthenticationKey()) + .addHeader("Content-type", "application/json").build(); Response response = CLIENT.newCall(request).execute(); return response.body().string(); } @@ -95,27 +97,25 @@ public class BingTranslator implements TextTranslator{ } String toTranslate = string.trim(); //Translates some text into English, without specifying the source langauge. - + // HTML files were producing lots of white space at the end - //Google Translate required us to replace (\r\n|\n) with
//but Bing Translator doesn not have that requirement. - //The free account has a maximum file size. If you have a paid account, //you probably still want to limit file size to prevent accidentally //translating very large documents. if (toTranslate.length() > MAX_STRING_LENGTH) { toTranslate = toTranslate.substring(0, MAX_STRING_LENGTH); } - + try { String response = postTranslationRequest(toTranslate); return parseJSONResponse(response); } catch (Throwable e) { - throw new TranslationException(e.getMessage()); + throw new TranslationException(e.getMessage()); } } - + @Messages({"BingTranslator.name.text=Bing Translator"}) @Override public String getName() { @@ -131,26 +131,15 @@ public class BingTranslator implements TextTranslator{ public void saveSettings() { settings.setAuthenticationKey(settingsPanel.getAuthenticationKey()); settings.setTargetLanguageCode(settingsPanel.getTargetLanguageCode()); + settings.saveSettings(); } private String parseJSONResponse(String json_text) throws TranslationException { - /* Here is an example of the text we get from Bing when input is "gato", - the Spanish word for cat: - [ - { - "detectedLanguage": { - "language": "es", - "score": 1.0 - }, - "translations": [ - { - "text": "cat", - "to": "en" - } - ] - } - ] - */ + /* + * Here is an example of the text we get from Bing when input is "gato", + * the Spanish word for cat: [ { "detectedLanguage": { "language": "es", + * "score": 1.0 }, "translations": [ { "text": "cat", "to": "en" } ] } ] + */ JsonParser parser = new JsonParser(); try { JsonArray responses = parser.parse(json_text).getAsJsonArray(); @@ -164,4 +153,4 @@ public class BingTranslator implements TextTranslator{ throw new TranslationException("JSON text does not match Bing Translator scheme: " + e); } } -} \ No newline at end of file +} diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java index b95887cea1..054f65a2f5 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java @@ -51,7 +51,6 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { */ public BingTranslatorSettingsPanel(String authenticationKey, String code) { initComponents(); - authenticationKeyField.setText(authenticationKey); authenticationKeyField.getDocument().addDocumentListener(new DocumentListener() { @Override @@ -284,6 +283,7 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { * cancellation, a connectivity problem or timeout. */ private boolean testTranslationSetup() { + testResultValueLabel.setText(""); MediaType mediaType = MediaType.parse("application/json"); JsonArray jsonArray = new JsonArray(); JsonObject jsonObject = new JsonObject(); diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties index 1d6a9318be..8eebeeab58 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties @@ -1,5 +1,5 @@ GoogleTranslatorSettingsPanel.browseButton.text=Browse -GoogleTranslatorSettingsPanel.credentialsLabel.text=Authentication key: +GoogleTranslatorSettingsPanel.credentialsLabel.text=Credentials Path: GoogleTranslatorSettingsPanel.warningLabel.text= GoogleTranslatorSettingsPanel.targetLanguageLabel.text=Target Language: BingTranslatorSettingsPanel.testButton.text=Test @@ -10,3 +10,7 @@ BingTranslatorSettingsPanel.translationSizeLabel.text=Translation Size: BingTranslatorSettingsPanel.targetLanguageLabel.text=Target Language: BingTranslatorSettingsPanel.unitsLabel.text=characters BingTranslatorSettingsPanel.authenticationKeyField.toolTipText=Enter the hash for the +GoogleTranslatorSettingsPanel.testButton.text=Test +GoogleTranslatorSettingsPanel.untranslatedLabel.text=Untranslated: +GoogleTranslatorSettingsPanel.resultLabel.text=Result: +GoogleTranslatorSettingsPanel.testResultValueLabel.text= diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED index 89f7d8b02a..fec94d3419 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED @@ -1,7 +1,7 @@ BingTranslator.name.text=Bing Translator GoogleTranslator.name.text=Google Translate GoogleTranslatorSettingsPanel.browseButton.text=Browse -GoogleTranslatorSettingsPanel.credentialsLabel.text=Authentication key: +GoogleTranslatorSettingsPanel.credentialsLabel.text=Credentials Path: GoogleTranslatorSettingsPanel.errorMessage.fileNotFound=Credentials file not found, please set the location to be a valid JSON credentials file. GoogleTranslatorSettingsPanel.errorMessage.noFileSelected=A JSON file must be selected to provide your credentials for Google Translate. GoogleTranslatorSettingsPanel.errorMessage.unableToMakeCredentials=Unable to construct credentials object from credentials file, please set the location to be a valid JSON credentials file. @@ -20,3 +20,7 @@ BingTranslatorSettingsPanel.translationSizeLabel.text=Translation Size: BingTranslatorSettingsPanel.targetLanguageLabel.text=Target Language: BingTranslatorSettingsPanel.unitsLabel.text=characters BingTranslatorSettingsPanel.authenticationKeyField.toolTipText=Enter the hash for the +GoogleTranslatorSettingsPanel.testButton.text=Test +GoogleTranslatorSettingsPanel.untranslatedLabel.text=Untranslated: +GoogleTranslatorSettingsPanel.resultLabel.text=Result: +GoogleTranslatorSettingsPanel.testResultValueLabel.text= diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.form index 1a78f115ac..7d728fd011 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.form @@ -16,13 +16,9 @@ - + - - - - @@ -31,7 +27,7 @@ - + @@ -42,6 +38,18 @@ + + + + + + + + + + + + @@ -60,9 +68,16 @@ - + + + + + + + + + -
@@ -118,5 +133,43 @@
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java index 83ad5cf302..8bccc01485 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java @@ -21,7 +21,9 @@ package org.sleuthkit.autopsy.texttranslation.translators; import com.google.auth.Credentials; import com.google.auth.oauth2.ServiceAccountCredentials; import com.google.cloud.translate.Language; +import com.google.cloud.translate.Translate; import com.google.cloud.translate.TranslateOptions; +import com.google.cloud.translate.Translation; import java.awt.event.ItemListener; import java.io.File; import java.io.FileInputStream; @@ -44,6 +46,7 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { private static final Logger logger = Logger.getLogger(GoogleTranslatorSettingsPanel.class.getName()); private static final String JSON_EXTENSION = "json"; + private static final String DEFUALT_TEST_STRING = "traducción exitoso"; //spanish which should translate to something along the lines of "successful translation" private static final long serialVersionUID = 1L; private final ItemListener listener = new ComboBoxSelectionListener(); private String targetLanguageCode = ""; @@ -60,16 +63,15 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { /** * Private method to make a temporary translation service given the current - * settings and use it to retrieve the available target languages for - * population of combobox with target language with unsaved settings. + * settings with unsaved settings. * - * @return A list of Languages + * @return A Translate object which is the translation service */ @Messages({"GoogleTranslatorSettingsPanel.errorMessage.fileNotFound=Credentials file not found, please set the location to be a valid JSON credentials file.", "GoogleTranslatorSettingsPanel.errorMessage.unableToReadCredentials=Unable to read credentials from credentials file, please set the location to be a valid JSON credentials file.", "GoogleTranslatorSettingsPanel.errorMessage.unableToMakeCredentials=Unable to construct credentials object from credentials file, please set the location to be a valid JSON credentials file.", "GoogleTranslatorSettingsPanel.errorMessage.unknownFailureGetting=Failure getting list of supported languages with current credentials file.",}) - private List getListOfTargetLanguages() { + private Translate getTemporaryTranslationService() { //This method also has the side effect of more or less validating the JSON file which was selected as it is necessary to get the list of target languages try { InputStream credentialStream; @@ -77,31 +79,31 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { credentialStream = new FileInputStream(credentialsPathField.getText()); } catch (FileNotFoundException ignored) { warningLabel.setText(Bundle.GoogleTranslatorSettingsPanel_errorMessage_fileNotFound()); - return new ArrayList<>(); + return null; } Credentials creds; try { creds = ServiceAccountCredentials.fromStream(credentialStream); } catch (IOException ignored) { warningLabel.setText(Bundle.GoogleTranslatorSettingsPanel_errorMessage_unableToMakeCredentials()); - return new ArrayList<>(); + return null; } if (creds == null) { warningLabel.setText(Bundle.GoogleTranslatorSettingsPanel_errorMessage_unableToReadCredentials()); logger.log(Level.WARNING, "Credentials were not successfully made, no translations will be available from the GoogleTranslator"); - return new ArrayList<>(); + return null; } else { TranslateOptions.Builder builder = TranslateOptions.newBuilder(); builder.setCredentials(creds); builder.setTargetLanguage(targetLanguageCode); //localize the list to the currently selected target language warningLabel.setText(""); //clear any previous warning text - return builder.build().getService().listSupportedLanguages(); + return builder.build().getService(); } } catch (Throwable throwable) { //Catching throwables because some of this Google Translate code throws throwables warningLabel.setText(Bundle.GoogleTranslatorSettingsPanel_errorMessage_unknownFailureGetting()); logger.log(Level.WARNING, "Throwable caught while getting list of supported languages", throwable); - return new ArrayList<>(); + return null; } } @@ -114,7 +116,13 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { targetLanguageComboBox.removeItemListener(listener); try { if (!StringUtils.isBlank(credentialsPathField.getText())) { - List listSupportedLanguages = getListOfTargetLanguages(); + List listSupportedLanguages; + Translate tempService = getTemporaryTranslationService(); + if (tempService != null) { + listSupportedLanguages = tempService.listSupportedLanguages(); + } else { + listSupportedLanguages = new ArrayList<>(); + } targetLanguageComboBox.removeAllItems(); if (!listSupportedLanguages.isEmpty()) { listSupportedLanguages.forEach((lang) -> { @@ -167,6 +175,11 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { targetLanguageComboBox = new javax.swing.JComboBox<>(); targetLanguageLabel = new javax.swing.JLabel(); warningLabel = new javax.swing.JLabel(); + testResultValueLabel = new javax.swing.JLabel(); + resultLabel = new javax.swing.JLabel(); + untranslatedLabel = new javax.swing.JLabel(); + testUntranslatedTextField = new javax.swing.JTextField(); + testButton = new javax.swing.JButton(); org.openide.awt.Mnemonics.setLocalizedText(credentialsLabel, org.openide.util.NbBundle.getMessage(GoogleTranslatorSettingsPanel.class, "GoogleTranslatorSettingsPanel.credentialsLabel.text")); // NOI18N @@ -186,6 +199,21 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { warningLabel.setForeground(new java.awt.Color(255, 0, 0)); org.openide.awt.Mnemonics.setLocalizedText(warningLabel, org.openide.util.NbBundle.getMessage(GoogleTranslatorSettingsPanel.class, "GoogleTranslatorSettingsPanel.warningLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(testResultValueLabel, org.openide.util.NbBundle.getMessage(GoogleTranslatorSettingsPanel.class, "GoogleTranslatorSettingsPanel.testResultValueLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(resultLabel, org.openide.util.NbBundle.getMessage(GoogleTranslatorSettingsPanel.class, "GoogleTranslatorSettingsPanel.resultLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(untranslatedLabel, org.openide.util.NbBundle.getMessage(GoogleTranslatorSettingsPanel.class, "GoogleTranslatorSettingsPanel.untranslatedLabel.text")); // NOI18N + + testUntranslatedTextField.setText(DEFUALT_TEST_STRING); + + org.openide.awt.Mnemonics.setLocalizedText(testButton, org.openide.util.NbBundle.getMessage(GoogleTranslatorSettingsPanel.class, "GoogleTranslatorSettingsPanel.testButton.text")); // NOI18N + testButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + testButtonActionPerformed(evt); + } + }); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -193,9 +221,6 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(warningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 551, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addComponent(credentialsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) @@ -203,13 +228,24 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(credentialsPathField, javax.swing.GroupLayout.DEFAULT_SIZE, 443, Short.MAX_VALUE) + .addComponent(credentialsPathField, javax.swing.GroupLayout.DEFAULT_SIZE, 451, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(browseButton) .addGap(14, 14, 14)) .addGroup(layout.createSequentialGroup() .addComponent(targetLanguageComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 317, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE)))))) + .addGap(0, 0, Short.MAX_VALUE)))) + .addComponent(warningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 551, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(layout.createSequentialGroup() + .addComponent(testButton, javax.swing.GroupLayout.PREFERRED_SIZE, 83, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(untranslatedLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(testUntranslatedTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 140, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(resultLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(testResultValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -223,9 +259,15 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(targetLanguageLabel) .addComponent(targetLanguageComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(warningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(23, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 15, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(testButton) + .addComponent(testUntranslatedTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(untranslatedLabel) + .addComponent(resultLabel) + .addComponent(testResultValueLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(warningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE)) ); }// //GEN-END:initComponents @@ -249,12 +291,31 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { } }//GEN-LAST:event_browseButtonActionPerformed + private void testButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_testButtonActionPerformed + testResultValueLabel.setText(""); + Translate tempTranslate = getTemporaryTranslationService(); + if (tempTranslate != null) { + try { + Translation translation = tempTranslate.translate(testUntranslatedTextField.getText()); + testResultValueLabel.setText(translation.getTranslatedText()); + warningLabel.setText(""); + } catch (Exception ex) { + warningLabel.setText("Invalid translation credentials path"); + } + } + }//GEN-LAST:event_testButtonActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton browseButton; private javax.swing.JLabel credentialsLabel; private javax.swing.JTextField credentialsPathField; + private javax.swing.JLabel resultLabel; private javax.swing.JComboBox targetLanguageComboBox; private javax.swing.JLabel targetLanguageLabel; + private javax.swing.JButton testButton; + private javax.swing.JLabel testResultValueLabel; + private javax.swing.JTextField testUntranslatedTextField; + private javax.swing.JLabel untranslatedLabel; private javax.swing.JLabel warningLabel; // End of variables declaration//GEN-END:variables From 670ef2cfb1d041c1654e84be1234bdae83893171 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 30 May 2019 16:05:30 -0400 Subject: [PATCH 013/115] 5061 fix label on bing translate options panel which was wrong --- .../BingTranslatorSettingsPanel.form | 18 +++++++++--------- .../BingTranslatorSettingsPanel.java | 11 +++++------ .../translators/Bundle.properties | 1 + .../translators/Bundle.properties-MERGED | 1 + 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form index 5b275b52e3..64227561b3 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form @@ -38,7 +38,7 @@ - + @@ -74,8 +74,8 @@ - + @@ -104,13 +104,6 @@ - - - - - - - @@ -207,5 +200,12 @@ + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java index 054f65a2f5..e477fbf662 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java @@ -28,7 +28,6 @@ import com.squareup.okhttp.Request; import com.squareup.okhttp.RequestBody; import com.squareup.okhttp.Response; import java.io.IOException; -import java.util.Map.Entry; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.event.DocumentEvent; @@ -118,7 +117,6 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { // //GEN-BEGIN:initComponents private void initComponents() { - authenticationKeyLabel = new javax.swing.JLabel(); authenticationKeyField = new javax.swing.JTextField(); warningLabel = new javax.swing.JLabel(); testButton = new javax.swing.JButton(); @@ -131,8 +129,7 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { untranslatedLabel = new javax.swing.JLabel(); resultLabel = new javax.swing.JLabel(); testResultValueLabel = new javax.swing.JLabel(); - - org.openide.awt.Mnemonics.setLocalizedText(authenticationKeyLabel, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "GoogleTranslatorSettingsPanel.credentialsLabel.text")); // NOI18N + authenticationKeyLabel = new javax.swing.JLabel(); authenticationKeyField.setToolTipText(org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "BingTranslatorSettingsPanel.authenticationKeyField.toolTipText")); // NOI18N @@ -168,6 +165,8 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { org.openide.awt.Mnemonics.setLocalizedText(testResultValueLabel, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "BingTranslatorSettingsPanel.testResultValueLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(authenticationKeyLabel, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "BingTranslatorSettingsPanel.authenticationKeyLabel.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -216,8 +215,8 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(authenticationKeyLabel) - .addComponent(authenticationKeyField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(authenticationKeyField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(authenticationKeyLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(targetLanguageLabel) diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties index 8eebeeab58..6ebd3002ef 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties @@ -14,3 +14,4 @@ GoogleTranslatorSettingsPanel.testButton.text=Test GoogleTranslatorSettingsPanel.untranslatedLabel.text=Untranslated: GoogleTranslatorSettingsPanel.resultLabel.text=Result: GoogleTranslatorSettingsPanel.testResultValueLabel.text= +BingTranslatorSettingsPanel.authenticationKeyLabel.text=Authentication Key: diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED index fec94d3419..35e06bda99 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED @@ -24,3 +24,4 @@ GoogleTranslatorSettingsPanel.testButton.text=Test GoogleTranslatorSettingsPanel.untranslatedLabel.text=Untranslated: GoogleTranslatorSettingsPanel.resultLabel.text=Result: GoogleTranslatorSettingsPanel.testResultValueLabel.text= +BingTranslatorSettingsPanel.authenticationKeyLabel.text=Authentication Key: From 74ab8af6e049bda6d0a352488517f247c85bee09 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 3 Jun 2019 11:01:11 -0400 Subject: [PATCH 014/115] 5092 populate ingest status column datasource summary --- .../Bundle.properties-MERGED | 1 + .../datasourcesummary/DataSourceBrowser.java | 11 +++- .../datasourcesummary/DataSourceSummary.java | 56 +++++++++++++++++++ .../DataSourceSummaryNode.java | 4 ++ 4 files changed, 69 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties-MERGED index 508e04b76a..fe998b0e57 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties-MERGED @@ -66,6 +66,7 @@ DataSourceSummaryDialog.window.title=Data Sources Summary DataSourceSummaryNode.column.dataSourceName.header=Data Source Name DataSourceSummaryNode.column.files.header=Files DataSourceSummaryNode.column.results.header=Results +DataSourceSummaryNode.column.status.header=Ingest Status DataSourceSummaryNode.column.tags.header=Tags DataSourceSummaryNode.column.type.header=Type DataSourceSummaryNode.viewDataSourceAction.text=Go to Data Source diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java index e3b9fa0e93..e946317da8 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java @@ -39,6 +39,7 @@ import org.sleuthkit.autopsy.casemodule.datasourcesummary.DataSourceSummaryNode. import static javax.swing.SwingConstants.RIGHT; import javax.swing.table.TableColumn; import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.IngestJobInfo; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; @@ -50,9 +51,10 @@ final class DataSourceBrowser extends javax.swing.JPanel implements ExplorerMana private static final long serialVersionUID = 1L; private static final Logger logger = Logger.getLogger(DataSourceBrowser.class.getName()); - private static final int COUNT_COLUMN_WIDTH = 25; - private static final int USAGE_COLUMN_WIDTH = 120; - private static final int DATA_SOURCE_COLUMN_WIDTH = 325; + private static final int COUNT_COLUMN_WIDTH = 20; + private static final int INGEST_STATUS_WIDTH = 50; + private static final int USAGE_COLUMN_WIDTH = 110; + private static final int DATA_SOURCE_COLUMN_WIDTH = 280; private final Outline outline; private final org.openide.explorer.view.OutlineView outlineView; private final ExplorerManager explorerManager; @@ -69,6 +71,7 @@ final class DataSourceBrowser extends javax.swing.JPanel implements ExplorerMana outlineView = new org.openide.explorer.view.OutlineView(); this.setVisible(true); outlineView.setPropertyColumns( + Bundle.DataSourceSummaryNode_column_status_header(), Bundle.DataSourceSummaryNode_column_status_header(), Bundle.DataSourceSummaryNode_column_type_header(), Bundle.DataSourceSummaryNode_column_type_header(), Bundle.DataSourceSummaryNode_column_files_header(), Bundle.DataSourceSummaryNode_column_files_header(), Bundle.DataSourceSummaryNode_column_results_header(), Bundle.DataSourceSummaryNode_column_results_header(), @@ -90,6 +93,8 @@ final class DataSourceBrowser extends javax.swing.JPanel implements ExplorerMana column.setPreferredWidth(COUNT_COLUMN_WIDTH); } else if (column.getHeaderValue().toString().equals(Bundle.DataSourceSummaryNode_column_type_header())) { column.setPreferredWidth(USAGE_COLUMN_WIDTH); + } else if (column.getHeaderValue().toString().equals(Bundle.DataSourceSummaryNode_column_status_header())) { + column.setPreferredWidth(INGEST_STATUS_WIDTH); } else { column.setPreferredWidth(DATA_SOURCE_COLUMN_WIDTH); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java index 1aa55d95b5..a04604b3cd 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java @@ -18,7 +18,17 @@ */ package org.sleuthkit.autopsy.casemodule.datasourcesummary; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; +import org.openide.util.Exceptions; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.datamodel.CaseDbAccessManager; import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.IngestJobInfo; +import org.sleuthkit.datamodel.IngestJobInfo.IngestJobStatusType; +import org.sleuthkit.datamodel.TskCoreException; /** * Wrapper object for a DataSource and the information associated with it. @@ -27,6 +37,7 @@ import org.sleuthkit.datamodel.DataSource; class DataSourceSummary { private final DataSource dataSource; + private String status = ""; private final String type; private final long filesCount; private final long resultsCount; @@ -45,12 +56,23 @@ class DataSourceSummary { */ DataSourceSummary(DataSource dSource, String typeValue, Long numberOfFiles, Long numberOfResults, Long numberOfTags) { dataSource = dSource; + updateStatus(); type = typeValue == null ? "" : typeValue; filesCount = numberOfFiles == null ? 0 : numberOfFiles; resultsCount = numberOfResults == null ? 0 : numberOfResults; tagsCount = numberOfTags == null ? 0 : numberOfTags; } + void updateStatus() { + try { + IngestJobQueryCallback callback = new IngestJobQueryCallback(); + Case.getCurrentCaseThrows().getSleuthkitCase().getCaseDbAccessManager().select("status_id FROM ingest_jobs WHERE obj_id=" + dataSource.getId(), callback); + status = callback.getStatus(); + } catch (NoCurrentCaseException | TskCoreException ex) { + + } + } + /** * Get the DataSource * @@ -87,6 +109,10 @@ class DataSourceSummary { return resultsCount; } + String getIngestStatus(){ + return status; + } + /** * Get the number of tagged content objects in this DataSource * @@ -95,4 +121,34 @@ class DataSourceSummary { long getTagsCount() { return tagsCount; } + + class IngestJobQueryCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { + + IngestJobStatusType jobStatus = null; + + @Override + public void process(ResultSet rs) { + try { + while (rs.next()) { + IngestJobStatusType currentStatus = IngestJobStatusType.fromID(rs.getInt("status_id")); + if (currentStatus == IngestJobStatusType.COMPLETED) { + jobStatus = currentStatus; + } else if (currentStatus == IngestJobStatusType.STARTED) { + jobStatus = currentStatus; + return; + } + } + } catch (SQLException ex) { + System.out.println("EEEP"); + } + } + + String getStatus() { + if (jobStatus == null) { + return ""; + } else { + return jobStatus.getDisplayName(); + } + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryNode.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryNode.java index 8323061a66..c9aef8c644 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryNode.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryNode.java @@ -109,6 +109,7 @@ final class DataSourceSummaryNode extends AbstractNode { static final class DataSourceSummaryEntryNode extends AbstractNode { private final DataSource dataSource; + private final String status; private final String type; private final long filesCount; private final long resultsCount; @@ -124,6 +125,7 @@ final class DataSourceSummaryNode extends AbstractNode { DataSourceSummaryEntryNode(DataSourceSummary dataSourceSummary) { super(Children.LEAF); dataSource = dataSourceSummary.getDataSource(); + status = dataSourceSummary.getIngestStatus(); type = dataSourceSummary.getType(); filesCount = dataSourceSummary.getFilesCount(); resultsCount = dataSourceSummary.getResultsCount(); @@ -143,6 +145,7 @@ final class DataSourceSummaryNode extends AbstractNode { } @Messages({"DataSourceSummaryNode.column.dataSourceName.header=Data Source Name", + "DataSourceSummaryNode.column.status.header=Ingest Status", "DataSourceSummaryNode.column.type.header=Type", "DataSourceSummaryNode.column.files.header=Files", "DataSourceSummaryNode.column.results.header=Results", @@ -157,6 +160,7 @@ final class DataSourceSummaryNode extends AbstractNode { } sheetSet.put(new NodeProperty<>(Bundle.DataSourceSummaryNode_column_dataSourceName_header(), Bundle.DataSourceSummaryNode_column_dataSourceName_header(), Bundle.DataSourceSummaryNode_column_dataSourceName_header(), dataSource)); + sheetSet.put(new NodeProperty<>(Bundle.DataSourceSummaryNode_column_status_header(), Bundle.DataSourceSummaryNode_column_status_header(), Bundle.DataSourceSummaryNode_column_status_header(), status)); sheetSet.put(new NodeProperty<>(Bundle.DataSourceSummaryNode_column_type_header(), Bundle.DataSourceSummaryNode_column_type_header(), Bundle.DataSourceSummaryNode_column_type_header(), type)); sheetSet.put(new NodeProperty<>(Bundle.DataSourceSummaryNode_column_files_header(), Bundle.DataSourceSummaryNode_column_files_header(), Bundle.DataSourceSummaryNode_column_files_header(), From 90898578ab9045ebdd527dff222d519d321b9058 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Mon, 3 Jun 2019 13:36:29 -0400 Subject: [PATCH 015/115] Renamed classes, cleaned up code, added comments --- .../casemodule/services/TagsManager.java | 24 ++ .../ApplicationTagsManager.java | 67 ---- .../ContentViewerTagManager.java | 232 ++++++++++++ .../autopsy/contentviewers/Bundle.properties | 2 +- .../contentviewers/Bundle.properties-MERGED | 2 +- .../contentviewers/MediaViewImagePanel.form | 42 ++- .../contentviewers/MediaViewImagePanel.java | 355 ++++++++++++++---- .../imagetagging/FocusChangeEvent.java | 48 --- .../imagetagging/FocusChangeListener.java | 18 - .../contentviewers/imagetagging/ImageTag.java | 343 +++++++++++++++++ ...ControlType.java => ImageTagControls.java} | 7 +- .../imagetagging/ImageTagCreator.java | 95 +++-- .../imagetagging/ImageTagRegion.java | 82 ++++ .../imagetagging/ImageTagsGroup.java | 124 ++++++ .../imagetagging/StoredTag.java | 269 ------------- .../imagetagging/StoredTagEvent.java | 40 -- .../imagetagging/StoredTagListener.java | 33 -- .../imagetagging/TopLevelTagsGroup.java | 103 ----- 18 files changed, 1169 insertions(+), 717 deletions(-) delete mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ApplicationTagsManager.java create mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ContentViewerTagManager.java delete mode 100755 Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/FocusChangeEvent.java delete mode 100755 Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/FocusChangeListener.java create mode 100755 Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTag.java rename Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/{ControlType.java => ImageTagControls.java} (84%) create mode 100755 Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagRegion.java create mode 100755 Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsGroup.java delete mode 100755 Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTag.java delete mode 100755 Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTagEvent.java delete mode 100755 Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTagListener.java delete mode 100755 Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/TopLevelTagsGroup.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 896298c2bd..e328b572de 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.casemodule.services; import java.io.Closeable; import java.io.IOException; import java.util.ArrayList; +import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -30,9 +31,11 @@ import java.util.logging.Level; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.casemodule.services.applicationtags.ContentViewerTagManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifactTag; +import org.sleuthkit.datamodel.CaseDbAccessManager; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.SleuthkitCase; @@ -48,6 +51,27 @@ public class TagsManager implements Closeable { private static final Logger LOGGER = Logger.getLogger(TagsManager.class.getName()); private final SleuthkitCase caseDb; + + static { + //Create the contentviewer tags table (beta) if the current case does not + //have the table present + Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), evt -> { + if (evt.getNewValue() != null) { + Case currentCase = (Case) evt.getNewValue(); + try { + CaseDbAccessManager caseDb = currentCase.getSleuthkitCase().getCaseDbAccessManager(); + //Create our custom application tags table, if need be. + if (!caseDb.tableExists(ContentViewerTagManager.TABLE_NAME)) { + caseDb.createTable(ContentViewerTagManager.TABLE_NAME, ContentViewerTagManager.TABLE_SCHEMA); + } + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, + String.format("Unable to create the %s table for image tag storage.", + ContentViewerTagManager.TABLE_NAME), ex); + } + } + }); + } /** * Tests whether or not a given tag display name contains an illegal diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ApplicationTagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ApplicationTagsManager.java deleted file mode 100755 index 65756d16c8..0000000000 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ApplicationTagsManager.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2019 Basis Technology Corp. - * Contact: carrier sleuthkit 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.casemodule.services.applicationtags; - -import java.util.EnumSet; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.datamodel.CaseDbAccessManager; -import org.sleuthkit.datamodel.TskCoreException; - -/** - * A per case Autopsy service that manages the addition of application content - * tags to the case database. - */ -public final class ApplicationTagsManager { - - private static CaseDbAccessManager dbManager; - - private static final String TABLE_NAME = "beta_tag_app_data"; - private static final String TABLE_SCHEMA = "(app_data_id INTEGER PRIMARY KEY, " - + "content_tag_id INTEGER NOT NULL, app_data TEXT NOT NULL," - + "FOREIGN KEY(content_tag_id) REFERENCES content_tags(tag_id))"; - - private final String INSERT_OR_REPLACE_TAG_DATA = "(content_tag_id, app_data) VALUES (?, ?)"; - private final String SELECT_TAG_DATA = "* FROM " + TABLE_NAME + " WHERE content_tag_id = ?"; - private final String DELETE_TAG_DATA = "WHERE app_data_id = ?"; - - static { - Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), evt -> { - if(evt.getNewValue() != null) { - Case currentCase = (Case) evt.getNewValue(); - try { - CaseDbAccessManager caseDb = currentCase.getSleuthkitCase().getCaseDbAccessManager(); - //Create our custom application tags table, if need be. - if (!caseDb.tableExists(TABLE_NAME)) { - caseDb.createTable(TABLE_NAME, TABLE_SCHEMA); - } - - dbManager = caseDb; - } catch (TskCoreException ex) { - //Log - } - } - }); - } - - //public createTag - //public updateTag - //public getTag - //public deleteTag - -} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ContentViewerTagManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ContentViewerTagManager.java new file mode 100755 index 0000000000..33b50bab07 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ContentViewerTagManager.java @@ -0,0 +1,232 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 Basis Technology Corp. + * Contact: carrier sleuthkit 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.casemodule.services.applicationtags; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * A per case Autopsy service that manages the addition of content viewer tags + * to the case database. This manager is also responsible for serializing and + * deserializing instances of your tag data objects for persistence and retrieval. + */ +public class ContentViewerTagManager { + + //Used to convert Java beans into the physical representation that will be stored + //in the database (for now, JSON was chosen). + private static final ObjectMapper SERIALIZER = new ObjectMapper(); + + public static final String TABLE_NAME = "beta_tag_app_data"; + public static final String TABLE_SCHEMA = "(app_data_id INTEGER PRIMARY KEY, " + + "content_tag_id INTEGER NOT NULL, app_data TEXT NOT NULL, " + + "FOREIGN KEY(content_tag_id) REFERENCES content_tags(tag_id))"; + + private static final String INSERT_TAG_DATA = "(content_tag_id, app_data) VALUES (%d, '%s')"; + private static final String UPDATE_TAG_DATA = "SET content_tag_id = %d, app_data = '%s' WHERE app_data_id = %d"; + private static final String SELECT_TAG_DATA = "* FROM " + TABLE_NAME + " WHERE content_tag_id = %d"; + private static final String DELETE_TAG_DATA = "WHERE app_data_id = %d"; + + /** + * Creates and saves a new ContentViewerTag in the case database. The + * generic tag data instance T will be automatically serialized into a + * storable format and persisted. + * + * @param Generic java bean class type that will be serialized into a + * storable format for persistence + * @param contentTag ContentTag that this ContentViewerTag is associated + * with (1:1) + * @param tagDataBean Data instance that contains the tag information to be + * persisted. + * @return An instance of a ContentViewerTag of type T, which contains all + * the stored information. + * + * @throws SerializationException Thrown if the tag data bean instance T + * could not be serialized into a storable format for persistence in the + * case database. + * @throws TskCoreException Thrown if this operation did not successfully + * persist in the case database. + * @throws NoCurrentCaseException Thrown if invocation of this method occurs + * when no case is open. + */ + public static ContentViewerTag saveTag(ContentTag contentTag, T tagDataBean) throws SerializationException, TskCoreException, NoCurrentCaseException { + try { + long contentTagId = contentTag.getId(); + String serialAppData = SERIALIZER.writeValueAsString(tagDataBean); + String insertTemplateInstance = String.format(INSERT_TAG_DATA, + contentTagId, serialAppData); + long insertId = Case.getCurrentCaseThrows().getSleuthkitCase().getCaseDbAccessManager().insert(TABLE_NAME, insertTemplateInstance); + return new ContentViewerTag<>(insertId, contentTag, tagDataBean); + } catch (JsonProcessingException ex) { + throw new SerializationException("Unable to convert object instance into a storable format", ex); + } + } + + /** + * Updates the ContentViewerTag instance with the new tag data T and + * persists the changes to the case database. + * + * @param Generic java bean class type that will be serialized into a + * storable format for persistence + * @param oldTag ContentViewerTag instance to be updated + * @param tagDataBean Data instance that contains the updated information to + * be persisted. + * + * @throws SerializationException Thrown if the tag data bean instance T + * could not be serialized into a storable format for persistence in the + * case database. + * @throws TskCoreException Thrown if this operation did not successfully + * persist in the case database. + * @throws NoCurrentCaseException Thrown if invocation of this method occurs + * when no case is open. + */ + public static ContentViewerTag updateTag(ContentViewerTag oldTag, T tagDataBean) + throws SerializationException, TskCoreException, NoCurrentCaseException { + try { + String serialAppData = SERIALIZER.writeValueAsString(tagDataBean); + String updateTemplateInstance = String.format(UPDATE_TAG_DATA, + oldTag.getContentTag().getId(), serialAppData, oldTag.getId()); + Case.getCurrentCaseThrows().getSleuthkitCase().getCaseDbAccessManager() + .update(TABLE_NAME, updateTemplateInstance); + return new ContentViewerTag<>(oldTag.getId(), oldTag.getContentTag(), tagDataBean); + } catch (JsonProcessingException ex) { + throw new SerializationException("Unable to convert object instance into a storable format", ex); + } + } + + /** + * Retrieves a ContentViewerTag instance that is associated with the + * specified ContentTag. The Java bean class that represents the technical + * details of the tag should be passed so that automatic binding can take + * place. + * + * @param Java bean class type that will be instantiated and filled in + * with data. + * @param contentTag ContentTag that this ContentViewerTag is associated + * with (1:1) + * @param clazz Java bean class that will be instantiated and filled in with + * data. + * @return ContentViewerTag with an instance of T as a member variable or + * null if the content tag does not have an associated ContentViewerTag of + * type T. + * + * @throws TskCoreException Thrown if this operation did not successfully + * persist in the case database. + * @throws NoCurrentCaseException Thrown if invocation of this method occurs + * when no case is open. + */ + public static ContentViewerTag getTag(ContentTag contentTag, Class clazz) throws TskCoreException, NoCurrentCaseException { + try { + String selectTemplateInstance = String.format(SELECT_TAG_DATA, contentTag.getId()); + final ArrayList result = new ArrayList<>(); + Case.getCurrentCaseThrows().getSleuthkitCase().getCaseDbAccessManager() + .select(selectTemplateInstance, (ResultSet rs) -> { + try { + if (rs.next()) { + long tagId = rs.getLong(1); + String appDetails = rs.getString(3); + try { + T instance = SERIALIZER.readValue(appDetails, clazz); + result.add(new ContentViewerTag<>(tagId, contentTag, instance)); + } catch (IOException ex) { + //Databind for type T failed. Not a system error + //but rather a logic error on the part of the caller. + result.add(null); + } + } + } catch (SQLException ex) { + throw new RuntimeException(ex); + } + }); + return result.get(0); + } catch (RuntimeException ex) { + throw new TskCoreException("Unable to select tags from db", (Exception) ex.getCause()); + } + } + + /** + * Deletes the content viewer tag with the specified id. + * + * @param contentViewerTag ContentViewerTag to delete + * @throws TskCoreException Thrown if this operation did not successfully + * persist in the case database. + * @throws NoCurrentCaseException Thrown if invocation of this method occurs + * when no case is open. + */ + public static void deleteTag(ContentViewerTag contentViewerTag) throws TskCoreException, NoCurrentCaseException { + String deleteTemplateInstance = String.format(DELETE_TAG_DATA, contentViewerTag.getId()); + Case.getCurrentCaseThrows().getSleuthkitCase().getCaseDbAccessManager() + .delete(TABLE_NAME, deleteTemplateInstance); + } + + /** + * This class represents a stored tag in the case database. It is a wrapper + * for the tag id, the attached Content tag object, and the Java bean + * instance that describes the technical details for reconstructing the tag. + * + * @param Java bean class type that will be instantiated and filled in + * with data. + */ + public static class ContentViewerTag { + + private final long id; + private final ContentTag contentTag; + private final T details; + + private ContentViewerTag(long id, ContentTag contentTag, T details) { + this.id = id; + this.contentTag = contentTag; + this.details = details; + } + + public long getId() { + return id; + } + + public ContentTag getContentTag() { + return contentTag; + } + + public T getDetails() { + return details; + } + } + + /** + * System exception thrown in the event that class instance T could not be + * properly serialized. + */ + public static class SerializationException extends Exception { + + public SerializationException(String message, Exception source) { + super(message, source); + } + } + + //Prevent this class from being instantiated. + private ContentViewerTagManager() { + } +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties index 631bb91273..a8b66e1c31 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties @@ -92,4 +92,4 @@ MediaPlayerPanel.infoLabel.text=No Errors MediaViewImagePanel.deleteTagButton.text=Delete Tag MediaViewImagePanel.createTagButton.text=Create Tag MediaViewImagePanel.jMenu1.text=jMenu1 -MediaViewImagePanel.editTagButton.text=Edit Tag Info +MediaViewImagePanel.showTagsButton.text=Hide Tags diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED index b18b79580c..44cae34fd9 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED @@ -154,7 +154,7 @@ MediaPlayerPanel.infoLabel.text=No Errors MediaViewImagePanel.deleteTagButton.text=Delete Tag MediaViewImagePanel.createTagButton.text=Create Tag MediaViewImagePanel.jMenu1.text=jMenu1 -MediaViewImagePanel.editTagButton.text=Edit Tag Info +MediaViewImagePanel.showTagsButton.text=Hide Tags # {0} - tableName SQLiteViewer.readTable.errorText=Error getting rows for table: {0} # {0} - tableName diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.form b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.form index ccfe83b2cc..447957d66c 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.form @@ -225,10 +225,18 @@ - - + + + + + + + + + + @@ -245,21 +253,6 @@ - - - - - - - - - - - - - - - @@ -274,6 +267,21 @@ + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java index b6ec14fba1..5d6fa7e193 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java @@ -18,18 +18,16 @@ */ package org.sleuthkit.autopsy.contentviewers; -import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagCreator; -import org.sleuthkit.autopsy.contentviewers.imagetagging.StoredTag; -import org.sleuthkit.autopsy.contentviewers.imagetagging.StoredTagListener; -import org.sleuthkit.autopsy.contentviewers.imagetagging.TopLevelTagsGroup; -import org.sleuthkit.autopsy.contentviewers.imagetagging.StoredTagEvent; import java.awt.EventQueue; import java.awt.event.ActionEvent; +import java.beans.PropertyChangeListener; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import static java.util.Objects.nonNull; import java.util.SortedSet; import java.util.concurrent.ExecutionException; +import java.util.logging.Level; import java.util.stream.Collectors; import javafx.application.Platform; import javafx.concurrent.Task; @@ -37,7 +35,7 @@ import javafx.embed.swing.JFXPanel; import javafx.geometry.Pos; import javafx.geometry.Rectangle2D; import javafx.scene.Cursor; -import javafx.scene.Node; +import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; @@ -54,14 +52,22 @@ import javax.imageio.ImageIO; import javax.swing.JPanel; import javax.swing.SwingUtilities; import org.controlsfx.control.MaskerPane; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.python.google.common.collect.Lists; import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog; import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog.TagNameAndComment; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.contentviewers.imagetagging.ControlType; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.casemodule.services.applicationtags.ContentViewerTagManager; +import org.sleuthkit.autopsy.casemodule.services.applicationtags.ContentViewerTagManager.ContentViewerTag; +import org.sleuthkit.autopsy.casemodule.services.applicationtags.ContentViewerTagManager.SerializationException; +import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagControls; +import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagRegion; +import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagCreator; +import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTag; +import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagsGroup; import org.sleuthkit.autopsy.coreutils.ImageUtils; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.FileNode; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.datamodel.AbstractFile; @@ -79,14 +85,15 @@ import org.sleuthkit.datamodel.TskCoreException; class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPanel { private static final Image EXTERNAL = new Image(MediaViewImagePanel.class.getResource("/org/sleuthkit/autopsy/images/external.png").toExternalForm()); + private final Logger LOGGER = Logger.getLogger(MediaViewImagePanel.class.getName()); private final boolean fxInited; private JFXPanel fxPanel; private AbstractFile file; - private StoredTag lastFocused; - private TopLevelTagsGroup imageGroup; - private ImageTagCreator tagger; + private Group masterGroup; + private ImageTagsGroup tagsGroup; + private ImageTagCreator imageTagCreator; private ImageView fxImageView; private ScrollPane scrollPane; private final ProgressBar progressBar = new ProgressBar(); @@ -132,22 +139,29 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan // build jfx ui (we could do this in FXML?) fxImageView = new ImageView(); // will hold image - imageGroup = new TopLevelTagsGroup(fxImageView); + masterGroup = new Group(fxImageView); + tagsGroup = new ImageTagsGroup(fxImageView); + masterGroup.getChildren().add(tagsGroup); deleteTagButton.setEnabled(false); - editTagButton.setEnabled(false); - imageGroup.addFocusChangeListener((event) -> { - if (event.getType() == ControlType.NOT_FOCUSED || event.getNode().equals(fxImageView)) { + + //Update buttons when users select (or unselect) image tags. + tagsGroup.addFocusChangeListener((event) -> { + if (event.getPropertyName().equals(ImageTagControls.NOT_FOCUSED.getName())) { deleteTagButton.setEnabled(false); - createTagButton.setEnabled(true); - editTagButton.setEnabled(false); - } else if (event.getType() == ControlType.FOCUSED) { + if (DisplayOptions.HIDE_TAGS.getName().equals(showTagsButton.getText())) { + createTagButton.setEnabled(true); + } + } else if (event.getPropertyName().equals(ImageTagControls.FOCUSED.getName())) { deleteTagButton.setEnabled(true); - editTagButton.setEnabled(true); createTagButton.setEnabled(false); - lastFocused = event.getNode(); + if (masterGroup.getChildren().contains(imageTagCreator)) { + imageTagCreator.disconnect(); + masterGroup.getChildren().remove(imageTagCreator); + } } }); - scrollPane = new ScrollPane(imageGroup); // scrolls and sizes imageview + + scrollPane = new ScrollPane(masterGroup); // scrolls and sizes imageview scrollPane.getStyleClass().add("bg"); //NOI18N scrollPane.setVbarPolicy(ScrollBarPolicy.AS_NEEDED); scrollPane.setHbarPolicy(ScrollBarPolicy.AS_NEEDED); @@ -178,9 +192,13 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan Platform.runLater(() -> { fxImageView.setViewport(new Rectangle2D(0, 0, 0, 0)); fxImageView.setImage(null); - imageGroup.getChildren().clear(); + masterGroup.getChildren().clear(); + if (imageTagCreator != null) { + imageTagCreator.disconnect(); + } + showTagsButton.setText("Hide Tags"); scrollPane.setContent(null); - scrollPane.setContent(imageGroup); + scrollPane.setContent(masterGroup); }); } @@ -228,14 +246,28 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan try { Image fxImage = readImageTask.get(); - imageGroup.getChildren().clear(); - imageGroup.getChildren().add(fxImageView); + masterGroup.getChildren().clear(); + tagsGroup.getChildren().clear(); this.file = file; if (nonNull(fxImage)) { // We have a non-null image, so let's show it. fxImageView.setImage(fxImage); resetView(); - scrollPane.setContent(imageGroup); + masterGroup.getChildren().add(fxImageView); + masterGroup.getChildren().add(tagsGroup); + + try { + List tags = Case.getCurrentCase().getServices() + .getTagsManager().getContentTagsByContent(file); + + List> contentViewerTags = getContentViewerTags(tags); + //Add all image tags + tagsGroup = buildImageTagsGroup(contentViewerTags); + } catch (TskCoreException | NoCurrentCaseException ex) { + LOGGER.log(Level.WARNING, "Could not retrieve image tags for file in case db", ex); //NON-NLS + //TODO - pop dialog + } + scrollPane.setContent(masterGroup); } else { showErrorNode(Bundle.MediaViewImagePanel_errorLabel_text(), file); } @@ -275,6 +307,65 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan }); } + /** + * Finds all ContentViewerTags that are of type 'ImageTagRegion' for the + * current file. + * + * @param contentTags + * @return + * @throws TskCoreException + * @throws NoCurrentCaseException + */ + private List> getContentViewerTags(List contentTags) + throws TskCoreException, NoCurrentCaseException { + List> contentViewerTags = new ArrayList<>(); + for (ContentTag contentTag : contentTags) { + ContentViewerTag contentViewerTag = ContentViewerTagManager + .getTag(contentTag, ImageTagRegion.class); + if (contentViewerTag == null) { + continue; + } + + contentViewerTags.add(contentViewerTag); + } + return contentViewerTags; + } + + /** + * Builds ImageTag instances from stored ContentViewerTags of the + * appropriate type. + * + * @param contentTags + * @return + * @throws TskCoreException + * @throws NoCurrentCaseException + */ + private ImageTagsGroup buildImageTagsGroup(List> contentViewerTags) { + + contentViewerTags.forEach(contentViewerTag -> { + /** + * Build the image tag, add an edit event call back to persist all + * edits made on this image tag instance. + */ + ImageTag imageTag = new ImageTag(contentViewerTag, fxImageView); + imageTag.subscribeToEditEvents((event) -> { + try { + scrollPane.setCursor(Cursor.WAIT); + ImageTagRegion newRegion = (ImageTagRegion) event.getNewValue(); + ContentViewerTagManager.updateTag(contentViewerTag, newRegion); + scrollPane.setCursor(Cursor.DEFAULT); + } catch (SerializationException | NoCurrentCaseException | TskCoreException ex) { + LOGGER.log(Level.WARNING, "Could not save edit for image tag in case db", ex); //NON-NLS + //TODO - pop dialog + } + }); + + tagsGroup.getChildren().add(imageTag); + }); + + return tagsGroup; + } + /** * @return supported mime types */ @@ -329,13 +420,13 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan zoomInButton = new javax.swing.JButton(); jSeparator2 = new javax.swing.JToolBar.Separator(); zoomResetButton = new javax.swing.JButton(); - jSeparator3 = new javax.swing.JToolBar.Separator(); filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0)); + filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0)); createTagButton = new javax.swing.JButton(); jSeparator4 = new javax.swing.JToolBar.Separator(); - editTagButton = new javax.swing.JButton(); - jSeparator5 = new javax.swing.JToolBar.Separator(); deleteTagButton = new javax.swing.JButton(); + jSeparator3 = new javax.swing.JToolBar.Separator(); + showTagsButton = new javax.swing.JButton(); org.openide.awt.Mnemonics.setLocalizedText(jMenu1, org.openide.util.NbBundle.getMessage(MediaViewImagePanel.class, "MediaViewImagePanel.jMenu1.text")); // NOI18N @@ -441,8 +532,8 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan } }); toolbar.add(zoomResetButton); - toolbar.add(jSeparator3); toolbar.add(filler1); + toolbar.add(filler2); org.openide.awt.Mnemonics.setLocalizedText(createTagButton, org.openide.util.NbBundle.getMessage(MediaViewImagePanel.class, "MediaViewImagePanel.createTagButton.text")); // NOI18N createTagButton.setFocusable(false); @@ -457,18 +548,6 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan toolbar.add(createTagButton); toolbar.add(jSeparator4); - org.openide.awt.Mnemonics.setLocalizedText(editTagButton, org.openide.util.NbBundle.getMessage(MediaViewImagePanel.class, "MediaViewImagePanel.editTagButton.text")); // NOI18N - editTagButton.setFocusable(false); - editTagButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - editTagButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - editTagButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - editTagButtonActionPerformed(evt); - } - }); - toolbar.add(editTagButton); - toolbar.add(jSeparator5); - org.openide.awt.Mnemonics.setLocalizedText(deleteTagButton, org.openide.util.NbBundle.getMessage(MediaViewImagePanel.class, "MediaViewImagePanel.deleteTagButton.text")); // NOI18N deleteTagButton.setFocusable(false); deleteTagButton.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); @@ -480,6 +559,18 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan } }); toolbar.add(deleteTagButton); + toolbar.add(jSeparator3); + + org.openide.awt.Mnemonics.setLocalizedText(showTagsButton, org.openide.util.NbBundle.getMessage(MediaViewImagePanel.class, "MediaViewImagePanel.showTagsButton.text")); // NOI18N + showTagsButton.setFocusable(false); + showTagsButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + showTagsButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + showTagsButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + showTagsButtonActionPerformed(evt); + } + }); + toolbar.add(showTagsButton); add(toolbar); }// //GEN-END:initComponents @@ -526,52 +617,162 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan private void deleteTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTagButtonActionPerformed Platform.runLater(() -> { - imageGroup.deleteNode(lastFocused); - }); - try { - Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(lastFocused.getContentTag()); - } catch (TskCoreException ex) { + ImageTag tagInFocus = tagsGroup.getFocus(); + //Null should not be expected, but just as a safetly precaution + if (tagInFocus == null) { + return; + } - } + try { + ContentViewerTag contentViewerTag = tagInFocus.getContentViewerTag(); + scrollPane.setCursor(Cursor.WAIT); + ContentViewerTagManager.deleteTag(contentViewerTag); + Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(contentViewerTag.getContentTag()); + tagsGroup.getChildren().remove(tagInFocus); + } catch (TskCoreException | NoCurrentCaseException ex) { + LOGGER.log(Level.WARNING, "Could not delete image tag in case db", ex); //NON-NLS + //TODO pop dialog + } + + scrollPane.setCursor(Cursor.DEFAULT); + }); + + deleteTagButton.setEnabled(false); + createTagButton.setEnabled(true); }//GEN-LAST:event_deleteTagButtonActionPerformed private void createTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_createTagButtonActionPerformed - Platform.runLater(() -> { - tagger = new ImageTagCreator(fxImageView); - StoredTagListener newTagListener = (StoredTagEvent event) -> { - StoredTag tag = event.getTag(); - imageGroup.getChildren().add(tag); - SwingUtilities.invokeLater(() -> { - TagNameAndComment result = GetTagNameAndCommentDialog.doDialog(); - if (result != null) { - try { - ContentTag t = Case.getCurrentCase().getServices().getTagsManager().addContentTag(file, - result.getTagName(), result.getComment()); - tag.addContentTag(t); - } catch (TskCoreException ex) { - Platform.runLater(() -> imageGroup.deleteNode(tag)); - } - } else { - Platform.runLater(() -> imageGroup.deleteNode(tag)); + createTagButton.setEnabled(false); + showTagsButton.setEnabled(false); + imageTagCreator = new ImageTagCreator(fxImageView); + + PropertyChangeListener newTagListener = (event) -> { + + SwingUtilities.invokeLater(() -> { + ImageTagRegion tag = (ImageTagRegion) event.getNewValue(); + //Ask the user for tag name and comment + TagNameAndComment result = GetTagNameAndCommentDialog.doDialog(); + if (result == null) { + createTagButton.setEnabled(true); + showTagsButton.setEnabled(true); + return; + } + + //Persist and build image tag + Platform.runLater(() -> { + try { + ContentViewerTag contentViewerTag = storeImageTag(tag, result); + ImageTag imageTag = buildImageTag(contentViewerTag); + tagsGroup.getChildren().add(imageTag); + } catch (TskCoreException | SerializationException | NoCurrentCaseException ex) { + LOGGER.log(Level.WARNING, "Could not save new image tag in case db", ex); //NON-NLS + //TODO pop dialog } }); - imageGroup.deleteNode(tagger); + }); - }; - tagger.addNewTagListener(newTagListener); - imageGroup.getChildren().add(tagger); - }); + //Remove image tag creator from panel + Platform.runLater(() -> { + imageTagCreator.disconnect(); + masterGroup.getChildren().remove(imageTagCreator); + }); + }; + + imageTagCreator.addNewTagListener(newTagListener); + Platform.runLater(() -> masterGroup.getChildren().add(imageTagCreator)); }//GEN-LAST:event_createTagButtonActionPerformed - private void editTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editTagButtonActionPerformed - ContentTag t = lastFocused.getContentTag(); - }//GEN-LAST:event_editTagButtonActionPerformed + /** + * + * @param contentViewerTag + * @return + */ + private ImageTag buildImageTag(ContentViewerTag contentViewerTag) { + ImageTag imageTag = new ImageTag(contentViewerTag, fxImageView); + + //Automatically persist edits made by user + imageTag.subscribeToEditEvents((edit) -> { + try { + scrollPane.setCursor(Cursor.WAIT); + ImageTagRegion newRegion = (ImageTagRegion) edit.getNewValue(); + ContentViewerTagManager.updateTag(contentViewerTag, newRegion); + scrollPane.setCursor(Cursor.DEFAULT); + } catch (SerializationException | TskCoreException | NoCurrentCaseException ex) { + LOGGER.log(Level.WARNING, "Could not save edit for image tag in case db", ex); //NON-NLS + //TODO pop dialog + } + }); + return imageTag; + } + + /** + * Stores the image tag by creating a ContentTag instance and associating + * the ImageTagRegion data with it in the case database. + * + * @param data + * @param result + */ + private ContentViewerTag storeImageTag(ImageTagRegion data, TagNameAndComment result) + throws TskCoreException, SerializationException, NoCurrentCaseException { + try { + scrollPane.setCursor(Cursor.WAIT); + ContentTag contentTag = Case.getCurrentCaseThrows().getServices().getTagsManager() + .addContentTag(file, result.getTagName(), result.getComment()); + ContentViewerTag contentViewerTag = ContentViewerTagManager.saveTag(contentTag, data); + return contentViewerTag; + } finally { + scrollPane.setCursor(Cursor.DEFAULT); + createTagButton.setEnabled(true); + showTagsButton.setEnabled(true); + } + } + + private void showTagsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showTagsButtonActionPerformed + Platform.runLater(() -> { + if (DisplayOptions.HIDE_TAGS.getName().equals(showTagsButton.getText())) { + //Temporarily remove the tags group and update buttons + masterGroup.getChildren().remove(tagsGroup); + showTagsButton.setText(DisplayOptions.SHOW_TAGS.getName()); + createTagButton.setEnabled(false); + deleteTagButton.setEnabled(false); + } else { + //Add tags group back in and update buttons + masterGroup.getChildren().add(tagsGroup); + showTagsButton.setText(DisplayOptions.HIDE_TAGS.getName()); + if (tagsGroup.getFocus() != null) { + createTagButton.setEnabled(false); + deleteTagButton.setEnabled(true); + } else { + createTagButton.setEnabled(true); + deleteTagButton.setEnabled(false); + } + } + }); + }//GEN-LAST:event_showTagsButtonActionPerformed + + /** + * Display states for the show/hide tags button. + */ + enum DisplayOptions { + HIDE_TAGS("Hide Tags"), + SHOW_TAGS("Show Tags"); + + private final String name; + + DisplayOptions(String name) { + this.name = name; + } + + String getName() { + return name; + } + } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton createTagButton; private javax.swing.JButton deleteTagButton; - private javax.swing.JButton editTagButton; private javax.swing.Box.Filler filler1; + private javax.swing.Box.Filler filler2; private javax.swing.JMenu jMenu1; private javax.swing.JPopupMenu jPopupMenu1; private javax.swing.JPopupMenu jPopupMenu2; @@ -579,10 +780,10 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan private javax.swing.JToolBar.Separator jSeparator2; private javax.swing.JToolBar.Separator jSeparator3; private javax.swing.JToolBar.Separator jSeparator4; - private javax.swing.JToolBar.Separator jSeparator5; private javax.swing.JButton rotateLeftButton; private javax.swing.JButton rotateRightButton; private javax.swing.JTextField rotationTextField; + private javax.swing.JButton showTagsButton; private javax.swing.JToolBar toolbar; private javax.swing.JButton zoomInButton; private javax.swing.JButton zoomOutButton; @@ -728,8 +929,8 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan // Add the transforms in reverse order of intended execution. // Note: They MUST be added in this order to ensure translate is // executed last. - imageGroup.getTransforms().clear(); - imageGroup.getTransforms().addAll(translate, rotate, scale); + masterGroup.getTransforms().clear(); + masterGroup.getTransforms().addAll(translate, rotate, scale); // Adjust scroll bar positions for view changes. if (viewportWidth > fxPanel.getWidth()) { diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/FocusChangeEvent.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/FocusChangeEvent.java deleted file mode 100755 index f8cac1a128..0000000000 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/FocusChangeEvent.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2019 Basis Technology Corp. - * Contact: carrier sleuthkit 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.contentviewers.imagetagging; - -import java.util.EventObject; -import javafx.event.Event; -import javafx.event.EventType; - -/** - * - * @author dsmyda - */ -public final class FocusChangeEvent extends EventObject{ - - private final EventType type; - private final StoredTag focused; - - public FocusChangeEvent(Object source, EventType type, StoredTag focused) { - super(source); - this.type = type; - this.focused = focused; - } - - public EventType getType() { - return type; - } - - public StoredTag getNode() { - return focused; - } - -} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/FocusChangeListener.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/FocusChangeListener.java deleted file mode 100755 index 6699e57002..0000000000 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/FocusChangeListener.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.sleuthkit.autopsy.contentviewers.imagetagging; - -import java.util.EventListener; - -/** - * - * @author dsmyda - */ -@FunctionalInterface -public interface FocusChangeListener extends EventListener{ - - void focusChanged(FocusChangeEvent event); -} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTag.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTag.java new file mode 100755 index 0000000000..e54d365331 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTag.java @@ -0,0 +1,343 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 Basis Technology Corp. + * Contact: carrier sleuthkit 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.contentviewers.imagetagging; + +import com.sun.javafx.event.EventDispatchChainImpl; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import javafx.collections.ListChangeListener; +import javafx.scene.Cursor; +import javafx.scene.Group; +import javafx.scene.Node; +import javafx.scene.control.Tooltip; +import javafx.scene.image.ImageView; +import javafx.scene.input.MouseEvent; +import javafx.scene.paint.Color; +import javafx.scene.shape.Circle; +import javafx.scene.shape.Rectangle; +import org.sleuthkit.autopsy.casemodule.services.applicationtags.ContentViewerTagManager.ContentViewerTag; + +/** + * A tagged region displayed over an image. This class contains a "physical tag" + * and 8 edit "handles". The physical tag is a plain old rectangle that defines + * the tag boundaries. The edit handles serve two purposes. One is to represent + * selection. All 8 edit handles will become visible overtop the physical tag + * when the user clicks on the rectangle. The other purpose is to allow the user to edit + * and manipulate the physical tag boundaries (hence the name, edit handle). + * This class should be treated as a logical image tag. + */ +public final class ImageTag extends Group { + + // Used to tell the 8 edit handles to hide if this tag is no longer selected + private final EventDispatchChainImpl ALL_CHILDREN; + + //Notifies listeners that the user has editted the tag boundaries + private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + + //The underlying presistent tag details that this image tag originates from + private final ContentViewerTag appTag; + + public ImageTag(ContentViewerTag appTag, ImageView image) { + ALL_CHILDREN = new EventDispatchChainImpl(); + this.appTag = appTag; + + this.getChildren().addListener((ListChangeListener) change -> { + change.next(); + change.getAddedSubList().forEach((node) -> ALL_CHILDREN.append(node.getEventDispatcher())); + }); + + ImageTagRegion details = appTag.getDetails(); + PhysicalTag physicalTag = new PhysicalTag(details); + + //Defines the max allowable boundary that a user may drag any given handle. + Boundary dragBoundary = (x, y) -> { + double boundingX = image.getX(); + double boundingY = image.getY(); + double width = image.getImage().getWidth(); + double height = image.getImage().getHeight(); + + return x > boundingX + details.getStrokeThickness() / 2 + && x < boundingX + width - details.getStrokeThickness() / 2 + && y > boundingY + details.getStrokeThickness() / 2 + && y < boundingY + height - details.getStrokeThickness() / 2; + }; + + EditHandle bottomLeft = new EditHandle(physicalTag) + .setPosition(Position.bottom(), Position.left()) + .setDrag(dragBoundary, Drag.bottom(), Drag.left()); + + EditHandle bottomRight = new EditHandle(physicalTag) + .setPosition(Position.bottom(), Position.right()) + .setDrag(dragBoundary, Drag.bottom(), Drag.right()); + + EditHandle topLeft = new EditHandle(physicalTag) + .setPosition(Position.top(), Position.left()) + .setDrag(dragBoundary, Drag.top(), Drag.left()); + + EditHandle topRight = new EditHandle(physicalTag) + .setPosition(Position.top(), Position.right()) + .setDrag(dragBoundary, Drag.top(), Drag.right()); + + EditHandle bottomMiddle = new EditHandle(physicalTag) + .setPosition(Position.bottom(), Position.xMiddle()) + .setDrag(dragBoundary, Drag.bottom()); + + EditHandle topMiddle = new EditHandle(physicalTag) + .setPosition(Position.top(), Position.xMiddle()) + .setDrag(dragBoundary, Drag.top()); + + EditHandle rightMiddle = new EditHandle(physicalTag) + .setPosition(Position.right(), Position.yMiddle()) + .setDrag(dragBoundary, Drag.right()); + + EditHandle leftMiddle = new EditHandle(physicalTag) + .setPosition(Position.left(), Position.yMiddle()) + .setDrag(dragBoundary, Drag.left()); + + //The "logical" tag is the Group + this.getChildren().addAll(physicalTag, bottomLeft, bottomRight, topLeft, + topRight, bottomMiddle, topMiddle, rightMiddle, leftMiddle); + + Tooltip.install(this, new Tooltip(appTag.getContentTag() + .getName().getDisplayName())); + + this.addEventHandler(ImageTagControls.NOT_FOCUSED, event -> ALL_CHILDREN.dispatchEvent(event)); + this.addEventHandler(ImageTagControls.FOCUSED, event -> ALL_CHILDREN.dispatchEvent(event)); + } + + /** + * Add a new listener for edit events. These events are generated when a + * user drags on one of the edit "knobs" of the tag. + * + * @param listener + */ + public void subscribeToEditEvents(PropertyChangeListener listener) { + pcs.addPropertyChangeListener(listener); + } + + /** + * Get the app tag that this class represents. + * + * @return + */ + public ContentViewerTag getContentViewerTag() { + return appTag; + } + + /** + * Plain old rectangle that represents an unselected Image Tag + */ + class PhysicalTag extends Rectangle { + + public PhysicalTag(ImageTagRegion details) { + this.setStroke(Color.RED); + this.setFill(Color.RED.deriveColor(0, 0, 0, 0)); + this.setStrokeWidth(details.getStrokeThickness()); + + setX(details.getX()); + setY(details.getY()); + setWidth(details.getWidth()); + setHeight(details.getHeight()); + + this.addEventHandler(ImageTagControls.NOT_FOCUSED, event -> this.setOpacity(1)); + this.addEventHandler(ImageTagControls.FOCUSED, event -> this.setOpacity(0.5)); + } + + /** + * Builds a portable description of the tag region. + * + * @return + */ + public ImageTagRegion getState() { + return new ImageTagRegion() + .setX(this.getX()) + .setY(this.getY()) + .setWidth(this.getWidth()) + .setHeight(this.getHeight()) + .setStrokeThickness(this.getStrokeWidth()); + } + } + + /** + * Draggable "knob" used to manipulate the physical tag boundaries. + */ + class EditHandle extends Circle { + + private final PhysicalTag parent; + + public EditHandle(PhysicalTag parent) { + this.setVisible(false); + + //Hide when the tag is not selected. + this.addEventHandler(ImageTagControls.NOT_FOCUSED, event -> this.setVisible(false)); + this.addEventHandler(ImageTagControls.FOCUSED, event -> this.setVisible(true)); + + this.setRadius(parent.getStrokeWidth()); + this.setFill(parent.getStroke()); + + this.setOnDragDetected(event -> { + this.getParent().setCursor(Cursor.CLOSED_HAND); + }); + + this.setOnMouseReleased(event -> { + this.getParent().setCursor(Cursor.DEFAULT); + pcs.firePropertyChange(new PropertyChangeEvent(this, "Tag Edit", null, parent.getState())); + }); + + this.parent = parent; + } + + /** + * Sets the positioning of this edit handle on the physical tag. + * + * @param vals + * @return + */ + public EditHandle setPosition(Position... vals) { + for (Position pos : vals) { + parent.widthProperty().addListener((obs, oldVal, newVal) -> pos.set(parent, this)); + parent.heightProperty().addListener((obs, oldVal, newVal) -> pos.set(parent, this)); + pos.set(parent, this); + } + return this; + } + + /** + * Sets the drag capabilities for manipulating the physical tag. + * + * @param bounds + * @param vals + * @return + */ + public EditHandle setDrag(Boundary bounds, Drag... vals) { + this.setOnMouseDragged((event) -> { + for (Drag drag : vals) { + drag.perform(parent, event, bounds); + } + }); + return this; + } + } + + /** + * Position strategies for "sticking" to a location on the physical tag when + * it is resized. + */ + static interface Position { + + void set(PhysicalTag parent, Circle knob); + + static Position left() { + return (parent, knob) -> knob.centerXProperty().bind(parent.xProperty()); + } + + static Position right() { + return (parent, knob) -> knob.centerXProperty().bind(parent.xProperty().add(parent.getWidth())); + } + + static Position top() { + return (parent, knob) -> knob.centerYProperty().bind(parent.yProperty()); + } + + static Position bottom() { + return (parent, knob) -> knob.centerYProperty().bind(parent.yProperty().add(parent.getHeight())); + } + + static Position xMiddle() { + return (parent, knob) -> knob.centerXProperty().bind(parent.xProperty().add(parent.getWidth() / 2)); + } + + static Position yMiddle() { + return (parent, knob) -> knob.centerYProperty().bind(parent.yProperty().add(parent.getHeight() / 2)); + } + } + + /** + * Defines the bounding box for which dragging is allowable. + */ + @FunctionalInterface + static interface Boundary { + + boolean isPointInBounds(double x, double y); + } + + /** + * Drag strategies for manipulating the physical tag from a given side of + * the rectangle. + */ + static interface Drag { + + void perform(PhysicalTag parent, MouseEvent event, Boundary b); + + static Drag bottom() { + return (parent, event, bounds) -> { + if (!bounds.isPointInBounds(event.getX(), event.getY())) { + return; + } + + double deltaY = event.getY() - parent.getY(); + if (deltaY > 0) { + parent.setHeight(deltaY); + } + }; + } + + static Drag top() { + return (parent, event, bounds) -> { + if (!bounds.isPointInBounds(event.getX(), event.getY())) { + return; + } + + double deltaY = parent.getY() + parent.getHeight() - event.getY(); + if (deltaY < parent.getY() + parent.getHeight() && deltaY > 0) { + parent.setHeight(deltaY); + parent.setY(event.getY()); + } + }; + } + + static Drag left() { + return (parent, event, bounds) -> { + if (!bounds.isPointInBounds(event.getX(), event.getY())) { + return; + } + + double deltaX = parent.getX() + parent.getWidth() - event.getX(); + if (deltaX < parent.getX() + parent.getWidth() && deltaX > 0) { + parent.setWidth(deltaX); + parent.setX(event.getX()); + } + }; + } + + static Drag right() { + return (parent, event, bounds) -> { + if (!bounds.isPointInBounds(event.getX(), event.getY())) { + return; + } + + double deltaX = event.getX() - parent.getX(); + if (deltaX > 0) { + parent.setWidth(deltaX); + } + }; + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ControlType.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagControls.java similarity index 84% rename from Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ControlType.java rename to Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagControls.java index 6e0c6a2493..d4ee799262 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ControlType.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagControls.java @@ -22,11 +22,10 @@ import javafx.event.Event; import javafx.event.EventType; /** - * - * @author dsmyda + * Focus events for ImageTags to consume. These events trigger selection behavior + * on ImageTags and are originated from the ImageTagsGroup class. */ -public class ControlType { +public class ImageTagControls { public static final EventType NOT_FOCUSED = new EventType<>("NOT_FOCUSED"); public static final EventType FOCUSED = new EventType<>("FOCUSED"); - public static final EventType DELETE = new EventType<>("DELETE"); } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagCreator.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagCreator.java index b0c114ada5..4df4328b2d 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagCreator.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagCreator.java @@ -16,11 +16,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.contentviewers.imagetagging; -import java.util.ArrayList; -import java.util.Collection; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; import javafx.event.EventHandler; import javafx.scene.image.ImageView; import javafx.scene.input.MouseEvent; @@ -28,7 +28,10 @@ import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; /** - * Creates image tags. This tool can be treated like any other JavaFX node. + * Creates image tags. This class attaches itself to a source image, waiting + * for mouse press, mouse drag, and mouse release events. Upon a mouse release + * event, any listeners are updated with the portable description of the new tag + * boundaries (ImageTagRegion). */ public final class ImageTagCreator extends Rectangle { @@ -39,12 +42,18 @@ public final class ImageTagCreator extends Rectangle { //a good balance between visual acuity and loss of selection at the borders //of the image. private double lineThicknessAsPercent = 1.5; - private final double minArea; - private final Collection listeners; + private final double minArea; + //Used to update listeners of the new tag boundaries + private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + private final EventHandler mousePressed; private final EventHandler mouseDragged; private final EventHandler mouseReleased; + + //Handles the unregistering this ImageTagCreator from mouse press, mouse drag, + //and mouse release events of the source image. + private final Runnable disconnect; /** * Adds tagging support to an image, where the 'tag' rectangle will be the @@ -53,8 +62,6 @@ public final class ImageTagCreator extends Rectangle { * @param image Image to tag */ public ImageTagCreator(ImageView image) { - listeners = new ArrayList<>(); - setStroke(Color.RED); setFill(Color.RED.deriveColor(0, 0, 0, 0)); @@ -65,7 +72,7 @@ public final class ImageTagCreator extends Rectangle { setStrokeWidth(lineThicknessPixels); minArea = lineThicknessPixels * lineThicknessPixels; setVisible(false); - + this.mousePressed = (MouseEvent event) -> { if (event.isSecondaryButtonDown()) { return; @@ -79,9 +86,9 @@ public final class ImageTagCreator extends Rectangle { setX(rectangleOriginX); setY(rectangleOriginY); }; - + image.addEventHandler(MouseEvent.MOUSE_PRESSED, this.mousePressed); - + this.mouseDragged = (MouseEvent event) -> { if (event.isSecondaryButtonDown()) { return; @@ -111,45 +118,55 @@ public final class ImageTagCreator extends Rectangle { } setHeight(Math.abs(offsetY)); }; - + image.addEventHandler(MouseEvent.MOUSE_DRAGGED, this.mouseDragged); - + this.mouseReleased = event -> { - if ((this.getWidth() - this.getStrokeWidth()) * - (this.getHeight() - this.getStrokeWidth()) <= minArea) { + //Reject any drags that are too small to count as a meaningful tag. + //Meaningful is described as having an area that is visible that is + //not consumed by the thickness of the stroke. + if ((this.getWidth() - this.getStrokeWidth()) + * (this.getHeight() - this.getStrokeWidth()) <= minArea) { defaultSettings(); return; - } - - //Notify listeners - StoredTagEvent newTagEvent = new StoredTagEvent(this, new StoredTag(image, this.getX(), this.getY(), - this.getX() + this.getWidth(), this.getY() + this.getHeight())); - - listeners.forEach((listener) -> { - listener.newTagEvent(newTagEvent); - }); - - defaultSettings(); + } + + this.pcs.firePropertyChange(new PropertyChangeEvent(this, "New Tag", + null, new ImageTagRegion() + .setX(this.getX()) + .setY(this.getY()) + .setWidth(this.getWidth()) + .setHeight(this.getHeight()) + .setStrokeThickness(lineThicknessPixels))); }; - + image.addEventHandler(MouseEvent.MOUSE_RELEASED, this.mouseReleased); - this.addEventHandler(ControlType.NOT_FOCUSED, (event) -> { + + //Used to remove itself from mouse events on the source image + disconnect = () -> { defaultSettings(); image.removeEventHandler(MouseEvent.MOUSE_RELEASED, mouseReleased); image.removeEventHandler(MouseEvent.MOUSE_DRAGGED, mouseDragged); image.removeEventHandler(MouseEvent.MOUSE_PRESSED, mousePressed); - }); - - this.addEventHandler(ControlType.DELETE, event -> { - defaultSettings(); - image.removeEventHandler(MouseEvent.MOUSE_RELEASED, mouseReleased); - image.removeEventHandler(MouseEvent.MOUSE_DRAGGED, mouseDragged); - image.removeEventHandler(MouseEvent.MOUSE_PRESSED, mousePressed); - }); + }; } - - public void addNewTagListener(StoredTagListener listener) { - listeners.add(listener); + + /** + * Registers a PCL for new tag events. Listeners are updated with a portable + * description (ImageTagRegion) of the new tag, which represent the + * rectangle boundaries. + * + * @param listener + */ + public void addNewTagListener(PropertyChangeListener listener) { + this.pcs.addPropertyChangeListener(listener); + } + + /** + * Removes itself from mouse events on the source image. + */ + public void disconnect() { + this.disconnect.run(); } /** diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagRegion.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagRegion.java new file mode 100755 index 0000000000..b4ba2035b0 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagRegion.java @@ -0,0 +1,82 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 Basis Technology Corp. + * Contact: carrier sleuthkit 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.contentviewers.imagetagging; + +/** + * Bean representation of an image tag. This class is used for storage and + * retrieval of ImageTags from the case database. + */ +public class ImageTagRegion { + + /** + * These fields will be serialized and stored in the case database by the + * ContentViewerTagManager. + */ + private double x; + private double y; + private double width; + private double height; + + private double strokeThickness; + + public ImageTagRegion setStrokeThickness(double thickness) { + this.strokeThickness = thickness; + return this; + } + + public ImageTagRegion setX(double x) { + this.x = x; + return this; + } + + public ImageTagRegion setWidth(double width) { + this.width = width; + return this; + } + + public ImageTagRegion setY(double y) { + this.y = y; + return this; + } + + public ImageTagRegion setHeight(double height) { + this.height = height; + return this; + } + + public double getX() { + return x; + } + + public double getWidth() { + return width; + } + + public double getY() { + return y; + } + + public double getHeight() { + return height; + } + + public double getStrokeThickness() { + return strokeThickness; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsGroup.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsGroup.java new file mode 100755 index 0000000000..86257e55f8 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsGroup.java @@ -0,0 +1,124 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 Basis Technology Corp. + * Contact: carrier sleuthkit 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.contentviewers.imagetagging; + +import com.sun.javafx.event.EventDispatchChainImpl; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import javafx.event.Event; +import javafx.scene.Group; +import javafx.scene.Node; +import javafx.scene.input.MouseEvent; + +/** + * Manages the focus and z-ordering of ImageTags. Only one image tag may be + * selected at a time. Image tags show their 8 edit "handles" upon selection + * (see ImageTag class for more details) and get the highest z-ordering to make + * editing easier. This class is responsible for setting and dropping focus as + * the user navigates from tag to tag. The ImageTag is treated as a logical + * unit, however it's underlying representation consists of the physical + * rectangle and the 8 edit handles. JavaFX will report selection on the Node + * level (so either the Rectangle, or a singe edit handle), which makes keeping + * the entire image tag in focus a non-trivial problem. + */ +public final class ImageTagsGroup extends Group { + + private final EventDispatchChainImpl NO_OP_CHAIN = new EventDispatchChainImpl(); + private final PropertyChangeSupport pcl = new PropertyChangeSupport(this); + + private volatile ImageTag currentFocus; + + public ImageTagsGroup(Node backDrop) { + + //Reset focus of current selection if the back drop has focus. + backDrop.setOnMousePressed((mouseEvent) -> { + if (currentFocus != null) { + currentFocus.getEventDispatcher().dispatchEvent( + new Event(ImageTagControls.NOT_FOCUSED), NO_OP_CHAIN); + currentFocus = null; + } + + this.pcl.firePropertyChange(new PropertyChangeEvent(this, + ImageTagControls.NOT_FOCUSED.getName(), currentFocus, null)); + }); + + //Set the focus of selected tag + this.addEventFilter(MouseEvent.MOUSE_PRESSED, (MouseEvent e) -> { + if (!e.isPrimaryButtonDown()) { + return; + } + + //Pull out the logical image tag that this node is associated with + Node topLevelChild = e.getPickResult().getIntersectedNode(); + while (!this.getChildren().contains(topLevelChild)) { + topLevelChild = topLevelChild.getParent(); + } + + requestFocus((ImageTag) topLevelChild); + }); + } + + /** + * Subscribe to focus change events on Image tags. + * + * @param fcl PCL to be notified which Image tag has been selected. + */ + public void addFocusChangeListener(PropertyChangeListener fcl) { + this.pcl.addPropertyChangeListener(fcl); + } + + /** + * Get the image tag that current has focus. + * + * @return ImageTag instance or null if no tag is in focus. + */ + public ImageTag getFocus() { + return currentFocus; + } + + /** + * Notifies the logical image tag that it is no longer in focus. + * + * @param n + */ + private void resetFocus(ImageTag n) { + n.getEventDispatcher().dispatchEvent(new Event(ImageTagControls.NOT_FOCUSED), NO_OP_CHAIN); + this.pcl.firePropertyChange(new PropertyChangeEvent(this, ImageTagControls.NOT_FOCUSED.getName(), n, null)); + } + + /** + * Notifies the logical image that it is in focus. + * + * @param n + */ + private void requestFocus(ImageTag n) { + if (currentFocus == n) { + return; + } else if (currentFocus != null && currentFocus != n) { + resetFocus(currentFocus); + } + + n.getEventDispatcher().dispatchEvent(new Event(ImageTagControls.FOCUSED), NO_OP_CHAIN); + this.pcl.firePropertyChange(new PropertyChangeEvent(this, ImageTagControls.FOCUSED.getName(), currentFocus, n)); + + currentFocus = n; + n.toFront(); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTag.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTag.java deleted file mode 100755 index 1a97918dee..0000000000 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTag.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2019 Basis Technology Corp. - * Contact: carrier sleuthkit 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.contentviewers.imagetagging; - -import com.sun.javafx.event.EventDispatchChainImpl; -import javafx.collections.ListChangeListener; -import javafx.scene.Cursor; -import javafx.scene.Group; -import javafx.scene.Node; -import javafx.scene.image.ImageView; -import javafx.scene.input.MouseEvent; -import javafx.scene.paint.Color; -import javafx.scene.shape.Circle; -import javafx.scene.shape.Rectangle; -import org.sleuthkit.datamodel.ContentTag; - -/** - * - * @author dsmyda - */ -public final class StoredTag extends Group { - - private final EventDispatchChainImpl ALL_CHILDREN; - private final PhysicalTag physicalTag; - - public StoredTag(ImageView image, double x, double y, double x1, double y1) { - ALL_CHILDREN = new EventDispatchChainImpl(); - - this.getChildren().addListener((ListChangeListener) change -> { - change.next(); - change.getAddedSubList().forEach((node) -> ALL_CHILDREN.append(node.getEventDispatcher())); - }); - - double min = Math.min(image.getImage().getWidth(), image.getImage().getHeight()); - double lineThicknessPixels = min * 1.5 / 100.0; - physicalTag = new PhysicalTag(image); - physicalTag.setStrokeWidth(lineThicknessPixels); - - EditHandle bottomLeft = new EditHandle(); - bottomLeft.setPosition(Position.bottom(), Position.left()); - bottomLeft.setDrag(Drag.bottom(), Drag.left()); - - EditHandle bottomRight = new EditHandle(); - bottomRight.setPosition(Position.bottom(), Position.right()); - bottomRight.setDrag(Drag.bottom(), Drag.right()); - - EditHandle topLeft = new EditHandle(); - topLeft.setPosition(Position.top(), Position.left()); - topLeft.setDrag(Drag.top(), Drag.left()); - - EditHandle topRight = new EditHandle(); - topRight.setPosition(Position.top(), Position.right()); - topRight.setDrag(Drag.top(), Drag.right()); - - EditHandle bottomMiddle = new EditHandle(); - bottomMiddle.setPosition(Position.bottom(), Position.xMiddle()); - bottomMiddle.setDrag(Drag.bottom()); - - EditHandle topMiddle = new EditHandle(); - topMiddle.setPosition(Position.top(), Position.xMiddle()); - topMiddle.setDrag(Drag.top()); - - EditHandle rightMiddle = new EditHandle(); - rightMiddle.setPosition(Position.right(), Position.yMiddle()); - rightMiddle.setDrag(Drag.right()); - - EditHandle leftMiddle = new EditHandle(); - leftMiddle.setPosition(Position.left(), Position.yMiddle()); - leftMiddle.setDrag(Drag.left()); - - this.getChildren().addAll(physicalTag, bottomLeft, bottomRight, topLeft, - topRight, bottomMiddle, topMiddle, rightMiddle, leftMiddle); - - //Position the tag on the image. The edit knobs will be notified of - //the new coords and adjust themselves. - physicalTag.setX(x); - physicalTag.setY(y); - physicalTag.setWidth(x1 - x); - physicalTag.setHeight(y1 - y); - - this.focusedProperty().addListener((ov, oldV, newV) -> { - if(!newV) { - System.out.println("NOT FOCUSED"); - } else { - System.out.println("GAINED FOCUS"); - } - }); - - this.addEventHandler(ControlType.NOT_FOCUSED, event -> ALL_CHILDREN.dispatchEvent(event)); - this.addEventHandler(ControlType.FOCUSED, event -> ALL_CHILDREN.dispatchEvent(event)); - this.addEventHandler(ControlType.DELETE, event -> ALL_CHILDREN.dispatchEvent(event)); - } - - public void addContentTag(ContentTag t) { - physicalTag.linkContentTag(t); - } - - public ContentTag getContentTag() { - return physicalTag.getContentTag(); - } - - class PhysicalTag extends Rectangle { - - private final ImageView image; - private ContentTag tag; - - public PhysicalTag(ImageView image) { - this.setStroke(Color.RED); - this.setFill(Color.RED.deriveColor(0, 0, 0, 0)); - - this.addEventHandler(ControlType.NOT_FOCUSED, event -> this.setOpacity(1)); - this.addEventHandler(ControlType.FOCUSED, event -> this.setOpacity(0.5)); - - this.addEventHandler(ControlType.DELETE, event -> { - this.setVisible(false); - //TODO - delete tag from persistent storage here. - }); - - this.image = image; - } - - private void save() { - //TODO - persist tag - } - - public void linkContentTag(ContentTag t) { - tag = t; - } - - public ContentTag getContentTag() { - return tag; - } - - private ImageView getUnderlyingImage() { - return image; - } - - private class ImageRegion { - - } - } - - class EditHandle extends Circle { - - public EditHandle() { - super(physicalTag.getStrokeWidth(), physicalTag.getStroke()); - this.setVisible(false); - - //Manipulate the parent rectangle when this knob is dragged. - this.addEventHandler(ControlType.NOT_FOCUSED, event -> this.setVisible(false)); - this.addEventHandler(ControlType.FOCUSED, event -> this.setVisible(true)); - this.addEventHandler(ControlType.DELETE, event -> this.setVisible(false)); - this.setOnDragDetected(event -> this.getParent().setCursor(Cursor.CLOSED_HAND)); - this.setOnMouseReleased(event -> { - this.getParent().setCursor(Cursor.DEFAULT); - physicalTag.save(); - }); - } - - public void setPosition(Position... vals) { - for (Position pos : vals) { - physicalTag.widthProperty().addListener((obs, oldVal, newVal) -> pos.set(physicalTag, this)); - physicalTag.heightProperty().addListener((obs, oldVal, newVal) -> pos.set(physicalTag, this)); - } - } - - public void setDrag(Drag... vals) { - this.setOnMouseDragged((event) -> { - for (Drag drag : vals) { - drag.perform(physicalTag, event, physicalTag.getUnderlyingImage()); - } - }); - } - } - - static interface Position { - - void set(Rectangle parent, Circle knob); - - static Position left() { - return (parent, knob) -> knob.centerXProperty().bind(parent.xProperty()); - } - - static Position right() { - return (parent, knob) -> knob.centerXProperty().bind(parent.xProperty().add(parent.getWidth())); - } - - static Position top() { - return (parent, knob) -> knob.centerYProperty().bind(parent.yProperty()); - } - - static Position bottom() { - return (parent, knob) -> knob.centerYProperty().bind(parent.yProperty().add(parent.getHeight())); - } - - static Position xMiddle() { - return (parent, knob) -> knob.centerXProperty().bind(parent.xProperty().add(parent.getWidth() / 2)); - } - - static Position yMiddle() { - return (parent, knob) -> knob.centerYProperty().bind(parent.yProperty().add(parent.getHeight() / 2)); - } - } - - static interface Drag { - - void perform(Rectangle parent, MouseEvent event, ImageView image); - - static Drag bottom() { - return (parent, event, image) -> { - double deltaY = event.getY() - parent.getY(); - if (deltaY > 0 && event.getY() - < image.getY() + image.getImage().getHeight() - - parent.getStrokeWidth() / 2) { - parent.setHeight(deltaY); - } - }; - } - - static Drag top() { - return (parent, event, image) -> { - double deltaY = parent.getY() + parent.getHeight() - event.getY(); - if (deltaY < parent.getY() + parent.getHeight() && event.getY() - > image.getY() + parent.getStrokeWidth() / 2 && deltaY > 0) { - parent.setHeight(deltaY); - parent.setY(event.getY()); - } - }; - } - - static Drag left() { - return (parent, event, image) -> { - double deltaX = parent.getX() + parent.getWidth() - event.getX(); - if (deltaX < parent.getX() + parent.getWidth() - && event.getX() > image.getX() + parent.getStrokeWidth() / 2 - && deltaX > 0) { - parent.setWidth(deltaX); - parent.setX(event.getX()); - } - }; - } - - static Drag right() { - return (parent, event, image) -> { - double deltaX = event.getX() - parent.getX(); - if (deltaX > 0 && event.getX() < image.getX() - + image.getImage().getWidth() - parent.getStrokeWidth() / 2) { - parent.setWidth(deltaX); - } - }; - } - } -} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTagEvent.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTagEvent.java deleted file mode 100755 index e1cba2d7f6..0000000000 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTagEvent.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2019 Basis Technology Corp. - * Contact: carrier sleuthkit 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.contentviewers.imagetagging; - - -import java.util.EventObject; - -/** - * - * @author dsmyda - */ -public final class StoredTagEvent extends EventObject { - private final StoredTag tag; - - public StoredTagEvent(Object source, StoredTag tag) { - super(source); - this.tag = tag; - } - - public StoredTag getTag() { - return tag; - } -} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTagListener.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTagListener.java deleted file mode 100755 index a727cc4f53..0000000000 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/StoredTagListener.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2019 Basis Technology Corp. - * Contact: carrier sleuthkit 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.contentviewers.imagetagging; - - -import java.util.EventListener; - -/** - * - * @author dsmyda - */ -@FunctionalInterface -public interface StoredTagListener extends EventListener { - - void newTagEvent(StoredTagEvent tagEvent); -} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/TopLevelTagsGroup.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/TopLevelTagsGroup.java deleted file mode 100755 index 2a00df6f7a..0000000000 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/TopLevelTagsGroup.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2019 Basis Technology Corp. - * Contact: carrier sleuthkit 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.contentviewers.imagetagging; - -import com.sun.javafx.event.EventDispatchChainImpl; -import java.util.ArrayList; -import java.util.Collection; -import javafx.event.Event; -import javafx.scene.Group; -import javafx.scene.Node; -import javafx.scene.image.ImageView; -import javafx.scene.input.MouseEvent; - -/** - * Top level group containing Image and all existing tags. - */ -public final class TopLevelTagsGroup extends Group { - - private final EventDispatchChainImpl NO_OP_CHAIN = new EventDispatchChainImpl(); - private final Collection listeners; - - private Node lastFocus; - private final ImageView baseImage; - - public TopLevelTagsGroup(ImageView image) { - super(image); - baseImage = image; - listeners = new ArrayList<>(); - - //Manage focus, such that only one child can be set at a time. - this.addEventFilter(MouseEvent.MOUSE_PRESSED, (MouseEvent e) -> { - if (!e.isPrimaryButtonDown()) { - return; - } - - Node topLevelChild = e.getPickResult().getIntersectedNode(); - while (!this.getChildren().contains(topLevelChild)) { - topLevelChild = topLevelChild.getParent(); - } - - requestFocus(topLevelChild); - }); - } - - public void addFocusChangeListener(FocusChangeListener fcl) { - listeners.add(fcl); - } - - private void resetFocus(Node n) { - n.getEventDispatcher().dispatchEvent(new Event(ControlType.NOT_FOCUSED), NO_OP_CHAIN); - if(n instanceof StoredTag) { - listeners.forEach((listener) -> { - listener.focusChanged(new FocusChangeEvent(this, ControlType.NOT_FOCUSED, (StoredTag) n)); - }); - } - } - - public void deleteNode(Node n) { - if (lastFocus == n) { - resetFocus(n); - lastFocus = null; - } - n.getEventDispatcher().dispatchEvent(new Event(ControlType.DELETE), NO_OP_CHAIN); - this.getChildren().remove(n); - } - - public void requestFocus(Node n) { - if (lastFocus == n) { - return; - } else if (lastFocus != null && lastFocus != n) { - resetFocus(lastFocus); - } - - n.getEventDispatcher().dispatchEvent(new Event(ControlType.FOCUSED), NO_OP_CHAIN); - if(n instanceof StoredTag) { - listeners.forEach((listener) -> { - listener.focusChanged(new FocusChangeEvent(this, ControlType.FOCUSED, (StoredTag) n)); - }); - } - - if (n != baseImage) { - n.toFront(); - } - - lastFocus = n; - } -} From 057fa9d48cd0e8acf0830f873d6cdae05c856bd5 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Mon, 3 Jun 2019 14:01:23 -0400 Subject: [PATCH 016/115] Bug fixes, comment fixes, more code clean up --- .../ContentViewerTagManager.java | 32 +++++++++---------- .../autopsy/contentviewers/Bundle.properties | 1 - .../contentviewers/Bundle.properties-MERGED | 1 - .../contentviewers/MediaViewImagePanel.form | 11 ------- .../contentviewers/MediaViewImagePanel.java | 32 +++++++------------ .../contentviewers/imagetagging/ImageTag.java | 8 ++--- .../imagetagging/ImageTagsGroup.java | 10 +++--- 7 files changed, 35 insertions(+), 60 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ContentViewerTagManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ContentViewerTagManager.java index 33b50bab07..105a643331 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ContentViewerTagManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ContentViewerTagManager.java @@ -37,7 +37,7 @@ import org.sleuthkit.datamodel.TskCoreException; public class ContentViewerTagManager { //Used to convert Java beans into the physical representation that will be stored - //in the database (for now, JSON was chosen). + //in the database. private static final ObjectMapper SERIALIZER = new ObjectMapper(); public static final String TABLE_NAME = "beta_tag_app_data"; @@ -53,20 +53,19 @@ public class ContentViewerTagManager { /** * Creates and saves a new ContentViewerTag in the case database. The * generic tag data instance T will be automatically serialized into a - * storable format and persisted. + * storable format. * - * @param Generic java bean class type that will be serialized into a - * storable format for persistence + * @param Generic class type that will be serialized into a + * storable format for persistence. * @param contentTag ContentTag that this ContentViewerTag is associated - * with (1:1) + * with (1:1). * @param tagDataBean Data instance that contains the tag information to be * persisted. * @return An instance of a ContentViewerTag of type T, which contains all * the stored information. * - * @throws SerializationException Thrown if the tag data bean instance T - * could not be serialized into a storable format for persistence in the - * case database. + * @throws SerializationException Thrown if the tag data instance T + * could not be serialized into a storable format. * @throws TskCoreException Thrown if this operation did not successfully * persist in the case database. * @throws NoCurrentCaseException Thrown if invocation of this method occurs @@ -89,15 +88,14 @@ public class ContentViewerTagManager { * Updates the ContentViewerTag instance with the new tag data T and * persists the changes to the case database. * - * @param Generic java bean class type that will be serialized into a - * storable format for persistence + * @param Generic class type that will be serialized into a + * storable format. * @param oldTag ContentViewerTag instance to be updated * @param tagDataBean Data instance that contains the updated information to * be persisted. * - * @throws SerializationException Thrown if the tag data bean instance T - * could not be serialized into a storable format for persistence in the - * case database. + * @throws SerializationException Thrown if the tag data instance T + * could not be serialized into a storable format. * @throws TskCoreException Thrown if this operation did not successfully * persist in the case database. * @throws NoCurrentCaseException Thrown if invocation of this method occurs @@ -119,15 +117,15 @@ public class ContentViewerTagManager { /** * Retrieves a ContentViewerTag instance that is associated with the - * specified ContentTag. The Java bean class that represents the technical + * specified ContentTag. The Java class T that represents the technical * details of the tag should be passed so that automatic binding can take * place. * - * @param Java bean class type that will be instantiated and filled in + * @param Generic class type that will be instantiated and filled in * with data. * @param contentTag ContentTag that this ContentViewerTag is associated * with (1:1) - * @param clazz Java bean class that will be instantiated and filled in with + * @param clazz Generic class that will be instantiated and filled in with * data. * @return ContentViewerTag with an instance of T as a member variable or * null if the content tag does not have an associated ContentViewerTag of @@ -187,7 +185,7 @@ public class ContentViewerTagManager { * for the tag id, the attached Content tag object, and the Java bean * instance that describes the technical details for reconstructing the tag. * - * @param Java bean class type that will be instantiated and filled in + * @param Generic class type that will be instantiated and filled in * with data. */ public static class ContentViewerTag { diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties index a8b66e1c31..0f5f1e841e 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties @@ -91,5 +91,4 @@ MediaPlayerPanel.playButton.text=\u25ba MediaPlayerPanel.infoLabel.text=No Errors MediaViewImagePanel.deleteTagButton.text=Delete Tag MediaViewImagePanel.createTagButton.text=Create Tag -MediaViewImagePanel.jMenu1.text=jMenu1 MediaViewImagePanel.showTagsButton.text=Hide Tags diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED index 44cae34fd9..f04db7f709 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED @@ -153,7 +153,6 @@ MediaPlayerPanel.playButton.text=\u25ba MediaPlayerPanel.infoLabel.text=No Errors MediaViewImagePanel.deleteTagButton.text=Delete Tag MediaViewImagePanel.createTagButton.text=Create Tag -MediaViewImagePanel.jMenu1.text=jMenu1 MediaViewImagePanel.showTagsButton.text=Hide Tags # {0} - tableName SQLiteViewer.readTable.errorText=Error getting rows for table: {0} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.form b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.form index 447957d66c..befc6fe7a6 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.form @@ -2,17 +2,6 @@
- - - - - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java index 5d6fa7e193..bb921a2974 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java @@ -196,7 +196,10 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan if (imageTagCreator != null) { imageTagCreator.disconnect(); } - showTagsButton.setText("Hide Tags"); + showTagsButton.setText(DisplayOptions.HIDE_TAGS.getName()); + showTagsButton.setEnabled(true); + createTagButton.setEnabled(true); + deleteTagButton.setEnabled(false); scrollPane.setContent(null); scrollPane.setContent(masterGroup); }); @@ -347,20 +350,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan * Build the image tag, add an edit event call back to persist all * edits made on this image tag instance. */ - ImageTag imageTag = new ImageTag(contentViewerTag, fxImageView); - imageTag.subscribeToEditEvents((event) -> { - try { - scrollPane.setCursor(Cursor.WAIT); - ImageTagRegion newRegion = (ImageTagRegion) event.getNewValue(); - ContentViewerTagManager.updateTag(contentViewerTag, newRegion); - scrollPane.setCursor(Cursor.DEFAULT); - } catch (SerializationException | NoCurrentCaseException | TskCoreException ex) { - LOGGER.log(Level.WARNING, "Could not save edit for image tag in case db", ex); //NON-NLS - //TODO - pop dialog - } - }); - - tagsGroup.getChildren().add(imageTag); + tagsGroup.getChildren().add(buildImageTag(contentViewerTag)); }); return tagsGroup; @@ -407,7 +397,6 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan // //GEN-BEGIN:initComponents private void initComponents() { - jMenu1 = new javax.swing.JMenu(); jPopupMenu1 = new javax.swing.JPopupMenu(); jPopupMenu2 = new javax.swing.JPopupMenu(); toolbar = new javax.swing.JToolBar(); @@ -428,8 +417,6 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan jSeparator3 = new javax.swing.JToolBar.Separator(); showTagsButton = new javax.swing.JButton(); - org.openide.awt.Mnemonics.setLocalizedText(jMenu1, org.openide.util.NbBundle.getMessage(MediaViewImagePanel.class, "MediaViewImagePanel.jMenu1.text")); // NOI18N - setBackground(new java.awt.Color(0, 0, 0)); addComponentListener(new java.awt.event.ComponentAdapter() { public void componentResized(java.awt.event.ComponentEvent evt) { @@ -661,6 +648,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan //Persist and build image tag Platform.runLater(() -> { try { + scrollPane.setCursor(Cursor.WAIT); ContentViewerTag contentViewerTag = storeImageTag(tag, result); ImageTag imageTag = buildImageTag(contentViewerTag); tagsGroup.getChildren().add(imageTag); @@ -668,6 +656,8 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan LOGGER.log(Level.WARNING, "Could not save new image tag in case db", ex); //NON-NLS //TODO pop dialog } + + scrollPane.setCursor(Cursor.DEFAULT); }); }); @@ -683,7 +673,8 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan }//GEN-LAST:event_createTagButtonActionPerformed /** - * + * Creates an ImageTag instance from the ContentViewerTag. + * * @param contentViewerTag * @return */ @@ -696,11 +687,11 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan scrollPane.setCursor(Cursor.WAIT); ImageTagRegion newRegion = (ImageTagRegion) edit.getNewValue(); ContentViewerTagManager.updateTag(contentViewerTag, newRegion); - scrollPane.setCursor(Cursor.DEFAULT); } catch (SerializationException | TskCoreException | NoCurrentCaseException ex) { LOGGER.log(Level.WARNING, "Could not save edit for image tag in case db", ex); //NON-NLS //TODO pop dialog } + scrollPane.setCursor(Cursor.DEFAULT); }); return imageTag; } @@ -773,7 +764,6 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan private javax.swing.JButton deleteTagButton; private javax.swing.Box.Filler filler1; private javax.swing.Box.Filler filler2; - private javax.swing.JMenu jMenu1; private javax.swing.JPopupMenu jPopupMenu1; private javax.swing.JPopupMenu jPopupMenu2; private javax.swing.JToolBar.Separator jSeparator1; diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTag.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTag.java index e54d365331..80b1cbe07f 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTag.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTag.java @@ -54,16 +54,16 @@ public final class ImageTag extends Group { //The underlying presistent tag details that this image tag originates from private final ContentViewerTag appTag; - public ImageTag(ContentViewerTag appTag, ImageView image) { + public ImageTag(ContentViewerTag contentViewerTag, ImageView image) { ALL_CHILDREN = new EventDispatchChainImpl(); - this.appTag = appTag; + this.appTag = contentViewerTag; this.getChildren().addListener((ListChangeListener) change -> { change.next(); change.getAddedSubList().forEach((node) -> ALL_CHILDREN.append(node.getEventDispatcher())); }); - ImageTagRegion details = appTag.getDetails(); + ImageTagRegion details = contentViewerTag.getDetails(); PhysicalTag physicalTag = new PhysicalTag(details); //Defines the max allowable boundary that a user may drag any given handle. @@ -115,7 +115,7 @@ public final class ImageTag extends Group { this.getChildren().addAll(physicalTag, bottomLeft, bottomRight, topLeft, topRight, bottomMiddle, topMiddle, rightMiddle, leftMiddle); - Tooltip.install(this, new Tooltip(appTag.getContentTag() + Tooltip.install(this, new Tooltip(contentViewerTag.getContentTag() .getName().getDisplayName())); this.addEventHandler(ImageTagControls.NOT_FOCUSED, event -> ALL_CHILDREN.dispatchEvent(event)); diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsGroup.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsGroup.java index 86257e55f8..828b083d80 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsGroup.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsGroup.java @@ -41,7 +41,7 @@ import javafx.scene.input.MouseEvent; public final class ImageTagsGroup extends Group { private final EventDispatchChainImpl NO_OP_CHAIN = new EventDispatchChainImpl(); - private final PropertyChangeSupport pcl = new PropertyChangeSupport(this); + private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); private volatile ImageTag currentFocus; @@ -55,7 +55,7 @@ public final class ImageTagsGroup extends Group { currentFocus = null; } - this.pcl.firePropertyChange(new PropertyChangeEvent(this, + this.pcs.firePropertyChange(new PropertyChangeEvent(this, ImageTagControls.NOT_FOCUSED.getName(), currentFocus, null)); }); @@ -81,7 +81,7 @@ public final class ImageTagsGroup extends Group { * @param fcl PCL to be notified which Image tag has been selected. */ public void addFocusChangeListener(PropertyChangeListener fcl) { - this.pcl.addPropertyChangeListener(fcl); + this.pcs.addPropertyChangeListener(fcl); } /** @@ -100,7 +100,7 @@ public final class ImageTagsGroup extends Group { */ private void resetFocus(ImageTag n) { n.getEventDispatcher().dispatchEvent(new Event(ImageTagControls.NOT_FOCUSED), NO_OP_CHAIN); - this.pcl.firePropertyChange(new PropertyChangeEvent(this, ImageTagControls.NOT_FOCUSED.getName(), n, null)); + this.pcs.firePropertyChange(new PropertyChangeEvent(this, ImageTagControls.NOT_FOCUSED.getName(), n, null)); } /** @@ -116,7 +116,7 @@ public final class ImageTagsGroup extends Group { } n.getEventDispatcher().dispatchEvent(new Event(ImageTagControls.FOCUSED), NO_OP_CHAIN); - this.pcl.firePropertyChange(new PropertyChangeEvent(this, ImageTagControls.FOCUSED.getName(), currentFocus, n)); + this.pcs.firePropertyChange(new PropertyChangeEvent(this, ImageTagControls.FOCUSED.getName(), currentFocus, n)); currentFocus = n; n.toFront(); From 64e7e03ec5b7f9c41e35a1eb16fb31096cc75b31 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Mon, 3 Jun 2019 14:04:38 -0400 Subject: [PATCH 017/115] Fixed generic type T warning --- .../services/applicationtags/ContentViewerTagManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ContentViewerTagManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ContentViewerTagManager.java index 105a643331..33d7987d8a 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ContentViewerTagManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ContentViewerTagManager.java @@ -139,7 +139,7 @@ public class ContentViewerTagManager { public static ContentViewerTag getTag(ContentTag contentTag, Class clazz) throws TskCoreException, NoCurrentCaseException { try { String selectTemplateInstance = String.format(SELECT_TAG_DATA, contentTag.getId()); - final ArrayList result = new ArrayList<>(); + final ArrayList> result = new ArrayList<>(); Case.getCurrentCaseThrows().getSleuthkitCase().getCaseDbAccessManager() .select(selectTemplateInstance, (ResultSet rs) -> { try { From 6a6a282e66acece02fa28477177550258be79da4 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Mon, 3 Jun 2019 14:21:56 -0400 Subject: [PATCH 018/115] Added more space for text in buttons --- .../contentviewers/MediaViewImagePanel.form | 21 +++++++++++++++++++ .../contentviewers/MediaViewImagePanel.java | 13 ++++++++---- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.form b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.form index befc6fe7a6..fe7843bf7a 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.form @@ -250,6 +250,16 @@ + + + + + + + + + + @@ -265,6 +275,17 @@ + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java index bb921a2974..1e039d614a 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java @@ -268,7 +268,6 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan tagsGroup = buildImageTagsGroup(contentViewerTags); } catch (TskCoreException | NoCurrentCaseException ex) { LOGGER.log(Level.WARNING, "Could not retrieve image tags for file in case db", ex); //NON-NLS - //TODO - pop dialog } scrollPane.setContent(masterGroup); } else { @@ -539,6 +538,10 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan deleteTagButton.setFocusable(false); deleteTagButton.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); deleteTagButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + deleteTagButton.setMaximumSize(new java.awt.Dimension(61, 21)); + deleteTagButton.setMinimumSize(new java.awt.Dimension(61, 21)); + deleteTagButton.setPreferredSize(new java.awt.Dimension(61, 21)); + deleteTagButton.setRequestFocusEnabled(false); deleteTagButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); deleteTagButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -551,6 +554,11 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan org.openide.awt.Mnemonics.setLocalizedText(showTagsButton, org.openide.util.NbBundle.getMessage(MediaViewImagePanel.class, "MediaViewImagePanel.showTagsButton.text")); // NOI18N showTagsButton.setFocusable(false); showTagsButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + showTagsButton.setMaximumSize(new java.awt.Dimension(61, 21)); + showTagsButton.setMinimumSize(new java.awt.Dimension(61, 21)); + showTagsButton.setOpaque(false); + showTagsButton.setPreferredSize(new java.awt.Dimension(61, 21)); + showTagsButton.setRolloverEnabled(false); showTagsButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); showTagsButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -618,7 +626,6 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan tagsGroup.getChildren().remove(tagInFocus); } catch (TskCoreException | NoCurrentCaseException ex) { LOGGER.log(Level.WARNING, "Could not delete image tag in case db", ex); //NON-NLS - //TODO pop dialog } scrollPane.setCursor(Cursor.DEFAULT); @@ -654,7 +661,6 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan tagsGroup.getChildren().add(imageTag); } catch (TskCoreException | SerializationException | NoCurrentCaseException ex) { LOGGER.log(Level.WARNING, "Could not save new image tag in case db", ex); //NON-NLS - //TODO pop dialog } scrollPane.setCursor(Cursor.DEFAULT); @@ -689,7 +695,6 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan ContentViewerTagManager.updateTag(contentViewerTag, newRegion); } catch (SerializationException | TskCoreException | NoCurrentCaseException ex) { LOGGER.log(Level.WARNING, "Could not save edit for image tag in case db", ex); //NON-NLS - //TODO pop dialog } scrollPane.setCursor(Cursor.DEFAULT); }); From 2cdf0dd66d6328934e61eb87b6e1647ddd9f37e6 Mon Sep 17 00:00:00 2001 From: Raman Date: Mon, 3 Jun 2019 15:45:00 -0400 Subject: [PATCH 019/115] 4963: DataResultTable is slow to load. - load S C & O columns data in background for AbstractContentNode and all it's derived classes. --- .../relationships/MessageNode.java | 11 -- .../datamodel/AbstractAbstractFileNode.java | 94 +++--------- .../datamodel/AbstractContentNode.java | 145 ++++++++++++++++++ .../datamodel/BlackboardArtifactNode.java | 84 ++++++---- .../datamodel/Bundle.properties-MERGED | 1 + .../autopsy/datamodel/GetSCOTask.java | 24 +-- 6 files changed, 234 insertions(+), 125 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java index e6ac3f507f..2f4ce1157a 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java @@ -81,17 +81,6 @@ final class MessageNode extends BlackboardArtifactNode { sheetSet.put(new NodeProperty<>("Type", Bundle.MessageNode_Node_Property_Type(), "", getDisplayName())); //NON-NLS - addScoreProperty(sheetSet, tags); - - CorrelationAttributeInstance correlationAttribute = null; - if (UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) { - correlationAttribute = getCorrelationAttributeInstance(); - } - addCommentProperty(sheetSet, tags, correlationAttribute); - - if (UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) { - addCountProperty(sheetSet, correlationAttribute); - } final BlackboardArtifact artifact = getArtifact(); BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID()); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java index d6b589f977..e8d71caae7 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2018 Basis Technology Corp. + * Copyright 2011-2019 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.datamodel; -import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.lang.ref.WeakReference; @@ -27,8 +26,6 @@ import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.logging.Level; import java.util.stream.Collectors; import org.apache.commons.io.FilenameUtils; @@ -65,6 +62,7 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.Tag; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; @@ -82,10 +80,6 @@ public abstract class AbstractAbstractFileNode extends A private static final Set CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.CURRENT_CASE, Case.Events.CONTENT_TAG_ADDED, Case.Events.CONTENT_TAG_DELETED, Case.Events.CR_COMMENT_CHANGED); - // pool to run long running translation and getSCO tasks in backgound - private static final ExecutorService translationSCOPool; - private static final Integer MAX_POOL_SIZE = 10; - /** * @param abstractFile file to wrap */ @@ -102,7 +96,7 @@ public abstract class AbstractAbstractFileNode extends A } if (UserPreferences.displayTranslatedFileNames()) { - AbstractAbstractFileNode.translationSCOPool.submit(new TranslationTask( + backgroundTasksPool.submit(new TranslationTask( new WeakReference<>(this), weakPcl)); } @@ -110,14 +104,7 @@ public abstract class AbstractAbstractFileNode extends A // or when tags are added. Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, weakPcl); } - - static { - //Initialize this pool only once! This will be used by every instance of AAFN - //to do their heavy duty SCO column and translation updates. - translationSCOPool = Executors.newFixedThreadPool(MAX_POOL_SIZE, - new ThreadFactoryBuilder().setNameFormat("translation-and-sco-task-thread-%d").build()); - } - + /** * The finalizer removes event listeners as the BlackboardArtifactNode is * being garbage collected. Yes, we know that finalizers are considered to @@ -138,17 +125,7 @@ public abstract class AbstractAbstractFileNode extends A Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, weakPcl); } - /** - * Event signals to indicate the background tasks have completed processing. - * Currently, we have one property task in the background: - * - * 1) Retreiving the translation of the file name - */ - enum NodeSpecificEvents { - TRANSLATION_AVAILABLE, - SCO_AVAILABLE - } - + private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> { String eventType = evt.getPropertyName(); @@ -192,7 +169,7 @@ public abstract class AbstractAbstractFileNode extends A } else if (eventType.equals(Case.Events.CONTENT_TAG_ADDED.toString())) { ContentTagAddedEvent event = (ContentTagAddedEvent) evt; if (event.getAddedTag().getContent().equals(content)) { - List tags = getContentTagsFromDatabase(); + List tags = this.getAllTagsFromDatabase(); Pair scorePropAndDescr = getScorePropertyAndDescription(tags); Score value = scorePropAndDescr.getLeft(); String descr = scorePropAndDescr.getRight(); @@ -204,7 +181,7 @@ public abstract class AbstractAbstractFileNode extends A } else if (eventType.equals(Case.Events.CONTENT_TAG_DELETED.toString())) { ContentTagDeletedEvent event = (ContentTagDeletedEvent) evt; if (event.getDeletedTagInfo().getContentID() == content.getId()) { - List tags = getContentTagsFromDatabase(); + List tags = getAllTagsFromDatabase(); Pair scorePropAndDescr = getScorePropertyAndDescription(tags); Score value = scorePropAndDescr.getLeft(); String descr = scorePropAndDescr.getRight(); @@ -216,7 +193,7 @@ public abstract class AbstractAbstractFileNode extends A } else if (eventType.equals(Case.Events.CR_COMMENT_CHANGED.toString())) { CommentChangedEvent event = (CommentChangedEvent) evt; if (event.getContentID() == content.getId()) { - List tags = getContentTagsFromDatabase(); + List tags = getAllTagsFromDatabase(); CorrelationAttributeInstance attribute = getCorrelationAttributeInstance(); updateSheet(new NodeProperty<>(COMMENT.toString(), COMMENT.toString(), NO_DESCR, getCommentProperty(tags, attribute))); } @@ -249,38 +226,6 @@ public abstract class AbstractAbstractFileNode extends A */ private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null); - /** - * Updates the values of the properties in the current property sheet with - * the new properties being passed in. Only if that property exists in the - * current sheet will it be applied. That way, we allow for subclasses to - * add their own (or omit some!) properties and we will not accidentally - * disrupt their UI. - * - * Race condition if not synchronized. Only one update should be applied at - * a time. - * - * @param newProps New file property instances to be updated in the current - * sheet. - */ - private synchronized void updateSheet(NodeProperty... newProps) { - //Refresh ONLY those properties in the sheet currently. Subclasses may have - //only added a subset of our properties or their own props.s - Sheet visibleSheet = this.getSheet(); - Sheet.Set visibleSheetSet = visibleSheet.get(Sheet.PROPERTIES); - Property[] visibleProps = visibleSheetSet.getProperties(); - for (NodeProperty newProp : newProps) { - for (int i = 0; i < visibleProps.length; i++) { - if (visibleProps[i].getName().equals(newProp.getName())) { - visibleProps[i] = newProp; - } - } - } - visibleSheetSet.put(visibleProps); - visibleSheet.put(visibleSheetSet); - //setSheet() will notify Netbeans to update this node in the UI. - this.setSheet(visibleSheet); - } - /* * This is called when the node is first initialized. Any new updates or * changes happen by directly manipulating the sheet. That means we can fire @@ -389,7 +334,7 @@ public abstract class AbstractAbstractFileNode extends A // Get the SCO columns data in a background task - AbstractAbstractFileNode.translationSCOPool.submit(new GetSCOTask( + backgroundTasksPool.submit(new GetSCOTask( new WeakReference<>(this), weakPcl)); properties.add(new NodeProperty<>(LOCATION.toString(), LOCATION.toString(), NO_DESCR, getContentPath(content))); @@ -453,7 +398,8 @@ public abstract class AbstractAbstractFileNode extends A "AbstractAbstractFileNode.createSheet.count.hashLookupNotRun.description=Hash lookup had not been run on this file when the column was populated", "# {0} - occuranceCount", "AbstractAbstractFileNode.createSheet.count.description=There were {0} datasource(s) found with occurances of the correlation value"}) - Pair getCountPropertyAndDescription(CorrelationAttributeInstance attribute) { + @Override + protected Pair getCountPropertyAndDescription(CorrelationAttributeInstance attribute) { Long count = -1L; //The column renderer will not display negative values, negative value used when count unavailble to preserve sorting String description = Bundle.AbstractAbstractFileNode_createSheet_count_noCentralRepo_description(); try { @@ -480,7 +426,8 @@ public abstract class AbstractAbstractFileNode extends A "AbstractAbstractFileNode.createSheet.taggedFile.description=File has been tagged.", "AbstractAbstractFileNode.createSheet.notableTaggedFile.description=File tagged with notable tag.", "AbstractAbstractFileNode.createSheet.noScore.description=No score"}) - Pair getScorePropertyAndDescription(List tags) { + @Override + protected Pair getScorePropertyAndDescription(List tags) { DataResultViewerTable.Score score = DataResultViewerTable.Score.NO_SCORE; String description = Bundle.AbstractAbstractFileNode_createSheet_noScore_description(); if (content.getKnown() == TskData.FileKnown.BAD) { @@ -498,7 +445,7 @@ public abstract class AbstractAbstractFileNode extends A if (!tags.isEmpty() && (score == DataResultViewerTable.Score.NO_SCORE || score == DataResultViewerTable.Score.INTERESTING_SCORE)) { score = DataResultViewerTable.Score.INTERESTING_SCORE; description = Bundle.AbstractAbstractFileNode_createSheet_taggedFile_description(); - for (ContentTag tag : tags) { + for (Tag tag : tags) { if (tag.getName().getKnownStatus() == TskData.FileKnown.BAD) { score = DataResultViewerTable.Score.NOTABLE_SCORE; description = Bundle.AbstractAbstractFileNode_createSheet_notableTaggedFile_description(); @@ -511,11 +458,12 @@ public abstract class AbstractAbstractFileNode extends A @NbBundle.Messages({ "AbstractAbstractFileNode.createSheet.comment.displayName=C"}) - HasCommentStatus getCommentProperty(List tags, CorrelationAttributeInstance attribute) { + @Override + protected HasCommentStatus getCommentProperty(List tags, CorrelationAttributeInstance attribute) { DataResultViewerTable.HasCommentStatus status = !tags.isEmpty() ? DataResultViewerTable.HasCommentStatus.TAG_NO_COMMENT : DataResultViewerTable.HasCommentStatus.NO_COMMENT; - for (ContentTag tag : tags) { + for (Tag tag : tags) { if (!StringUtils.isBlank(tag.getComment())) { //if the tag is null or empty or contains just white space it will indicate there is not a comment status = DataResultViewerTable.HasCommentStatus.TAG_COMMENT; @@ -583,7 +531,13 @@ public abstract class AbstractAbstractFileNode extends A return tags; } - CorrelationAttributeInstance getCorrelationAttributeInstance() { + @Override + protected List getAllTagsFromDatabase() { + return new ArrayList<>(getContentTagsFromDatabase()); + } + + @Override + protected CorrelationAttributeInstance getCorrelationAttributeInstance() { CorrelationAttributeInstance attribute = null; if (EamDb.isEnabled() && !UserPreferences.hideCentralRepoCommentsAndOccurrences()) { attribute = EamArtifactUtil.getInstanceFromContent(content); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java index 4f6f2e5f47..7a2577e407 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java @@ -18,20 +18,30 @@ */ package org.sleuthkit.autopsy.datamodel; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.logging.Level; +import org.apache.commons.lang3.tuple.Pair; import org.openide.nodes.Children; +import org.openide.nodes.Sheet; import org.openide.util.lookup.Lookups; import org.openide.util.Lookup; +import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; +import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.Tag; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskException; @@ -50,6 +60,34 @@ public abstract class AbstractContentNode extends ContentNode T content; private static final Logger logger = Logger.getLogger(AbstractContentNode.class.getName()); + /** + * A pool of background tasks to run any long computation needed to + * populate this node. + */ + static final ExecutorService backgroundTasksPool; + static final Integer MAX_POOL_SIZE = 10; + + @NbBundle.Messages("AbstractContentNode.nodescription=no description") + private static final String NO_DESCR = Bundle.AbstractContentNode_nodescription(); + + + /** + * Event signals to indicate the background tasks have completed processing. + * Currently, we have one property task in the background: + * + * 1) Retrieving the translation of the file name + */ + enum NodeSpecificEvents { + TRANSLATION_AVAILABLE, + SCO_AVAILABLE + } + + static { + //Initialize this pool only once! This will be used by every instance of AAFN + //to do their heavy duty SCO column and translation updates. + backgroundTasksPool = Executors.newFixedThreadPool(MAX_POOL_SIZE, + new ThreadFactoryBuilder().setNameFormat("content-node-background-task-%d").build()); + } /** * Handles aspects that depend on the Content object * @@ -240,4 +278,111 @@ public abstract class AbstractContentNode extends ContentNode public int read(byte[] buf, long offset, long len) throws TskException { return content.read(buf, offset, len); } + + + /** + * Updates the values of the properties in the current property sheet with + * the new properties being passed in. Only if that property exists in the + * current sheet will it be applied. That way, we allow for subclasses to + * add their own (or omit some!) properties and we will not accidentally + * disrupt their UI. + * + * Race condition if not synchronized. Only one update should be applied at + * a time. + * + * @param newProps New file property instances to be updated in the current + * sheet. + */ + protected synchronized void updateSheet(NodeProperty... newProps) { + //Refresh ONLY those properties in the sheet currently. Subclasses may have + //only added a subset of our properties or their own props.s + Sheet visibleSheet = this.getSheet(); + Sheet.Set visibleSheetSet = visibleSheet.get(Sheet.PROPERTIES); + Property[] visibleProps = visibleSheetSet.getProperties(); + for (NodeProperty newProp : newProps) { + for (int i = 0; i < visibleProps.length; i++) { + if (visibleProps[i].getName().equals(newProp.getName())) { + visibleProps[i] = newProp; + } + } + } + visibleSheetSet.put(visibleProps); + visibleSheet.put(visibleSheetSet); + //setSheet() will notify Netbeans to update this node in the UI. + this.setSheet(visibleSheet); + } + + /** + * Reads and returns a list of all tags associated with this content node. + * + * This default implementation returns an empty list. + * The derived classes should override with an implementation specific + * to the type of node. + * + * @return list of tags associated with the node. + */ + protected List getAllTagsFromDatabase() { + return new ArrayList<>(); + } + /** + * Returns correlation attribute instance for the underlying content of the node. + * + * This default implementation returns null. + * The derived classes should override with an implementation specific + * to the type of node. + * + * @return correlation attribute instance for the underlying content of the node. + * + */ + protected CorrelationAttributeInstance getCorrelationAttributeInstance() { + return null; + } + + /** + * Returns Score property for the node. + * + * This default implementation returns NO_SCORE. + * The derived classes should override with an implementation specific + * to the type of node. + * + * @param tags list of tags. + * + * @return Score property for the underlying content of the node. + * + */ + protected Pair getScorePropertyAndDescription(List tags) { + + return Pair.of(DataResultViewerTable.Score.NO_SCORE, NO_DESCR); + } + /** + * Returns comment property for the node. + * + * This default implementation returns NO_COMMENT. + * The derived classes should override with an implementation specific + * to the type of node. + * + * @param tags list of tags + * @param attribute correlation attribute instance + * + * @return Comment property for the underlying content of the node. + * + */ + protected DataResultViewerTable.HasCommentStatus getCommentProperty(List tags, CorrelationAttributeInstance attribute) { + return DataResultViewerTable.HasCommentStatus.NO_COMMENT; + } + /** + * Returns occurrences/count property for the node. + * + * This default implementation returns -1. + * The derived classes should override with an implementation specific + * to the type of node. + * + * @param attribute correlation attribute instance + * + * @return count property for the underlying content of the node. + * + */ + protected Pair getCountPropertyAndDescription(CorrelationAttributeInstance attribute) { + return Pair.of(-1L, NO_DESCR); + } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java index 55e81acd17..1f871363f9 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2018 Basis Technology Corp. + * Copyright 2011-2019 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,6 +22,7 @@ import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.lang.ref.WeakReference; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; @@ -37,6 +38,7 @@ import java.util.logging.Level; import java.util.stream.Collectors; import javax.swing.Action; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; import org.openide.nodes.Sheet; import org.openide.util.Lookup; import org.openide.util.NbBundle; @@ -55,11 +57,13 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; import org.sleuthkit.autopsy.core.UserPreferences; +import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable.Score; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import static org.sleuthkit.autopsy.datamodel.DisplayableItemNode.findLinked; import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable.HasCommentStatus; +import static org.sleuthkit.autopsy.datamodel.AbstractContentNode.backgroundTasksPool; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager; import org.sleuthkit.autopsy.timeline.actions.ViewArtifactInTimelineAction; import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction; @@ -96,7 +100,7 @@ public class BlackboardArtifactNode extends AbstractContentNode> customProperties; - private final static String NO_DESCR = NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.noDesc.text"); + protected final static String NO_DESCR = NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.noDesc.text"); /* @@ -151,6 +155,19 @@ public class BlackboardArtifactNode extends AbstractContentNode(Bundle.BlackboardArtifactNode_createSheet_score_name(), Bundle.BlackboardArtifactNode_createSheet_score_displayName(), scoData.getScoreAndDescription().getRight(), scoData.getScoreAndDescription().getLeft())); + } + if (scoData.getComment() != null) { + updateSheet(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_comment_name(), Bundle.BlackboardArtifactNode_createSheet_comment_displayName(), NO_DESCR, scoData.getComment())); + } + if (scoData.getCountAndDescription() != null && + !UserPreferences.hideCentralRepoCommentsAndOccurrences()) { + updateSheet(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_count_name(), Bundle.BlackboardArtifactNode_createSheet_count_displayName(), scoData.getCountAndDescription().getRight(), scoData.getCountAndDescription().getLeft())); + } + } } }; @@ -335,8 +352,6 @@ public class BlackboardArtifactNode extends AbstractContentNode tags = getAllTagsFromDatabase(); - Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES); if (sheetSet == null) { sheetSet = Sheet.createPropertiesSet(); @@ -351,17 +366,15 @@ public class BlackboardArtifactNode extends AbstractContentNode(Bundle.BlackboardArtifactNode_createSheet_score_name(), Bundle.BlackboardArtifactNode_createSheet_score_displayName(), NO_DESCR, "")); + sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_comment_name(), Bundle.BlackboardArtifactNode_createSheet_comment_displayName(), NO_DESCR, "")); + sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_count_name(), Bundle.BlackboardArtifactNode_createSheet_count_displayName(), NO_DESCR, "")); + + // Get the SCO columns data in a background task + backgroundTasksPool.submit(new GetSCOTask( + new WeakReference<>(this), weakPcl)); + if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) { try { BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT)); @@ -520,6 +533,7 @@ public class BlackboardArtifactNode extends AbstractContentNode getAllTagsFromDatabase() { List tags = new ArrayList<>(); try { @@ -569,6 +583,7 @@ public class BlackboardArtifactNode extends AbstractContentNode t.getName().getDisplayName()).collect(Collectors.joining(", ")))); } + @Override protected final CorrelationAttributeInstance getCorrelationAttributeInstance() { CorrelationAttributeInstance correlationAttribute = null; if (EamDb.isEnabled()) { @@ -581,16 +596,17 @@ public class BlackboardArtifactNode extends AbstractContentNode tags, CorrelationAttributeInstance attribute) { + @Override + protected DataResultViewerTable.HasCommentStatus getCommentProperty(List tags, CorrelationAttributeInstance attribute) { + HasCommentStatus status = tags.size() > 0 ? HasCommentStatus.TAG_NO_COMMENT : HasCommentStatus.NO_COMMENT; for (Tag tag : tags) { if (!StringUtils.isBlank(tag.getComment())) { @@ -609,17 +625,16 @@ public class BlackboardArtifactNode extends AbstractContentNode(Bundle.BlackboardArtifactNode_createSheet_comment_name(), Bundle.BlackboardArtifactNode_createSheet_comment_displayName(), NO_DESCR, - status)); + return status; } - + /** * Used by (subclasses of) BlackboardArtifactNode to add the Score property * to their sheets. * - * @param sheetSet the modifiable Sheet.Set returned by - * Sheet.get(Sheet.PROPERTIES) * @param tags the list of tags associated with the file + * + * @return score property */ @NbBundle.Messages({"BlackboardArtifactNode.createSheet.score.name=S", "BlackboardArtifactNode.createSheet.score.displayName=S", @@ -628,8 +643,10 @@ public class BlackboardArtifactNode extends AbstractContentNode tags) { - Score score = Score.NO_SCORE; + + @Override + protected Pair getScorePropertyAndDescription(List tags) { + Score score = Score.NO_SCORE; String description = Bundle.BlackboardArtifactNode_createSheet_noScore_description(); if (associated instanceof AbstractFile) { if (((AbstractFile) associated).getKnown() == TskData.FileKnown.BAD) { @@ -673,9 +690,10 @@ public class BlackboardArtifactNode extends AbstractContentNode(Bundle.BlackboardArtifactNode_createSheet_score_name(), Bundle.BlackboardArtifactNode_createSheet_score_displayName(), description, score)); + + return Pair.of(score, description); } - + @NbBundle.Messages({"BlackboardArtifactNode.createSheet.count.name=O", "BlackboardArtifactNode.createSheet.count.displayName=O", "BlackboardArtifactNode.createSheet.count.noCentralRepo.description=Central repository was not enabled when this column was populated", @@ -683,7 +701,8 @@ public class BlackboardArtifactNode extends AbstractContentNode getCountPropertyAndDescription(CorrelationAttributeInstance attribute) { Long count = -1L; //The column renderer will not display negative values, negative value used when count unavailble to preserve sorting String description = Bundle.BlackboardArtifactNode_createSheet_count_noCentralRepo_description(); try { @@ -699,14 +718,13 @@ public class BlackboardArtifactNode extends AbstractContentNode(Bundle.BlackboardArtifactNode_createSheet_count_name(), Bundle.BlackboardArtifactNode_createSheet_count_displayName(), description, count)); - } - + return Pair.of(count, description); + } + private void updateSheet() { this.setSheet(createSheet()); } - + private String getRootParentName() { String parentName = associated.getName(); Content parent = associated; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED index 1d8fb7eb14..8d2bd5952d 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED @@ -37,6 +37,7 @@ AbstractAbstractFileNode.tagsProperty.displayName=Tags AbstractAbstractFileNode.typeDirColLbl=Type(Dir) AbstractAbstractFileNode.typeMetaColLbl=Type(Meta) AbstractAbstractFileNode.useridColLbl=UserID +AbstractContentNode.nodescription=no description AbstractFsContentNode.noDesc.text=no description ArtifactStringContent.attrsTableHeader.sources=Source(s) ArtifactStringContent.attrsTableHeader.type=Type diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java b/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java index e8a7b5b1f5..4278f99d66 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java @@ -25,42 +25,44 @@ import java.util.List; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.events.AutopsyEvent; -import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.Tag; /** - * Background task to get Score, Comment and Occurrences values for a Abstract file node. + * Background task to get Score, Comment and Occurrences values for an + * Abstract content node. * */ class GetSCOTask implements Runnable { - private final WeakReference> weakNodeRef; + private final WeakReference> weakNodeRef; private final PropertyChangeListener listener; - public GetSCOTask(WeakReference> weakContentRef, PropertyChangeListener listener) { + public GetSCOTask(WeakReference> weakContentRef, PropertyChangeListener listener) { this.weakNodeRef = weakContentRef; this.listener = listener; } @Override public void run() { - AbstractAbstractFileNode fileNode = weakNodeRef.get(); + AbstractContentNode contentNode = weakNodeRef.get(); //Check for stale reference - if (fileNode == null) { + if (contentNode == null) { return; } // get the SCO column values - List tags = fileNode.getContentTagsFromDatabase(); - CorrelationAttributeInstance attribute = fileNode.getCorrelationAttributeInstance(); + List tags = contentNode.getAllTagsFromDatabase(); + CorrelationAttributeInstance attribute = contentNode.getCorrelationAttributeInstance(); SCOData scoData = new SCOData(); - scoData.setScoreAndDescription(fileNode.getScorePropertyAndDescription(tags)); - scoData.setComment(fileNode.getCommentProperty(tags, attribute)); + scoData.setScoreAndDescription(contentNode.getScorePropertyAndDescription(tags)); + scoData.setComment(contentNode.getCommentProperty(tags, attribute)); if (!UserPreferences.hideCentralRepoCommentsAndOccurrences()) { - scoData.setCountAndDescription(fileNode.getCountPropertyAndDescription(attribute)); + scoData.setCountAndDescription(contentNode.getCountPropertyAndDescription(attribute)); } + // signal SCO data is available. if (listener != null) { listener.propertyChange(new PropertyChangeEvent( AutopsyEvent.SourceType.LOCAL.toString(), From 2a37021c809da9f976a5cab47d158de350361f24 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 3 Jun 2019 18:35:28 -0400 Subject: [PATCH 020/115] 5092 working changes to update status in table --- .../datasourcesummary/DataSourceBrowser.java | 42 ++++++++++++++++++- .../DataSourceSummaryDialog.java | 11 +++++ .../DataSourceSummaryNode.java | 6 ++- 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java index e946317da8..9c73ddadda 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java @@ -37,7 +37,10 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.datasourcesummary.DataSourceSummaryNode.DataSourceSummaryEntryNode; import static javax.swing.SwingConstants.RIGHT; +import javax.swing.SwingUtilities; import javax.swing.table.TableColumn; +import org.openide.util.Exceptions; +import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.IngestJobInfo; import org.sleuthkit.datamodel.SleuthkitCase; @@ -58,7 +61,7 @@ final class DataSourceBrowser extends javax.swing.JPanel implements ExplorerMana private final Outline outline; private final org.openide.explorer.view.OutlineView outlineView; private final ExplorerManager explorerManager; - private final List dataSourceSummaryList; + private List dataSourceSummaryList; private final RightAlignedTableCellRenderer rightAlignedRenderer = new RightAlignedTableCellRenderer(); /** @@ -187,6 +190,43 @@ final class DataSourceBrowser extends javax.swing.JPanel implements ExplorerMana return null; } + void refresh(long jobId, IngestJobInfo.IngestJobStatusType newStatus) { + Node[] selectedNodes = explorerManager.getSelectedNodes(); + //attempt to update the status of any datasources that had status which was STARTED + for (DataSourceSummary summary : dataSourceSummaryList) { + //attempt to update the status of any datasources that had status which was STARTED + //the database may not have been updated when this event is received so we need to manually update the UI + if (summary.getIngestStatus() == IngestJobInfo.IngestJobStatusType.STARTED && summary.getJobId() == jobId) { + System.out.println("UPDATING STATUS"); + summary.setStatus(newStatus); + } + } + SwingUtilities.invokeLater(() -> { + explorerManager.setRootContext(new DataSourceSummaryNode(dataSourceSummaryList)); + List nodesToSelect = new ArrayList<>(); + for (Node node : explorerManager.getRootContext().getChildren().getNodes()) { + if (node instanceof DataSourceSummaryEntryNode) { + //there should only be one selected node as multi-select is disabled + for (Node selectedNode : selectedNodes) { + if (((DataSourceSummaryEntryNode) node).getDataSource().equals(((DataSourceSummaryEntryNode) selectedNode).getDataSource())) { + System.out.println("NODE TO SELECT ADDED"); + nodesToSelect.add(node); + } + } + } + } + //reselect the previously selected Nodes + try { + explorerManager.setSelectedNodes(nodesToSelect.toArray(new Node[nodesToSelect.size()])); + } catch (PropertyVetoException ex) { + logger.log(Level.WARNING, "Error selecting previously selected nodes", ex); + } + revalidate(); + repaint(); + + }); + } + /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDialog.java index 3fd86c8de8..91ad7da792 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDialog.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.casemodule.datasourcesummary; import java.awt.Frame; +import java.beans.PropertyChangeEvent; import java.util.Map; import java.util.Observable; import java.util.Observer; @@ -26,7 +27,9 @@ import java.util.logging.Logger; import javax.swing.event.ListSelectionEvent; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.IngestJobInfoPanel; +import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.IngestJobInfo; /** * Dialog for displaying the Data Sources Summary information @@ -73,6 +76,14 @@ final class DataSourceSummaryDialog extends javax.swing.JDialog implements Obser this.repaint(); } }); + IngestManager.getInstance().addIngestJobEventListener((PropertyChangeEvent evt) -> { + if (evt.getPropertyName().equals(IngestManager.IngestJobEvent.CANCELLED.toString())){ + dataSourcesPanel.refresh((long)evt.getOldValue(), null); + } + else if (evt.getPropertyName().equals(IngestManager.IngestJobEvent.COMPLETED.toString())) { + dataSourcesPanel.refresh((long)evt.getOldValue(), IngestJobInfo.IngestJobStatusType.COMPLETED); + } + }); this.pack(); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryNode.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryNode.java index c9aef8c644..6c5a212d9d 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryNode.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryNode.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.casemodule.datasourcesummary; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Observable; import java.util.Observer; import javax.swing.Action; @@ -125,7 +126,7 @@ final class DataSourceSummaryNode extends AbstractNode { DataSourceSummaryEntryNode(DataSourceSummary dataSourceSummary) { super(Children.LEAF); dataSource = dataSourceSummary.getDataSource(); - status = dataSourceSummary.getIngestStatus(); + status = dataSourceSummary.getIngestStatus() == null ? "" : dataSourceSummary.getIngestStatus().toString(); type = dataSourceSummary.getType(); filesCount = dataSourceSummary.getFilesCount(); resultsCount = dataSourceSummary.getResultsCount(); @@ -183,7 +184,8 @@ final class DataSourceSummaryNode extends AbstractNode { } @Override - public Action[] getActions(boolean context) { + public Action[] getActions(boolean context + ) { List actions = new ArrayList<>(); actions.add(new ViewDataSourceInContextAction()); return actions.toArray(new Action[actions.size()]); From fb17d40ca49cd1e1c0f8300f1a2d901684d4f632 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 3 Jun 2019 18:40:46 -0400 Subject: [PATCH 021/115] 5092 query for status --- .../datasourcesummary/DataSourceSummary.java | 46 +++++++++++-------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java index a04604b3cd..a3de258fe8 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java @@ -20,13 +20,10 @@ package org.sleuthkit.autopsy.casemodule.datasourcesummary; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.List; -import org.openide.util.Exceptions; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.datamodel.CaseDbAccessManager; import org.sleuthkit.datamodel.DataSource; -import org.sleuthkit.datamodel.IngestJobInfo; import org.sleuthkit.datamodel.IngestJobInfo.IngestJobStatusType; import org.sleuthkit.datamodel.TskCoreException; @@ -37,7 +34,8 @@ import org.sleuthkit.datamodel.TskCoreException; class DataSourceSummary { private final DataSource dataSource; - private String status = ""; + private IngestJobStatusType status = null; + private Long jobId = null; private final String type; private final long filesCount; private final long resultsCount; @@ -56,23 +54,29 @@ class DataSourceSummary { */ DataSourceSummary(DataSource dSource, String typeValue, Long numberOfFiles, Long numberOfResults, Long numberOfTags) { dataSource = dSource; - updateStatus(); + getStatusFromDatabase(); type = typeValue == null ? "" : typeValue; filesCount = numberOfFiles == null ? 0 : numberOfFiles; resultsCount = numberOfResults == null ? 0 : numberOfResults; tagsCount = numberOfTags == null ? 0 : numberOfTags; } - void updateStatus() { + private void getStatusFromDatabase() { try { IngestJobQueryCallback callback = new IngestJobQueryCallback(); - Case.getCurrentCaseThrows().getSleuthkitCase().getCaseDbAccessManager().select("status_id FROM ingest_jobs WHERE obj_id=" + dataSource.getId(), callback); + Case.getCurrentCaseThrows().getSleuthkitCase().getCaseDbAccessManager().select("ingest_job_id, status_id FROM ingest_jobs WHERE obj_id=" + dataSource.getId(), callback); status = callback.getStatus(); + jobId = callback.getJobId(); + System.out.println("NEW STATUS: " + status); } catch (NoCurrentCaseException | TskCoreException ex) { } } + void setStatus(IngestJobStatusType newStatus){ + status = newStatus; + } + /** * Get the DataSource * @@ -82,6 +86,10 @@ class DataSourceSummary { return dataSource; } + Long getJobId() { + return jobId; + } + /** * Get the type of this DataSource * @@ -109,10 +117,10 @@ class DataSourceSummary { return resultsCount; } - String getIngestStatus(){ + IngestJobStatusType getIngestStatus() { return status; } - + /** * Get the number of tagged content objects in this DataSource * @@ -124,16 +132,18 @@ class DataSourceSummary { class IngestJobQueryCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { - IngestJobStatusType jobStatus = null; + private IngestJobStatusType jobStatus = null; + private Long ingestJobId = null; @Override public void process(ResultSet rs) { try { while (rs.next()) { IngestJobStatusType currentStatus = IngestJobStatusType.fromID(rs.getInt("status_id")); - if (currentStatus == IngestJobStatusType.COMPLETED) { + if (currentStatus == IngestJobStatusType.COMPLETED) { jobStatus = currentStatus; - } else if (currentStatus == IngestJobStatusType.STARTED) { + } else if (currentStatus == IngestJobStatusType.STARTED) { + ingestJobId = rs.getLong("ingest_job_id"); jobStatus = currentStatus; return; } @@ -143,12 +153,12 @@ class DataSourceSummary { } } - String getStatus() { - if (jobStatus == null) { - return ""; - } else { - return jobStatus.getDisplayName(); - } + IngestJobStatusType getStatus() { + return jobStatus; + } + + Long getJobId() { + return ingestJobId; } } } From ea6687c2c596939dc4e0bc40d022da947f91d543 Mon Sep 17 00:00:00 2001 From: Raman Date: Tue, 4 Jun 2019 08:20:40 -0400 Subject: [PATCH 022/115] Address Codacy comments. --- .../datamodel/AbstractContentNode.java | 53 ++++----------- .../autopsy/datamodel/ImageNode.java | 67 ++++++++++++++++++ .../autopsy/datamodel/VolumeNode.java | 68 +++++++++++++++++++ 3 files changed, 147 insertions(+), 41 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java index 7a2577e407..f90a15ac42 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java @@ -67,8 +67,11 @@ public abstract class AbstractContentNode extends ContentNode static final ExecutorService backgroundTasksPool; static final Integer MAX_POOL_SIZE = 10; + /** + * Default no description string + */ @NbBundle.Messages("AbstractContentNode.nodescription=no description") - private static final String NO_DESCR = Bundle.AbstractContentNode_nodescription(); + protected static final String NO_DESCR = Bundle.AbstractContentNode_nodescription(); /** @@ -315,74 +318,42 @@ public abstract class AbstractContentNode extends ContentNode /** * Reads and returns a list of all tags associated with this content node. * - * This default implementation returns an empty list. - * The derived classes should override with an implementation specific - * to the type of node. - * * @return list of tags associated with the node. */ - protected List getAllTagsFromDatabase() { - return new ArrayList<>(); - } + abstract protected List getAllTagsFromDatabase(); + /** * Returns correlation attribute instance for the underlying content of the node. * - * This default implementation returns null. - * The derived classes should override with an implementation specific - * to the type of node. - * * @return correlation attribute instance for the underlying content of the node. - * */ - protected CorrelationAttributeInstance getCorrelationAttributeInstance() { - return null; - } + abstract protected CorrelationAttributeInstance getCorrelationAttributeInstance(); /** * Returns Score property for the node. * - * This default implementation returns NO_SCORE. - * The derived classes should override with an implementation specific - * to the type of node. - * * @param tags list of tags. * * @return Score property for the underlying content of the node. - * */ - protected Pair getScorePropertyAndDescription(List tags) { - - return Pair.of(DataResultViewerTable.Score.NO_SCORE, NO_DESCR); - } + abstract protected Pair getScorePropertyAndDescription(List tags); + /** * Returns comment property for the node. * - * This default implementation returns NO_COMMENT. - * The derived classes should override with an implementation specific - * to the type of node. - * * @param tags list of tags * @param attribute correlation attribute instance * * @return Comment property for the underlying content of the node. - * */ - protected DataResultViewerTable.HasCommentStatus getCommentProperty(List tags, CorrelationAttributeInstance attribute) { - return DataResultViewerTable.HasCommentStatus.NO_COMMENT; - } + abstract protected DataResultViewerTable.HasCommentStatus getCommentProperty(List tags, CorrelationAttributeInstance attribute); + /** * Returns occurrences/count property for the node. * - * This default implementation returns -1. - * The derived classes should override with an implementation specific - * to the type of node. - * * @param attribute correlation attribute instance * * @return count property for the underlying content of the node. - * */ - protected Pair getCountPropertyAndDescription(CorrelationAttributeInstance attribute) { - return Pair.of(-1L, NO_DESCR); - } + abstract protected Pair getCountPropertyAndDescription(CorrelationAttributeInstance attribute); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java index 584a405fcc..b2c80f1322 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java @@ -28,12 +28,15 @@ import java.util.EnumSet; import java.util.List; import java.util.logging.Level; import javax.swing.Action; +import org.apache.commons.lang3.tuple.Pair; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.datasourcesummary.ViewSummaryInformationAction; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; +import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.ExplorerNodeActionVisitor; import org.sleuthkit.autopsy.directorytree.FileSearchAction; @@ -47,6 +50,7 @@ import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.VirtualDirectory; import org.sleuthkit.autopsy.datamodel.BaseChildFactory.NoSuchEventBusException; +import org.sleuthkit.datamodel.Tag; /** * This class is used to represent the "Node" for the image. The children of @@ -250,4 +254,67 @@ public class ImageNode extends AbstractContentNode { } }; + /** + * Reads and returns a list of all tags associated with this content node. + * + * Null implementation of an abstract method. + * + * @return list of tags associated with the node. + */ + @Override + protected List getAllTagsFromDatabase() { + return new ArrayList<>(); + } + /** + * Returns correlation attribute instance for the underlying content of the node. + * + * Null implementation of an abstract method. + * + * @return correlation attribute instance for the underlying content of the node. + */ + @Override + protected CorrelationAttributeInstance getCorrelationAttributeInstance() { + return null; + } + + /** + * Returns Score property for the node. + * + * Null implementation of an abstract method. + * + * @param tags list of tags. + * + * @return Score property for the underlying content of the node. + */ + @Override + protected Pair getScorePropertyAndDescription(List tags) { + return Pair.of(DataResultViewerTable.Score.NO_SCORE, NO_DESCR); + } + /** + * Returns comment property for the node. + * + * Null implementation of an abstract method. + * + * @param tags list of tags + * @param attribute correlation attribute instance + * + * @return Comment property for the underlying content of the node. + */ + @Override + protected DataResultViewerTable.HasCommentStatus getCommentProperty(List tags, CorrelationAttributeInstance attribute) { + return DataResultViewerTable.HasCommentStatus.NO_COMMENT; + } + /** + * Returns occurrences/count property for the node. + * + * Null implementation of an abstract method. + * + * @param attribute correlation attribute instance + * + * @return count property for the underlying content of the node. + */ + @Override + protected Pair getCountPropertyAndDescription(CorrelationAttributeInstance attribute) { + return Pair.of(-1L, NO_DESCR); + } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/VolumeNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/VolumeNode.java index d25b50d59f..233d098071 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/VolumeNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/VolumeNode.java @@ -25,10 +25,14 @@ import java.util.EnumSet; import java.util.List; import java.util.logging.Level; import javax.swing.Action; +import org.apache.commons.lang3.tuple.Pair; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; +import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; import org.sleuthkit.autopsy.coreutils.Logger; +import static org.sleuthkit.autopsy.datamodel.AbstractContentNode.NO_DESCR; import org.sleuthkit.autopsy.datamodel.BaseChildFactory.NoSuchEventBusException; import org.sleuthkit.autopsy.directorytree.ExplorerNodeActionVisitor; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; @@ -39,6 +43,7 @@ import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.VirtualDirectory; import org.sleuthkit.datamodel.Volume; import org.sleuthkit.autopsy.directorytree.FileSystemDetailsAction; +import org.sleuthkit.datamodel.Tag; /** * This class is used to represent the "Node" for the volume. Its child is the @@ -212,4 +217,67 @@ public class VolumeNode extends AbstractContentNode { public String getItemType() { return DisplayableItemNode.FILE_PARENT_NODE_KEY; } + /** + * Reads and returns a list of all tags associated with this content node. + * + * Null implementation of an abstract method. + * + * @return list of tags associated with the node. + */ + @Override + protected List getAllTagsFromDatabase() { + return new ArrayList<>(); + } + /** + * Returns correlation attribute instance for the underlying content of the node. + * + * Null implementation of an abstract method. + * + * @return correlation attribute instance for the underlying content of the node. + */ + @Override + protected CorrelationAttributeInstance getCorrelationAttributeInstance() { + return null; + } + + /** + * Returns Score property for the node. + * + * Null implementation of an abstract method. + * + * @param tags list of tags. + * + * @return Score property for the underlying content of the node. + */ + @Override + protected Pair getScorePropertyAndDescription(List tags) { + return Pair.of(DataResultViewerTable.Score.NO_SCORE, NO_DESCR); + } + /** + * Returns comment property for the node. + * + * Null implementation of an abstract method. + * + * @param tags list of tags + * @param attribute correlation attribute instance + * + * @return Comment property for the underlying content of the node. + */ + @Override + protected DataResultViewerTable.HasCommentStatus getCommentProperty(List tags, CorrelationAttributeInstance attribute) { + return DataResultViewerTable.HasCommentStatus.NO_COMMENT; + } + /** + * Returns occurrences/count property for the node. + * + * Null implementation of an abstract method. + * + * @param attribute correlation attribute instance + * + * @return count property for the underlying content of the node. + */ + @Override + protected Pair getCountPropertyAndDescription(CorrelationAttributeInstance attribute) { + return Pair.of(-1L, NO_DESCR); + } } From ed4da71c1aabd6d2c12e66de88671bab92b6d5a7 Mon Sep 17 00:00:00 2001 From: Raman Date: Tue, 4 Jun 2019 08:29:37 -0400 Subject: [PATCH 023/115] Remove unused import. --- .../src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java index f90a15ac42..154ca68d50 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.datamodel; import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; From ff9a26a447e0c6ef9b7a49f0f163b6c1760d0523 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Tue, 4 Jun 2019 12:38:39 -0400 Subject: [PATCH 024/115] Adding export CSV action --- .../datamodel/DataModelActionsFactory.java | 11 + .../autopsy/datamodel/DirectoryNode.java | 2 + .../sleuthkit/autopsy/datamodel/FileNode.java | 2 + .../autopsy/datamodel/LayoutFileNode.java | 2 + .../autopsy/datamodel/LocalFileNode.java | 2 + .../autopsy/datamodel/SlackFileNode.java | 2 + .../datamodel/SpecialDirectoryNode.java | 2 + .../directorytree/Bundle.properties-MERGED | 9 + .../directorytree/DataResultFilterNode.java | 1 + .../ExplorerNodeActionVisitor.java | 5 + .../directorytree/ExportCSVAction.java | 298 ++++++++++++++++++ .../keywordsearch/AdHocSearchFilterNode.java | 2 + 12 files changed, 338 insertions(+) create mode 100644 Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java index 13a0753ca1..bdb4a394a8 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java @@ -36,6 +36,7 @@ import org.sleuthkit.autopsy.actions.ReplaceBlackboardArtifactTagAction; import org.sleuthkit.autopsy.actions.ReplaceContentTagAction; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.datamodel.Reports.ReportNode; +import org.sleuthkit.autopsy.directorytree.ExportCSVAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; @@ -92,6 +93,7 @@ public class DataModelActionsFactory { } actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); + actionsList.add(ExportCSVAction.getInstance()); actionsList.add(null); // creates a menu separator actionsList.add(AddContentTagAction.getInstance()); if (isArtifactSource) { @@ -119,6 +121,7 @@ public class DataModelActionsFactory { actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, slackFileNode)); actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); + actionsList.add(ExportCSVAction.getInstance()); actionsList.add(null); // creates a menu separator actionsList.add(AddContentTagAction.getInstance()); if (isArtifactSource) { @@ -155,6 +158,7 @@ public class DataModelActionsFactory { } actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance());// + actionsList.add(ExportCSVAction.getInstance()); actionsList.add(null); // creates a menu separator actionsList.add(AddContentTagAction.getInstance()); if (isArtifactSource) { @@ -189,6 +193,7 @@ public class DataModelActionsFactory { } actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); + actionsList.add(ExportCSVAction.getInstance()); actionsList.add(null); // creates a menu separator actionsList.add(AddContentTagAction.getInstance()); if (isArtifactSource) { @@ -223,6 +228,7 @@ public class DataModelActionsFactory { } actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); + actionsList.add(ExportCSVAction.getInstance()); actionsList.add(null); // creates a menu separator actionsList.add(AddContentTagAction.getInstance()); if (isArtifactSource) { @@ -257,6 +263,7 @@ public class DataModelActionsFactory { } actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); + actionsList.add(ExportCSVAction.getInstance()); actionsList.add(null); // creates a menu separator actionsList.add(AddContentTagAction.getInstance()); if (isArtifactSource) { @@ -291,6 +298,7 @@ public class DataModelActionsFactory { } actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); + actionsList.add(ExportCSVAction.getInstance()); actionsList.add(null); // creates a menu separator actionsList.add(AddContentTagAction.getInstance()); if (isArtifactSource) { @@ -325,6 +333,7 @@ public class DataModelActionsFactory { } actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); + actionsList.add(ExportCSVAction.getInstance()); actionsList.add(null); // creates a menu separator actionsList.add(AddContentTagAction.getInstance()); if (isArtifactSource) { @@ -379,6 +388,7 @@ public class DataModelActionsFactory { } actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); + actionsList.add(ExportCSVAction.getInstance()); actionsList.add(null); // creates a menu separator actionsList.add(AddContentTagAction.getInstance()); if (isArtifactSource) { @@ -415,6 +425,7 @@ public class DataModelActionsFactory { } actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); + actionsList.add(ExportCSVAction.getInstance()); actionsList.add(null); // creates a menu separator actionsList.add(AddContentTagAction.getInstance()); if (isArtifactSource) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java index 97b0fd8216..5a3476f896 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java @@ -28,6 +28,7 @@ import org.openide.util.Utilities; import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; +import org.sleuthkit.autopsy.directorytree.ExportCSVAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; @@ -89,6 +90,7 @@ public class DirectoryNode extends AbstractFsContentNode { actionsList.add(ViewFileInTimelineAction.createViewFileAction(content)); actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); + actionsList.add(ExportCSVAction.getInstance()); actionsList.add(null); // creates a menu separator actionsList.add(new RunIngestModulesAction(content)); actionsList.add(null); // creates a menu separator diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java index 1695b253b0..7b3a55c20b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java @@ -32,6 +32,7 @@ import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.directorytree.ExportCSVAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; @@ -173,6 +174,7 @@ public class FileNode extends AbstractFsContentNode { actionsList.add(null); // Creates an item separator actionsList.add(ExtractAction.getInstance()); + actionsList.add(ExportCSVAction.getInstance()); actionsList.add(null); // Creates an item separator actionsList.add(AddContentTagAction.getInstance()); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java index bfd8f7bd91..41ecad0340 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java @@ -29,6 +29,7 @@ import org.openide.util.Utilities; import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; +import org.sleuthkit.autopsy.directorytree.ExportCSVAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; @@ -105,6 +106,7 @@ public class LayoutFileNode extends AbstractAbstractFileNode { } actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); + actionsList.add(ExportCSVAction.getInstance()); actionsList.add(null); // creates a menu separator actionsList.add(AddContentTagAction.getInstance()); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java index 6d64aeb621..4a62cd9e4f 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java @@ -31,6 +31,7 @@ import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.directorytree.ExportCSVAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; @@ -82,6 +83,7 @@ public class LocalFileNode extends AbstractAbstractFileNode { actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); + actionsList.add(ExportCSVAction.getInstance()); actionsList.add(null); // creates a menu separator actionsList.add(AddContentTagAction.getInstance()); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/SlackFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/SlackFileNode.java index 49d1b9da54..0e7bce56cc 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/SlackFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/SlackFileNode.java @@ -28,6 +28,7 @@ import org.openide.util.Utilities; import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; +import org.sleuthkit.autopsy.directorytree.ExportCSVAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; @@ -85,6 +86,7 @@ public class SlackFileNode extends AbstractFsContentNode { NbBundle.getMessage(this.getClass(), "SlackFileNode.getActions.viewInNewWin.text"), this)); actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); + actionsList.add(ExportCSVAction.getInstance()); actionsList.add(null); // creates a menu separator actionsList.add(AddContentTagAction.getInstance()); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java index 47f616de12..ce5948ce68 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java @@ -25,6 +25,7 @@ import javax.swing.Action; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.datasourcesummary.ViewSummaryInformationAction; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; +import org.sleuthkit.autopsy.directorytree.ExportCSVAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.FileSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; @@ -61,6 +62,7 @@ public abstract class SpecialDirectoryNode extends AbstractAbstractFileNode visit(final DerivedFile d) { List actionsList = new ArrayList<>(); actionsList.add(ExtractAction.getInstance()); + actionsList.add(ExportCSVAction.getInstance()); actionsList.add(AddContentTagAction.getInstance()); final Collection selectedFilesList = @@ -166,6 +169,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default visit(final LocalFile d) { List actionsList = new ArrayList<>(); actionsList.add(ExtractAction.getInstance()); + actionsList.add(ExportCSVAction.getInstance()); actionsList.add(AddContentTagAction.getInstance()); final Collection selectedFilesList = @@ -182,6 +186,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default visit(final org.sleuthkit.datamodel.File d) { List actionsList = new ArrayList<>(); actionsList.add(ExtractAction.getInstance()); + actionsList.add(ExportCSVAction.getInstance()); actionsList.add(AddContentTagAction.getInstance()); final Collection selectedFilesList = diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java new file mode 100644 index 0000000000..169701a55c --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java @@ -0,0 +1,298 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013-2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this content 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.directorytree; + +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.io.File; +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import javax.swing.AbstractAction; +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; +import javax.swing.SwingWorker; +import javax.swing.filechooser.FileNameExtensionFilter; +import org.netbeans.api.progress.ProgressHandle; +import org.openide.util.Cancellable; +import org.openide.util.NbBundle; +import org.openide.util.Utilities; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.coreutils.FileUtil; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.datamodel.ContentUtils; +import org.sleuthkit.autopsy.datamodel.ContentUtils.ExtractFscContentVisitor; +import org.sleuthkit.autopsy.datamodel.FileNode; +import org.sleuthkit.datamodel.AbstractFile; +import org.openide.nodes.AbstractNode; +import org.openide.nodes.Node; +import org.openide.nodes.Node.PropertySet; +import org.openide.nodes.Node.Property; + +/** + * Exports CSV version of result nodes to a location selected by the user. + */ +public final class ExportCSVAction extends AbstractAction { + + private Logger logger = Logger.getLogger(ExportCSVAction.class.getName()); + + private String userDefinedExportPath; + + // This class is a singleton to support multi-selection of nodes, since + // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every + // node in the array returns a reference to the same action object from Node.getActions(boolean). + private static ExportCSVAction instance; + + public static synchronized ExportCSVAction getInstance() { + if (null == instance) { + instance = new ExportCSVAction(); + } + return instance; + } + + /** + * Private constructor for the action. + */ + @NbBundle.Messages({"ExportCSV.title.text=Export to CSV"}) + private ExportCSVAction() { + super(Bundle.ExportCSV_title_text()); + } + + /** + * Asks user to choose destination, then extracts content to destination + * (recursing on directories). + * + * @param e The action event. + */ + @NbBundle.Messages({ + "# {0} - Output file", + "ExportCSV.actionPerformed.fileExists=File {0} already exists", + "ExportCSV.actionPerformed.noCurrentCase=No open case available"}) + @Override + public void actionPerformed(ActionEvent e) { + + Collection selectedNodes = Utilities.actionsGlobalContext().lookupAll(Node.class); + if (selectedNodes.isEmpty()) { + return; + } + + Node parent = selectedNodes.iterator().next().getParentNode(); + if (parent != null) { + System.out.println("HTML name: " + parent.getHtmlDisplayName()); + System.out.println("Display name: " + parent.getDisplayName()); + System.out.println("Class: " + parent.getClass().getCanonicalName()); + for (PropertySet set : parent.getPropertySets()) { + for (Property prop : set.getProperties()) { + try { + System.out.println(" " + prop.getDisplayName() + " : " + prop.getValue().toString()); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } + } + + try { + String fileName = String.format("%1$tY%1$tm%1$te%1$tI%1$tM%1$tS_listing.csv", Calendar.getInstance()); + JFileChooser fileChooser = new JFileChooser(); + fileChooser.setCurrentDirectory(new File(getExportDirectory(Case.getCurrentCaseThrows()))); + fileChooser.setSelectedFile(new File(fileName)); + fileChooser.setFileFilter(new FileNameExtensionFilter("csv file", "csv")); + + int returnVal = fileChooser.showSaveDialog((Component) e.getSource()); + if (returnVal == JFileChooser.APPROVE_OPTION) { + + File selectedFile = fileChooser.getSelectedFile(); + if (!selectedFile.getName().endsWith(".csv")) { // NON-NLS + selectedFile = new File(selectedFile.toString() + ".csv"); // NON-NLS + } + updateExportDirectory(selectedFile.getParent(), Case.getCurrentCaseThrows()); + + if (selectedFile.exists()) { + logger.log(Level.SEVERE, "File {0} already exists", selectedFile.getAbsolutePath()); //NON-NLS + MessageNotifyUtil.Message.info(Bundle.ExportCSV_actionPerformed_fileExists(selectedFile)); + return; + } + + CSVWriter writer = new CSVWriter(selectedNodes, selectedFile); + writer.execute(); + } + } catch (NoCurrentCaseException ex) { + JOptionPane.showMessageDialog((Component) e.getSource(), Bundle.ExportCSV_actionPerformed_noCurrentCase()); + logger.log(Level.INFO, "Exception while getting open case.", ex); //NON-NLS + } + } + + /** + * Get the export directory path. + * + * @param openCase The current case. + * + * @return The export directory path. + */ + private String getExportDirectory(Case openCase) { + String caseExportPath = openCase.getExportDirectory(); + + if (userDefinedExportPath == null) { + return caseExportPath; + } + + File file = new File(userDefinedExportPath); + if (file.exists() == false || file.isDirectory() == false) { + return caseExportPath; + } + + return userDefinedExportPath; + } + + /** + * Update the default export directory. If the directory path matches the + * case export directory, then the directory used will always match the + * export directory of any given case. Otherwise, the path last used will be + * saved. + * + * @param exportPath The export path. + * @param openCase The current case. + */ + private void updateExportDirectory(String exportPath, Case openCase) { + if (exportPath.equalsIgnoreCase(openCase.getExportDirectory())) { + userDefinedExportPath = null; + } else { + userDefinedExportPath = exportPath; + } + } + + + /** + * Thread that does the actual extraction work + */ + private class CSVWriter extends SwingWorker { + + private final Logger logger = Logger.getLogger(CSVWriter.class.getName()); + private ProgressHandle progress; + + private final List nodesToExport; + private final File outputFile; + + /** + * Create an instance of the CSVWriter. + * + * @param extractionTasks List of file extraction tasks. + */ + CSVWriter(Collection selectedNodes, File outputFile) { + this.nodesToExport = new ArrayList<>(selectedNodes); + this.outputFile = outputFile; + } + + @NbBundle.Messages({"CSVWriter.progress.extracting=Exporting to CSV file", + "CSVWriter.progress.cancelling=Cancelling"}) + @Override + protected Object doInBackground() throws Exception { + if (nodesToExport.isEmpty()) { + return null; + } + + // Set up progress bar. + final String displayName = Bundle.CSVWriter_progress_extracting(); + progress = ProgressHandle.createHandle(displayName, new Cancellable() { + @Override + public boolean cancel() { + if (progress != null) { + progress.setDisplayName(Bundle.CSVWriter_progress_cancelling()); + } + return ExportCSVAction.CSVWriter.this.cancel(true); + } + }); + progress.start(); + progress.switchToIndeterminate(); + + try (BufferedWriter br = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputFile), StandardCharsets.UTF_8))) { + // Write BOM + br.write('\ufeff'); + + // Write the header + List headers = new ArrayList<>(); + PropertySet[] sets = nodesToExport.get(0).getPropertySets(); + for(PropertySet set : sets) { + for (Property prop : set.getProperties()) { + headers.add(prop.getDisplayName()); + } + } + br.write(listToCSV(headers)); + + // Write each line + for (Node node : nodesToExport) { + if (this.isCancelled()) { + break; + } + + List values = new ArrayList<>(); + sets = node.getPropertySets(); + for(PropertySet set : sets) { + for (Property prop : set.getProperties()) { + values.add(prop.getValue().toString()); + } + } + br.write(listToCSV(values)); + } + } + + return null; + } + + private String listToCSV(List values) { + return "\"" + String.join("\",\"", values) + "\"\n"; + } + + @NbBundle.Messages({"CSVWriter.done.notifyMsg.error=Error exporting to CSV file", + "# {0} - Output file", + "CSVWriter.done.notifyMsg.success=Wrote to {0}"}) + @Override + protected void done() { + boolean msgDisplayed = false; + try { + super.get(); + } catch (InterruptedException | ExecutionException ex) { + logger.log(Level.SEVERE, "Fatal error during file extraction", ex); //NON-NLS + MessageNotifyUtil.Message.info(Bundle.CSVWriter_done_notifyMsg_error()); + msgDisplayed = true; + } catch (java.util.concurrent.CancellationException ex) { + // catch and ignore if we were cancelled + } finally { + progress.finish(); + if (!this.isCancelled() && !msgDisplayed) { + MessageNotifyUtil.Message.info(Bundle.CSVWriter_done_notifyMsg_success(outputFile)); + } + } + } + } +} diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchFilterNode.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchFilterNode.java index 57b84b11d6..cff13cc16e 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchFilterNode.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/AdHocSearchFilterNode.java @@ -32,6 +32,7 @@ import org.openide.util.NbBundle; import org.openide.util.Utilities; import org.openide.util.lookup.ProxyLookup; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; +import org.sleuthkit.autopsy.directorytree.ExportCSVAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.actions.AddContentTagAction; @@ -163,6 +164,7 @@ class AdHocSearchFilterNode extends FilterNode { actionsList.add(new ExternalViewerAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.openExternViewActLbl"), getOriginal())); actionsList.add(null); actionsList.add(ExtractAction.getInstance()); + actionsList.add(ExportCSVAction.getInstance()); actionsList.add(null); // creates a menu separator actionsList.add(AddContentTagAction.getInstance()); From 20334eb7d5b81f3e41d54d89ee0d767a7cb0511b Mon Sep 17 00:00:00 2001 From: esaunders Date: Tue, 4 Jun 2019 13:47:41 -0400 Subject: [PATCH 025/115] Use asynchronous node creation for directory tree to support view file in directory functionality. --- .../corecomponents/DataResultViewerTable.java | 30 ++++++++++--------- .../datamodel/AbstractContentNode.java | 2 +- .../autopsy/datamodel/DataSourcesNode.java | 2 +- .../datamodel/RootContentChildren.java | 4 ++- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java index a5bbc461b8..47662e3c8f 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java @@ -293,20 +293,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer { this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); try { - /* - * If the given node is not null and has children, set it as the - * root context of the child OutlineView, otherwise make an - * "empty"node the root context. - * - * IMPORTANT NOTE: This is the first of many times where a - * getChildren call on the current root node causes all of the - * children of the root node to be created and defeats lazy child - * node creation, if it is enabled. It also likely leads to many - * case database round trips. - */ - if (rootNode != null && rootNode.getChildren().getNodesCount() > 0) { - this.rootNode = rootNode; - + if (rootNode != null) { /** * Check to see if we have previously created a paging support * class for this node. @@ -355,6 +342,21 @@ public class DataResultViewerTable extends AbstractDataResultViewer { // No-op } }); + } + + /* + * If the given node is not null and has children, set it as the + * root context of the child OutlineView, otherwise make an + * "empty"node the root context. + * + * IMPORTANT NOTE: This is the first of many times where a + * getChildren call on the current root node causes all of the + * children of the root node to be created and defeats lazy child + * node creation, if it is enabled. It also likely leads to many + * case database round trips. + */ + if (rootNode != null && rootNode.getChildren().getNodesCount() > 0) { + this.rootNode = rootNode; this.getExplorerManager().setRootContext(this.rootNode); setupTable(); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java index 4f6f2e5f47..29522bce4b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java @@ -66,7 +66,7 @@ public abstract class AbstractContentNode extends ContentNode * @param lookup The Lookup object for the node. */ AbstractContentNode(T content, Lookup lookup) { - super(Children.create(new ContentChildren(content), true), lookup); + super(Children.create(new ContentChildren(content), false), lookup); this.content = content; //super.setName(ContentUtils.getSystemName(content)); super.setName("content_" + Long.toString(content.getId())); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java index 1265db5658..5ab29a5376 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java @@ -57,7 +57,7 @@ public class DataSourcesNode extends DisplayableItemNode { } public DataSourcesNode(long dsObjId) { - super(Children.create(new DataSourcesNodeChildren(dsObjId), true), Lookups.singleton(NAME)); + super(Children.create(new DataSourcesNodeChildren(dsObjId), false), Lookups.singleton(NAME)); displayName = (dsObjId > 0) ? NbBundle.getMessage(DataSourcesNode.class, "DataSourcesNode.group_by_datasource.name") : NAME; init(); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java index 66291955a8..c5d77692c8 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java @@ -25,6 +25,7 @@ import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.datamodel.accounts.Accounts; +import org.sleuthkit.datamodel.SleuthkitVisitableItem; /** * Children implementation for the root node of a ContentNode tree. Accepts a @@ -34,6 +35,7 @@ public class RootContentChildren extends Children.Keys { private final Collection contentKeys; private final CreateAutopsyNodeVisitor createAutopsyNodeVisitor = new CreateAutopsyNodeVisitor(); + private final CreateSleuthkitNodeVisitor createSleuthkitNodeVisitor = new CreateSleuthkitNodeVisitor(); /** * @param contentKeys root Content objects for the Node tree @@ -68,7 +70,7 @@ public class RootContentChildren extends Children.Keys { if (key instanceof AutopsyVisitableItem) { return new Node[] {((AutopsyVisitableItem)key).accept(createAutopsyNodeVisitor)}; } else { - return null; + return new Node[] {((SleuthkitVisitableItem)key).accept(createSleuthkitNodeVisitor)}; } } From 4a5fbe3aeb7b3ad27b8f3c063f8f0dbc5a91f2ec Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 4 Jun 2019 14:35:17 -0400 Subject: [PATCH 026/115] 5092 working updates for ingest status --- .../datasourcesummary/DataSourceBrowser.java | 13 +++------- .../datasourcesummary/DataSourceSummary.java | 26 +++++-------------- .../DataSourceSummaryDialog.java | 17 ++++++++---- .../DataSourceSummaryNode.java | 2 +- 4 files changed, 23 insertions(+), 35 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java index 9c73ddadda..3fcb50b02e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java @@ -190,15 +190,12 @@ final class DataSourceBrowser extends javax.swing.JPanel implements ExplorerMana return null; } - void refresh(long jobId, IngestJobInfo.IngestJobStatusType newStatus) { + void refresh(content datasource, IngestJobInfo.IngestJobStatusType newStatus) { Node[] selectedNodes = explorerManager.getSelectedNodes(); //attempt to update the status of any datasources that had status which was STARTED for (DataSourceSummary summary : dataSourceSummaryList) { - //attempt to update the status of any datasources that had status which was STARTED - //the database may not have been updated when this event is received so we need to manually update the UI - if (summary.getIngestStatus() == IngestJobInfo.IngestJobStatusType.STARTED && summary.getJobId() == jobId) { - System.out.println("UPDATING STATUS"); - summary.setStatus(newStatus); + if (summary.getDataSource().equals(datasource)) { + summary.updateStatusFromDatabase(); } } SwingUtilities.invokeLater(() -> { @@ -209,7 +206,6 @@ final class DataSourceBrowser extends javax.swing.JPanel implements ExplorerMana //there should only be one selected node as multi-select is disabled for (Node selectedNode : selectedNodes) { if (((DataSourceSummaryEntryNode) node).getDataSource().equals(((DataSourceSummaryEntryNode) selectedNode).getDataSource())) { - System.out.println("NODE TO SELECT ADDED"); nodesToSelect.add(node); } } @@ -221,10 +217,9 @@ final class DataSourceBrowser extends javax.swing.JPanel implements ExplorerMana } catch (PropertyVetoException ex) { logger.log(Level.WARNING, "Error selecting previously selected nodes", ex); } - revalidate(); - repaint(); }); + } /** diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java index a3de258fe8..071be6e3cb 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java @@ -35,7 +35,6 @@ class DataSourceSummary { private final DataSource dataSource; private IngestJobStatusType status = null; - private Long jobId = null; private final String type; private final long filesCount; private final long resultsCount; @@ -54,29 +53,24 @@ class DataSourceSummary { */ DataSourceSummary(DataSource dSource, String typeValue, Long numberOfFiles, Long numberOfResults, Long numberOfTags) { dataSource = dSource; - getStatusFromDatabase(); + updateStatusFromDatabase(); type = typeValue == null ? "" : typeValue; filesCount = numberOfFiles == null ? 0 : numberOfFiles; resultsCount = numberOfResults == null ? 0 : numberOfResults; tagsCount = numberOfTags == null ? 0 : numberOfTags; } - private void getStatusFromDatabase() { + final void updateStatusFromDatabase() { try { IngestJobQueryCallback callback = new IngestJobQueryCallback(); - Case.getCurrentCaseThrows().getSleuthkitCase().getCaseDbAccessManager().select("ingest_job_id, status_id FROM ingest_jobs WHERE obj_id=" + dataSource.getId(), callback); + Case.getCurrentCaseThrows().getSleuthkitCase().getCaseDbAccessManager().select("status_id FROM ingest_jobs WHERE obj_id=" + dataSource.getId(), callback); status = callback.getStatus(); - jobId = callback.getJobId(); - System.out.println("NEW STATUS: " + status); + System.out.println("STATUS IN DB: " + status.getDisplayName()); } catch (NoCurrentCaseException | TskCoreException ex) { } } - - void setStatus(IngestJobStatusType newStatus){ - status = newStatus; - } - + /** * Get the DataSource * @@ -85,11 +79,7 @@ class DataSourceSummary { DataSource getDataSource() { return dataSource; } - - Long getJobId() { - return jobId; - } - + /** * Get the type of this DataSource * @@ -143,7 +133,6 @@ class DataSourceSummary { if (currentStatus == IngestJobStatusType.COMPLETED) { jobStatus = currentStatus; } else if (currentStatus == IngestJobStatusType.STARTED) { - ingestJobId = rs.getLong("ingest_job_id"); jobStatus = currentStatus; return; } @@ -157,8 +146,5 @@ class DataSourceSummary { return jobStatus; } - Long getJobId() { - return ingestJobId; - } } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDialog.java index 91ad7da792..1ac367c990 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDialog.java @@ -28,6 +28,8 @@ import javax.swing.event.ListSelectionEvent; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.IngestJobInfoPanel; import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisCompletedEvent; +import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisCompletedEvent.Reason; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.IngestJobInfo; @@ -77,11 +79,16 @@ final class DataSourceSummaryDialog extends javax.swing.JDialog implements Obser } }); IngestManager.getInstance().addIngestJobEventListener((PropertyChangeEvent evt) -> { - if (evt.getPropertyName().equals(IngestManager.IngestJobEvent.CANCELLED.toString())){ - dataSourcesPanel.refresh((long)evt.getOldValue(), null); - } - else if (evt.getPropertyName().equals(IngestManager.IngestJobEvent.COMPLETED.toString())) { - dataSourcesPanel.refresh((long)evt.getOldValue(), IngestJobInfo.IngestJobStatusType.COMPLETED); + if (evt instanceof DataSourceAnalysisCompletedEvent) { + DataSourceAnalysisCompletedEvent dsEvent = (DataSourceAnalysisCompletedEvent) evt; + if (dsEvent.getResult() == Reason.ANALYSIS_COMPLETED) { + System.out.println("DS JOB ID: " + dsEvent.getDataSourceIngestJobId()); + System.out.println("JOB ID: " + dsEvent.getIngestJobId()); + dataSourcesPanel.refresh(dsEvent.getDataSource().getId(), IngestJobInfo.IngestJobStatusType.COMPLETED); + + } else if (dsEvent.getResult() == Reason.ANALYSIS_CANCELLED) { + dataSourcesPanel.refresh(dsEvent.getDataSource().getId(), null); + } } }); this.pack(); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryNode.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryNode.java index 6c5a212d9d..b833e39743 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryNode.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryNode.java @@ -126,7 +126,7 @@ final class DataSourceSummaryNode extends AbstractNode { DataSourceSummaryEntryNode(DataSourceSummary dataSourceSummary) { super(Children.LEAF); dataSource = dataSourceSummary.getDataSource(); - status = dataSourceSummary.getIngestStatus() == null ? "" : dataSourceSummary.getIngestStatus().toString(); + status = dataSourceSummary.getIngestStatus() == null ? "" : dataSourceSummary.getIngestStatus().getDisplayName(); type = dataSourceSummary.getType(); filesCount = dataSourceSummary.getFilesCount(); resultsCount = dataSourceSummary.getResultsCount(); From d2154cd3809de5981c86e6af32ce29a188327fea Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 4 Jun 2019 14:37:17 -0400 Subject: [PATCH 027/115] 5092 fix accidently reverted check of datasource id --- .../casemodule/datasourcesummary/DataSourceBrowser.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java index 3fcb50b02e..9f74f71e2e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java @@ -190,11 +190,11 @@ final class DataSourceBrowser extends javax.swing.JPanel implements ExplorerMana return null; } - void refresh(content datasource, IngestJobInfo.IngestJobStatusType newStatus) { + void refresh(long dataSourceId, IngestJobInfo.IngestJobStatusType newStatus) { Node[] selectedNodes = explorerManager.getSelectedNodes(); //attempt to update the status of any datasources that had status which was STARTED for (DataSourceSummary summary : dataSourceSummaryList) { - if (summary.getDataSource().equals(datasource)) { + if (summary.getDataSource().getId() == dataSourceId) { summary.updateStatusFromDatabase(); } } From c1029fc154a5228395a5f9bbd4ec9191b0cbcf56 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 4 Jun 2019 14:41:20 -0400 Subject: [PATCH 028/115] 5092 reduce number of database queries necessary to display status --- .../casemodule/datasourcesummary/DataSourceBrowser.java | 2 +- .../casemodule/datasourcesummary/DataSourceSummary.java | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java index 9f74f71e2e..0df95720cf 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java @@ -195,7 +195,7 @@ final class DataSourceBrowser extends javax.swing.JPanel implements ExplorerMana //attempt to update the status of any datasources that had status which was STARTED for (DataSourceSummary summary : dataSourceSummaryList) { if (summary.getDataSource().getId() == dataSourceId) { - summary.updateStatusFromDatabase(); + summary.setIngestStatus(newStatus); } } SwingUtilities.invokeLater(() -> { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java index 071be6e3cb..010c7b17ee 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java @@ -53,14 +53,14 @@ class DataSourceSummary { */ DataSourceSummary(DataSource dSource, String typeValue, Long numberOfFiles, Long numberOfResults, Long numberOfTags) { dataSource = dSource; - updateStatusFromDatabase(); + getStatusFromDatabase(); type = typeValue == null ? "" : typeValue; filesCount = numberOfFiles == null ? 0 : numberOfFiles; resultsCount = numberOfResults == null ? 0 : numberOfResults; tagsCount = numberOfTags == null ? 0 : numberOfTags; } - final void updateStatusFromDatabase() { + private void getStatusFromDatabase() { try { IngestJobQueryCallback callback = new IngestJobQueryCallback(); Case.getCurrentCaseThrows().getSleuthkitCase().getCaseDbAccessManager().select("status_id FROM ingest_jobs WHERE obj_id=" + dataSource.getId(), callback); @@ -80,6 +80,10 @@ class DataSourceSummary { return dataSource; } + void setIngestStatus(IngestJobStatusType ingestStatus){ + status = ingestStatus; + } + /** * Get the type of this DataSource * From c9c451945db17955c1e4aaa80714fccb833a74c5 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 4 Jun 2019 15:02:28 -0400 Subject: [PATCH 029/115] 5092 add comments to better document how ingest job status is updated --- .../datasourcesummary/DataSourceBrowser.java | 11 +++-- .../datasourcesummary/DataSourceSummary.java | 47 +++++++++++++++---- .../DataSourceSummaryDialog.java | 5 -- 3 files changed, 45 insertions(+), 18 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java index 0df95720cf..f423b8a75a 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java @@ -39,8 +39,6 @@ import org.sleuthkit.autopsy.casemodule.datasourcesummary.DataSourceSummaryNode. import static javax.swing.SwingConstants.RIGHT; import javax.swing.SwingUtilities; import javax.swing.table.TableColumn; -import org.openide.util.Exceptions; -import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.IngestJobInfo; import org.sleuthkit.datamodel.SleuthkitCase; @@ -61,7 +59,7 @@ final class DataSourceBrowser extends javax.swing.JPanel implements ExplorerMana private final Outline outline; private final org.openide.explorer.view.OutlineView outlineView; private final ExplorerManager explorerManager; - private List dataSourceSummaryList; + private final List dataSourceSummaryList; private final RightAlignedTableCellRenderer rightAlignedRenderer = new RightAlignedTableCellRenderer(); /** @@ -190,6 +188,13 @@ final class DataSourceBrowser extends javax.swing.JPanel implements ExplorerMana return null; } + /** + * Update the DataSourceBrowser to display up to date status information for + * the data sources. + * + * @param dataSourceId the ID of the data source which should be updated + * @param newStatus the new status which the data source should have + */ void refresh(long dataSourceId, IngestJobInfo.IngestJobStatusType newStatus) { Node[] selectedNodes = explorerManager.getSelectedNodes(); //attempt to update the status of any datasources that had status which was STARTED diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java index 010c7b17ee..fedb11884a 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java @@ -20,6 +20,8 @@ package org.sleuthkit.autopsy.casemodule.datasourcesummary; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.logging.Level; +import java.util.logging.Logger; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.datamodel.CaseDbAccessManager; @@ -33,6 +35,8 @@ import org.sleuthkit.datamodel.TskCoreException; */ class DataSourceSummary { + private static final Logger logger = Logger.getLogger(DataSourceSummary.class.getName()); + private static final String INGEST_JOB_STATUS_QUERY = "status_id FROM ingest_jobs WHERE obj_id="; private final DataSource dataSource; private IngestJobStatusType status = null; private final String type; @@ -60,17 +64,19 @@ class DataSourceSummary { tagsCount = numberOfTags == null ? 0 : numberOfTags; } + /** + * Get the status of the ingest job from the case database + */ private void getStatusFromDatabase() { try { IngestJobQueryCallback callback = new IngestJobQueryCallback(); - Case.getCurrentCaseThrows().getSleuthkitCase().getCaseDbAccessManager().select("status_id FROM ingest_jobs WHERE obj_id=" + dataSource.getId(), callback); + Case.getCurrentCaseThrows().getSleuthkitCase().getCaseDbAccessManager().select(INGEST_JOB_STATUS_QUERY + dataSource.getId(), callback); status = callback.getStatus(); - System.out.println("STATUS IN DB: " + status.getDisplayName()); } catch (NoCurrentCaseException | TskCoreException ex) { } } - + /** * Get the DataSource * @@ -79,11 +85,17 @@ class DataSourceSummary { DataSource getDataSource() { return dataSource; } - - void setIngestStatus(IngestJobStatusType ingestStatus){ + + /** + * Manually set the ingest job status + * + * @param ingestStatus the status which the ingest job should have + * currently, null to display empty string + */ + void setIngestStatus(IngestJobStatusType ingestStatus) { status = ingestStatus; } - + /** * Get the type of this DataSource * @@ -111,6 +123,12 @@ class DataSourceSummary { return resultsCount; } + /** + * Get the IngestJobStatusType associated with this data source. + * + * @return the IngestJobStatusType associated with this data source. Can be + * null if the IngestJobStatusType is not STARTED or COMPLETED. + */ IngestJobStatusType getIngestStatus() { return status; } @@ -124,28 +142,37 @@ class DataSourceSummary { return tagsCount; } + /** + * Callback to parse result set, getting the status to be associated with + * this data source + */ class IngestJobQueryCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { private IngestJobStatusType jobStatus = null; - private Long ingestJobId = null; @Override public void process(ResultSet rs) { try { while (rs.next()) { IngestJobStatusType currentStatus = IngestJobStatusType.fromID(rs.getInt("status_id")); - if (currentStatus == IngestJobStatusType.COMPLETED) { + if (currentStatus == IngestJobStatusType.COMPLETED) { jobStatus = currentStatus; - } else if (currentStatus == IngestJobStatusType.STARTED) { + } else if (currentStatus == IngestJobStatusType.STARTED) { jobStatus = currentStatus; return; } } } catch (SQLException ex) { - System.out.println("EEEP"); + logger.log(Level.WARNING, "Error getting status for ingest job", ex); } } + /** + * Get the status which was determined for this callback + * + * @return the status of the data source which was + * queried for + */ IngestJobStatusType getStatus() { return jobStatus; } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDialog.java index 1ac367c990..f322731f42 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDialog.java @@ -23,7 +23,6 @@ import java.beans.PropertyChangeEvent; import java.util.Map; import java.util.Observable; import java.util.Observer; -import java.util.logging.Logger; import javax.swing.event.ListSelectionEvent; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.IngestJobInfoPanel; @@ -43,7 +42,6 @@ final class DataSourceSummaryDialog extends javax.swing.JDialog implements Obser private final DataSourceSummaryDetailsPanel detailsPanel; private final DataSourceBrowser dataSourcesPanel; private final IngestJobInfoPanel ingestHistoryPanel; - private static final Logger logger = Logger.getLogger(DataSourceSummaryDialog.class.getName()); /** * Creates new form DataSourceSummaryDialog for displaying a summary of the @@ -82,10 +80,7 @@ final class DataSourceSummaryDialog extends javax.swing.JDialog implements Obser if (evt instanceof DataSourceAnalysisCompletedEvent) { DataSourceAnalysisCompletedEvent dsEvent = (DataSourceAnalysisCompletedEvent) evt; if (dsEvent.getResult() == Reason.ANALYSIS_COMPLETED) { - System.out.println("DS JOB ID: " + dsEvent.getDataSourceIngestJobId()); - System.out.println("JOB ID: " + dsEvent.getIngestJobId()); dataSourcesPanel.refresh(dsEvent.getDataSource().getId(), IngestJobInfo.IngestJobStatusType.COMPLETED); - } else if (dsEvent.getResult() == Reason.ANALYSIS_CANCELLED) { dataSourcesPanel.refresh(dsEvent.getDataSource().getId(), null); } From 8637f1dfe0305ffb1e61609787d1d2cf140a55d4 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 4 Jun 2019 15:20:07 -0400 Subject: [PATCH 030/115] 5092 minor cleanup before pr --- .../casemodule/datasourcesummary/DataSourceBrowser.java | 4 +++- .../casemodule/datasourcesummary/DataSourceSummary.java | 3 +-- .../casemodule/datasourcesummary/DataSourceSummaryDialog.java | 1 + .../casemodule/datasourcesummary/DataSourceSummaryNode.java | 3 +-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java index f423b8a75a..ac09010de1 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceBrowser.java @@ -196,13 +196,15 @@ final class DataSourceBrowser extends javax.swing.JPanel implements ExplorerMana * @param newStatus the new status which the data source should have */ void refresh(long dataSourceId, IngestJobInfo.IngestJobStatusType newStatus) { - Node[] selectedNodes = explorerManager.getSelectedNodes(); + //attempt to update the status of any datasources that had status which was STARTED for (DataSourceSummary summary : dataSourceSummaryList) { if (summary.getDataSource().getId() == dataSourceId) { summary.setIngestStatus(newStatus); } } + //figure out which nodes were previously selected + Node[] selectedNodes = explorerManager.getSelectedNodes(); SwingUtilities.invokeLater(() -> { explorerManager.setRootContext(new DataSourceSummaryNode(dataSourceSummaryList)); List nodesToSelect = new ArrayList<>(); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java index fedb11884a..c9c5b551ce 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java @@ -170,8 +170,7 @@ class DataSourceSummary { /** * Get the status which was determined for this callback * - * @return the status of the data source which was - * queried for + * @return the status of the data source which was queried for */ IngestJobStatusType getStatus() { return jobStatus; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDialog.java index f322731f42..1535cbefe0 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryDialog.java @@ -76,6 +76,7 @@ final class DataSourceSummaryDialog extends javax.swing.JDialog implements Obser this.repaint(); } }); + //add listener to refresh jobs with Started status when they complete IngestManager.getInstance().addIngestJobEventListener((PropertyChangeEvent evt) -> { if (evt instanceof DataSourceAnalysisCompletedEvent) { DataSourceAnalysisCompletedEvent dsEvent = (DataSourceAnalysisCompletedEvent) evt; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryNode.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryNode.java index b833e39743..703e1f1373 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryNode.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryNode.java @@ -184,8 +184,7 @@ final class DataSourceSummaryNode extends AbstractNode { } @Override - public Action[] getActions(boolean context - ) { + public Action[] getActions(boolean context) { List actions = new ArrayList<>(); actions.add(new ViewDataSourceInContextAction()); return actions.toArray(new Action[actions.size()]); From d34610fb58c118a75196a440d92cb5f43e74be7a Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 4 Jun 2019 15:32:21 -0400 Subject: [PATCH 031/115] 5092 address codacy complaints --- .../datasourcesummary/DataSourceSummary.java | 10 +++++----- .../datasourcesummary/DataSourceSummaryNode.java | 1 - 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java index c9c5b551ce..390dce1afe 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummary.java @@ -34,7 +34,7 @@ import org.sleuthkit.datamodel.TskCoreException; * */ class DataSourceSummary { - + private static final Logger logger = Logger.getLogger(DataSourceSummary.class.getName()); private static final String INGEST_JOB_STATUS_QUERY = "status_id FROM ingest_jobs WHERE obj_id="; private final DataSource dataSource; @@ -73,7 +73,7 @@ class DataSourceSummary { Case.getCurrentCaseThrows().getSleuthkitCase().getCaseDbAccessManager().select(INGEST_JOB_STATUS_QUERY + dataSource.getId(), callback); status = callback.getStatus(); } catch (NoCurrentCaseException | TskCoreException ex) { - + logger.log(Level.WARNING, "Error getting status for data source from case database", ex); } } @@ -147,9 +147,9 @@ class DataSourceSummary { * this data source */ class IngestJobQueryCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { - + private IngestJobStatusType jobStatus = null; - + @Override public void process(ResultSet rs) { try { @@ -175,6 +175,6 @@ class DataSourceSummary { IngestJobStatusType getStatus() { return jobStatus; } - + } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryNode.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryNode.java index 703e1f1373..0411d94bb2 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryNode.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourcesummary/DataSourceSummaryNode.java @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.casemodule.datasourcesummary; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.List; -import java.util.Objects; import java.util.Observable; import java.util.Observer; import javax.swing.Action; From 21615fca2f339b57b744f772d49b8588fe46ad35 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 5 Jun 2019 10:59:45 -0400 Subject: [PATCH 032/115] 5061 remove translation size setting --- .../BingTranslatorSettingsPanel.form | 56 +++---------------- .../BingTranslatorSettingsPanel.java | 42 +++----------- .../translators/Bundle.properties | 2 - .../GoogleTranslatorSettingsPanel.form | 4 ++ .../GoogleTranslatorSettingsPanel.java | 22 ++++++-- 5 files changed, 38 insertions(+), 88 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form index 64227561b3..54dfaa4827 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form @@ -39,28 +39,15 @@ - - - - + - - - - - - - - - - - - - - - - - + + + + + + + @@ -83,12 +70,6 @@ - - - - - - @@ -151,27 +132,6 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java index e477fbf662..5a73bca0fa 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java @@ -122,9 +122,6 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { testButton = new javax.swing.JButton(); targetLanguageLabel = new javax.swing.JLabel(); targetLanguageComboBox = new javax.swing.JComboBox<>(); - translationSizeLabel = new javax.swing.JLabel(); - translationSizeSpinner = new javax.swing.JSpinner(); - unitsLabel = new javax.swing.JLabel(); testUntranslatedTextField = new javax.swing.JTextField(); untranslatedLabel = new javax.swing.JLabel(); resultLabel = new javax.swing.JLabel(); @@ -151,12 +148,6 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { } }); - org.openide.awt.Mnemonics.setLocalizedText(translationSizeLabel, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "BingTranslatorSettingsPanel.translationSizeLabel.text")); // NOI18N - - translationSizeSpinner.setModel(new javax.swing.SpinnerNumberModel(5000, 5000, 500000, 5000)); - - org.openide.awt.Mnemonics.setLocalizedText(unitsLabel, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "BingTranslatorSettingsPanel.unitsLabel.text")); // NOI18N - testUntranslatedTextField.setText(DEFUALT_TEST_STRING); org.openide.awt.Mnemonics.setLocalizedText(untranslatedLabel, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "BingTranslatorSettingsPanel.untranslatedLabel.text")); // NOI18N @@ -190,24 +181,15 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { .addComponent(authenticationKeyField, javax.swing.GroupLayout.PREFERRED_SIZE, 486, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(0, 20, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(translationSizeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(testButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(testButton, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(25, 25, 25) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(translationSizeSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, 77, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(unitsLabel) - .addGap(0, 0, Short.MAX_VALUE)) - .addGroup(layout.createSequentialGroup() - .addComponent(untranslatedLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(testUntranslatedTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 140, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(resultLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(testResultValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))) + .addComponent(untranslatedLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(testUntranslatedTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 140, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(resultLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(testResultValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) .addContainerGap()))) ); layout.setVerticalGroup( @@ -222,11 +204,6 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { .addComponent(targetLanguageLabel) .addComponent(targetLanguageComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(translationSizeLabel) - .addComponent(translationSizeSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(unitsLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(testButton) .addComponent(testUntranslatedTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) @@ -264,9 +241,6 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { private javax.swing.JButton testButton; private javax.swing.JLabel testResultValueLabel; private javax.swing.JTextField testUntranslatedTextField; - private javax.swing.JLabel translationSizeLabel; - private javax.swing.JSpinner translationSizeSpinner; - private javax.swing.JLabel unitsLabel; private javax.swing.JLabel untranslatedLabel; private javax.swing.JLabel warningLabel; // End of variables declaration//GEN-END:variables diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties index 6ebd3002ef..0021118e14 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties @@ -6,9 +6,7 @@ BingTranslatorSettingsPanel.testButton.text=Test BingTranslatorSettingsPanel.testResultValueLabel.text= BingTranslatorSettingsPanel.resultLabel.text=Result: BingTranslatorSettingsPanel.untranslatedLabel.text=Untranslated: -BingTranslatorSettingsPanel.translationSizeLabel.text=Translation Size: BingTranslatorSettingsPanel.targetLanguageLabel.text=Target Language: -BingTranslatorSettingsPanel.unitsLabel.text=characters BingTranslatorSettingsPanel.authenticationKeyField.toolTipText=Enter the hash for the GoogleTranslatorSettingsPanel.testButton.text=Test GoogleTranslatorSettingsPanel.untranslatedLabel.text=Untranslated: diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.form index 7d728fd011..b55a40b30f 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.form @@ -145,6 +145,7 @@ + @@ -152,6 +153,7 @@ + @@ -159,6 +161,7 @@ + @@ -166,6 +169,7 @@ + diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java index 8bccc01485..0041860182 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java @@ -130,21 +130,31 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { }); selectLanguageByCode(targetLanguageCode); targetLanguageComboBox.addItemListener(listener); - targetLanguageComboBox.setEnabled(true); + enableControls(true); + } else { - targetLanguageComboBox.setEnabled(false); + enableControls(false); } } else { warningLabel.setText(Bundle.GoogleTranslatorSettingsPanel_errorMessage_noFileSelected()); - targetLanguageComboBox.setEnabled(false); + enableControls(false); } } catch (Throwable throwable) { warningLabel.setText(Bundle.GoogleTranslatorSettingsPanel_errorMessage_unknownFailurePopulating()); logger.log(Level.WARNING, "Throwable caught while populating list of supported languages", throwable); - targetLanguageComboBox.setEnabled(false); + enableControls(false); } } + private void enableControls(boolean enabled) { + targetLanguageComboBox.setEnabled(enabled); + testButton.setEnabled(enabled); + testResultValueLabel.setEnabled(enabled); + testUntranslatedTextField.setEnabled(enabled); + untranslatedLabel.setEnabled(enabled); + resultLabel.setEnabled(enabled); + } + /** * Given a language code select the corresponding language in the combo box * if it is present @@ -202,12 +212,16 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { org.openide.awt.Mnemonics.setLocalizedText(testResultValueLabel, org.openide.util.NbBundle.getMessage(GoogleTranslatorSettingsPanel.class, "GoogleTranslatorSettingsPanel.testResultValueLabel.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(resultLabel, org.openide.util.NbBundle.getMessage(GoogleTranslatorSettingsPanel.class, "GoogleTranslatorSettingsPanel.resultLabel.text")); // NOI18N + resultLabel.setEnabled(false); org.openide.awt.Mnemonics.setLocalizedText(untranslatedLabel, org.openide.util.NbBundle.getMessage(GoogleTranslatorSettingsPanel.class, "GoogleTranslatorSettingsPanel.untranslatedLabel.text")); // NOI18N + untranslatedLabel.setEnabled(false); testUntranslatedTextField.setText(DEFUALT_TEST_STRING); + testUntranslatedTextField.setEnabled(false); org.openide.awt.Mnemonics.setLocalizedText(testButton, org.openide.util.NbBundle.getMessage(GoogleTranslatorSettingsPanel.class, "GoogleTranslatorSettingsPanel.testButton.text")); // NOI18N + testButton.setEnabled(false); testButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { testButtonActionPerformed(evt); From 2ecd3a56b4f5740dc03992b21a05765cd5dbcde7 Mon Sep 17 00:00:00 2001 From: Raman Date: Wed, 5 Jun 2019 11:13:32 -0400 Subject: [PATCH 033/115] Addressed review comments. --- .../relationships/MessageNode.java | 5 -- .../datamodel/AbstractAbstractFileNode.java | 10 +-- .../datamodel/AbstractContentNode.java | 7 +- .../datamodel/BlackboardArtifactNode.java | 82 +++++++++++++++---- .../datamodel/Bundle.properties-MERGED | 2 +- .../autopsy/datamodel/GetSCOTask.java | 2 +- 6 files changed, 79 insertions(+), 29 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java index 2f4ce1157a..d1cdcbabf2 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java @@ -18,13 +18,10 @@ */ package org.sleuthkit.autopsy.communications.relationships; -import java.util.List; import java.util.TimeZone; import java.util.logging.Level; import org.apache.commons.lang3.StringUtils; import org.openide.nodes.Sheet; -import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; -import org.sleuthkit.autopsy.core.UserPreferences; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; @@ -40,7 +37,6 @@ import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHO import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT; import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME; -import org.sleuthkit.datamodel.Tag; import org.sleuthkit.datamodel.TimeUtilities; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.communications.Utils; @@ -72,7 +68,6 @@ final class MessageNode extends BlackboardArtifactNode { @Override protected Sheet createSheet() { Sheet sheet = super.createSheet(); - List tags = getAllTagsFromDatabase(); Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES); if (sheetSet == null) { sheetSet = Sheet.createPropertiesSet(); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java index e8d71caae7..158f2ef4d9 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java @@ -74,8 +74,6 @@ import org.sleuthkit.datamodel.TskData; public abstract class AbstractAbstractFileNode extends AbstractContentNode { private static final Logger logger = Logger.getLogger(AbstractAbstractFileNode.class.getName()); - @NbBundle.Messages("AbstractAbstractFileNode.addFileProperty.desc=no description") - private static final String NO_DESCR = AbstractAbstractFileNode_addFileProperty_desc(); private static final Set CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.CURRENT_CASE, Case.Events.CONTENT_TAG_ADDED, Case.Events.CONTENT_TAG_DELETED, Case.Events.CR_COMMENT_CHANGED); @@ -328,9 +326,11 @@ public abstract class AbstractAbstractFileNode extends A } // Create place holders for S C O - properties.add(new NodeProperty<>(SCORE.toString(), SCORE.toString(), NO_DESCR, "")); - properties.add(new NodeProperty<>(COMMENT.toString(), COMMENT.toString(), NO_DESCR, "")); - properties.add(new NodeProperty<>(OCCURRENCES.toString(), OCCURRENCES.toString(), NO_DESCR, "")); + properties.add(new NodeProperty<>(SCORE.toString(), SCORE.toString(), VALUE_LOADING, "")); + properties.add(new NodeProperty<>(COMMENT.toString(), COMMENT.toString(), VALUE_LOADING, "")); + if (UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) { + properties.add(new NodeProperty<>(OCCURRENCES.toString(), OCCURRENCES.toString(), VALUE_LOADING, "")); + } // Get the SCO columns data in a background task diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java index 154ca68d50..b9e012e6af 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java @@ -64,14 +64,15 @@ public abstract class AbstractContentNode extends ContentNode * populate this node. */ static final ExecutorService backgroundTasksPool; - static final Integer MAX_POOL_SIZE = 10; + private static final Integer MAX_POOL_SIZE = 10; /** * Default no description string */ - @NbBundle.Messages("AbstractContentNode.nodescription=no description") + @NbBundle.Messages({"AbstractContentNode.nodescription=no description", + "AbstractContentNode.valueLoading=value loading"}) protected static final String NO_DESCR = Bundle.AbstractContentNode_nodescription(); - + protected static final String VALUE_LOADING = Bundle.AbstractContentNode_valueLoading(); /** * Event signals to indicate the background tasks have completed processing. diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java index 1f871363f9..23ab78fa01 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java @@ -99,10 +99,7 @@ public class BlackboardArtifactNode extends AbstractContentNode> customProperties; - - protected final static String NO_DESCR = NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.noDesc.text"); - - + /* * Artifact types which should have the full unique path of the associated * content as a property. @@ -367,9 +364,11 @@ public class BlackboardArtifactNode extends AbstractContentNode(Bundle.BlackboardArtifactNode_createSheet_score_name(), Bundle.BlackboardArtifactNode_createSheet_score_displayName(), NO_DESCR, "")); - sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_comment_name(), Bundle.BlackboardArtifactNode_createSheet_comment_displayName(), NO_DESCR, "")); - sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_count_name(), Bundle.BlackboardArtifactNode_createSheet_count_displayName(), NO_DESCR, "")); + sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_score_name(), Bundle.BlackboardArtifactNode_createSheet_score_displayName(), VALUE_LOADING, "")); + sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_comment_name(), Bundle.BlackboardArtifactNode_createSheet_comment_displayName(), VALUE_LOADING, "")); + if (UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) { + sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_count_name(), Bundle.BlackboardArtifactNode_createSheet_count_displayName(), VALUE_LOADING, "")); + } // Get the SCO columns data in a background task backgroundTasksPool.submit(new GetSCOTask( @@ -596,14 +595,33 @@ public class BlackboardArtifactNode extends AbstractContentNode tags, CorrelationAttributeInstance attribute) { + HasCommentStatus status = getCommentProperty(tags, attribute ); + sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_comment_name(), Bundle.BlackboardArtifactNode_createSheet_comment_displayName(), NO_DESCR, + status)); + } + + /** + * Gets the comment property for the node + * * @param tags the list of tags associated with the file * @param attribute the correlation attribute associated with this * artifact's associated file, null if central repo is not * enabled * @return comment property */ - @NbBundle.Messages({"BlackboardArtifactNode.createSheet.comment.name=C", - "BlackboardArtifactNode.createSheet.comment.displayName=C"}) @Override protected DataResultViewerTable.HasCommentStatus getCommentProperty(List tags, CorrelationAttributeInstance attribute) { @@ -627,14 +645,15 @@ public class BlackboardArtifactNode extends AbstractContentNode tags) { + Pair scoreAndDescription = getScorePropertyAndDescription(tags); + sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_score_name(), Bundle.BlackboardArtifactNode_createSheet_score_displayName(), scoreAndDescription.getRight(), scoreAndDescription.getLeft())); + } + /** + * Get the score property for the node. + * + * @param tags the list of tags associated with the file + * + * @return score property and description + */ @Override protected Pair getScorePropertyAndDescription(List tags) { Score score = Score.NO_SCORE; @@ -693,17 +724,40 @@ public class BlackboardArtifactNode extends AbstractContentNode countAndDescription = getCountPropertyAndDescription(attribute); + sheetSet.put( + new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_count_name(), Bundle.BlackboardArtifactNode_createSheet_count_displayName(), countAndDescription.getRight(), countAndDescription.getLeft())); + } + + /** + * Gets the Occurrences property for the node. + * + * @param attribute correlation attribute instance + * + * @return count and description + * + */ @Override protected Pair getCountPropertyAndDescription(CorrelationAttributeInstance attribute) { - Long count = -1L; //The column renderer will not display negative values, negative value used when count unavailble to preserve sorting + Long count = -1L; String description = Bundle.BlackboardArtifactNode_createSheet_count_noCentralRepo_description(); try { //don't perform the query if there is no correlation value diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED index 8d2bd5952d..0386b0fef2 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED @@ -1,5 +1,4 @@ AbstractAbstractFileNode.accessTimeColLbl=Access Time -AbstractAbstractFileNode.addFileProperty.desc=no description AbstractAbstractFileNode.attrAddrColLbl=Attr. Addr. AbstractAbstractFileNode.changeTimeColLbl=Change Time AbstractAbstractFileNode.createdTimeColLbl=Created Time @@ -38,6 +37,7 @@ AbstractAbstractFileNode.typeDirColLbl=Type(Dir) AbstractAbstractFileNode.typeMetaColLbl=Type(Meta) AbstractAbstractFileNode.useridColLbl=UserID AbstractContentNode.nodescription=no description +AbstractContentNode.valueLoading=value loading AbstractFsContentNode.noDesc.text=no description ArtifactStringContent.attrsTableHeader.sources=Source(s) ArtifactStringContent.attrsTableHeader.type=Type diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java b/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java index 4278f99d66..b7f4e38a5e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java @@ -37,7 +37,7 @@ class GetSCOTask implements Runnable { private final WeakReference> weakNodeRef; private final PropertyChangeListener listener; - public GetSCOTask(WeakReference> weakContentRef, PropertyChangeListener listener) { + GetSCOTask(WeakReference> weakContentRef, PropertyChangeListener listener) { this.weakNodeRef = weakContentRef; this.listener = listener; } From 852ad67e05f59a3e2860210136e464de054006e7 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 5 Jun 2019 12:16:16 -0400 Subject: [PATCH 034/115] 5061 fix initial selection of english --- .../BingTranslatorSettingsPanel.form | 1 + .../BingTranslatorSettingsPanel.java | 15 ++++++--- .../translators/Bundle.properties-MERGED | 5 +-- .../translators/GoogleTranslator.java | 31 +++++++++++-------- .../GoogleTranslatorSettingsPanel.java | 24 +++++++------- 5 files changed, 46 insertions(+), 30 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form index 54dfaa4827..cd855ac419 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form @@ -124,6 +124,7 @@ + diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java index 5a73bca0fa..c6d4c9b932 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java @@ -33,6 +33,7 @@ import java.util.logging.Logger; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import org.apache.commons.lang3.StringUtils; +import org.openide.util.NbBundle.Messages; /** * Settings panel for the GoogleTranslator @@ -68,11 +69,12 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { } }); - targetLanguageCode = code; populateComboBox(); - selectLanguageByCode(targetLanguageCode); + selectLanguageByCode(code); + targetLanguageCode = code; } + @Messages({"BingTranslatorSettingsPanel.warning.targetLanguageFailure=Unable to get list of target languages or parse the result that was received"}) private void populateComboBox() { Request get_request = new Request.Builder() .url(GET_TARGET_LANGUAGES_URL).build(); @@ -87,8 +89,11 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { responses.entrySet().forEach((entry) -> { targetLanguageComboBox.addItem(new LanguageWrapper(entry.getKey(), entry.getValue().getAsJsonObject().get("name").getAsString())); }); + targetLanguageComboBox.setEnabled(true); } catch (IOException | IllegalStateException | ClassCastException | NullPointerException | IndexOutOfBoundsException ex) { - logger.log(Level.WARNING, "Unable to get list of target languages or parse the result that was received", ex); + logger.log(Level.SEVERE, Bundle.BingTranslatorSettingsPanel_warning_targetLanguageFailure(), ex); + warningLabel.setText(Bundle.BingTranslatorSettingsPanel_warning_targetLanguageFailure()); + targetLanguageComboBox.setEnabled(false); } } @@ -142,6 +147,7 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { org.openide.awt.Mnemonics.setLocalizedText(targetLanguageLabel, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "BingTranslatorSettingsPanel.targetLanguageLabel.text")); // NOI18N + targetLanguageComboBox.setEnabled(false); targetLanguageComboBox.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent evt) { targetLanguageComboBoxSelected(evt); @@ -216,11 +222,12 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { ); }// //GEN-END:initComponents + @Messages({"BingTranslatorSettingsPanel.warning.invalidKey=Invalid translation authentication key"}) private void testButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_testButtonActionPerformed if (testTranslationSetup()) { warningLabel.setText(""); } else { - warningLabel.setText("Invalid translation authentication key"); + warningLabel.setText(Bundle.BingTranslatorSettingsPanel_warning_invalidKey()); } }//GEN-LAST:event_testButtonActionPerformed diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED index 35e06bda99..51cbb9a26f 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED @@ -1,9 +1,12 @@ BingTranslator.name.text=Bing Translator +BingTranslatorSettingsPanel.warning.invalidKey=Invalid translation authentication key +BingTranslatorSettingsPanel.warning.targetLanguageFailure=Unable to get list of target languages or parse the result that was received GoogleTranslator.name.text=Google Translate GoogleTranslatorSettingsPanel.browseButton.text=Browse GoogleTranslatorSettingsPanel.credentialsLabel.text=Credentials Path: GoogleTranslatorSettingsPanel.errorMessage.fileNotFound=Credentials file not found, please set the location to be a valid JSON credentials file. GoogleTranslatorSettingsPanel.errorMessage.noFileSelected=A JSON file must be selected to provide your credentials for Google Translate. +GoogleTranslatorSettingsPanel.errorMessage.translationFailure=Translation failure with specified credentials GoogleTranslatorSettingsPanel.errorMessage.unableToMakeCredentials=Unable to construct credentials object from credentials file, please set the location to be a valid JSON credentials file. GoogleTranslatorSettingsPanel.errorMessage.unableToReadCredentials=Unable to read credentials from credentials file, please set the location to be a valid JSON credentials file. GoogleTranslatorSettingsPanel.errorMessage.unknownFailureGetting=Failure getting list of supported languages with current credentials file. @@ -16,9 +19,7 @@ BingTranslatorSettingsPanel.testButton.text=Test BingTranslatorSettingsPanel.testResultValueLabel.text= BingTranslatorSettingsPanel.resultLabel.text=Result: BingTranslatorSettingsPanel.untranslatedLabel.text=Untranslated: -BingTranslatorSettingsPanel.translationSizeLabel.text=Translation Size: BingTranslatorSettingsPanel.targetLanguageLabel.text=Target Language: -BingTranslatorSettingsPanel.unitsLabel.text=characters BingTranslatorSettingsPanel.authenticationKeyField.toolTipText=Enter the hash for the GoogleTranslatorSettingsPanel.testButton.text=Test GoogleTranslatorSettingsPanel.untranslatedLabel.text=Untranslated: diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslator.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslator.java index d55316b86c..3bb6a6c9ed 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslator.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslator.java @@ -32,6 +32,7 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.util.logging.Level; import java.util.logging.Logger; +import org.apache.commons.lang3.StringUtils; import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.coreutils.EscapeUtil; @@ -59,26 +60,26 @@ public final class GoogleTranslator implements TextTranslator { settingsPanel = new GoogleTranslatorSettingsPanel(settings.getCredentialPath(), settings.getTargetLanguageCode()); loadTranslator(); } - + private static boolean googleIsReachable() { String host = "www.google.com"; InetAddress address; try { address = InetAddress.getByName(host); return address.isReachable(1500); - }catch (UnknownHostException ex) { + } catch (UnknownHostException ex) { return false; } catch (IOException ex) { return false; } } - + @Override public String translate(String string) throws TranslationException { if (!googleIsReachable()) { throw new TranslationException("Failure translating using GoogleTranslator: Cannot connect to Google"); } - + if (googleTranslate != null) { try { // Translates some text into English, without specifying the source language. @@ -89,7 +90,7 @@ public final class GoogleTranslator implements TextTranslator { // We can't currently set parameters, so we are using the default behavior of // assuming the input is HTML. We need to replace newlines with
for Google to preserve them substring = substring.replaceAll("(\r\n|\n)", "
"); - + // The API complains if the "Payload" is over 204800 bytes. I'm assuming that // deals with the full request. At some point, we get different errors about too // much text. Officially, Google says they will googleTranslate only 5k chars, @@ -101,15 +102,15 @@ public final class GoogleTranslator implements TextTranslator { Translation translation = googleTranslate.translate(substring); String translatedString = translation.getTranslatedText(); - + // put back the newlines translatedString = translatedString.replaceAll("
", "\n"); - + // With our current settings, Google Translate outputs HTML // so we need to undo the escape characters. translatedString = EscapeUtil.unEscapeHtml(translatedString); return translatedString; - } catch (Throwable ex) { + } catch (Throwable ex) { //Catching throwables because some of this Google Translate code throws throwables throw new TranslationException("Failure translating using GoogleTranslator", ex); } @@ -117,7 +118,7 @@ public final class GoogleTranslator implements TextTranslator { throw new TranslationException("Google Translator has not been configured, credentials need to be specified"); } } - + @Messages({"GoogleTranslator.name.text=Google Translate"}) @Override public String getName() { @@ -136,10 +137,14 @@ public final class GoogleTranslator implements TextTranslator { private void loadTranslator() { InputStream credentialStream = null; Credentials creds = null; - try { - credentialStream = new FileInputStream(settings.getCredentialPath()); - } catch (FileNotFoundException ex) { - logger.log(Level.WARNING, "JSON file for GoogleTranslator credentials not found", ex); + if (StringUtils.isBlank(settings.getCredentialPath())) { + logger.log(Level.INFO, "No credentials file has been provided for Google Translator"); + } else { + try { + credentialStream = new FileInputStream(settings.getCredentialPath()); + } catch (FileNotFoundException ex) { + logger.log(Level.WARNING, "JSON file for GoogleTranslator credentials not found", ex); + } } if (credentialStream != null) { try { diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java index 0041860182..4032d69a05 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java @@ -305,18 +305,20 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { } }//GEN-LAST:event_browseButtonActionPerformed + @Messages({"GoogleTranslatorSettingsPanel.errorMessage.translationFailure=Translation failure with specified credentials"}) private void testButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_testButtonActionPerformed - testResultValueLabel.setText(""); - Translate tempTranslate = getTemporaryTranslationService(); - if (tempTranslate != null) { - try { - Translation translation = tempTranslate.translate(testUntranslatedTextField.getText()); - testResultValueLabel.setText(translation.getTranslatedText()); - warningLabel.setText(""); - } catch (Exception ex) { - warningLabel.setText("Invalid translation credentials path"); - } - } + testResultValueLabel.setText(""); + Translate tempTranslate = getTemporaryTranslationService(); + if (tempTranslate != null) { + try { + Translation translation = tempTranslate.translate(testUntranslatedTextField.getText()); + testResultValueLabel.setText(translation.getTranslatedText()); + warningLabel.setText(""); + } catch (Exception ex) { + warningLabel.setText(Bundle.GoogleTranslatorSettingsPanel_errorMessage_translationFailure()); + logger.log(Level.WARNING, Bundle.GoogleTranslatorSettingsPanel_errorMessage_translationFailure(), ex); + } + } }//GEN-LAST:event_testButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables From f8d02a3002e361f9d94be229b16bd75163c0d67b Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Wed, 5 Jun 2019 12:19:38 -0400 Subject: [PATCH 035/115] Added button --- .../autopsy/corecomponents/Bundle.properties | 1 + .../corecomponents/Bundle.properties-MERGED | 1 + .../corecomponents/DataResultViewerTable.form | 24 +++- .../corecomponents/DataResultViewerTable.java | 29 +++-- .../directorytree/Bundle.properties-MERGED | 6 +- .../directorytree/ExportCSVAction.java | 117 ++++++++++++------ 6 files changed, 122 insertions(+), 56 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties index 7eb261880f..fae74a30ac 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties @@ -217,3 +217,4 @@ DataResultViewerTable.pageNumLabel.text= DataResultViewerTable.pageLabel.text=Page: ViewPreferencesPanel.maxResultsLabel.text=Maximum number of Results to show in table: ViewPreferencesPanel.maxResultsLabel.toolTipText=\nSetting this value to 0 will display all results in the results table.\n
Note that setting this value to 0 may result in poor UI responsiveness when there are large numbers of results.\n +DataResultViewerTable.exportCSVButton.text=Save table as CSV diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED index cd75ae919e..43ceba39ba 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED @@ -270,3 +270,4 @@ DataResultViewerTable.pageNumLabel.text= DataResultViewerTable.pageLabel.text=Page: ViewPreferencesPanel.maxResultsLabel.text=Maximum number of Results to show in table: ViewPreferencesPanel.maxResultsLabel.toolTipText=\nSetting this value to 0 will display all results in the results table.\n
Note that setting this value to 0 may result in poor UI responsiveness when there are large numbers of results.\n +DataResultViewerTable.exportCSVButton.text=Save table as CSV diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.form b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.form index 6b17cfd6dd..87e771695b 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.form @@ -16,9 +16,10 @@ - - - + + + + @@ -39,7 +40,7 @@ - + @@ -48,9 +49,10 @@ + - - + + @@ -164,5 +166,15 @@
+ + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java index a5bbc461b8..eb5fad97f5 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java @@ -1291,6 +1291,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer { outlineView = new OutlineView(DataResultViewerTable.FIRST_COLUMN_LABEL); gotoPageLabel = new javax.swing.JLabel(); gotoPageTextField = new javax.swing.JTextField(); + exportCSVButton = new javax.swing.JButton(); pageLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerTable.class, "DataResultViewerTable.pageLabel.text")); // NOI18N @@ -1338,13 +1339,21 @@ public class DataResultViewerTable extends AbstractDataResultViewer { } }); + exportCSVButton.setText(org.openide.util.NbBundle.getMessage(DataResultViewerTable.class, "DataResultViewerTable.exportCSVButton.text")); // NOI18N + exportCSVButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + exportCSVButtonActionPerformed(evt); + } + }); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap(608, Short.MAX_VALUE) + .addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 904, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(exportCSVButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(pageLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(pageNumLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 53, javax.swing.GroupLayout.PREFERRED_SIZE) @@ -1366,7 +1375,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer { layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap() + .addGap(3, 3, 3) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) .addComponent(pageLabel) .addComponent(pageNumLabel) @@ -1374,9 +1383,10 @@ public class DataResultViewerTable extends AbstractDataResultViewer { .addComponent(pagePrevButton, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(pageNextButton, javax.swing.GroupLayout.PREFERRED_SIZE, 15, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(gotoPageLabel) - .addComponent(gotoPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 324, Short.MAX_VALUE) + .addComponent(gotoPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(exportCSVButton)) + .addGap(3, 3, 3) + .addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 321, Short.MAX_VALUE) .addContainerGap()) ); @@ -1397,7 +1407,12 @@ public class DataResultViewerTable extends AbstractDataResultViewer { pagingSupport.gotoPage(); }//GEN-LAST:event_gotoPageTextFieldActionPerformed + private void exportCSVButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exportCSVButtonActionPerformed + org.sleuthkit.autopsy.directorytree.ExportCSVAction.saveNodesToCSV(java.util.Arrays.asList(rootNode.getChildren().getNodes()), this); + }//GEN-LAST:event_exportCSVButtonActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton exportCSVButton; private javax.swing.JLabel gotoPageLabel; private javax.swing.JTextField gotoPageTextField; private org.openide.explorer.view.OutlineView outlineView; diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties-MERGED index d58338c450..6ec6a0e76b 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties-MERGED @@ -11,9 +11,9 @@ DirectoryTreeTopComponent.componentOpened.groupDataSources.title=Group by data s DirectoryTreeTopComponent.emptyMimeNode.text=Data not available. Run file type identification module. DirectoryTreeTopComponent.resultsView.title=Listing # {0} - Output file -ExportCSV.actionPerformed.fileExists=File {0} already exists -ExportCSV.actionPerformed.noCurrentCase=No open case available -ExportCSV.title.text=Export to CSV +ExportCSV.saveNodesToCSV.fileExists=File {0} already exists +ExportCSV.saveNodesToCSV.noCurrentCase=No open case available +ExportCSV.title.text=Export selected rows to CSV ExternalViewerAction.actionPerformed.failure.exe.message=The file is an executable and will not be opened. ExternalViewerAction.actionPerformed.failure.IO.message=There is no associated editor for files of this type or the associated application failed to launch. ExternalViewerAction.actionPerformed.failure.missingFile.message=The file no longer exists. diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java index 169701a55c..dce6244084 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java @@ -25,8 +25,10 @@ import java.io.BufferedWriter; import java.io.FileWriter; import java.io.FileOutputStream; import java.io.OutputStreamWriter; +import java.lang.reflect.InvocationTargetException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.HashSet; @@ -63,9 +65,11 @@ import org.openide.nodes.Node.Property; */ public final class ExportCSVAction extends AbstractAction { - private Logger logger = Logger.getLogger(ExportCSVAction.class.getName()); + private static Logger logger = Logger.getLogger(ExportCSVAction.class.getName()); + private final static String DEFAULT_FILENAME = "Results"; + private final static List columnsToSkip = Arrays.asList("S", "C", "O"); - private String userDefinedExportPath; + private static volatile String userDefinedExportPath; // TODO make volatile or whatever // This class is a singleton to support multi-selection of nodes, since // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every @@ -82,53 +86,44 @@ public final class ExportCSVAction extends AbstractAction { /** * Private constructor for the action. */ - @NbBundle.Messages({"ExportCSV.title.text=Export to CSV"}) + @NbBundle.Messages({"ExportCSV.title.text=Export selected rows to CSV"}) private ExportCSVAction() { super(Bundle.ExportCSV_title_text()); } - + /** * Asks user to choose destination, then extracts content to destination * (recursing on directories). * * @param e The action event. */ - @NbBundle.Messages({ - "# {0} - Output file", - "ExportCSV.actionPerformed.fileExists=File {0} already exists", - "ExportCSV.actionPerformed.noCurrentCase=No open case available"}) + @Override public void actionPerformed(ActionEvent e) { - Collection selectedNodes = Utilities.actionsGlobalContext().lookupAll(Node.class); - if (selectedNodes.isEmpty()) { + saveNodesToCSV(selectedNodes, (Component)e.getSource()); + } + + @NbBundle.Messages({ + "# {0} - Output file", + "ExportCSV.saveNodesToCSV.fileExists=File {0} already exists", + "ExportCSV.saveNodesToCSV.noCurrentCase=No open case available"}) + public static void saveNodesToCSV(Collection nodesToExport, Component component) { + + if (nodesToExport.isEmpty()) { return; } - Node parent = selectedNodes.iterator().next().getParentNode(); - if (parent != null) { - System.out.println("HTML name: " + parent.getHtmlDisplayName()); - System.out.println("Display name: " + parent.getDisplayName()); - System.out.println("Class: " + parent.getClass().getCanonicalName()); - for (PropertySet set : parent.getPropertySets()) { - for (Property prop : set.getProperties()) { - try { - System.out.println(" " + prop.getDisplayName() + " : " + prop.getValue().toString()); - } catch (Exception ex) { - ex.printStackTrace(); - } - } - } - } - try { - String fileName = String.format("%1$tY%1$tm%1$te%1$tI%1$tM%1$tS_listing.csv", Calendar.getInstance()); + + String fileName = getDefaultOutputFileName(nodesToExport.iterator().next().getParentNode()); + JFileChooser fileChooser = new JFileChooser(); fileChooser.setCurrentDirectory(new File(getExportDirectory(Case.getCurrentCaseThrows()))); fileChooser.setSelectedFile(new File(fileName)); fileChooser.setFileFilter(new FileNameExtensionFilter("csv file", "csv")); - int returnVal = fileChooser.showSaveDialog((Component) e.getSource()); + int returnVal = fileChooser.showSaveDialog(component); if (returnVal == JFileChooser.APPROVE_OPTION) { File selectedFile = fileChooser.getSelectedFile(); @@ -143,15 +138,51 @@ public final class ExportCSVAction extends AbstractAction { return; } - CSVWriter writer = new CSVWriter(selectedNodes, selectedFile); + CSVWriter writer = new CSVWriter(nodesToExport, selectedFile); writer.execute(); } } catch (NoCurrentCaseException ex) { - JOptionPane.showMessageDialog((Component) e.getSource(), Bundle.ExportCSV_actionPerformed_noCurrentCase()); + JOptionPane.showMessageDialog(component, Bundle.ExportCSV_actionPerformed_noCurrentCase()); logger.log(Level.INFO, "Exception while getting open case.", ex); //NON-NLS } } + /** + * Create a default name for the CSV output. + * + * @param parent The parent node for the selected nodes + * + * @return the default name + */ + private static String getDefaultOutputFileName(Node parent) { + String dateStr = String.format("%1$tY%1$tm%1$te%1$tI%1$tM%1$tS", Calendar.getInstance()); + + if (parent != null) { + // The first value in the property set is generally a reasonable name + for (PropertySet set : parent.getPropertySets()) { + for (Property prop : set.getProperties()) { + try { + String parentName = prop.getValue().toString(); + + // Strip off the count (if present) + System.out.println("parentName (raw) : " + parentName); + parentName = parentName.replaceAll("\\([0-9]+\\)$", ""); + System.out.println("parentName (after paren regex) : " + parentName); + + // Strip out any invalid characters + parentName = parentName.replaceAll("[\\\\/:*?\"<>|]", "_"); + System.out.println("parentName (after char regex) : " + parentName); + + return parentName + " " + dateStr; + } catch (IllegalAccessException | InvocationTargetException ex) { + logger.log(Level.WARNING, "Failed to get property set value as string", ex); + } + } + } + } + return DEFAULT_FILENAME + " " + dateStr; + } + /** * Get the export directory path. * @@ -159,7 +190,7 @@ public final class ExportCSVAction extends AbstractAction { * * @return The export directory path. */ - private String getExportDirectory(Case openCase) { + private static String getExportDirectory(Case openCase) { // TODO sync String caseExportPath = openCase.getExportDirectory(); if (userDefinedExportPath == null) { @@ -183,7 +214,7 @@ public final class ExportCSVAction extends AbstractAction { * @param exportPath The export path. * @param openCase The current case. */ - private void updateExportDirectory(String exportPath, Case openCase) { + private static void updateExportDirectory(String exportPath, Case openCase) { // TODO sync if (exportPath.equalsIgnoreCase(openCase.getExportDirectory())) { userDefinedExportPath = null; } else { @@ -195,12 +226,12 @@ public final class ExportCSVAction extends AbstractAction { /** * Thread that does the actual extraction work */ - private class CSVWriter extends SwingWorker { + private static class CSVWriter extends SwingWorker { private final Logger logger = Logger.getLogger(CSVWriter.class.getName()); private ProgressHandle progress; - private final List nodesToExport; + private final Collection nodesToExport; private final File outputFile; /** @@ -208,8 +239,8 @@ public final class ExportCSVAction extends AbstractAction { * * @param extractionTasks List of file extraction tasks. */ - CSVWriter(Collection selectedNodes, File outputFile) { - this.nodesToExport = new ArrayList<>(selectedNodes); + CSVWriter(Collection nodesToExport, File outputFile) { + this.nodesToExport = nodesToExport; this.outputFile = outputFile; } @@ -241,25 +272,31 @@ public final class ExportCSVAction extends AbstractAction { // Write the header List headers = new ArrayList<>(); - PropertySet[] sets = nodesToExport.get(0).getPropertySets(); + PropertySet[] sets = nodesToExport.iterator().next().getPropertySets(); for(PropertySet set : sets) { for (Property prop : set.getProperties()) { - headers.add(prop.getDisplayName()); + if ( ! columnsToSkip.contains(prop.getDisplayName())) { + headers.add(prop.getDisplayName()); + } } } br.write(listToCSV(headers)); // Write each line - for (Node node : nodesToExport) { + Iterator nodeIterator = nodesToExport.iterator(); + while (nodeIterator.hasNext()) { if (this.isCancelled()) { break; } + Node node = (Node)nodeIterator.next(); List values = new ArrayList<>(); sets = node.getPropertySets(); for(PropertySet set : sets) { for (Property prop : set.getProperties()) { - values.add(prop.getValue().toString()); + if ( ! columnsToSkip.contains(prop.getDisplayName())) { + values.add(prop.getValue().toString()); + } } } br.write(listToCSV(values)); From 3d319be5b8af8f35cb48868e27399c7ab662af37 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 5 Jun 2019 12:27:53 -0400 Subject: [PATCH 036/115] 5061 adjust comments for clarity and completeness --- .../translators/BingTranslator.java | 28 ++++++++++++++--- .../BingTranslatorSettingsPanel.java | 3 ++ .../translators/GoogleTranslator.java | 7 ++++- .../GoogleTranslatorSettingsPanel.java | 30 +++++++++++-------- 4 files changed, 51 insertions(+), 17 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java index 78f1cf9afd..775cdf3588 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java @@ -40,22 +40,32 @@ import org.sleuthkit.autopsy.texttranslation.TranslationException; @ServiceProvider(service = TextTranslator.class) public class BingTranslator implements TextTranslator { - //In the String below, "en" is the target language. You can include multiple target + //The target language follows the to= in the string below. You can include multiple target //languages separated by commas. A full list of supported languages is here: //https://docs.microsoft.com/en-us/azure/cognitive-services/translator/language-support private static final String BASE_URL = "https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to="; + private static final int MAX_STRING_LENGTH = 5000; private final BingTranslatorSettingsPanel settingsPanel; private final BingTranslatorSettings settings = new BingTranslatorSettings(); // This sends messages to Microsoft. private final OkHttpClient CLIENT = new OkHttpClient(); - //We might want to make this a configurable setting for anyone who has a - //paid account that's willing to pay for long documents. - private final int MAX_STRING_LENGTH = 5000; + /** + * Create a Bing Translator + */ public BingTranslator() { settingsPanel = new BingTranslatorSettingsPanel(settings.getAuthenticationKey(), settings.getTargetLanguageCode()); } + /** + * Get the tranlationurl for the specified language code + * + * + * + * @param languageCode language code for language to translate to + * + * @return a string representation of the url to request translation from + */ static String getTranlatorUrl(String languageCode) { return BASE_URL + languageCode; } @@ -134,6 +144,16 @@ public class BingTranslator implements TextTranslator { settings.saveSettings(); } + /** + * Parse the response to get the translated text + * + * @param json_text the json which was received as a response to a + * translation request + * + * @return the translated text + * + * @throws TranslationException + */ private String parseJSONResponse(String json_text) throws TranslationException { /* * Here is an example of the text we get from Bing when input is "gato", diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java index c6d4c9b932..cb115354e2 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java @@ -74,6 +74,9 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { targetLanguageCode = code; } + /** + * Populate the target language combo box with available target languages + */ @Messages({"BingTranslatorSettingsPanel.warning.targetLanguageFailure=Unable to get list of target languages or parse the result that was received"}) private void populateComboBox() { Request get_request = new Request.Builder() diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslator.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslator.java index 3bb6a6c9ed..de61222072 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslator.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslator.java @@ -61,6 +61,11 @@ public final class GoogleTranslator implements TextTranslator { loadTranslator(); } + /** + * Check if google is able to be reached + * + * @return true if it can be, false otherwise + */ private static boolean googleIsReachable() { String host = "www.google.com"; InetAddress address; @@ -138,7 +143,7 @@ public final class GoogleTranslator implements TextTranslator { InputStream credentialStream = null; Credentials creds = null; if (StringUtils.isBlank(settings.getCredentialPath())) { - logger.log(Level.INFO, "No credentials file has been provided for Google Translator"); + logger.log(Level.INFO, "No credentials file has been provided for Google Translator"); } else { try { credentialStream = new FileInputStream(settings.getCredentialPath()); diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java index 4032d69a05..84fad9e8e1 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java @@ -146,6 +146,12 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { } } + /** + * Helper method to enable/disable all controls which are dependent on valid + * credentials having been provided + * + * @param enabled true to enable the controls, false to disable them + */ private void enableControls(boolean enabled) { targetLanguageComboBox.setEnabled(enabled); testButton.setEnabled(enabled); @@ -307,18 +313,18 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { @Messages({"GoogleTranslatorSettingsPanel.errorMessage.translationFailure=Translation failure with specified credentials"}) private void testButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_testButtonActionPerformed - testResultValueLabel.setText(""); - Translate tempTranslate = getTemporaryTranslationService(); - if (tempTranslate != null) { - try { - Translation translation = tempTranslate.translate(testUntranslatedTextField.getText()); - testResultValueLabel.setText(translation.getTranslatedText()); - warningLabel.setText(""); - } catch (Exception ex) { - warningLabel.setText(Bundle.GoogleTranslatorSettingsPanel_errorMessage_translationFailure()); - logger.log(Level.WARNING, Bundle.GoogleTranslatorSettingsPanel_errorMessage_translationFailure(), ex); - } - } + testResultValueLabel.setText(""); + Translate tempTranslate = getTemporaryTranslationService(); + if (tempTranslate != null) { + try { + Translation translation = tempTranslate.translate(testUntranslatedTextField.getText()); + testResultValueLabel.setText(translation.getTranslatedText()); + warningLabel.setText(""); + } catch (Exception ex) { + warningLabel.setText(Bundle.GoogleTranslatorSettingsPanel_errorMessage_translationFailure()); + logger.log(Level.WARNING, Bundle.GoogleTranslatorSettingsPanel_errorMessage_translationFailure(), ex); + } + } }//GEN-LAST:event_testButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables From 938d0826d7e08b68d32e8f8a7a00520e4997b6ce Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 5 Jun 2019 12:56:49 -0400 Subject: [PATCH 037/115] 5061 address easy to fix codacy issues --- .../translators/BingTranslator.java | 7 +++---- .../translators/BingTranslatorTest.java | 14 +++++++------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java index 775cdf3588..4c2526ab9b 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java @@ -121,8 +121,8 @@ public class BingTranslator implements TextTranslator { try { String response = postTranslationRequest(toTranslate); return parseJSONResponse(response); - } catch (Throwable e) { - throw new TranslationException(e.getMessage()); + } catch (IOException | TranslationException ex) { + throw new TranslationException("Exception while attempting to translate using BingTranslator", ex); } } @@ -167,8 +167,7 @@ public class BingTranslator implements TextTranslator { JsonObject response0 = responses.get(0).getAsJsonObject(); JsonArray translations = response0.getAsJsonArray("translations"); JsonObject translation0 = translations.get(0).getAsJsonObject(); - String text = translation0.get("text").getAsString(); - return text; + return translation0.get("text").getAsString(); } catch (IllegalStateException | ClassCastException | NullPointerException | IndexOutOfBoundsException e) { throw new TranslationException("JSON text does not match Bing Translator scheme: " + e); } diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorTest.java index 48c29543d3..25c78ba049 100644 --- a/Core/test/unit/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorTest.java @@ -18,13 +18,13 @@ */ package org.sleuthkit.autopsy.texttranslation.translators; -import java.io.IOException; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; +//import java.io.IOException; +//import org.junit.After; +//import org.junit.AfterClass; +//import org.junit.Before; +//import org.junit.BeforeClass; import org.junit.Test; -import static org.junit.Assert.*; +//import static org.junit.Assert.*; /** * Tests for the BingTranslator translation service, these tests have been @@ -33,7 +33,7 @@ import static org.junit.Assert.*; public class BingTranslatorTest { @Test - public void testTranslate() throws Exception { + public void testTranslate() { // BingTranslator translator = new BingTranslator(); // String input = "gato"; // String expectedTranslation = "cat"; From 1741726732129caa9c173ec466e3af840096ee98 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Wed, 5 Jun 2019 14:37:44 -0400 Subject: [PATCH 038/115] Checkout point, major functionality implemented --- .../autopsy/contentviewers/Bundle.properties | 4 +- .../contentviewers/Bundle.properties-MERGED | 7 +- .../contentviewers/MediaViewImagePanel.form | 76 +--- .../contentviewers/MediaViewImagePanel.java | 423 +++++++++++------- .../imagetagging/ImageTagsGroup.java | 10 + .../imagetagging/ImageTagsUtil.java | 48 ++ 6 files changed, 343 insertions(+), 225 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsUtil.java diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties index 0f5f1e841e..a588e6eabb 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties @@ -89,6 +89,4 @@ MediaPlayerPanel.VolumeIcon.text=\ \ \ \ \ Volume MediaPlayerPanel.progressLabel.text=00:00:00/00:00:00 MediaPlayerPanel.playButton.text=\u25ba MediaPlayerPanel.infoLabel.text=No Errors -MediaViewImagePanel.deleteTagButton.text=Delete Tag -MediaViewImagePanel.createTagButton.text=Create Tag -MediaViewImagePanel.showTagsButton.text=Hide Tags +MediaViewImagePanel.tagsMenu.text_1=Tags Menu diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED index f04db7f709..10bc33a767 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED @@ -44,7 +44,10 @@ MediaPlayerPanel.timeFormat=%02d:%02d:%02d MediaPlayerPanel.unknownTime=Unknown MediaViewImagePanel.errorLabel.OOMText=Could not load file into Media View: insufficent memory. MediaViewImagePanel.errorLabel.text=Could not load file into Media View. +MediaViewImagePanel.exportSaveText=Save MediaViewImagePanel.externalViewerButton.text=Open in External Viewer Ctrl+E +MediaViewImagePanel.successfulExport=Tagged image was successfully saved. +MediaViewImagePanel.unsuccessfulExport=Unable to export tagged image to disk. MediaViewVideoPanel.pauseButton.text=\u25ba MediaViewVideoPanel.progressLabel.text=00:00 MediaViewVideoPanel.infoLabel.text=info @@ -151,9 +154,7 @@ MediaPlayerPanel.VolumeIcon.text=\ \ \ \ \ Volume MediaPlayerPanel.progressLabel.text=00:00:00/00:00:00 MediaPlayerPanel.playButton.text=\u25ba MediaPlayerPanel.infoLabel.text=No Errors -MediaViewImagePanel.deleteTagButton.text=Delete Tag -MediaViewImagePanel.createTagButton.text=Create Tag -MediaViewImagePanel.showTagsButton.text=Hide Tags +MediaViewImagePanel.tagsMenu.text_1=Tags Menu # {0} - tableName SQLiteViewer.readTable.errorText=Error getting rows for table: {0} # {0} - tableName diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.form b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.form index fe7843bf7a..b157f7a033 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.form @@ -1,20 +1,6 @@
- - - - - - - - - - - - - - @@ -33,7 +19,7 @@ - + @@ -226,70 +212,30 @@ - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - - + - - + diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java index 1e039d614a..a4bf52cfd4 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java @@ -20,8 +20,15 @@ package org.sleuthkit.autopsy.contentviewers; import java.awt.EventQueue; import java.awt.event.ActionEvent; +import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; import static java.util.Objects.nonNull; @@ -30,6 +37,7 @@ import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.stream.Collectors; import javafx.application.Platform; +import javafx.collections.ListChangeListener.Change; import javafx.concurrent.Task; import javafx.embed.swing.JFXPanel; import javafx.geometry.Pos; @@ -49,8 +57,15 @@ import javafx.scene.transform.Rotate; import javafx.scene.transform.Scale; import javafx.scene.transform.Translate; import javax.imageio.ImageIO; +import javax.swing.JFileChooser; +import javafx.scene.Node; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JSeparator; import javax.swing.SwingUtilities; +import org.apache.commons.io.FilenameUtils; import org.controlsfx.control.MaskerPane; import org.openide.util.NbBundle; import org.python.google.common.collect.Lists; @@ -61,6 +76,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.applicationtags.ContentViewerTagManager; import org.sleuthkit.autopsy.casemodule.services.applicationtags.ContentViewerTagManager.ContentViewerTag; import org.sleuthkit.autopsy.casemodule.services.applicationtags.ContentViewerTagManager.SerializationException; +import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagsUtil; import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagControls; import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagRegion; import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagCreator; @@ -99,6 +115,14 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan private final ProgressBar progressBar = new ProgressBar(); private final MaskerPane maskerPane = new MaskerPane(); + private final JPopupMenu popupMenu = new JPopupMenu(); + private final JMenuItem createTag; + private final JMenuItem deleteTag; + private final JMenuItem hideTags; + private final JMenuItem exportTags; + + private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + private double zoomRatio; private double rotation; // Can be 0, 90, 180, and 270. @@ -134,49 +158,138 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan public MediaViewImagePanel() { initComponents(); fxInited = org.sleuthkit.autopsy.core.Installer.isJavaFxInited(); + createTag = new JMenuItem("Create"); + createTag.addActionListener((event) -> createTag()); + createTag.setToolTipText("You may drag anywhere on the image after selecting this option."); + popupMenu.add(createTag); + + popupMenu.add(new JSeparator()); // SEPARATOR + + deleteTag = new JMenuItem("Delete"); + deleteTag.addActionListener((event) -> deleteTag()); + deleteTag.setToolTipText("Delete the selected tag."); + popupMenu.add(deleteTag); + + popupMenu.add(new JSeparator()); // SEPARATOR + + hideTags = new JMenuItem("Hide"); + hideTags.addActionListener((event) -> showOrHideTags()); + hideTags.setToolTipText("Hide the tags on this image."); + popupMenu.add(hideTags); + + popupMenu.add(new JSeparator()); // SEPARATOR + + exportTags = new JMenuItem("Export"); + exportTags.addActionListener((event) -> exportTags()); + exportTags.setToolTipText("Save the image with tags applied."); + popupMenu.add(exportTags); + + popupMenu.setPopupSize(300, 150); + if (fxInited) { - Platform.runLater(() -> { - - // build jfx ui (we could do this in FXML?) - fxImageView = new ImageView(); // will hold image - masterGroup = new Group(fxImageView); - tagsGroup = new ImageTagsGroup(fxImageView); - masterGroup.getChildren().add(tagsGroup); - deleteTagButton.setEnabled(false); - - //Update buttons when users select (or unselect) image tags. - tagsGroup.addFocusChangeListener((event) -> { - if (event.getPropertyName().equals(ImageTagControls.NOT_FOCUSED.getName())) { - deleteTagButton.setEnabled(false); - if (DisplayOptions.HIDE_TAGS.getName().equals(showTagsButton.getText())) { - createTagButton.setEnabled(true); + Platform.runLater(new Runnable() { + @Override + public void run() { + // build jfx ui (we could do this in FXML?) + fxImageView = new ImageView(); // will hold image + masterGroup = new Group(fxImageView); + tagsGroup = new ImageTagsGroup(fxImageView); + tagsGroup.getChildren().addListener((Change c) -> { + if (c.getList().isEmpty()) { + pcs.firePropertyChange(new PropertyChangeEvent(this, + "state", null, State.EMPTY)); } - } else if (event.getPropertyName().equals(ImageTagControls.FOCUSED.getName())) { - deleteTagButton.setEnabled(true); - createTagButton.setEnabled(false); - if (masterGroup.getChildren().contains(imageTagCreator)) { - imageTagCreator.disconnect(); - masterGroup.getChildren().remove(imageTagCreator); + }); + + pcs.addPropertyChangeListener((event) -> { + State currentState = (State) event.getNewValue(); + switch (currentState) { + case CREATE: + createTag.setEnabled(true); + deleteTag.setEnabled(false); + hideTags.setEnabled(true); + exportTags.setEnabled(true); + break; + case SELECTED: + if (masterGroup.getChildren().contains(imageTagCreator)) { + imageTagCreator.disconnect(); + masterGroup.getChildren().remove(imageTagCreator); + } + createTag.setEnabled(false); + deleteTag.setEnabled(true); + hideTags.setEnabled(true); + exportTags.setEnabled(true); + break; + case HIDDEN: + createTag.setEnabled(false); + deleteTag.setEnabled(false); + hideTags.setEnabled(true); + hideTags.setText(DisplayOptions.SHOW_TAGS.getName()); + exportTags.setEnabled(false); + break; + case VISIBLE: + createTag.setEnabled(true); + deleteTag.setEnabled(false); + hideTags.setEnabled(true); + hideTags.setText(DisplayOptions.HIDE_TAGS.getName()); + exportTags.setEnabled(true); + break; + case DEFAULT: + case EMPTY: + if (masterGroup.getChildren().contains(imageTagCreator)) { + imageTagCreator.disconnect(); + } + createTag.setEnabled(true); + deleteTag.setEnabled(false); + hideTags.setEnabled(false); + hideTags.setText(DisplayOptions.HIDE_TAGS.getName()); + exportTags.setEnabled(false); + break; + case NONEMPTY: + createTag.setEnabled(true); + deleteTag.setEnabled(false); + hideTags.setEnabled(true); + exportTags.setEnabled(true); + break; + case DISABLE: + createTag.setEnabled(false); + deleteTag.setEnabled(false); + hideTags.setEnabled(false); + exportTags.setEnabled(false); + break; } - } - }); + }); - scrollPane = new ScrollPane(masterGroup); // scrolls and sizes imageview - scrollPane.getStyleClass().add("bg"); //NOI18N - scrollPane.setVbarPolicy(ScrollBarPolicy.AS_NEEDED); - scrollPane.setHbarPolicy(ScrollBarPolicy.AS_NEEDED); + masterGroup.getChildren().add(tagsGroup); - fxPanel = new JFXPanel(); // bridge jfx-swing - Scene scene = new Scene(scrollPane); //root of jfx tree - scene.getStylesheets().add(MediaViewImagePanel.class.getResource("MediaViewImagePanel.css").toExternalForm()); //NOI18N - fxPanel.setScene(scene); + //Update buttons when users select (or unselect) image tags. + tagsGroup.addFocusChangeListener((event) -> { + if (event.getPropertyName().equals(ImageTagControls.NOT_FOCUSED.getName())) { + pcs.firePropertyChange(new PropertyChangeEvent(this, + "state", null, State.CREATE)); + } else if (event.getPropertyName().equals(ImageTagControls.FOCUSED.getName())) { + pcs.firePropertyChange(new PropertyChangeEvent(this, + "state", null, State.SELECTED)); + } + }); - fxImageView.setSmooth(true); - fxImageView.setCache(true); + scrollPane = new ScrollPane(masterGroup); // scrolls and sizes imageview + scrollPane.getStyleClass().add("bg"); //NOI18N + scrollPane.setVbarPolicy(ScrollBarPolicy.AS_NEEDED); + scrollPane.setHbarPolicy(ScrollBarPolicy.AS_NEEDED); - EventQueue.invokeLater(() -> { - add(fxPanel);//add jfx ui to JPanel - }); + fxPanel = new JFXPanel(); // bridge jfx-swing + Scene scene = new Scene(scrollPane); //root of jfx tree + scene.getStylesheets().add(MediaViewImagePanel.class.getResource("MediaViewImagePanel.css").toExternalForm()); //NOI18N + fxPanel.setScene(scene); + + fxImageView.setSmooth(true); + fxImageView.setCache(true); + + EventQueue.invokeLater(() -> { + add(fxPanel);//add jfx ui to JPanel + }); + } }); } } @@ -192,14 +305,9 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan Platform.runLater(() -> { fxImageView.setViewport(new Rectangle2D(0, 0, 0, 0)); fxImageView.setImage(null); + pcs.firePropertyChange(new PropertyChangeEvent(this, + "state", null, State.DEFAULT)); masterGroup.getChildren().clear(); - if (imageTagCreator != null) { - imageTagCreator.disconnect(); - } - showTagsButton.setText(DisplayOptions.HIDE_TAGS.getName()); - showTagsButton.setEnabled(true); - createTagButton.setEnabled(true); - deleteTagButton.setEnabled(false); scrollPane.setContent(null); scrollPane.setContent(masterGroup); }); @@ -266,6 +374,10 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan List> contentViewerTags = getContentViewerTags(tags); //Add all image tags tagsGroup = buildImageTagsGroup(contentViewerTags); + if(!tagsGroup.getChildren().isEmpty()) { + pcs.firePropertyChange(new PropertyChangeEvent(this, + "state", null, State.NONEMPTY)); + } } catch (TskCoreException | NoCurrentCaseException ex) { LOGGER.log(Level.WARNING, "Could not retrieve image tags for file in case db", ex); //NON-NLS } @@ -396,8 +508,6 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan // //GEN-BEGIN:initComponents private void initComponents() { - jPopupMenu1 = new javax.swing.JPopupMenu(); - jPopupMenu2 = new javax.swing.JPopupMenu(); toolbar = new javax.swing.JToolBar(); rotationTextField = new javax.swing.JTextField(); rotateLeftButton = new javax.swing.JButton(); @@ -410,11 +520,8 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan zoomResetButton = new javax.swing.JButton(); filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0)); filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0)); - createTagButton = new javax.swing.JButton(); - jSeparator4 = new javax.swing.JToolBar.Separator(); - deleteTagButton = new javax.swing.JButton(); - jSeparator3 = new javax.swing.JToolBar.Separator(); - showTagsButton = new javax.swing.JButton(); + jPanel1 = new javax.swing.JPanel(); + tagsMenu = new javax.swing.JButton(); setBackground(new java.awt.Color(0, 0, 0)); addComponentListener(new java.awt.event.ComponentAdapter() { @@ -520,52 +627,21 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan toolbar.add(zoomResetButton); toolbar.add(filler1); toolbar.add(filler2); + toolbar.add(jPanel1); - org.openide.awt.Mnemonics.setLocalizedText(createTagButton, org.openide.util.NbBundle.getMessage(MediaViewImagePanel.class, "MediaViewImagePanel.createTagButton.text")); // NOI18N - createTagButton.setFocusable(false); - createTagButton.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); - createTagButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - createTagButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - createTagButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - createTagButtonActionPerformed(evt); + org.openide.awt.Mnemonics.setLocalizedText(tagsMenu, org.openide.util.NbBundle.getMessage(MediaViewImagePanel.class, "MediaViewImagePanel.tagsMenu.text_1")); // NOI18N + tagsMenu.setFocusable(false); + tagsMenu.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + tagsMenu.setMaximumSize(new java.awt.Dimension(75, 21)); + tagsMenu.setMinimumSize(new java.awt.Dimension(75, 21)); + tagsMenu.setPreferredSize(new java.awt.Dimension(75, 21)); + tagsMenu.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + tagsMenu.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + tagsMenuMousePressed(evt); } }); - toolbar.add(createTagButton); - toolbar.add(jSeparator4); - - org.openide.awt.Mnemonics.setLocalizedText(deleteTagButton, org.openide.util.NbBundle.getMessage(MediaViewImagePanel.class, "MediaViewImagePanel.deleteTagButton.text")); // NOI18N - deleteTagButton.setFocusable(false); - deleteTagButton.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); - deleteTagButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - deleteTagButton.setMaximumSize(new java.awt.Dimension(61, 21)); - deleteTagButton.setMinimumSize(new java.awt.Dimension(61, 21)); - deleteTagButton.setPreferredSize(new java.awt.Dimension(61, 21)); - deleteTagButton.setRequestFocusEnabled(false); - deleteTagButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - deleteTagButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - deleteTagButtonActionPerformed(evt); - } - }); - toolbar.add(deleteTagButton); - toolbar.add(jSeparator3); - - org.openide.awt.Mnemonics.setLocalizedText(showTagsButton, org.openide.util.NbBundle.getMessage(MediaViewImagePanel.class, "MediaViewImagePanel.showTagsButton.text")); // NOI18N - showTagsButton.setFocusable(false); - showTagsButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - showTagsButton.setMaximumSize(new java.awt.Dimension(61, 21)); - showTagsButton.setMinimumSize(new java.awt.Dimension(61, 21)); - showTagsButton.setOpaque(false); - showTagsButton.setPreferredSize(new java.awt.Dimension(61, 21)); - showTagsButton.setRolloverEnabled(false); - showTagsButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - showTagsButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - showTagsButtonActionPerformed(evt); - } - }); - toolbar.add(showTagsButton); + toolbar.add(tagsMenu); add(toolbar); }// //GEN-END:initComponents @@ -610,7 +686,10 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan updateView(); }//GEN-LAST:event_formComponentResized - private void deleteTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTagButtonActionPerformed + /** + * + */ + private void deleteTag() { Platform.runLater(() -> { ImageTag tagInFocus = tagsGroup.getFocus(); //Null should not be expected, but just as a safetly precaution @@ -631,40 +710,41 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan scrollPane.setCursor(Cursor.DEFAULT); }); - deleteTagButton.setEnabled(false); - createTagButton.setEnabled(true); - }//GEN-LAST:event_deleteTagButtonActionPerformed + pcs.firePropertyChange(new PropertyChangeEvent(this, + "state", null, State.CREATE)); + } - private void createTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_createTagButtonActionPerformed - createTagButton.setEnabled(false); - showTagsButton.setEnabled(false); + /** + * + */ + private void createTag() { + pcs.firePropertyChange(new PropertyChangeEvent(this, + "state", null, State.DISABLE)); imageTagCreator = new ImageTagCreator(fxImageView); PropertyChangeListener newTagListener = (event) -> { - SwingUtilities.invokeLater(() -> { ImageTagRegion tag = (ImageTagRegion) event.getNewValue(); //Ask the user for tag name and comment TagNameAndComment result = GetTagNameAndCommentDialog.doDialog(); - if (result == null) { - createTagButton.setEnabled(true); - showTagsButton.setEnabled(true); - return; + if (result != null) { + //Persist and build image tag + Platform.runLater(() -> { + try { + scrollPane.setCursor(Cursor.WAIT); + ContentViewerTag contentViewerTag = storeImageTag(tag, result); + ImageTag imageTag = buildImageTag(contentViewerTag); + tagsGroup.getChildren().add(imageTag); + } catch (TskCoreException | SerializationException | NoCurrentCaseException ex) { + LOGGER.log(Level.WARNING, "Could not save new image tag in case db", ex); //NON-NLS + } + + scrollPane.setCursor(Cursor.DEFAULT); + }); } - //Persist and build image tag - Platform.runLater(() -> { - try { - scrollPane.setCursor(Cursor.WAIT); - ContentViewerTag contentViewerTag = storeImageTag(tag, result); - ImageTag imageTag = buildImageTag(contentViewerTag); - tagsGroup.getChildren().add(imageTag); - } catch (TskCoreException | SerializationException | NoCurrentCaseException ex) { - LOGGER.log(Level.WARNING, "Could not save new image tag in case db", ex); //NON-NLS - } - - scrollPane.setCursor(Cursor.DEFAULT); - }); + pcs.firePropertyChange(new PropertyChangeEvent(this, + "state", null, State.CREATE)); }); //Remove image tag creator from panel @@ -676,11 +756,11 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan imageTagCreator.addNewTagListener(newTagListener); Platform.runLater(() -> masterGroup.getChildren().add(imageTagCreator)); - }//GEN-LAST:event_createTagButtonActionPerformed + } /** * Creates an ImageTag instance from the ContentViewerTag. - * + * * @param contentViewerTag * @return */ @@ -710,48 +790,77 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan */ private ContentViewerTag storeImageTag(ImageTagRegion data, TagNameAndComment result) throws TskCoreException, SerializationException, NoCurrentCaseException { - try { - scrollPane.setCursor(Cursor.WAIT); - ContentTag contentTag = Case.getCurrentCaseThrows().getServices().getTagsManager() - .addContentTag(file, result.getTagName(), result.getComment()); - ContentViewerTag contentViewerTag = ContentViewerTagManager.saveTag(contentTag, data); - return contentViewerTag; - } finally { - scrollPane.setCursor(Cursor.DEFAULT); - createTagButton.setEnabled(true); - showTagsButton.setEnabled(true); - } + scrollPane.setCursor(Cursor.WAIT); + ContentTag contentTag = Case.getCurrentCaseThrows().getServices().getTagsManager() + .addContentTag(file, result.getTagName(), result.getComment()); + ContentViewerTag contentViewerTag = ContentViewerTagManager.saveTag(contentTag, data); + scrollPane.setCursor(Cursor.DEFAULT); + return contentViewerTag; } - private void showTagsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showTagsButtonActionPerformed + /** + * + */ + private void showOrHideTags() { Platform.runLater(() -> { - if (DisplayOptions.HIDE_TAGS.getName().equals(showTagsButton.getText())) { + if (DisplayOptions.HIDE_TAGS.getName().equals(hideTags.getText())) { //Temporarily remove the tags group and update buttons masterGroup.getChildren().remove(tagsGroup); - showTagsButton.setText(DisplayOptions.SHOW_TAGS.getName()); - createTagButton.setEnabled(false); - deleteTagButton.setEnabled(false); + hideTags.setText(DisplayOptions.SHOW_TAGS.getName()); + tagsGroup.clearFocus(); + pcs.firePropertyChange(new PropertyChangeEvent(this, + "state", null, State.HIDDEN)); } else { //Add tags group back in and update buttons masterGroup.getChildren().add(tagsGroup); - showTagsButton.setText(DisplayOptions.HIDE_TAGS.getName()); - if (tagsGroup.getFocus() != null) { - createTagButton.setEnabled(false); - deleteTagButton.setEnabled(true); - } else { - createTagButton.setEnabled(true); - deleteTagButton.setEnabled(false); - } + hideTags.setText(DisplayOptions.HIDE_TAGS.getName()); + pcs.firePropertyChange(new PropertyChangeEvent(this, + "state", null, State.VISIBLE)); } }); - }//GEN-LAST:event_showTagsButtonActionPerformed + } + + @NbBundle.Messages({ + "MediaViewImagePanel.exportSaveText=Save", + "MediaViewImagePanel.successfulExport=Tagged image was successfully saved.", + "MediaViewImagePanel.unsuccessfulExport=Unable to export tagged image to disk." + }) + private void exportTags() { + tagsGroup.clearFocus(); + JFileChooser fileChooser = new JFileChooser(); + fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + int returnVal = fileChooser.showDialog(this, Bundle.MediaViewImagePanel_exportSaveText()); + if (returnVal == JFileChooser.APPROVE_OPTION) { + Platform.runLater(() -> { + try { + List tags = Case.getCurrentCase().getServices() + .getTagsManager().getContentTagsByContent(file); + List> contentViewerTags = getContentViewerTags(tags); + Collection regions = contentViewerTags.stream() + .map(cvTag -> cvTag.getDetails()).collect(Collectors.toList()); + byte[] jpgImage = ImageTagsUtil.exportTags(file, regions, ".jpg"); + Path output = Paths.get(fileChooser.getSelectedFile().getPath(), + FilenameUtils.getBaseName(file.getName()) + "-with_tags.jpg"); + Files.write(output, jpgImage); + JOptionPane.showMessageDialog(null, Bundle.MediaViewImagePanel_successfulExport()); + } catch (TskCoreException | NoCurrentCaseException | IOException ex) { + LOGGER.log(Level.WARNING, "Unable to export tagged image to disk", ex); //NON-NLS + JOptionPane.showMessageDialog(null, Bundle.MediaViewImagePanel_unsuccessfulExport()); + } + }); + } + } + + private void tagsMenuMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_tagsMenuMousePressed + popupMenu.show(tagsMenu, -300 + tagsMenu.getWidth(), tagsMenu.getHeight() + 3); + }//GEN-LAST:event_tagsMenuMousePressed /** * Display states for the show/hide tags button. */ enum DisplayOptions { - HIDE_TAGS("Hide Tags"), - SHOW_TAGS("Show Tags"); + HIDE_TAGS("Hide"), + SHOW_TAGS("Show"); private final String name; @@ -764,21 +873,27 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan } } + enum State { + HIDDEN, + VISIBLE, + SELECTED, + CREATE, + EMPTY, + NONEMPTY, + DEFAULT, + DISABLE; + } + // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JButton createTagButton; - private javax.swing.JButton deleteTagButton; private javax.swing.Box.Filler filler1; private javax.swing.Box.Filler filler2; - private javax.swing.JPopupMenu jPopupMenu1; - private javax.swing.JPopupMenu jPopupMenu2; + private javax.swing.JPanel jPanel1; private javax.swing.JToolBar.Separator jSeparator1; private javax.swing.JToolBar.Separator jSeparator2; - private javax.swing.JToolBar.Separator jSeparator3; - private javax.swing.JToolBar.Separator jSeparator4; private javax.swing.JButton rotateLeftButton; private javax.swing.JButton rotateRightButton; private javax.swing.JTextField rotationTextField; - private javax.swing.JButton showTagsButton; + private javax.swing.JButton tagsMenu; private javax.swing.JToolBar toolbar; private javax.swing.JButton zoomInButton; private javax.swing.JButton zoomOutButton; diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsGroup.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsGroup.java index 828b083d80..e226c9f2a3 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsGroup.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsGroup.java @@ -92,6 +92,16 @@ public final class ImageTagsGroup extends Group { public ImageTag getFocus() { return currentFocus; } + + /** + * Clears the current focus + */ + public void clearFocus() { + if(currentFocus != null) { + resetFocus(currentFocus); + currentFocus = null; + } + } /** * Notifies the logical image tag that it is no longer in focus. diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsUtil.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsUtil.java new file mode 100755 index 0000000000..391a8700ea --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsUtil.java @@ -0,0 +1,48 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.contentviewers.imagetagging; + +import java.util.Collection; +import org.opencv.core.Core; +import org.opencv.core.Mat; +import org.opencv.core.MatOfByte; +import org.opencv.core.Point; +import org.opencv.core.Scalar; +import org.opencv.highgui.Highgui; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * + * @author dsmyda + */ +public class ImageTagsUtil { + + public static byte[] exportTags(AbstractFile file, Collection tagRegions, String outputEncoding) throws TskCoreException { + byte[] imageInMemory = new byte[(int) file.getSize()]; + file.read(imageInMemory, 0, file.getSize()); + Mat originalImage = Highgui.imdecode(new MatOfByte(imageInMemory), Highgui.IMREAD_UNCHANGED); + + tagRegions.forEach((region) -> { + Core.rectangle( + originalImage, //Matrix obj of the image + new Point(region.getX(), region.getY()), //p1 + new Point(region.getX() + region.getWidth(), region.getY() + region.getHeight()), //p2 + new Scalar(0, 0, 255), //Scalar object for color + (int) Math.rint(region.getStrokeThickness()) + ); + }); + + MatOfByte matOfByte = new MatOfByte(); + Highgui.imencode(outputEncoding, originalImage, matOfByte); + + originalImage.release(); + byte[] output = matOfByte.toArray(); + matOfByte.release(); + + return output; + } +} From 366e784a317f920960e75e16a5afd1e6ec4e6893 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Wed, 5 Jun 2019 15:49:08 -0400 Subject: [PATCH 039/115] Made filechooser remember selection, fixed some enable/disable bugs, removed tooltips --- .../contentviewers/Bundle.properties-MERGED | 1 + .../contentviewers/MediaViewImagePanel.java | 112 +++++++++++------- .../imagetagging/ImageTagsGroup.java | 2 +- 3 files changed, 73 insertions(+), 42 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED index 10bc33a767..2779cef39a 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED @@ -46,6 +46,7 @@ MediaViewImagePanel.errorLabel.OOMText=Could not load file into Media View: insu MediaViewImagePanel.errorLabel.text=Could not load file into Media View. MediaViewImagePanel.exportSaveText=Save MediaViewImagePanel.externalViewerButton.text=Open in External Viewer Ctrl+E +MediaViewImagePanel.fileChooserTitle=Choose a directory to save the image MediaViewImagePanel.successfulExport=Tagged image was successfully saved. MediaViewImagePanel.unsuccessfulExport=Unable to export tagged image to disk. MediaViewVideoPanel.pauseButton.text=\u25ba diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java index a4bf52cfd4..e1c0e70281 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java @@ -65,6 +65,7 @@ import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JSeparator; import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; import org.apache.commons.io.FilenameUtils; import org.controlsfx.control.MaskerPane; import org.openide.util.NbBundle; @@ -121,6 +122,8 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan private final JMenuItem hideTags; private final JMenuItem exportTags; + private final JFileChooser exportChooser; + private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); private double zoomRatio; @@ -158,30 +161,31 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan public MediaViewImagePanel() { initComponents(); fxInited = org.sleuthkit.autopsy.core.Installer.isJavaFxInited(); + + exportChooser = new JFileChooser(); + exportChooser.setDialogTitle(Bundle.MediaViewImagePanel_fileChooserTitle()); + + //Build popupMenu when Tags Menu button is pressed. createTag = new JMenuItem("Create"); createTag.addActionListener((event) -> createTag()); - createTag.setToolTipText("You may drag anywhere on the image after selecting this option."); popupMenu.add(createTag); - popupMenu.add(new JSeparator()); // SEPARATOR + popupMenu.add(new JSeparator()); deleteTag = new JMenuItem("Delete"); deleteTag.addActionListener((event) -> deleteTag()); - deleteTag.setToolTipText("Delete the selected tag."); popupMenu.add(deleteTag); - popupMenu.add(new JSeparator()); // SEPARATOR + popupMenu.add(new JSeparator()); hideTags = new JMenuItem("Hide"); hideTags.addActionListener((event) -> showOrHideTags()); - hideTags.setToolTipText("Hide the tags on this image."); popupMenu.add(hideTags); - popupMenu.add(new JSeparator()); // SEPARATOR + popupMenu.add(new JSeparator()); exportTags = new JMenuItem("Export"); exportTags.addActionListener((event) -> exportTags()); - exportTags.setToolTipText("Save the image with tags applied."); popupMenu.add(exportTags); popupMenu.setPopupSize(300, 150); @@ -201,6 +205,8 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan } }); + //Respond to state events by enabling/disabling the correct + //buttons. pcs.addPropertyChangeListener((event) -> { State currentState = (State) event.getNewValue(); switch (currentState) { @@ -265,8 +271,17 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan //Update buttons when users select (or unselect) image tags. tagsGroup.addFocusChangeListener((event) -> { if (event.getPropertyName().equals(ImageTagControls.NOT_FOCUSED.getName())) { - pcs.firePropertyChange(new PropertyChangeEvent(this, + if (masterGroup.getChildren().contains(imageTagCreator)) { + return; + } + + if(tagsGroup.getChildren().isEmpty()) { + pcs.firePropertyChange(new PropertyChangeEvent(this, + "state", null, State.EMPTY)); + } else { + pcs.firePropertyChange(new PropertyChangeEvent(this, "state", null, State.CREATE)); + } } else if (event.getPropertyName().equals(ImageTagControls.FOCUSED.getName())) { pcs.firePropertyChange(new PropertyChangeEvent(this, "state", null, State.SELECTED)); @@ -374,9 +389,9 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan List> contentViewerTags = getContentViewerTags(tags); //Add all image tags tagsGroup = buildImageTagsGroup(contentViewerTags); - if(!tagsGroup.getChildren().isEmpty()) { + if (!tagsGroup.getChildren().isEmpty()) { pcs.firePropertyChange(new PropertyChangeEvent(this, - "state", null, State.NONEMPTY)); + "state", null, State.NONEMPTY)); } } catch (TskCoreException | NoCurrentCaseException ex) { LOGGER.log(Level.WARNING, "Could not retrieve image tags for file in case db", ex); //NON-NLS @@ -687,7 +702,8 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan }//GEN-LAST:event_formComponentResized /** - * + * Deletes the selected tag when the Delete button is pressed in the Tag + * Menu. */ private void deleteTag() { Platform.runLater(() -> { @@ -715,7 +731,8 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan } /** - * + * Enables create tag logic when the Create button is pressed in the Tags + * Menu. */ private void createTag() { pcs.firePropertyChange(new PropertyChangeEvent(this, @@ -791,15 +808,19 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan private ContentViewerTag storeImageTag(ImageTagRegion data, TagNameAndComment result) throws TskCoreException, SerializationException, NoCurrentCaseException { scrollPane.setCursor(Cursor.WAIT); - ContentTag contentTag = Case.getCurrentCaseThrows().getServices().getTagsManager() - .addContentTag(file, result.getTagName(), result.getComment()); - ContentViewerTag contentViewerTag = ContentViewerTagManager.saveTag(contentTag, data); - scrollPane.setCursor(Cursor.DEFAULT); - return contentViewerTag; + try { + ContentTag contentTag = Case.getCurrentCaseThrows().getServices().getTagsManager() + .addContentTag(file, result.getTagName(), result.getComment()); + ContentViewerTag contentViewerTag = ContentViewerTagManager.saveTag(contentTag, data); + return contentViewerTag; + } finally { + scrollPane.setCursor(Cursor.DEFAULT); + } } /** - * + * Hides or show tags when the Hide or Show button is pressed in the Tags + * Menu. */ private void showOrHideTags() { Platform.runLater(() -> { @@ -809,13 +830,13 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan hideTags.setText(DisplayOptions.SHOW_TAGS.getName()); tagsGroup.clearFocus(); pcs.firePropertyChange(new PropertyChangeEvent(this, - "state", null, State.HIDDEN)); + "state", null, State.HIDDEN)); } else { //Add tags group back in and update buttons masterGroup.getChildren().add(tagsGroup); hideTags.setText(DisplayOptions.HIDE_TAGS.getName()); - pcs.firePropertyChange(new PropertyChangeEvent(this, - "state", null, State.VISIBLE)); + pcs.firePropertyChange(new PropertyChangeEvent(this, + "state", null, State.VISIBLE)); } }); } @@ -823,31 +844,36 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan @NbBundle.Messages({ "MediaViewImagePanel.exportSaveText=Save", "MediaViewImagePanel.successfulExport=Tagged image was successfully saved.", - "MediaViewImagePanel.unsuccessfulExport=Unable to export tagged image to disk." + "MediaViewImagePanel.unsuccessfulExport=Unable to export tagged image to disk.", + "MediaViewImagePanel.fileChooserTitle=Choose a directory to save the image" }) private void exportTags() { tagsGroup.clearFocus(); - JFileChooser fileChooser = new JFileChooser(); - fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - int returnVal = fileChooser.showDialog(this, Bundle.MediaViewImagePanel_exportSaveText()); + exportChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + int returnVal = exportChooser.showDialog(this, Bundle.MediaViewImagePanel_exportSaveText()); if (returnVal == JFileChooser.APPROVE_OPTION) { - Platform.runLater(() -> { - try { - List tags = Case.getCurrentCase().getServices() - .getTagsManager().getContentTagsByContent(file); - List> contentViewerTags = getContentViewerTags(tags); - Collection regions = contentViewerTags.stream() - .map(cvTag -> cvTag.getDetails()).collect(Collectors.toList()); - byte[] jpgImage = ImageTagsUtil.exportTags(file, regions, ".jpg"); - Path output = Paths.get(fileChooser.getSelectedFile().getPath(), - FilenameUtils.getBaseName(file.getName()) + "-with_tags.jpg"); - Files.write(output, jpgImage); - JOptionPane.showMessageDialog(null, Bundle.MediaViewImagePanel_successfulExport()); - } catch (TskCoreException | NoCurrentCaseException | IOException ex) { - LOGGER.log(Level.WARNING, "Unable to export tagged image to disk", ex); //NON-NLS - JOptionPane.showMessageDialog(null, Bundle.MediaViewImagePanel_unsuccessfulExport()); + exportChooser.setCurrentDirectory(exportChooser.getSelectedFile()); + new SwingWorker() { + @Override + protected Void doInBackground() throws Exception { + try { + List tags = Case.getCurrentCase().getServices() + .getTagsManager().getContentTagsByContent(file); + List> contentViewerTags = getContentViewerTags(tags); + Collection regions = contentViewerTags.stream() + .map(cvTag -> cvTag.getDetails()).collect(Collectors.toList()); + byte[] jpgImage = ImageTagsUtil.exportTags(file, regions, ".jpg"); + Path output = Paths.get(exportChooser.getSelectedFile().getPath(), + FilenameUtils.getBaseName(file.getName()) + "-with_tags.jpg"); //NON-NLS + Files.write(output, jpgImage); + JOptionPane.showMessageDialog(null, Bundle.MediaViewImagePanel_successfulExport()); + } catch (TskCoreException | NoCurrentCaseException | IOException ex) { + LOGGER.log(Level.WARNING, "Unable to export tagged image to disk", ex); //NON-NLS + JOptionPane.showMessageDialog(null, Bundle.MediaViewImagePanel_unsuccessfulExport()); + } + return null; } - }); + }.execute(); } } @@ -873,6 +899,10 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan } } + /** + * Different states that the content viewer can be in. These states drive + * which buttons are enabled for tagging. + */ enum State { HIDDEN, VISIBLE, diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsGroup.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsGroup.java index e226c9f2a3..fcbbb145bd 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsGroup.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsGroup.java @@ -52,11 +52,11 @@ public final class ImageTagsGroup extends Group { if (currentFocus != null) { currentFocus.getEventDispatcher().dispatchEvent( new Event(ImageTagControls.NOT_FOCUSED), NO_OP_CHAIN); - currentFocus = null; } this.pcs.firePropertyChange(new PropertyChangeEvent(this, ImageTagControls.NOT_FOCUSED.getName(), currentFocus, null)); + currentFocus = null; }); //Set the focus of selected tag From 0541a3368b12007934ec9fc16e7bf9903dcf7c44 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Wed, 5 Jun 2019 16:16:13 -0400 Subject: [PATCH 040/115] Fixed some codacy suggestions, added comments, minor changes --- .../contentviewers/Bundle.properties-MERGED | 2 +- .../contentviewers/MediaViewImagePanel.java | 115 +++++++++--------- ...ageTagsUtil.java => ImageTagsUtility.java} | 34 ++++-- 3 files changed, 85 insertions(+), 66 deletions(-) rename Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/{ImageTagsUtil.java => ImageTagsUtility.java} (58%) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED index 2779cef39a..d13fe56608 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED @@ -46,7 +46,7 @@ MediaViewImagePanel.errorLabel.OOMText=Could not load file into Media View: insu MediaViewImagePanel.errorLabel.text=Could not load file into Media View. MediaViewImagePanel.exportSaveText=Save MediaViewImagePanel.externalViewerButton.text=Open in External Viewer Ctrl+E -MediaViewImagePanel.fileChooserTitle=Choose a directory to save the image +MediaViewImagePanel.fileChooserTitle=Choose a save location MediaViewImagePanel.successfulExport=Tagged image was successfully saved. MediaViewImagePanel.unsuccessfulExport=Unable to export tagged image to disk. MediaViewVideoPanel.pauseButton.text=\u25ba diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java index e1c0e70281..b4d1202f15 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java @@ -77,7 +77,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.applicationtags.ContentViewerTagManager; import org.sleuthkit.autopsy.casemodule.services.applicationtags.ContentViewerTagManager.ContentViewerTag; import org.sleuthkit.autopsy.casemodule.services.applicationtags.ContentViewerTagManager.SerializationException; -import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagsUtil; +import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagsUtility; import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagControls; import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagRegion; import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagCreator; @@ -102,7 +102,7 @@ import org.sleuthkit.datamodel.TskCoreException; class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPanel { private static final Image EXTERNAL = new Image(MediaViewImagePanel.class.getResource("/org/sleuthkit/autopsy/images/external.png").toExternalForm()); - private final Logger LOGGER = Logger.getLogger(MediaViewImagePanel.class.getName()); + private final static Logger LOGGER = Logger.getLogger(MediaViewImagePanel.class.getName()); private final boolean fxInited; @@ -117,10 +117,10 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan private final MaskerPane maskerPane = new MaskerPane(); private final JPopupMenu popupMenu = new JPopupMenu(); - private final JMenuItem createTag; - private final JMenuItem deleteTag; - private final JMenuItem hideTags; - private final JMenuItem exportTags; + private final JMenuItem createTagMenuItem; + private final JMenuItem deleteTagMenuItem; + private final JMenuItem hideTagsMenuItem; + private final JMenuItem exportTagsMenuItem; private final JFileChooser exportChooser; @@ -166,27 +166,27 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan exportChooser.setDialogTitle(Bundle.MediaViewImagePanel_fileChooserTitle()); //Build popupMenu when Tags Menu button is pressed. - createTag = new JMenuItem("Create"); - createTag.addActionListener((event) -> createTag()); - popupMenu.add(createTag); + createTagMenuItem = new JMenuItem("Create"); + createTagMenuItem.addActionListener((event) -> createTag()); + popupMenu.add(createTagMenuItem); popupMenu.add(new JSeparator()); - deleteTag = new JMenuItem("Delete"); - deleteTag.addActionListener((event) -> deleteTag()); - popupMenu.add(deleteTag); + deleteTagMenuItem = new JMenuItem("Delete"); + deleteTagMenuItem.addActionListener((event) -> deleteTag()); + popupMenu.add(deleteTagMenuItem); popupMenu.add(new JSeparator()); - hideTags = new JMenuItem("Hide"); - hideTags.addActionListener((event) -> showOrHideTags()); - popupMenu.add(hideTags); + hideTagsMenuItem = new JMenuItem("Hide"); + hideTagsMenuItem.addActionListener((event) -> showOrHideTags()); + popupMenu.add(hideTagsMenuItem); popupMenu.add(new JSeparator()); - exportTags = new JMenuItem("Export"); - exportTags.addActionListener((event) -> exportTags()); - popupMenu.add(exportTags); + exportTagsMenuItem = new JMenuItem("Export"); + exportTagsMenuItem.addActionListener((event) -> exportTags()); + popupMenu.add(exportTagsMenuItem); popupMenu.setPopupSize(300, 150); @@ -211,57 +211,59 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan State currentState = (State) event.getNewValue(); switch (currentState) { case CREATE: - createTag.setEnabled(true); - deleteTag.setEnabled(false); - hideTags.setEnabled(true); - exportTags.setEnabled(true); + createTagMenuItem.setEnabled(true); + deleteTagMenuItem.setEnabled(false); + hideTagsMenuItem.setEnabled(true); + exportTagsMenuItem.setEnabled(true); break; case SELECTED: if (masterGroup.getChildren().contains(imageTagCreator)) { imageTagCreator.disconnect(); masterGroup.getChildren().remove(imageTagCreator); } - createTag.setEnabled(false); - deleteTag.setEnabled(true); - hideTags.setEnabled(true); - exportTags.setEnabled(true); + createTagMenuItem.setEnabled(false); + deleteTagMenuItem.setEnabled(true); + hideTagsMenuItem.setEnabled(true); + exportTagsMenuItem.setEnabled(true); break; case HIDDEN: - createTag.setEnabled(false); - deleteTag.setEnabled(false); - hideTags.setEnabled(true); - hideTags.setText(DisplayOptions.SHOW_TAGS.getName()); - exportTags.setEnabled(false); + createTagMenuItem.setEnabled(false); + deleteTagMenuItem.setEnabled(false); + hideTagsMenuItem.setEnabled(true); + hideTagsMenuItem.setText(DisplayOptions.SHOW_TAGS.getName()); + exportTagsMenuItem.setEnabled(false); break; case VISIBLE: - createTag.setEnabled(true); - deleteTag.setEnabled(false); - hideTags.setEnabled(true); - hideTags.setText(DisplayOptions.HIDE_TAGS.getName()); - exportTags.setEnabled(true); + createTagMenuItem.setEnabled(true); + deleteTagMenuItem.setEnabled(false); + hideTagsMenuItem.setEnabled(true); + hideTagsMenuItem.setText(DisplayOptions.HIDE_TAGS.getName()); + exportTagsMenuItem.setEnabled(true); break; case DEFAULT: case EMPTY: if (masterGroup.getChildren().contains(imageTagCreator)) { imageTagCreator.disconnect(); } - createTag.setEnabled(true); - deleteTag.setEnabled(false); - hideTags.setEnabled(false); - hideTags.setText(DisplayOptions.HIDE_TAGS.getName()); - exportTags.setEnabled(false); + createTagMenuItem.setEnabled(true); + deleteTagMenuItem.setEnabled(false); + hideTagsMenuItem.setEnabled(false); + hideTagsMenuItem.setText(DisplayOptions.HIDE_TAGS.getName()); + exportTagsMenuItem.setEnabled(false); break; case NONEMPTY: - createTag.setEnabled(true); - deleteTag.setEnabled(false); - hideTags.setEnabled(true); - exportTags.setEnabled(true); + createTagMenuItem.setEnabled(true); + deleteTagMenuItem.setEnabled(false); + hideTagsMenuItem.setEnabled(true); + exportTagsMenuItem.setEnabled(true); break; case DISABLE: - createTag.setEnabled(false); - deleteTag.setEnabled(false); - hideTags.setEnabled(false); - exportTags.setEnabled(false); + createTagMenuItem.setEnabled(false); + deleteTagMenuItem.setEnabled(false); + hideTagsMenuItem.setEnabled(false); + exportTagsMenuItem.setEnabled(false); + break; + default: break; } }); @@ -811,8 +813,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan try { ContentTag contentTag = Case.getCurrentCaseThrows().getServices().getTagsManager() .addContentTag(file, result.getTagName(), result.getComment()); - ContentViewerTag contentViewerTag = ContentViewerTagManager.saveTag(contentTag, data); - return contentViewerTag; + return ContentViewerTagManager.saveTag(contentTag, data); } finally { scrollPane.setCursor(Cursor.DEFAULT); } @@ -824,17 +825,17 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan */ private void showOrHideTags() { Platform.runLater(() -> { - if (DisplayOptions.HIDE_TAGS.getName().equals(hideTags.getText())) { + if (DisplayOptions.HIDE_TAGS.getName().equals(hideTagsMenuItem.getText())) { //Temporarily remove the tags group and update buttons masterGroup.getChildren().remove(tagsGroup); - hideTags.setText(DisplayOptions.SHOW_TAGS.getName()); + hideTagsMenuItem.setText(DisplayOptions.SHOW_TAGS.getName()); tagsGroup.clearFocus(); pcs.firePropertyChange(new PropertyChangeEvent(this, "state", null, State.HIDDEN)); } else { //Add tags group back in and update buttons masterGroup.getChildren().add(tagsGroup); - hideTags.setText(DisplayOptions.HIDE_TAGS.getName()); + hideTagsMenuItem.setText(DisplayOptions.HIDE_TAGS.getName()); pcs.firePropertyChange(new PropertyChangeEvent(this, "state", null, State.VISIBLE)); } @@ -845,7 +846,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan "MediaViewImagePanel.exportSaveText=Save", "MediaViewImagePanel.successfulExport=Tagged image was successfully saved.", "MediaViewImagePanel.unsuccessfulExport=Unable to export tagged image to disk.", - "MediaViewImagePanel.fileChooserTitle=Choose a directory to save the image" + "MediaViewImagePanel.fileChooserTitle=Choose a save location" }) private void exportTags() { tagsGroup.clearFocus(); @@ -855,14 +856,14 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan exportChooser.setCurrentDirectory(exportChooser.getSelectedFile()); new SwingWorker() { @Override - protected Void doInBackground() throws Exception { + protected Void doInBackground() { try { List tags = Case.getCurrentCase().getServices() .getTagsManager().getContentTagsByContent(file); List> contentViewerTags = getContentViewerTags(tags); Collection regions = contentViewerTags.stream() .map(cvTag -> cvTag.getDetails()).collect(Collectors.toList()); - byte[] jpgImage = ImageTagsUtil.exportTags(file, regions, ".jpg"); + byte[] jpgImage = ImageTagsUtility.exportTags(file, regions, ".jpg"); Path output = Paths.get(exportChooser.getSelectedFile().getPath(), FilenameUtils.getBaseName(file.getName()) + "-with_tags.jpg"); //NON-NLS Files.write(output, jpgImage); diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsUtil.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsUtility.java similarity index 58% rename from Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsUtil.java rename to Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsUtility.java index 391a8700ea..67ec058c84 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsUtil.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsUtility.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2019 Basis Technology Corp. + * Contact: carrier sleuthkit 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.contentviewers.imagetagging; @@ -15,12 +28,17 @@ import org.opencv.highgui.Highgui; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TskCoreException; -/** - * - * @author dsmyda - */ -public class ImageTagsUtil { +public class ImageTagsUtility { + /** + * Embeds the tag regions into an image (represented as an AbstractFile). + * + * @param file Base Image + * @param tagRegions Tag regions to be saved into the image + * @param outputEncoding Output file type encoding (ex. .jpg, .png) + * @return output image in byte array + * @throws TskCoreException + */ public static byte[] exportTags(AbstractFile file, Collection tagRegions, String outputEncoding) throws TskCoreException { byte[] imageInMemory = new byte[(int) file.getSize()]; file.read(imageInMemory, 0, file.getSize()); From a652fda0debe32549ebfd7e6ed7690ace826a91e Mon Sep 17 00:00:00 2001 From: Joe Ho Date: Wed, 5 Jun 2019 22:23:27 -0400 Subject: [PATCH 041/115] Initial code, use setVisible --- .../autopsy/casemodule/Bundle.properties | 14 +- .../casemodule/Bundle.properties-MERGED | 13 +- .../casemodule/LogicalImagerPanel.form | 342 ++++++++++-------- .../casemodule/LogicalImagerPanel.java | 272 +++++++++----- 4 files changed, 384 insertions(+), 257 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index 2683f71d6d..108f2d0488 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -238,13 +238,9 @@ OpenMultiUserCasePanel.cancelButton.text=Cancel OpenMultiUserCasePanel.openSingleUserCaseButton.text=Open Single-User Case... OpenMultiUserCasePanel.openSelectedCaseButton.text=Open Selected Case OpenMultiUserCasePanel.searchLabel.text=Select any case and start typing to search by case name -LogicalImagerPanel.jLabel1.text=Insert external drive -LogicalImagerPanel.scanButton.text=Scan -LogicalImagerPanel.jLabel6.text=Or, pick a Logical Imager folder LogicalImagerPanel.browseButton.text=Browse -LogicalImagerPanel.topLabel.text=Import Autopsy Imager Results LogicalImagerPanel.selectDriveLabel.text=Select Drive -LogicalImagerPanel.messageLabel.text=Error/Status message +LogicalImagerPanel.messageLabel.text= UnpackagePortableCaseDialog.desc2Label.text=Portable Case Report Module. UnpackagePortableCaseDialog.desc1Label.text=Unpackage a portable case so it can be opened in Autopsy. Portable cases are created through the UnpackagePortableCaseDialog.exitButton.text=Exit @@ -259,4 +255,10 @@ UnpackagePortableCaseProgressDialog.cancelButton.text=Cancel UnpackagePortableCaseProgressDialog.okButton.text=OK UnpackagePortableCaseProgressDialog.resultLabel.text=resultLabel UnpackagePortableCaseDialog.extractLabel.text=Folder to extract to: -UnpackagePortableCaseDialog.caseLabel.text=Portable Case: \ No newline at end of file +UnpackagePortableCaseDialog.caseLabel.text=Portable Case: +LogicalImagerPanel.importRadioButton.text=Import From External Drive +LogicalImagerPanel.manualRadioButton.text=Manually Choose Folder +LogicalImagerPanel.refreshButton.text=Refresh +LogicalImagerPanel.selectFromDriveLabel.text=Select Acquisition From Drive +LogicalImagerPanel.importRadioButton.toolTipText= +LogicalImagerPanel.pathTextField.text= diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED index 5ad9042e9f..2e7b74a649 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED @@ -191,7 +191,6 @@ LogicalImagerDSProcessor.failToCreateDirectory=Failed to create directory {0} LogicalImagerDSProcessor.imageDirPathNotFound={0} not found.\nUSB drive has been ejected. LogicalImagerPanel.imageTable.columnModel.title0=Hostname LogicalImagerPanel.imageTable.columnModel.title1=Extracted Date -LogicalImagerPanel.messageLabel.clickScanOrBrowse=Click SCAN or BROWSE button to find images # {0} - sparseImageDirectory # {1} - image LogicalImagerPanel.messageLabel.directoryDoesNotContainSparseImage=Directory {0} does not contain {1} @@ -475,13 +474,9 @@ OpenMultiUserCasePanel.cancelButton.text=Cancel OpenMultiUserCasePanel.openSingleUserCaseButton.text=Open Single-User Case... OpenMultiUserCasePanel.openSelectedCaseButton.text=Open Selected Case OpenMultiUserCasePanel.searchLabel.text=Select any case and start typing to search by case name -LogicalImagerPanel.jLabel1.text=Insert external drive -LogicalImagerPanel.scanButton.text=Scan -LogicalImagerPanel.jLabel6.text=Or, pick a Logical Imager folder LogicalImagerPanel.browseButton.text=Browse -LogicalImagerPanel.topLabel.text=Import Autopsy Imager Results LogicalImagerPanel.selectDriveLabel.text=Select Drive -LogicalImagerPanel.messageLabel.text=Error/Status message +LogicalImagerPanel.messageLabel.text=Error message UnpackagePortableCaseDialog.desc2Label.text=Portable Case Report Module. UnpackagePortableCaseDialog.desc1Label.text=Unpackage a portable case so it can be opened in Autopsy. Portable cases are created through the UnpackagePortableCaseDialog.exitButton.text=Exit @@ -497,3 +492,9 @@ UnpackagePortableCaseProgressDialog.okButton.text=OK UnpackagePortableCaseProgressDialog.resultLabel.text=resultLabel UnpackagePortableCaseDialog.extractLabel.text=Folder to extract to: UnpackagePortableCaseDialog.caseLabel.text=Portable Case: +LogicalImagerPanel.importRadioButton.text=Import From External Drive +LogicalImagerPanel.manualRadioButton.text=Manually Choose Folder +LogicalImagerPanel.refreshButton.text=Refresh +LogicalImagerPanel.selectFromDriveLabel.text=Select Acquisition From Drive +LogicalImagerPanel.importRadioButton.toolTipText= +LogicalImagerPanel.pathTextField.text= diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LogicalImagerPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/LogicalImagerPanel.form index 79e6241551..cfeffd47fd 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LogicalImagerPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LogicalImagerPanel.form @@ -1,6 +1,10 @@ + + + + @@ -24,52 +28,31 @@ - - - - - - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - + + - + @@ -78,159 +61,212 @@ - - + + + + + - - - - - - + - - - - - - - - - - - - - + + + - + - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LogicalImagerPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/LogicalImagerPanel.java index cfc0f87eb1..1781c0e1c1 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LogicalImagerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LogicalImagerPanel.java @@ -19,6 +19,11 @@ package org.sleuthkit.autopsy.casemodule; import java.awt.Color; +import java.awt.Component; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; import java.io.File; import java.io.IOException; import java.nio.file.FileStore; @@ -86,13 +91,9 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { * * @return instance of the LogicalImagerPanel */ - @Messages({ - "LogicalImagerPanel.messageLabel.clickScanOrBrowse=Click SCAN or BROWSE button to find images" - }) public static synchronized LogicalImagerPanel createInstance(String context) { LogicalImagerPanel instance = new LogicalImagerPanel(context); // post-constructor initialization of listener support without leaking references of uninitialized objects - instance.messageLabel.setText(Bundle.LogicalImagerPanel_messageLabel_clickScanOrBrowse()); instance.imageTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); return instance; } @@ -105,35 +106,55 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { // //GEN-BEGIN:initComponents private void initComponents() { - topLabel = new javax.swing.JLabel(); - jLabel1 = new javax.swing.JLabel(); - scanButton = new javax.swing.JButton(); + buttonGroup1 = new javax.swing.ButtonGroup(); messageLabel = new javax.swing.JLabel(); + browseButton = new javax.swing.JButton(); + importRadioButton = new javax.swing.JRadioButton(); + manualRadioButton = new javax.swing.JRadioButton(); + pathTextField = new javax.swing.JTextField(); + importPanel = new javax.swing.JPanel(); selectDriveLabel = new javax.swing.JLabel(); driveListScrollPane = new javax.swing.JScrollPane(); driveList = new javax.swing.JList<>(); - selectAcquisitionFromDriveLabel = new javax.swing.JLabel(); - jLabel6 = new javax.swing.JLabel(); - browseButton = new javax.swing.JButton(); + refreshButton = new javax.swing.JButton(); imageScrollPane = new javax.swing.JScrollPane(); imageTable = new javax.swing.JTable(); - jSeparator1 = new javax.swing.JSeparator(); + selectFromDriveLabel = new javax.swing.JLabel(); setMinimumSize(new java.awt.Dimension(0, 65)); setPreferredSize(new java.awt.Dimension(403, 65)); - org.openide.awt.Mnemonics.setLocalizedText(topLabel, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.topLabel.text")); // NOI18N + messageLabel.setForeground(java.awt.Color.red); + org.openide.awt.Mnemonics.setLocalizedText(messageLabel, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.messageLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.jLabel1.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(scanButton, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.scanButton.text")); // NOI18N - scanButton.addActionListener(new java.awt.event.ActionListener() { + org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.browseButton.text")); // NOI18N + browseButton.setEnabled(false); + browseButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - scanButtonActionPerformed(evt); + browseButtonActionPerformed(evt); } }); - org.openide.awt.Mnemonics.setLocalizedText(messageLabel, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.messageLabel.text")); // NOI18N + buttonGroup1.add(importRadioButton); + importRadioButton.setSelected(true); + org.openide.awt.Mnemonics.setLocalizedText(importRadioButton, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.importRadioButton.text")); // NOI18N + importRadioButton.setToolTipText(org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.importRadioButton.toolTipText")); // NOI18N + importRadioButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + importRadioButtonActionPerformed(evt); + } + }); + + buttonGroup1.add(manualRadioButton); + org.openide.awt.Mnemonics.setLocalizedText(manualRadioButton, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.manualRadioButton.text")); // NOI18N + manualRadioButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + manualRadioButtonActionPerformed(evt); + } + }); + + pathTextField.setText(org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.pathTextField.text")); // NOI18N + pathTextField.setEnabled(false); org.openide.awt.Mnemonics.setLocalizedText(selectDriveLabel, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.selectDriveLabel.text")); // NOI18N @@ -150,14 +171,10 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { }); driveListScrollPane.setViewportView(driveList); - org.openide.awt.Mnemonics.setLocalizedText(selectAcquisitionFromDriveLabel, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.selectAcquisitionFromDriveLabel.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(jLabel6, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.jLabel6.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.browseButton.text")); // NOI18N - browseButton.addActionListener(new java.awt.event.ActionListener() { + org.openide.awt.Mnemonics.setLocalizedText(refreshButton, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.refreshButton.text")); // NOI18N + refreshButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - browseButtonActionPerformed(evt); + refreshButtonActionPerformed(evt); } }); @@ -190,71 +207,81 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { imageScrollPane.setViewportView(imageTable); imageTable.getColumnModel().getSelectionModel().setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); + org.openide.awt.Mnemonics.setLocalizedText(selectFromDriveLabel, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.selectFromDriveLabel.text")); // NOI18N + + javax.swing.GroupLayout importPanelLayout = new javax.swing.GroupLayout(importPanel); + importPanel.setLayout(importPanelLayout); + importPanelLayout.setHorizontalGroup( + importPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, importPanelLayout.createSequentialGroup() + .addGap(21, 21, 21) + .addGroup(importPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(selectDriveLabel) + .addGroup(importPanelLayout.createSequentialGroup() + .addGroup(importPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(driveListScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 211, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(refreshButton)) + .addGap(28, 28, 28) + .addGroup(importPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(selectFromDriveLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 305, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(imageScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))) + .addContainerGap(12, Short.MAX_VALUE)) + ); + importPanelLayout.setVerticalGroup( + importPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(importPanelLayout.createSequentialGroup() + .addGroup(importPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(selectDriveLabel) + .addComponent(selectFromDriveLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(importPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(imageScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addComponent(driveListScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 146, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(refreshButton)) + ); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGap(238, 238, 238) - .addComponent(topLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 163, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE)) - .addGroup(layout.createSequentialGroup() - .addGap(28, 28, 28) + .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(messageLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addComponent(jSeparator1, javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(selectDriveLabel) - .addGap(289, 289, 289)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(scanButton) - .addGap(126, 126, 126))) - .addGap(36, 36, 36) - .addComponent(browseButton)) - .addGroup(layout.createSequentialGroup() - .addComponent(driveListScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 211, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(28, 28, 28) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(selectAcquisitionFromDriveLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 305, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(imageScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 346, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addGroup(layout.createSequentialGroup() - .addGap(346, 346, 346) - .addComponent(jLabel6, javax.swing.GroupLayout.PREFERRED_SIZE, 154, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addGap(144, 144, 144) - .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 116, javax.swing.GroupLayout.PREFERRED_SIZE)))) - .addContainerGap(48, Short.MAX_VALUE)))) + .addGap(21, 21, 21) + .addComponent(importPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(25, Short.MAX_VALUE)) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(pathTextField) + .addComponent(messageLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(manualRadioButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(browseButton)) + .addComponent(importRadioButton)) + .addGap(0, 0, Short.MAX_VALUE))) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(topLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabel1) - .addComponent(jLabel6)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(scanButton) - .addComponent(browseButton)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 4, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(16, 16, 16) + .addComponent(importRadioButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(importPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 46, Short.MAX_VALUE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(selectDriveLabel) - .addComponent(selectAcquisitionFromDriveLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(imageScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) - .addComponent(driveListScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 194, Short.MAX_VALUE)) - .addGap(26, 26, 26) + .addComponent(browseButton) + .addComponent(manualRadioButton)) + .addGap(11, 11, 11) + .addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(messageLabel) - .addGap(154, 154, 154)) + .addContainerGap()) ); }// //GEN-END:initComponents @@ -272,7 +299,7 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { "LogicalImagerPanel.messageLabel.scanningExternalDrives=Scanning external drives for sparse_image.vhd ...", "LogicalImagerPanel.messageLabel.noExternalDriveFound=No drive found" }) - private void scanButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scanButtonActionPerformed + private void refreshButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_refreshButtonActionPerformed // Scan external drives for sparse_image.vhd clearImageTable(); setNormalMessage(Bundle.LogicalImagerPanel_messageLabel_scanningExternalDrives()); @@ -307,7 +334,7 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { setErrorMessage(Bundle.LogicalImagerPanel_messageLabel_noExternalDriveFound()); } firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false); - }//GEN-LAST:event_scanButtonActionPerformed + }//GEN-LAST:event_refreshButtonActionPerformed @Messages({ "# {0} - sparseImageDirectory", @@ -398,7 +425,7 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { } } } - selectAcquisitionFromDriveLabel.setText(Bundle.LogicalImagerPanel_selectAcquisitionFromDriveLabel_text() + selectFromDriveLabel.setText(Bundle.LogicalImagerPanel_selectAcquisitionFromDriveLabel_text() + " " + driveLetter); imageTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN); imageTable.setModel(imageTableModel); @@ -423,11 +450,12 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { private void setErrorMessage(String msg) { messageLabel.setForeground(Color.red); messageLabel.setText(msg); + pathTextField.setText(""); } private void setNormalMessage(String msg) { - messageLabel.setForeground(Color.black); - messageLabel.setText(msg); + pathTextField.setText(msg); + messageLabel.setText(""); } private void clearImageTable() { @@ -451,20 +479,85 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false); }//GEN-LAST:event_imageTableKeyReleased + MouseAdapter mouseAdapter = new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + System.err.println(e.getPoint().toString()); + e.consume(); + } + }; + + KeyListener keyListener = new KeyListener() { + @Override + public void keyTyped(KeyEvent e) { + System.err.println(e.toString()); + e.consume(); + } + + @Override + public void keyPressed(KeyEvent e) { + System.err.println(e.toString()); + e.consume(); + } + + @Override + public void keyReleased(KeyEvent e) { + System.err.println(e.toString()); + e.consume(); + } + }; + + private void toggleMouseAndKeyListeners(Component component, boolean isEnable) { + component.setEnabled(isEnable); + component.setVisible(isEnable); + } + + private void manualRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_manualRadioButtonActionPerformed + browseButton.setEnabled(true); + + // disable import panel + toggleMouseAndKeyListeners(importPanel, false); + toggleMouseAndKeyListeners(driveList, false); + toggleMouseAndKeyListeners(driveListScrollPane, false); + toggleMouseAndKeyListeners(imageScrollPane, false); + toggleMouseAndKeyListeners(imageTable, false); + + refreshButton.setEnabled(false); + + choosenImageDirPath = null; + setNormalMessage(""); + }//GEN-LAST:event_manualRadioButtonActionPerformed + + private void importRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importRadioButtonActionPerformed + browseButton.setEnabled(false); + + toggleMouseAndKeyListeners(importPanel, true); + toggleMouseAndKeyListeners(driveList, true); + toggleMouseAndKeyListeners(driveListScrollPane, true); + toggleMouseAndKeyListeners(imageScrollPane, true); + toggleMouseAndKeyListeners(imageTable, true); + + refreshButton.setEnabled(true); + + choosenImageDirPath = null; + setNormalMessage(""); + }//GEN-LAST:event_importRadioButtonActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton browseButton; + private javax.swing.ButtonGroup buttonGroup1; private javax.swing.JList driveList; private javax.swing.JScrollPane driveListScrollPane; private javax.swing.JScrollPane imageScrollPane; private javax.swing.JTable imageTable; - private javax.swing.JLabel jLabel1; - private javax.swing.JLabel jLabel6; - private javax.swing.JSeparator jSeparator1; + private javax.swing.JPanel importPanel; + private javax.swing.JRadioButton importRadioButton; + private javax.swing.JRadioButton manualRadioButton; private javax.swing.JLabel messageLabel; - private javax.swing.JButton scanButton; - private javax.swing.JLabel selectAcquisitionFromDriveLabel; + private javax.swing.JTextField pathTextField; + private javax.swing.JButton refreshButton; private javax.swing.JLabel selectDriveLabel; - private javax.swing.JLabel topLabel; + private javax.swing.JLabel selectFromDriveLabel; // End of variables declaration//GEN-END:variables public void reset() { @@ -472,7 +565,6 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { choosenImageDirPath = null; driveList.setListData(EMPTY_LIST_DATA); clearImageTable(); - setNormalMessage(Bundle.LogicalImagerPanel_messageLabel_clickScanOrBrowse()); } /** @@ -488,10 +580,6 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { return choosenImageDirPath; } - public void setMessageLabel(String message) { - messageLabel.setText(message); - } - @Override public void insertUpdate(DocumentEvent e) { } From fcb1120076d8118b003f9d4e6e346f970c2179ef Mon Sep 17 00:00:00 2001 From: Joe Ho Date: Wed, 5 Jun 2019 23:34:34 -0400 Subject: [PATCH 042/115] Ignore mouse and keyboard input when in browse mode --- .../casemodule/Bundle.properties-MERGED | 2 +- .../casemodule/LogicalImagerPanel.java | 55 +++++-------------- 2 files changed, 16 insertions(+), 41 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED index 2e7b74a649..6e8c9318d9 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED @@ -476,7 +476,7 @@ OpenMultiUserCasePanel.openSelectedCaseButton.text=Open Selected Case OpenMultiUserCasePanel.searchLabel.text=Select any case and start typing to search by case name LogicalImagerPanel.browseButton.text=Browse LogicalImagerPanel.selectDriveLabel.text=Select Drive -LogicalImagerPanel.messageLabel.text=Error message +LogicalImagerPanel.messageLabel.text= UnpackagePortableCaseDialog.desc2Label.text=Portable Case Report Module. UnpackagePortableCaseDialog.desc1Label.text=Unpackage a portable case so it can be opened in Autopsy. Portable cases are created through the UnpackagePortableCaseDialog.exitButton.text=Exit diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LogicalImagerPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/LogicalImagerPanel.java index 1781c0e1c1..6ca1aee5da 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LogicalImagerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LogicalImagerPanel.java @@ -20,10 +20,6 @@ package org.sleuthkit.autopsy.casemodule; import java.awt.Color; import java.awt.Component; -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; import java.io.File; import java.io.IOException; import java.nio.file.FileStore; @@ -385,7 +381,9 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { } private void imageTableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_imageTableMouseClicked - imageTableSelect(); + if (importRadioButton.isSelected()) { + imageTableSelect(); + } }//GEN-LAST:event_imageTableMouseClicked private void driveListSelect() { @@ -465,51 +463,28 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { } private void driveListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_driveListMouseClicked - driveListSelect(); - firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false); + if (importRadioButton.isSelected()) { + driveListSelect(); + firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false); + } }//GEN-LAST:event_driveListMouseClicked private void driveListKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_driveListKeyReleased - driveListSelect(); - firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false); + if (importRadioButton.isSelected()) { + driveListSelect(); + firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false); + } }//GEN-LAST:event_driveListKeyReleased private void imageTableKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_imageTableKeyReleased - imageTableSelect(); - firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false); + if (importRadioButton.isSelected()) { + imageTableSelect(); + firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false); + } }//GEN-LAST:event_imageTableKeyReleased - MouseAdapter mouseAdapter = new MouseAdapter() { - @Override - public void mousePressed(MouseEvent e) { - System.err.println(e.getPoint().toString()); - e.consume(); - } - }; - - KeyListener keyListener = new KeyListener() { - @Override - public void keyTyped(KeyEvent e) { - System.err.println(e.toString()); - e.consume(); - } - - @Override - public void keyPressed(KeyEvent e) { - System.err.println(e.toString()); - e.consume(); - } - - @Override - public void keyReleased(KeyEvent e) { - System.err.println(e.toString()); - e.consume(); - } - }; - private void toggleMouseAndKeyListeners(Component component, boolean isEnable) { component.setEnabled(isEnable); - component.setVisible(isEnable); } private void manualRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_manualRadioButtonActionPerformed From 3ef9746d2647f76d29d04dea6e21c6c7164f727d Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Thu, 6 Jun 2019 10:26:02 -0400 Subject: [PATCH 043/115] Handle empty tables. Cleanup --- .../corecomponents/Bundle.properties-MERGED | 1 + .../corecomponents/DataResultViewerTable.form | 10 ++-- .../corecomponents/DataResultViewerTable.java | 27 +++++++--- .../directorytree/Bundle.properties-MERGED | 1 + .../directorytree/ExportCSVAction.java | 50 ++++++++++++------- 5 files changed, 59 insertions(+), 30 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED index 43ceba39ba..b0e36da986 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED @@ -32,6 +32,7 @@ DataResultViewerTable.commentRenderer.noComment.toolTip=No comments found DataResultViewerTable.commentRenderer.tagComment.toolTip=Comment exists on associated tag(s) DataResultViewerTable.countRender.name=O DataResultViewerTable.countRender.toolTip=O(ccurrences) indicates the number of data sources containing the item in the Central Repository +DataResultViewerTable.exportCSVButtonActionPerformed.empty=No data to export DataResultViewerTable.firstColLbl=Name DataResultViewerTable.goToPageTextField.err=Invalid page number # {0} - totalPages diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.form b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.form index 87e771695b..6aeda07298 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.form @@ -18,12 +18,11 @@ - - + - + - + @@ -33,7 +32,8 @@ - + + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java index eb5fad97f5..e6c1110038 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java @@ -77,6 +77,7 @@ import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.datamodel.NodeProperty; import org.sleuthkit.autopsy.datamodel.NodeSelectionInfo; @@ -176,6 +177,13 @@ public class DataResultViewerTable extends AbstractDataResultViewer { initComponents(); initializePagingSupport(); + + /* + * Disable the CSV export button for the common properties results + */ + if (this instanceof org.sleuthkit.autopsy.commonpropertiessearch.CommonAttributesSearchResultsViewerTable) { + exportCSVButton.setEnabled(false); + } /* * Configure the child OutlineView (explorer view) component. @@ -1352,12 +1360,11 @@ public class DataResultViewerTable extends AbstractDataResultViewer { layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 904, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() - .addComponent(exportCSVButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap() .addComponent(pageLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(pageNumLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 53, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGap(14, 14, 14) .addComponent(pagesLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(pagePrevButton, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE) @@ -1367,7 +1374,8 @@ public class DataResultViewerTable extends AbstractDataResultViewer { .addComponent(gotoPageLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(gotoPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 33, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap()) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(exportCSVButton)) ); layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {pageNextButton, pagePrevButton}); @@ -1407,8 +1415,15 @@ public class DataResultViewerTable extends AbstractDataResultViewer { pagingSupport.gotoPage(); }//GEN-LAST:event_gotoPageTextFieldActionPerformed + @NbBundle.Messages({"DataResultViewerTable.exportCSVButtonActionPerformed.empty=No data to export" + }) private void exportCSVButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exportCSVButtonActionPerformed - org.sleuthkit.autopsy.directorytree.ExportCSVAction.saveNodesToCSV(java.util.Arrays.asList(rootNode.getChildren().getNodes()), this); + Node currentRoot = this.getExplorerManager().getRootContext(); + if (currentRoot != null && currentRoot.getChildren().getNodesCount() > 0) { + org.sleuthkit.autopsy.directorytree.ExportCSVAction.saveNodesToCSV(java.util.Arrays.asList(currentRoot.getChildren().getNodes()), this); + } else { + MessageNotifyUtil.Message.info(Bundle.DataResultViewerTable_exportCSVButtonActionPerformed_empty()); + } }//GEN-LAST:event_exportCSVButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties-MERGED index 6ec6a0e76b..f70a374bc5 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties-MERGED @@ -10,6 +10,7 @@ DirectoryTreeTopComponent.componentOpened.groupDataSources.text=This case contai DirectoryTreeTopComponent.componentOpened.groupDataSources.title=Group by data source? DirectoryTreeTopComponent.emptyMimeNode.text=Data not available. Run file type identification module. DirectoryTreeTopComponent.resultsView.title=Listing +ExportCSV.saveNodesToCSV.empty=No data to export # {0} - Output file ExportCSV.saveNodesToCSV.fileExists=File {0} already exists ExportCSV.saveNodesToCSV.noCurrentCase=No open case available diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java index dce6244084..7fa4560afc 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-2018 Basis Technology Corp. + * Copyright 2019 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,7 +22,6 @@ import java.awt.Component; import java.awt.event.ActionEvent; import java.io.File; import java.io.BufferedWriter; -import java.io.FileWriter; import java.io.FileOutputStream; import java.io.OutputStreamWriter; import java.lang.reflect.InvocationTargetException; @@ -31,10 +30,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collection; -import java.util.HashSet; import java.util.Iterator; import java.util.List; -import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.logging.Level; import javax.swing.AbstractAction; @@ -48,14 +45,8 @@ import org.openide.util.NbBundle; import org.openide.util.Utilities; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.coreutils.FileUtil; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.autopsy.datamodel.ContentUtils; -import org.sleuthkit.autopsy.datamodel.ContentUtils.ExtractFscContentVisitor; -import org.sleuthkit.autopsy.datamodel.FileNode; -import org.sleuthkit.datamodel.AbstractFile; -import org.openide.nodes.AbstractNode; import org.openide.nodes.Node; import org.openide.nodes.Node.PropertySet; import org.openide.nodes.Node.Property; @@ -76,6 +67,12 @@ public final class ExportCSVAction extends AbstractAction { // node in the array returns a reference to the same action object from Node.getActions(boolean). private static ExportCSVAction instance; + /** + * Get an instance of the Action. See above for why + * the class is a singleton. + * + * @return the instance + */ public static synchronized ExportCSVAction getInstance() { if (null == instance) { instance = new ExportCSVAction(); @@ -104,20 +101,28 @@ public final class ExportCSVAction extends AbstractAction { saveNodesToCSV(selectedNodes, (Component)e.getSource()); } + /** + * Save the selected nodes to a CSV file + * + * @param nodesToExport the nodes to save + * @param component + */ @NbBundle.Messages({ "# {0} - Output file", "ExportCSV.saveNodesToCSV.fileExists=File {0} already exists", - "ExportCSV.saveNodesToCSV.noCurrentCase=No open case available"}) + "ExportCSV.saveNodesToCSV.noCurrentCase=No open case available", + "ExportCSV.saveNodesToCSV.empty=No data to export"}) public static void saveNodesToCSV(Collection nodesToExport, Component component) { if (nodesToExport.isEmpty()) { + MessageNotifyUtil.Message.info(Bundle.ExportCSV_saveNodesToCSV_empty()); return; } try { - + // Set up the file chooser with a default name and either the Export + // folder or the last used folder. String fileName = getDefaultOutputFileName(nodesToExport.iterator().next().getParentNode()); - JFileChooser fileChooser = new JFileChooser(); fileChooser.setCurrentDirectory(new File(getExportDirectory(Case.getCurrentCaseThrows()))); fileChooser.setSelectedFile(new File(fileName)); @@ -126,15 +131,18 @@ public final class ExportCSVAction extends AbstractAction { int returnVal = fileChooser.showSaveDialog(component); if (returnVal == JFileChooser.APPROVE_OPTION) { + // Get the file name, appending .csv if necessary File selectedFile = fileChooser.getSelectedFile(); if (!selectedFile.getName().endsWith(".csv")) { // NON-NLS selectedFile = new File(selectedFile.toString() + ".csv"); // NON-NLS } + + // Save the directory used for next time updateExportDirectory(selectedFile.getParent(), Case.getCurrentCaseThrows()); if (selectedFile.exists()) { logger.log(Level.SEVERE, "File {0} already exists", selectedFile.getAbsolutePath()); //NON-NLS - MessageNotifyUtil.Message.info(Bundle.ExportCSV_actionPerformed_fileExists(selectedFile)); + MessageNotifyUtil.Message.info(Bundle.ExportCSV_saveNodesToCSV_fileExists(selectedFile)); return; } @@ -142,7 +150,7 @@ public final class ExportCSVAction extends AbstractAction { writer.execute(); } } catch (NoCurrentCaseException ex) { - JOptionPane.showMessageDialog(component, Bundle.ExportCSV_actionPerformed_noCurrentCase()); + JOptionPane.showMessageDialog(component, Bundle.ExportCSV_saveNodesToCSV_noCurrentCase()); logger.log(Level.INFO, "Exception while getting open case.", ex); //NON-NLS } } @@ -165,13 +173,10 @@ public final class ExportCSVAction extends AbstractAction { String parentName = prop.getValue().toString(); // Strip off the count (if present) - System.out.println("parentName (raw) : " + parentName); parentName = parentName.replaceAll("\\([0-9]+\\)$", ""); - System.out.println("parentName (after paren regex) : " + parentName); // Strip out any invalid characters parentName = parentName.replaceAll("[\\\\/:*?\"<>|]", "_"); - System.out.println("parentName (after char regex) : " + parentName); return parentName + " " + dateStr; } catch (IllegalAccessException | InvocationTargetException ex) { @@ -190,7 +195,7 @@ public final class ExportCSVAction extends AbstractAction { * * @return The export directory path. */ - private static String getExportDirectory(Case openCase) { // TODO sync + private static String getExportDirectory(Case openCase) { String caseExportPath = openCase.getExportDirectory(); if (userDefinedExportPath == null) { @@ -306,6 +311,13 @@ public final class ExportCSVAction extends AbstractAction { return null; } + /** + * Convert list of values to a comma separated string. + * + * @param values Values to convert + * + * @return values as CSV + */ private String listToCSV(List values) { return "\"" + String.join("\",\"", values) + "\"\n"; } From f55fced435e62f61723b3fc01567a92847c8aca1 Mon Sep 17 00:00:00 2001 From: Joe Ho Date: Thu, 6 Jun 2019 10:31:42 -0400 Subject: [PATCH 044/115] Fix the layout and logic --- .../autopsy/casemodule/Bundle.properties | 7 +- .../casemodule/Bundle.properties-MERGED | 2 +- .../casemodule/LogicalImagerPanel.form | 85 ++++--- .../casemodule/LogicalImagerPanel.java | 214 +++++++++--------- 4 files changed, 167 insertions(+), 141 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index 108f2d0488..907f4b6c82 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -239,7 +239,6 @@ OpenMultiUserCasePanel.openSingleUserCaseButton.text=Open Single-User Case... OpenMultiUserCasePanel.openSelectedCaseButton.text=Open Selected Case OpenMultiUserCasePanel.searchLabel.text=Select any case and start typing to search by case name LogicalImagerPanel.browseButton.text=Browse -LogicalImagerPanel.selectDriveLabel.text=Select Drive LogicalImagerPanel.messageLabel.text= UnpackagePortableCaseDialog.desc2Label.text=Portable Case Report Module. UnpackagePortableCaseDialog.desc1Label.text=Unpackage a portable case so it can be opened in Autopsy. Portable cases are created through the @@ -258,7 +257,9 @@ UnpackagePortableCaseDialog.extractLabel.text=Folder to extract to: UnpackagePortableCaseDialog.caseLabel.text=Portable Case: LogicalImagerPanel.importRadioButton.text=Import From External Drive LogicalImagerPanel.manualRadioButton.text=Manually Choose Folder -LogicalImagerPanel.refreshButton.text=Refresh -LogicalImagerPanel.selectFromDriveLabel.text=Select Acquisition From Drive LogicalImagerPanel.importRadioButton.toolTipText= LogicalImagerPanel.pathTextField.text= +LogicalImagerPanel.selectFolderLabel.text=Selected Folder: +LogicalImagerPanel.refreshButton.text=Refresh +LogicalImagerPanel.selectDriveLabel.text=Select Drive +LogicalImagerPanel.selectFromDriveLabel.text=Select Acquisition From Drive diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED index 6e8c9318d9..aba801d6bb 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED @@ -200,7 +200,6 @@ LogicalImagerPanel.messageLabel.driveHasNoImages=Drive has no images LogicalImagerPanel.messageLabel.noExternalDriveFound=No drive found LogicalImagerPanel.messageLabel.noImageSelected=No image selected LogicalImagerPanel.messageLabel.scanningExternalDrives=Scanning external drives for sparse_image.vhd ... -LogicalImagerPanel.messageLabel.selectedImage=Selected folder LogicalImagerPanel.selectAcquisitionFromDriveLabel.text=Select acquisition from Drive Menu/Case/OpenRecentCase=Open Recent Case CTL_CaseDeleteAction=Delete Case @@ -498,3 +497,4 @@ LogicalImagerPanel.refreshButton.text=Refresh LogicalImagerPanel.selectFromDriveLabel.text=Select Acquisition From Drive LogicalImagerPanel.importRadioButton.toolTipText= LogicalImagerPanel.pathTextField.text= +LogicalImagerPanel.selectFolderLabel.text=Selected Folder: diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LogicalImagerPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/LogicalImagerPanel.form index cfeffd47fd..5f160ca76b 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LogicalImagerPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LogicalImagerPanel.form @@ -28,32 +28,32 @@ - - + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + @@ -63,18 +63,21 @@ - - - + + + - - - - - + + + + + + + + @@ -144,23 +147,26 @@ - - + + - - + - + - + - + + + + + + - @@ -174,7 +180,7 @@ - + @@ -268,5 +274,12 @@ + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LogicalImagerPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/LogicalImagerPanel.java index 6ca1aee5da..1248912505 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LogicalImagerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LogicalImagerPanel.java @@ -47,7 +47,6 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; * select a file. */ @Messages({ - "LogicalImagerPanel.messageLabel.selectedImage=Selected folder", "LogicalImagerPanel.messageLabel.noImageSelected=No image selected", "LogicalImagerPanel.messageLabel.driveHasNoImages=Drive has no images", "LogicalImagerPanel.selectAcquisitionFromDriveLabel.text=Select acquisition from Drive",}) @@ -56,7 +55,6 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { private static final long serialVersionUID = 1L; private static final String SPARSE_IMAGE_VHD = "sparse_image.vhd"; //NON-NLS - private static final String SELECTED_IMAGE = Bundle.LogicalImagerPanel_messageLabel_selectedImage(); private static final String NO_IMAGE_SELECTED = Bundle.LogicalImagerPanel_messageLabel_noImageSelected(); private static final String DRIVE_HAS_NO_IMAGES = Bundle.LogicalImagerPanel_messageLabel_driveHasNoImages(); private static final String[] EMPTY_LIST_DATA = {}; @@ -116,6 +114,7 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { imageScrollPane = new javax.swing.JScrollPane(); imageTable = new javax.swing.JTable(); selectFromDriveLabel = new javax.swing.JLabel(); + selectFolderLabel = new javax.swing.JLabel(); setMinimumSize(new java.awt.Dimension(0, 65)); setPreferredSize(new java.awt.Dimension(403, 65)); @@ -209,19 +208,21 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { importPanel.setLayout(importPanelLayout); importPanelLayout.setHorizontalGroup( importPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, importPanelLayout.createSequentialGroup() + .addGroup(importPanelLayout.createSequentialGroup() .addGap(21, 21, 21) .addGroup(importPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(selectDriveLabel) - .addGroup(importPanelLayout.createSequentialGroup() + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, importPanelLayout.createSequentialGroup() .addGroup(importPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) - .addComponent(driveListScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 211, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(refreshButton)) - .addGap(28, 28, 28) + .addComponent(refreshButton) + .addComponent(driveListScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(importPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(selectFromDriveLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 305, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(imageScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))) - .addContainerGap(12, Short.MAX_VALUE)) + .addComponent(imageScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGap(22, 22, 22)) + .addGroup(importPanelLayout.createSequentialGroup() + .addComponent(selectDriveLabel) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) ); importPanelLayout.setVerticalGroup( importPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -232,11 +233,13 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(importPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(imageScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) - .addComponent(driveListScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 146, Short.MAX_VALUE)) + .addComponent(driveListScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 185, Short.MAX_VALUE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(refreshButton)) ); + org.openide.awt.Mnemonics.setLocalizedText(selectFolderLabel, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.selectFolderLabel.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -244,39 +247,41 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGap(21, 21, 21) - .addComponent(importPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(25, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(pathTextField) - .addComponent(messageLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(manualRadioButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(browseButton)) - .addComponent(importRadioButton)) - .addGap(0, 0, Short.MAX_VALUE))) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) + .addComponent(manualRadioButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(browseButton)) + .addComponent(importRadioButton)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(messageLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 639, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addComponent(selectFolderLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 81, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(pathTextField))) + .addGap(25, 25, 25)) + .addComponent(importPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(16, 16, 16) .addComponent(importRadioButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(importPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 46, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(importPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGap(37, 37, 37) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(browseButton) .addComponent(manualRadioButton)) - .addGap(11, 11, 11) - .addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(3, 3, 3) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(selectFolderLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(messageLabel) + .addComponent(messageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 19, javax.swing.GroupLayout.PREFERRED_SIZE) .addContainerGap()) ); }// //GEN-END:initComponents @@ -291,47 +296,6 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre); //NON-NLS } - @Messages({ - "LogicalImagerPanel.messageLabel.scanningExternalDrives=Scanning external drives for sparse_image.vhd ...", - "LogicalImagerPanel.messageLabel.noExternalDriveFound=No drive found" - }) - private void refreshButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_refreshButtonActionPerformed - // Scan external drives for sparse_image.vhd - clearImageTable(); - setNormalMessage(Bundle.LogicalImagerPanel_messageLabel_scanningExternalDrives()); - List listData = new ArrayList<>(); - File[] roots = File.listRoots(); - int firstRemovableDrive = -1; - int i = 0; - for (File root : roots) { - String description = FileSystemView.getFileSystemView().getSystemTypeDescription(root); - long spaceInBytes = root.getTotalSpace(); - String sizeWithUnit = humanReadableByteCount(spaceInBytes, false); - listData.add(root + " (" + description + ") (" + sizeWithUnit + ")"); - if (firstRemovableDrive == -1) { - try { - FileStore fileStore = Files.getFileStore(root.toPath()); - if ((boolean) fileStore.getAttribute("volume:isRemovable")) { //NON-NLS - firstRemovableDrive = i; - } - } catch (IOException ex) { - ; // skip - } - } - i++; - } - driveList.setListData(listData.toArray(new String[0])); - if (!listData.isEmpty()) { - // auto-select the first external drive, if any - driveList.setSelectedIndex(firstRemovableDrive == -1 ? 0 : firstRemovableDrive); - driveListMouseClicked(null); - driveList.requestFocusInWindow(); - } else { - setErrorMessage(Bundle.LogicalImagerPanel_messageLabel_noExternalDriveFound()); - } - firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false); - }//GEN-LAST:event_refreshButtonActionPerformed - @Messages({ "# {0} - sparseImageDirectory", "# {1} - image", @@ -356,7 +320,7 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { return; } choosenImageDirPath = Paths.get(path); - setNormalMessage(SELECTED_IMAGE + " " + path); + setNormalMessage(path); firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true); } else { setErrorMessage(Bundle.LogicalImagerPanel_messageLabel_directoryFormatInvalid(path)); @@ -371,7 +335,7 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { int index = imageTable.getSelectedRow(); if (index != -1) { choosenImageDirPath = Paths.get((String) imageTableModel.getValueAt(index, 2)); - setNormalMessage(SELECTED_IMAGE + " " + choosenImageDirPath.toString()); + setNormalMessage(choosenImageDirPath.toString()); firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true); } else { choosenImageDirPath = null; @@ -380,12 +344,6 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { } } - private void imageTableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_imageTableMouseClicked - if (importRadioButton.isSelected()) { - imageTableSelect(); - } - }//GEN-LAST:event_imageTableMouseClicked - private void driveListSelect() { String selectedStr = driveList.getSelectedValue(); if (selectedStr == null) { @@ -436,6 +394,10 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { choosenImageDirPath = null; setErrorMessage(DRIVE_HAS_NO_IMAGES); } + } else { + clearImageTable(); + choosenImageDirPath = null; + setErrorMessage(DRIVE_HAS_NO_IMAGES); } } @@ -462,27 +424,6 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { fixImageTableColumnWidth(); } - private void driveListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_driveListMouseClicked - if (importRadioButton.isSelected()) { - driveListSelect(); - firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false); - } - }//GEN-LAST:event_driveListMouseClicked - - private void driveListKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_driveListKeyReleased - if (importRadioButton.isSelected()) { - driveListSelect(); - firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false); - } - }//GEN-LAST:event_driveListKeyReleased - - private void imageTableKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_imageTableKeyReleased - if (importRadioButton.isSelected()) { - imageTableSelect(); - firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false); - } - }//GEN-LAST:event_imageTableKeyReleased - private void toggleMouseAndKeyListeners(Component component, boolean isEnable) { component.setEnabled(isEnable); } @@ -501,6 +442,7 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { choosenImageDirPath = null; setNormalMessage(""); + firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false); }//GEN-LAST:event_manualRadioButtonActionPerformed private void importRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importRadioButtonActionPerformed @@ -516,7 +458,76 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { choosenImageDirPath = null; setNormalMessage(""); + refreshButton.doClick(); }//GEN-LAST:event_importRadioButtonActionPerformed + + private void imageTableKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_imageTableKeyReleased + if (importRadioButton.isSelected()) { + imageTableSelect(); + firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false); + } + }//GEN-LAST:event_imageTableKeyReleased + + private void imageTableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_imageTableMouseClicked + if (importRadioButton.isSelected()) { + imageTableSelect(); + } + }//GEN-LAST:event_imageTableMouseClicked + + @Messages({ + "LogicalImagerPanel.messageLabel.scanningExternalDrives=Scanning external drives for sparse_image.vhd ...", + "LogicalImagerPanel.messageLabel.noExternalDriveFound=No drive found" + }) + private void refreshButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_refreshButtonActionPerformed + // Scan external drives for sparse_image.vhd + clearImageTable(); + setNormalMessage(Bundle.LogicalImagerPanel_messageLabel_scanningExternalDrives()); + List listData = new ArrayList<>(); + File[] roots = File.listRoots(); + int firstRemovableDrive = -1; + int i = 0; + for (File root : roots) { + String description = FileSystemView.getFileSystemView().getSystemTypeDescription(root); + long spaceInBytes = root.getTotalSpace(); + String sizeWithUnit = humanReadableByteCount(spaceInBytes, false); + listData.add(root + " (" + description + ") (" + sizeWithUnit + ")"); + if (firstRemovableDrive == -1) { + try { + FileStore fileStore = Files.getFileStore(root.toPath()); + if ((boolean) fileStore.getAttribute("volume:isRemovable")) { //NON-NLS + firstRemovableDrive = i; + } + } catch (IOException ex) { + ; // skip + } + } + i++; + } + driveList.setListData(listData.toArray(new String[0])); + if (!listData.isEmpty()) { + // auto-select the first external drive, if any + driveList.setSelectedIndex(firstRemovableDrive == -1 ? 0 : firstRemovableDrive); + driveListMouseClicked(null); + driveList.requestFocusInWindow(); + } else { + setErrorMessage(Bundle.LogicalImagerPanel_messageLabel_noExternalDriveFound()); + } + firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false); + }//GEN-LAST:event_refreshButtonActionPerformed + + private void driveListKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_driveListKeyReleased + if (importRadioButton.isSelected()) { + driveListSelect(); + firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false); + } + }//GEN-LAST:event_driveListKeyReleased + + private void driveListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_driveListMouseClicked + if (importRadioButton.isSelected()) { + driveListSelect(); + firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false); + } + }//GEN-LAST:event_driveListMouseClicked // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton browseButton; @@ -532,6 +543,7 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { private javax.swing.JTextField pathTextField; private javax.swing.JButton refreshButton; private javax.swing.JLabel selectDriveLabel; + private javax.swing.JLabel selectFolderLabel; private javax.swing.JLabel selectFromDriveLabel; // End of variables declaration//GEN-END:variables From 07ec6bdc3e9fa49092bfc1b0a26dd77ff16769a8 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Thu, 6 Jun 2019 11:09:28 -0400 Subject: [PATCH 045/115] Disable Interesting File buttons when no set is selected --- .../modules/interestingitems/FilesSetDefsPanel.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java index e919bf189f..d226e6765b 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java @@ -278,6 +278,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp //enable the new button FilesSetDefsPanel.this.newSetButton.setEnabled(canBeEnabled); FilesSetDefsPanel.this.importSetButton.setEnabled(canBeEnabled); + // Get the selected interesting files set and populate the set // components. FilesSet selectedSet = FilesSetDefsPanel.this.setsList.getSelectedValue(); @@ -302,6 +303,12 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp if (!FilesSetDefsPanel.this.rulesListModel.isEmpty()) { FilesSetDefsPanel.this.rulesList.setSelectedIndex(0); } + } else { + // Disable the edit, delete, copy, and export buttons + FilesSetDefsPanel.this.editSetButton.setEnabled(false); + FilesSetDefsPanel.this.deleteSetButton.setEnabled(false); + FilesSetDefsPanel.this.copySetButton.setEnabled(false); + FilesSetDefsPanel.this.exportSetButton.setEnabled(false); } } From f07c60c21582321c4e77e8ceb21dc8a089985580 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Thu, 6 Jun 2019 11:31:55 -0400 Subject: [PATCH 046/115] Fixed codacy issues and postgres problem --- .../casemodule/services/TagsManager.java | 12 +- .../ContentViewerTagManager.java | 122 ++++++++++----- .../contentviewers/MediaViewImagePanel.java | 142 +++++++++--------- .../contentviewers/imagetagging/ImageTag.java | 32 ++-- .../imagetagging/ImageTagCreator.java | 8 +- .../imagetagging/ImageTagsGroup.java | 4 +- .../imagetagging/ImageTagsUtility.java | 6 + 7 files changed, 195 insertions(+), 131 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index e328b572de..a86d2bdb81 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -42,6 +42,7 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; +import org.sleuthkit.datamodel.TskData.DbType; /** * A per case Autopsy service that manages the addition of content and artifact @@ -60,13 +61,16 @@ public class TagsManager implements Closeable { Case currentCase = (Case) evt.getNewValue(); try { CaseDbAccessManager caseDb = currentCase.getSleuthkitCase().getCaseDbAccessManager(); - //Create our custom application tags table, if need be. if (!caseDb.tableExists(ContentViewerTagManager.TABLE_NAME)) { - caseDb.createTable(ContentViewerTagManager.TABLE_NAME, ContentViewerTagManager.TABLE_SCHEMA); + if (currentCase.getSleuthkitCase().getDatabaseType().equals(DbType.SQLITE)) { + caseDb.createTable(ContentViewerTagManager.TABLE_NAME, ContentViewerTagManager.TABLE_SCHEMA_SQLITE); + } else if (currentCase.getSleuthkitCase().getDatabaseType().equals(DbType.POSTGRESQL)) { + caseDb.createTable(ContentViewerTagManager.TABLE_NAME, ContentViewerTagManager.TABLE_SCHEMA_POSTGRES); + } } } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, - String.format("Unable to create the %s table for image tag storage.", + LOGGER.log(Level.SEVERE, + String.format("Unable to create the %s table for image tag storage.", ContentViewerTagManager.TABLE_NAME), ex); } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ContentViewerTagManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ContentViewerTagManager.java index 33d7987d8a..d97bae73dc 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ContentViewerTagManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ContentViewerTagManager.java @@ -23,7 +23,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.ArrayList; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.datamodel.ContentTag; @@ -32,7 +31,8 @@ import org.sleuthkit.datamodel.TskCoreException; /** * A per case Autopsy service that manages the addition of content viewer tags * to the case database. This manager is also responsible for serializing and - * deserializing instances of your tag data objects for persistence and retrieval. + * deserializing instances of your tag data objects for persistence and + * retrieval. */ public class ContentViewerTagManager { @@ -41,7 +41,10 @@ public class ContentViewerTagManager { private static final ObjectMapper SERIALIZER = new ObjectMapper(); public static final String TABLE_NAME = "beta_tag_app_data"; - public static final String TABLE_SCHEMA = "(app_data_id INTEGER PRIMARY KEY, " + public static final String TABLE_SCHEMA_SQLITE = "(app_data_id INTEGER PRIMARY KEY, " + + "content_tag_id INTEGER NOT NULL, app_data TEXT NOT NULL, " + + "FOREIGN KEY(content_tag_id) REFERENCES content_tags(tag_id))"; + public static final String TABLE_SCHEMA_POSTGRES = "(app_data_id BIGSERIAL PRIMARY KEY, " + "content_tag_id INTEGER NOT NULL, app_data TEXT NOT NULL, " + "FOREIGN KEY(content_tag_id) REFERENCES content_tags(tag_id))"; @@ -55,8 +58,8 @@ public class ContentViewerTagManager { * generic tag data instance T will be automatically serialized into a * storable format. * - * @param Generic class type that will be serialized into a - * storable format for persistence. + * @param Generic class type that will be serialized into a storable + * format for persistence. * @param contentTag ContentTag that this ContentViewerTag is associated * with (1:1). * @param tagDataBean Data instance that contains the tag information to be @@ -64,20 +67,24 @@ public class ContentViewerTagManager { * @return An instance of a ContentViewerTag of type T, which contains all * the stored information. * - * @throws SerializationException Thrown if the tag data instance T - * could not be serialized into a storable format. + * @throws SerializationException Thrown if the tag data instance T could + * not be serialized into a storable format. * @throws TskCoreException Thrown if this operation did not successfully * persist in the case database. * @throws NoCurrentCaseException Thrown if invocation of this method occurs * when no case is open. */ - public static ContentViewerTag saveTag(ContentTag contentTag, T tagDataBean) throws SerializationException, TskCoreException, NoCurrentCaseException { + public static ContentViewerTag saveTag(ContentTag contentTag, T tagDataBean) + throws SerializationException, TskCoreException, NoCurrentCaseException { try { long contentTagId = contentTag.getId(); String serialAppData = SERIALIZER.writeValueAsString(tagDataBean); String insertTemplateInstance = String.format(INSERT_TAG_DATA, contentTagId, serialAppData); - long insertId = Case.getCurrentCaseThrows().getSleuthkitCase().getCaseDbAccessManager().insert(TABLE_NAME, insertTemplateInstance); + long insertId = Case.getCurrentCaseThrows() + .getSleuthkitCase() + .getCaseDbAccessManager() + .insert(TABLE_NAME, insertTemplateInstance); return new ContentViewerTag<>(insertId, contentTag, tagDataBean); } catch (JsonProcessingException ex) { throw new SerializationException("Unable to convert object instance into a storable format", ex); @@ -88,14 +95,14 @@ public class ContentViewerTagManager { * Updates the ContentViewerTag instance with the new tag data T and * persists the changes to the case database. * - * @param Generic class type that will be serialized into a - * storable format. + * @param Generic class type that will be serialized into a storable + * format. * @param oldTag ContentViewerTag instance to be updated * @param tagDataBean Data instance that contains the updated information to * be persisted. * - * @throws SerializationException Thrown if the tag data instance T - * could not be serialized into a storable format. + * @throws SerializationException Thrown if the tag data instance T could + * not be serialized into a storable format. * @throws TskCoreException Thrown if this operation did not successfully * persist in the case database. * @throws NoCurrentCaseException Thrown if invocation of this method occurs @@ -107,7 +114,9 @@ public class ContentViewerTagManager { String serialAppData = SERIALIZER.writeValueAsString(tagDataBean); String updateTemplateInstance = String.format(UPDATE_TAG_DATA, oldTag.getContentTag().getId(), serialAppData, oldTag.getId()); - Case.getCurrentCaseThrows().getSleuthkitCase().getCaseDbAccessManager() + Case.getCurrentCaseThrows() + .getSleuthkitCase() + .getCaseDbAccessManager() .update(TABLE_NAME, updateTemplateInstance); return new ContentViewerTag<>(oldTag.getId(), oldTag.getContentTag(), tagDataBean); } catch (JsonProcessingException ex) { @@ -137,31 +146,66 @@ public class ContentViewerTagManager { * when no case is open. */ public static ContentViewerTag getTag(ContentTag contentTag, Class clazz) throws TskCoreException, NoCurrentCaseException { - try { - String selectTemplateInstance = String.format(SELECT_TAG_DATA, contentTag.getId()); - final ArrayList> result = new ArrayList<>(); - Case.getCurrentCaseThrows().getSleuthkitCase().getCaseDbAccessManager() - .select(selectTemplateInstance, (ResultSet rs) -> { - try { - if (rs.next()) { - long tagId = rs.getLong(1); - String appDetails = rs.getString(3); - try { - T instance = SERIALIZER.readValue(appDetails, clazz); - result.add(new ContentViewerTag<>(tagId, contentTag, instance)); - } catch (IOException ex) { - //Databind for type T failed. Not a system error - //but rather a logic error on the part of the caller. - result.add(null); - } + String selectTemplateInstance = String.format(SELECT_TAG_DATA, contentTag.getId()); + final ResultWrapper> result = new ResultWrapper<>(); + Case.getCurrentCaseThrows() + .getSleuthkitCase() + .getCaseDbAccessManager() + .select(selectTemplateInstance, (ResultSet rs) -> { + try { + if (rs.next()) { + long tagId = rs.getLong(1); + String appDetails = rs.getString(3); + try { + T instance = SERIALIZER.readValue(appDetails, clazz); + result.setResult(new ContentViewerTag<>(tagId, contentTag, instance)); + } catch (IOException ex) { + //Databind for type T failed. Not a system error + //but rather a logic error on the part of the caller. + result.setResult(null); } - } catch (SQLException ex) { - throw new RuntimeException(ex); } - }); - return result.get(0); - } catch (RuntimeException ex) { - throw new TskCoreException("Unable to select tags from db", (Exception) ex.getCause()); + } catch (SQLException ex) { + result.setException(ex); + } + }); + + if (result.hasException()) { + throw new TskCoreException("Unable to select tag from case db", result.getException()); + } + + return result.getResult(); + } + + /** + * Wrapper for holding state in the CaseDbAccessQueryCallback. + * CaseDbAccessQueryCallback has no support for exception handling. + * + * @param + */ + private static class ResultWrapper { + + private T result; + private SQLException ex = null; + + public void setResult(T result) { + this.result = result; + } + + public void setException(SQLException ex) { + this.ex = ex; + } + + public boolean hasException() { + return this.ex != null; + } + + public SQLException getException() { + return ex; + } + + public T getResult() { + return result; } } @@ -176,7 +220,9 @@ public class ContentViewerTagManager { */ public static void deleteTag(ContentViewerTag contentViewerTag) throws TskCoreException, NoCurrentCaseException { String deleteTemplateInstance = String.format(DELETE_TAG_DATA, contentViewerTag.getId()); - Case.getCurrentCaseThrows().getSleuthkitCase().getCaseDbAccessManager() + Case.getCurrentCaseThrows() + .getSleuthkitCase() + .getCaseDbAccessManager() .delete(TABLE_NAME, deleteTemplateInstance); } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java index b4d1202f15..d9590059ea 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.contentviewers; +import com.sun.glass.events.KeyEvent; import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; @@ -64,6 +65,7 @@ import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JSeparator; +import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import org.apache.commons.io.FilenameUtils; @@ -205,68 +207,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan } }); - //Respond to state events by enabling/disabling the correct - //buttons. - pcs.addPropertyChangeListener((event) -> { - State currentState = (State) event.getNewValue(); - switch (currentState) { - case CREATE: - createTagMenuItem.setEnabled(true); - deleteTagMenuItem.setEnabled(false); - hideTagsMenuItem.setEnabled(true); - exportTagsMenuItem.setEnabled(true); - break; - case SELECTED: - if (masterGroup.getChildren().contains(imageTagCreator)) { - imageTagCreator.disconnect(); - masterGroup.getChildren().remove(imageTagCreator); - } - createTagMenuItem.setEnabled(false); - deleteTagMenuItem.setEnabled(true); - hideTagsMenuItem.setEnabled(true); - exportTagsMenuItem.setEnabled(true); - break; - case HIDDEN: - createTagMenuItem.setEnabled(false); - deleteTagMenuItem.setEnabled(false); - hideTagsMenuItem.setEnabled(true); - hideTagsMenuItem.setText(DisplayOptions.SHOW_TAGS.getName()); - exportTagsMenuItem.setEnabled(false); - break; - case VISIBLE: - createTagMenuItem.setEnabled(true); - deleteTagMenuItem.setEnabled(false); - hideTagsMenuItem.setEnabled(true); - hideTagsMenuItem.setText(DisplayOptions.HIDE_TAGS.getName()); - exportTagsMenuItem.setEnabled(true); - break; - case DEFAULT: - case EMPTY: - if (masterGroup.getChildren().contains(imageTagCreator)) { - imageTagCreator.disconnect(); - } - createTagMenuItem.setEnabled(true); - deleteTagMenuItem.setEnabled(false); - hideTagsMenuItem.setEnabled(false); - hideTagsMenuItem.setText(DisplayOptions.HIDE_TAGS.getName()); - exportTagsMenuItem.setEnabled(false); - break; - case NONEMPTY: - createTagMenuItem.setEnabled(true); - deleteTagMenuItem.setEnabled(false); - hideTagsMenuItem.setEnabled(true); - exportTagsMenuItem.setEnabled(true); - break; - case DISABLE: - createTagMenuItem.setEnabled(false); - deleteTagMenuItem.setEnabled(false); - hideTagsMenuItem.setEnabled(false); - exportTagsMenuItem.setEnabled(false); - break; - default: - break; - } - }); + subscribeTagMenuItemsToStateChanges(); masterGroup.getChildren().add(tagsGroup); @@ -276,13 +217,13 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan if (masterGroup.getChildren().contains(imageTagCreator)) { return; } - - if(tagsGroup.getChildren().isEmpty()) { + + if (tagsGroup.getChildren().isEmpty()) { pcs.firePropertyChange(new PropertyChangeEvent(this, - "state", null, State.EMPTY)); + "state", null, State.EMPTY)); } else { pcs.firePropertyChange(new PropertyChangeEvent(this, - "state", null, State.CREATE)); + "state", null, State.CREATE)); } } else if (event.getPropertyName().equals(ImageTagControls.FOCUSED.getName())) { pcs.firePropertyChange(new PropertyChangeEvent(this, @@ -311,6 +252,74 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan } } + /** + * Handle tags menu item enabling and disabling given the state of the + * content viewer. For example, when the tags group is empty (no tags on image), + * disable delete menu item, hide menu item, and export menu item. + */ + private void subscribeTagMenuItemsToStateChanges() { + pcs.addPropertyChangeListener((event) -> { + State currentState = (State) event.getNewValue(); + switch (currentState) { + case CREATE: + createTagMenuItem.setEnabled(true); + deleteTagMenuItem.setEnabled(false); + hideTagsMenuItem.setEnabled(true); + exportTagsMenuItem.setEnabled(true); + break; + case SELECTED: + if (masterGroup.getChildren().contains(imageTagCreator)) { + imageTagCreator.disconnect(); + masterGroup.getChildren().remove(imageTagCreator); + } + createTagMenuItem.setEnabled(false); + deleteTagMenuItem.setEnabled(true); + hideTagsMenuItem.setEnabled(true); + exportTagsMenuItem.setEnabled(true); + break; + case HIDDEN: + createTagMenuItem.setEnabled(false); + deleteTagMenuItem.setEnabled(false); + hideTagsMenuItem.setEnabled(true); + hideTagsMenuItem.setText(DisplayOptions.SHOW_TAGS.getName()); + exportTagsMenuItem.setEnabled(false); + break; + case VISIBLE: + createTagMenuItem.setEnabled(true); + deleteTagMenuItem.setEnabled(false); + hideTagsMenuItem.setEnabled(true); + hideTagsMenuItem.setText(DisplayOptions.HIDE_TAGS.getName()); + exportTagsMenuItem.setEnabled(true); + break; + case DEFAULT: + case EMPTY: + if (masterGroup.getChildren().contains(imageTagCreator)) { + imageTagCreator.disconnect(); + } + createTagMenuItem.setEnabled(true); + deleteTagMenuItem.setEnabled(false); + hideTagsMenuItem.setEnabled(false); + hideTagsMenuItem.setText(DisplayOptions.HIDE_TAGS.getName()); + exportTagsMenuItem.setEnabled(false); + break; + case NONEMPTY: + createTagMenuItem.setEnabled(true); + deleteTagMenuItem.setEnabled(false); + hideTagsMenuItem.setEnabled(true); + exportTagsMenuItem.setEnabled(true); + break; + case DISABLE: + createTagMenuItem.setEnabled(false); + deleteTagMenuItem.setEnabled(false); + hideTagsMenuItem.setEnabled(false); + exportTagsMenuItem.setEnabled(false); + break; + default: + break; + } + }); + } + public boolean isInited() { return fxInited; } @@ -710,7 +719,6 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan private void deleteTag() { Platform.runLater(() -> { ImageTag tagInFocus = tagsGroup.getFocus(); - //Null should not be expected, but just as a safetly precaution if (tagInFocus == null) { return; } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTag.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTag.java index 80b1cbe07f..765d98c4b2 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTag.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTag.java @@ -81,35 +81,35 @@ public final class ImageTag extends Group { EditHandle bottomLeft = new EditHandle(physicalTag) .setPosition(Position.bottom(), Position.left()) - .setDrag(dragBoundary, Drag.bottom(), Drag.left()); + .setDrag(dragBoundary, Draggable.bottom(), Draggable.left()); EditHandle bottomRight = new EditHandle(physicalTag) .setPosition(Position.bottom(), Position.right()) - .setDrag(dragBoundary, Drag.bottom(), Drag.right()); + .setDrag(dragBoundary, Draggable.bottom(), Draggable.right()); EditHandle topLeft = new EditHandle(physicalTag) .setPosition(Position.top(), Position.left()) - .setDrag(dragBoundary, Drag.top(), Drag.left()); + .setDrag(dragBoundary, Draggable.top(), Draggable.left()); EditHandle topRight = new EditHandle(physicalTag) .setPosition(Position.top(), Position.right()) - .setDrag(dragBoundary, Drag.top(), Drag.right()); + .setDrag(dragBoundary, Draggable.top(), Draggable.right()); EditHandle bottomMiddle = new EditHandle(physicalTag) .setPosition(Position.bottom(), Position.xMiddle()) - .setDrag(dragBoundary, Drag.bottom()); + .setDrag(dragBoundary, Draggable.bottom()); EditHandle topMiddle = new EditHandle(physicalTag) .setPosition(Position.top(), Position.xMiddle()) - .setDrag(dragBoundary, Drag.top()); + .setDrag(dragBoundary, Draggable.top()); EditHandle rightMiddle = new EditHandle(physicalTag) .setPosition(Position.right(), Position.yMiddle()) - .setDrag(dragBoundary, Drag.right()); + .setDrag(dragBoundary, Draggable.right()); EditHandle leftMiddle = new EditHandle(physicalTag) .setPosition(Position.left(), Position.yMiddle()) - .setDrag(dragBoundary, Drag.left()); + .setDrag(dragBoundary, Draggable.left()); //The "logical" tag is the Group this.getChildren().addAll(physicalTag, bottomLeft, bottomRight, topLeft, @@ -133,7 +133,7 @@ public final class ImageTag extends Group { } /** - * Get the app tag that this class represents. + * Get the content viewer tag that this class represents. * * @return */ @@ -226,9 +226,9 @@ public final class ImageTag extends Group { * @param vals * @return */ - public EditHandle setDrag(Boundary bounds, Drag... vals) { + public EditHandle setDrag(Boundary bounds, Draggable... vals) { this.setOnMouseDragged((event) -> { - for (Drag drag : vals) { + for (Draggable drag : vals) { drag.perform(parent, event, bounds); } }); @@ -282,11 +282,11 @@ public final class ImageTag extends Group { * Drag strategies for manipulating the physical tag from a given side of * the rectangle. */ - static interface Drag { + static interface Draggable { void perform(PhysicalTag parent, MouseEvent event, Boundary b); - static Drag bottom() { + static Draggable bottom() { return (parent, event, bounds) -> { if (!bounds.isPointInBounds(event.getX(), event.getY())) { return; @@ -299,7 +299,7 @@ public final class ImageTag extends Group { }; } - static Drag top() { + static Draggable top() { return (parent, event, bounds) -> { if (!bounds.isPointInBounds(event.getX(), event.getY())) { return; @@ -313,7 +313,7 @@ public final class ImageTag extends Group { }; } - static Drag left() { + static Draggable left() { return (parent, event, bounds) -> { if (!bounds.isPointInBounds(event.getX(), event.getY())) { return; @@ -327,7 +327,7 @@ public final class ImageTag extends Group { }; } - static Drag right() { + static Draggable right() { return (parent, event, bounds) -> { if (!bounds.isPointInBounds(event.getX(), event.getY())) { return; diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagCreator.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagCreator.java index 4df4328b2d..b2500baa24 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagCreator.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagCreator.java @@ -41,7 +41,7 @@ public final class ImageTagCreator extends Rectangle { //Rectangle lines should be 1.5% of the image. This level of thickness has //a good balance between visual acuity and loss of selection at the borders //of the image. - private double lineThicknessAsPercent = 1.5; + private final double lineThicknessAsPercent = 1.5; private final double minArea; //Used to update listeners of the new tag boundaries @@ -53,7 +53,7 @@ public final class ImageTagCreator extends Rectangle { //Handles the unregistering this ImageTagCreator from mouse press, mouse drag, //and mouse release events of the source image. - private final Runnable disconnect; + private final Runnable disconnectRunnable; /** * Adds tagging support to an image, where the 'tag' rectangle will be the @@ -143,7 +143,7 @@ public final class ImageTagCreator extends Rectangle { image.addEventHandler(MouseEvent.MOUSE_RELEASED, this.mouseReleased); //Used to remove itself from mouse events on the source image - disconnect = () -> { + disconnectRunnable = () -> { defaultSettings(); image.removeEventHandler(MouseEvent.MOUSE_RELEASED, mouseReleased); image.removeEventHandler(MouseEvent.MOUSE_DRAGGED, mouseDragged); @@ -166,7 +166,7 @@ public final class ImageTagCreator extends Rectangle { * Removes itself from mouse events on the source image. */ public void disconnect() { - this.disconnect.run(); + this.disconnectRunnable.run(); } /** diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsGroup.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsGroup.java index fcbbb145bd..a9f23304a3 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsGroup.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsGroup.java @@ -119,9 +119,9 @@ public final class ImageTagsGroup extends Group { * @param n */ private void requestFocus(ImageTag n) { - if (currentFocus == n) { + if (n.equals(currentFocus)) { return; - } else if (currentFocus != null && currentFocus != n) { + } else if (currentFocus != null && !currentFocus.equals(n)) { resetFocus(currentFocus); } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsUtility.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsUtility.java index 67ec058c84..36982afec1 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsUtility.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsUtility.java @@ -28,6 +28,9 @@ import org.opencv.highgui.Highgui; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TskCoreException; +/** + * Utility class for handling content viewer tags on images. + */ public class ImageTagsUtility { /** @@ -63,4 +66,7 @@ public class ImageTagsUtility { return output; } + + private ImageTagsUtility(){ + } } From d7daf2b38370899cb2d35d1a14053c54932e9744 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Thu, 6 Jun 2019 11:48:50 -0400 Subject: [PATCH 047/115] Removed unused imports --- .../sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java index d9590059ea..f4af5752b9 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.contentviewers; -import com.sun.glass.events.KeyEvent; import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; @@ -65,7 +64,6 @@ import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JSeparator; -import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import org.apache.commons.io.FilenameUtils; From e2ded8a6454f0dfc9f613be9396c4ee153a069af Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Thu, 6 Jun 2019 11:56:54 -0400 Subject: [PATCH 048/115] Fixed new round of codacy issues and renamed package to reflect naming conventions --- .../autopsy/casemodule/services/TagsManager.java | 16 +++++++++------- .../ContentViewerTagManager.java | 4 ++-- .../contentviewers/MediaViewImagePanel.java | 6 +++--- .../contentviewers/imagetagging/ImageTag.java | 2 +- .../imagetagging/ImageTagCreator.java | 2 +- .../imagetagging/ImageTagsUtility.java | 2 +- 6 files changed, 17 insertions(+), 15 deletions(-) rename Core/src/org/sleuthkit/autopsy/casemodule/services/{applicationtags => contentviewertags}/ContentViewerTagManager.java (98%) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index a86d2bdb81..40597e9af3 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -31,7 +31,7 @@ import java.util.logging.Level; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.casemodule.services.applicationtags.ContentViewerTagManager; +import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifactTag; @@ -61,12 +61,14 @@ public class TagsManager implements Closeable { Case currentCase = (Case) evt.getNewValue(); try { CaseDbAccessManager caseDb = currentCase.getSleuthkitCase().getCaseDbAccessManager(); - if (!caseDb.tableExists(ContentViewerTagManager.TABLE_NAME)) { - if (currentCase.getSleuthkitCase().getDatabaseType().equals(DbType.SQLITE)) { - caseDb.createTable(ContentViewerTagManager.TABLE_NAME, ContentViewerTagManager.TABLE_SCHEMA_SQLITE); - } else if (currentCase.getSleuthkitCase().getDatabaseType().equals(DbType.POSTGRESQL)) { - caseDb.createTable(ContentViewerTagManager.TABLE_NAME, ContentViewerTagManager.TABLE_SCHEMA_POSTGRES); - } + if (caseDb.tableExists(ContentViewerTagManager.TABLE_NAME)) { + return; + } + + if (currentCase.getSleuthkitCase().getDatabaseType().equals(DbType.SQLITE)) { + caseDb.createTable(ContentViewerTagManager.TABLE_NAME, ContentViewerTagManager.TABLE_SCHEMA_SQLITE); + } else if (currentCase.getSleuthkitCase().getDatabaseType().equals(DbType.POSTGRESQL)) { + caseDb.createTable(ContentViewerTagManager.TABLE_NAME, ContentViewerTagManager.TABLE_SCHEMA_POSTGRESQL); } } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ContentViewerTagManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/contentviewertags/ContentViewerTagManager.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ContentViewerTagManager.java rename to Core/src/org/sleuthkit/autopsy/casemodule/services/contentviewertags/ContentViewerTagManager.java index d97bae73dc..8d117e908b 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/applicationtags/ContentViewerTagManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/contentviewertags/ContentViewerTagManager.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.casemodule.services.applicationtags; +package org.sleuthkit.autopsy.casemodule.services.contentviewertags; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; @@ -44,7 +44,7 @@ public class ContentViewerTagManager { public static final String TABLE_SCHEMA_SQLITE = "(app_data_id INTEGER PRIMARY KEY, " + "content_tag_id INTEGER NOT NULL, app_data TEXT NOT NULL, " + "FOREIGN KEY(content_tag_id) REFERENCES content_tags(tag_id))"; - public static final String TABLE_SCHEMA_POSTGRES = "(app_data_id BIGSERIAL PRIMARY KEY, " + public static final String TABLE_SCHEMA_POSTGRESQL = "(app_data_id BIGSERIAL PRIMARY KEY, " + "content_tag_id INTEGER NOT NULL, app_data TEXT NOT NULL, " + "FOREIGN KEY(content_tag_id) REFERENCES content_tags(tag_id))"; diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java index f4af5752b9..3f33d8ff47 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java @@ -74,9 +74,9 @@ import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog; import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog.TagNameAndComment; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.casemodule.services.applicationtags.ContentViewerTagManager; -import org.sleuthkit.autopsy.casemodule.services.applicationtags.ContentViewerTagManager.ContentViewerTag; -import org.sleuthkit.autopsy.casemodule.services.applicationtags.ContentViewerTagManager.SerializationException; +import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager; +import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager.ContentViewerTag; +import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager.SerializationException; import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagsUtility; import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagControls; import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagRegion; diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTag.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTag.java index 765d98c4b2..10708f9d1a 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTag.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTag.java @@ -32,7 +32,7 @@ import javafx.scene.input.MouseEvent; import javafx.scene.paint.Color; import javafx.scene.shape.Circle; import javafx.scene.shape.Rectangle; -import org.sleuthkit.autopsy.casemodule.services.applicationtags.ContentViewerTagManager.ContentViewerTag; +import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager.ContentViewerTag; /** * A tagged region displayed over an image. This class contains a "physical tag" diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagCreator.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagCreator.java index b2500baa24..885dd6c18f 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagCreator.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagCreator.java @@ -41,7 +41,7 @@ public final class ImageTagCreator extends Rectangle { //Rectangle lines should be 1.5% of the image. This level of thickness has //a good balance between visual acuity and loss of selection at the borders //of the image. - private final double lineThicknessAsPercent = 1.5; + private final static double lineThicknessAsPercent = 1.5; private final double minArea; //Used to update listeners of the new tag boundaries diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsUtility.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsUtility.java index 36982afec1..1d1d164e2f 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsUtility.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsUtility.java @@ -31,7 +31,7 @@ import org.sleuthkit.datamodel.TskCoreException; /** * Utility class for handling content viewer tags on images. */ -public class ImageTagsUtility { +public final class ImageTagsUtility { /** * Embeds the tag regions into an image (represented as an AbstractFile). From 65bf9cc4970a9323f5a822496e970c57c432797d Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 6 Jun 2019 12:52:09 -0400 Subject: [PATCH 049/115] 5061 log unlogged exceptions, fix copy paste and typo comment errors --- .../translators/BingTranslator.java | 2 +- .../translators/BingTranslatorSettings.java | 4 ++-- .../translators/BingTranslatorSettingsPanel.java | 16 +++++++--------- .../translators/GoogleTranslator.java | 2 ++ 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java index 4c2526ab9b..2b234f71d3 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java @@ -71,7 +71,7 @@ public class BingTranslator implements TextTranslator { } /** - * Converts an input test to the JSON format required by Bing Translator, + * Converts an input text to the JSON format required by Bing Translator, * posts it to Microsoft, and returns the JSON text response. * * @param string The input text to be translated. diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettings.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettings.java index dcd54fd6f9..d00ed61f77 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettings.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettings.java @@ -22,7 +22,7 @@ import org.apache.commons.lang3.StringUtils; import org.sleuthkit.autopsy.coreutils.ModuleSettings; /** - * Class to handle the settings associated with the GoogleTranslator + * Class to handle the settings associated with the BingTranslator */ public final class BingTranslatorSettings { @@ -35,7 +35,7 @@ public final class BingTranslatorSettings { private String targetLanguageCode; /** - * Construct a new GoogleTranslatorSettingsObject + * Construct a new BingTranslatorSettings object */ BingTranslatorSettings() { loadSettings(); diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java index cb115354e2..9df244d034 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java @@ -36,7 +36,7 @@ import org.apache.commons.lang3.StringUtils; import org.openide.util.NbBundle.Messages; /** - * Settings panel for the GoogleTranslator + * Settings panel for the BingTranslator */ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { @@ -47,7 +47,7 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { private String targetLanguageCode = ""; /** - * Creates new form GoogleTranslatorSettingsPanel + * Creates new form BingTranslatorSettingsPanel */ public BingTranslatorSettingsPanel(String authenticationKey, String code) { initComponents(); @@ -254,16 +254,13 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { private javax.swing.JLabel untranslatedLabel; private javax.swing.JLabel warningLabel; // End of variables declaration//GEN-END:variables + /** - * Converts an input test to the JSON format required by Bing Translator, - * posts it to Microsoft, and returns the JSON text response. + * Attempts to translate the text specified in the Untranslated field using + * the settings currently specified but not necessarily saved * - * @param string The input text to be translated. + * @return true if the translation was able to be performed, false otherwise * - * @return The translation response as a JSON string - * - * @throws IOException if the request could not be executed due to - * cancellation, a connectivity problem or timeout. */ private boolean testTranslationSetup() { testResultValueLabel.setText(""); @@ -291,6 +288,7 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { testResultValueLabel.setText(translation0.get("text").getAsString()); return true; } catch (IOException | IllegalStateException | ClassCastException | NullPointerException | IndexOutOfBoundsException e) { + logger.log(Level.WARNING, "Test of Bing Translator failed due to exception", ex); return false; } } diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslator.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslator.java index de61222072..46bdd6da67 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslator.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslator.java @@ -73,8 +73,10 @@ public final class GoogleTranslator implements TextTranslator { address = InetAddress.getByName(host); return address.isReachable(1500); } catch (UnknownHostException ex) { + logger.log(Level.WARNING, "Unable to reach google.com due to unknown host", ex); return false; } catch (IOException ex) { + logger.log(Level.WARNING, "Unable to reach google.com due IOException", ex); return false; } } From 3610495657754e2850886dd19a09d673f5aeef0f Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 6 Jun 2019 12:54:50 -0400 Subject: [PATCH 050/115] 5061 fix typo in exception variable name --- .../translators/BingTranslatorSettingsPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java index 9df244d034..1be932873c 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java @@ -288,7 +288,7 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { testResultValueLabel.setText(translation0.get("text").getAsString()); return true; } catch (IOException | IllegalStateException | ClassCastException | NullPointerException | IndexOutOfBoundsException e) { - logger.log(Level.WARNING, "Test of Bing Translator failed due to exception", ex); + logger.log(Level.WARNING, "Test of Bing Translator failed due to exception", e); return false; } } From 2823ef0396924550e9e0a33c9501fb1dd36c54f5 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 6 Jun 2019 13:55:07 -0400 Subject: [PATCH 051/115] Disabled 'Text' content viewer tab for diectories and empty files --- .../textcontentviewer/TextContentViewer.java | 12 ++++++++++++ .../textcontentviewer/TextContentViewerPanel.java | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/textcontentviewer/TextContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/textcontentviewer/TextContentViewer.java index 81384acbaa..d7f853caab 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/textcontentviewer/TextContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/textcontentviewer/TextContentViewer.java @@ -23,6 +23,7 @@ import org.openide.nodes.Node; import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; +import org.sleuthkit.datamodel.AbstractFile; /** * A DataContentViewer that displays text with the TextViewers available. @@ -90,6 +91,17 @@ public class TextContentViewer implements DataContentViewer { if (node == null) { return false; } + // get the node's File, if it has one + AbstractFile file = node.getLookup().lookup(AbstractFile.class); + if (file == null) { + return false; + } + + // disable the text content viewer for directories and empty files + if (file.isDir() || file.getSize() == 0) { + return false; + } + return panel.isSupported(node); } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/textcontentviewer/TextContentViewerPanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/textcontentviewer/TextContentViewerPanel.java index e1af060cfc..7c80d606fd 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/textcontentviewer/TextContentViewerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/textcontentviewer/TextContentViewerPanel.java @@ -79,7 +79,7 @@ public class TextContentViewerPanel extends javax.swing.JPanel implements DataCo } /** - * Deterime wether the content viewer which displays this panel isSupported. + * Determine whether the content viewer which displays this panel isSupported. * This panel is supported if any of the TextViewer's displayed in it are * supported. * From ae0aeddc5fa73266597cca05d540bf0740c7f400 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Thu, 6 Jun 2019 14:07:33 -0400 Subject: [PATCH 052/115] cleanup --- .../org/sleuthkit/autopsy/directorytree/ExportCSVAction.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java index 7fa4560afc..4a87f72828 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java @@ -60,7 +60,7 @@ public final class ExportCSVAction extends AbstractAction { private final static String DEFAULT_FILENAME = "Results"; private final static List columnsToSkip = Arrays.asList("S", "C", "O"); - private static volatile String userDefinedExportPath; // TODO make volatile or whatever + private static String userDefinedExportPath; // This class is a singleton to support multi-selection of nodes, since // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every @@ -219,7 +219,7 @@ public final class ExportCSVAction extends AbstractAction { * @param exportPath The export path. * @param openCase The current case. */ - private static void updateExportDirectory(String exportPath, Case openCase) { // TODO sync + private static void updateExportDirectory(String exportPath, Case openCase) { if (exportPath.equalsIgnoreCase(openCase.getExportDirectory())) { userDefinedExportPath = null; } else { From 1285e914f24d6b13bdf81f072185009546de8f90 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 6 Jun 2019 14:28:11 -0400 Subject: [PATCH 053/115] 5129 add new labels for instructions --- .../BingTranslatorSettingsPanel.form | 93 +++++++++++++------ .../BingTranslatorSettingsPanel.java | 64 ++++++++----- .../translators/Bundle.properties | 2 + .../translators/Bundle.properties-MERGED | 1 + .../GoogleTranslatorSettingsPanel.form | 60 ++++++++++-- .../GoogleTranslatorSettingsPanel.java | 44 ++++++++- .../texttranslation/ui/Bundle.properties | 1 + .../ui/Bundle.properties-MERGED | 1 + .../ui/TranslationOptionsPanel.form | 24 +++-- .../ui/TranslationOptionsPanel.java | 13 ++- 10 files changed, 233 insertions(+), 70 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form index cd855ac419..44ca6e1c39 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.form @@ -16,50 +16,54 @@ - - + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + + - + + + @@ -79,7 +83,7 @@ - + @@ -168,5 +172,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java index 1be932873c..9cc6ae560c 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslatorSettingsPanel.java @@ -135,6 +135,8 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { resultLabel = new javax.swing.JLabel(); testResultValueLabel = new javax.swing.JLabel(); authenticationKeyLabel = new javax.swing.JLabel(); + instructionsScrollPane = new javax.swing.JScrollPane(); + instructionsTextArea = new javax.swing.JTextArea(); authenticationKeyField.setToolTipText(org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "BingTranslatorSettingsPanel.authenticationKeyField.toolTipText")); // NOI18N @@ -167,6 +169,19 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { org.openide.awt.Mnemonics.setLocalizedText(authenticationKeyLabel, org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "BingTranslatorSettingsPanel.authenticationKeyLabel.text")); // NOI18N + instructionsScrollPane.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + instructionsScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + + instructionsTextArea.setEditable(false); + instructionsTextArea.setBackground(new java.awt.Color(240, 240, 240)); + instructionsTextArea.setColumns(20); + instructionsTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N + instructionsTextArea.setLineWrap(true); + instructionsTextArea.setRows(2); + instructionsTextArea.setText(org.openide.util.NbBundle.getMessage(BingTranslatorSettingsPanel.class, "BingTranslatorSettingsPanel.instructionsTextArea.text")); // NOI18N + instructionsTextArea.setWrapStyleWord(true); + instructionsScrollPane.setViewportView(instructionsTextArea); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -174,37 +189,40 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(instructionsScrollPane) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(warningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 551, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(layout.createSequentialGroup() - .addComponent(targetLanguageLabel) - .addGap(18, 18, 18) - .addComponent(targetLanguageComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 192, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addGap(0, 0, Short.MAX_VALUE)) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(authenticationKeyLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(authenticationKeyField, javax.swing.GroupLayout.PREFERRED_SIZE, 486, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 20, Short.MAX_VALUE)) + .addComponent(authenticationKeyField, javax.swing.GroupLayout.PREFERRED_SIZE, 486, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(warningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 551, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(layout.createSequentialGroup() - .addComponent(testButton, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(25, 25, 25) - .addComponent(untranslatedLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(testUntranslatedTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 140, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(resultLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(testResultValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) - .addContainerGap()))) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(targetLanguageLabel) + .addComponent(testButton, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(18, 18, 18) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(untranslatedLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 66, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(testUntranslatedTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 140, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(resultLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(testResultValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(layout.createSequentialGroup() + .addComponent(targetLanguageComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGap(276, 276, 276))))) + .addGap(0, 0, Short.MAX_VALUE))) + .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addContainerGap() + .addComponent(instructionsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(authenticationKeyField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(authenticationKeyLabel)) @@ -221,7 +239,7 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { .addComponent(testResultValueLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(warningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap()) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -245,6 +263,8 @@ public class BingTranslatorSettingsPanel extends javax.swing.JPanel { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JTextField authenticationKeyField; private javax.swing.JLabel authenticationKeyLabel; + private javax.swing.JScrollPane instructionsScrollPane; + private javax.swing.JTextArea instructionsTextArea; private javax.swing.JLabel resultLabel; private javax.swing.JComboBox targetLanguageComboBox; private javax.swing.JLabel targetLanguageLabel; diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties index 0021118e14..9cc11dd938 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties @@ -13,3 +13,5 @@ GoogleTranslatorSettingsPanel.untranslatedLabel.text=Untranslated: GoogleTranslatorSettingsPanel.resultLabel.text=Result: GoogleTranslatorSettingsPanel.testResultValueLabel.text= BingTranslatorSettingsPanel.authenticationKeyLabel.text=Authentication Key: +BingTranslatorSettingsPanel.instructionsTextArea.text=You will need to provide a Microsoft Translation authenitcation key for your Microsoft Translation account. Instruction on how to create one are available here: +GoogleTranslatorSettingsPanel.instructionsTextArea.text=You will need a JSON credentials file which contains your service account key for your Google Translate account. Information on how to create a service account key is available here: https://cloud.google.com/iam/docs/creating-managing-service-account-keys diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED index 51cbb9a26f..3cc13aa983 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED @@ -26,3 +26,4 @@ GoogleTranslatorSettingsPanel.untranslatedLabel.text=Untranslated: GoogleTranslatorSettingsPanel.resultLabel.text=Result: GoogleTranslatorSettingsPanel.testResultValueLabel.text= BingTranslatorSettingsPanel.authenticationKeyLabel.text=Authentication Key: +GoogleTranslatorSettingsPanel.jTextArea1.text=You will need a JSON credentials file which contains your service account key for your Google Translate account. Information on how to create a service account key is available here: https://cloud.google.com/iam/docs/creating-managing-service-account-keys diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.form index b55a40b30f..cf280d463c 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.form @@ -16,9 +16,13 @@ - - + + + + + + @@ -27,7 +31,7 @@ - + @@ -38,7 +42,6 @@ - @@ -50,6 +53,10 @@ + + + + @@ -58,17 +65,19 @@ + + - + - + @@ -78,6 +87,7 @@ + @@ -94,6 +104,9 @@ + + + @@ -175,5 +188,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java index 84fad9e8e1..23aaf0902a 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java @@ -196,10 +196,17 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { untranslatedLabel = new javax.swing.JLabel(); testUntranslatedTextField = new javax.swing.JTextField(); testButton = new javax.swing.JButton(); + instructionsScrollPane = new javax.swing.JScrollPane(); + instructionsTextArea = new javax.swing.JTextArea(); org.openide.awt.Mnemonics.setLocalizedText(credentialsLabel, org.openide.util.NbBundle.getMessage(GoogleTranslatorSettingsPanel.class, "GoogleTranslatorSettingsPanel.credentialsLabel.text")); // NOI18N credentialsPathField.setEditable(false); + credentialsPathField.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + credentialsPathFieldActionPerformed(evt); + } + }); org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(GoogleTranslatorSettingsPanel.class, "GoogleTranslatorSettingsPanel.browseButton.text")); // NOI18N browseButton.addActionListener(new java.awt.event.ActionListener() { @@ -234,6 +241,19 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { } }); + instructionsScrollPane.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + instructionsScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + + instructionsTextArea.setEditable(false); + instructionsTextArea.setBackground(new java.awt.Color(240, 240, 240)); + instructionsTextArea.setColumns(20); + instructionsTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N + instructionsTextArea.setLineWrap(true); + instructionsTextArea.setRows(2); + instructionsTextArea.setText(org.openide.util.NbBundle.getMessage(GoogleTranslatorSettingsPanel.class, "GoogleTranslatorSettingsPanel.instructionsTextArea.text")); // NOI18N + instructionsTextArea.setWrapStyleWord(true); + instructionsScrollPane.setViewportView(instructionsTextArea); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -241,6 +261,9 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(instructionsScrollPane) + .addContainerGap()) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addComponent(credentialsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) @@ -248,14 +271,13 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(credentialsPathField, javax.swing.GroupLayout.DEFAULT_SIZE, 451, Short.MAX_VALUE) + .addComponent(credentialsPathField) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(browseButton) .addGap(14, 14, 14)) .addGroup(layout.createSequentialGroup() .addComponent(targetLanguageComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 317, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(0, 0, Short.MAX_VALUE)))) - .addComponent(warningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 551, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(layout.createSequentialGroup() .addComponent(testButton, javax.swing.GroupLayout.PREFERRED_SIZE, 83, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) @@ -265,12 +287,17 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(resultLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(testResultValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) + .addComponent(testResultValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(layout.createSequentialGroup() + .addComponent(warningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 551, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() + .addComponent(instructionsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(credentialsLabel) .addComponent(credentialsPathField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) @@ -279,7 +306,7 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(targetLanguageLabel) .addComponent(targetLanguageComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 15, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(testButton) .addComponent(testUntranslatedTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) @@ -287,7 +314,8 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { .addComponent(resultLabel) .addComponent(testResultValueLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(warningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(warningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -327,10 +355,16 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { } }//GEN-LAST:event_testButtonActionPerformed + private void credentialsPathFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_credentialsPathFieldActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_credentialsPathFieldActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton browseButton; private javax.swing.JLabel credentialsLabel; private javax.swing.JTextField credentialsPathField; + private javax.swing.JScrollPane instructionsScrollPane; + private javax.swing.JTextArea instructionsTextArea; private javax.swing.JLabel resultLabel; private javax.swing.JComboBox targetLanguageComboBox; private javax.swing.JLabel targetLanguageLabel; diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/ui/Bundle.properties b/Core/src/org/sleuthkit/autopsy/texttranslation/ui/Bundle.properties index 08c2523b0f..9f01ce498c 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/ui/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/ui/Bundle.properties @@ -6,3 +6,4 @@ TranslationContentPanel.ocrLabel.text=OCR: TranslationOptionsPanel.translationServiceLabel.text=Text translator: TranslationOptionsPanelController.moduleErr=Module Error TranslationOptionsPanelController.moduleErr.msg=A module caused an error listening to TranslationSettingsPanelController updates. See log to determine which module. Some data could be incomplete. +TranslationOptionsPanel.translationOptionsDescription.text=Configure a 3rd party text translation service to enable text and file name translation. diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/texttranslation/ui/Bundle.properties-MERGED index 0304d7b1f3..00718e5aa1 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/ui/Bundle.properties-MERGED @@ -25,3 +25,4 @@ TranslationOptionsPanel.translationDisabled.text=Translation disabled TranslationOptionsPanel.translationServiceLabel.text=Text translator: TranslationOptionsPanelController.moduleErr=Module Error TranslationOptionsPanelController.moduleErr.msg=A module caused an error listening to TranslationSettingsPanelController updates. See log to determine which module. Some data could be incomplete. +TranslationOptionsPanel.translationOptionsDescription.text=Configure a 3rd party text translation service to enable text and file name translation. diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/ui/TranslationOptionsPanel.form b/Core/src/org/sleuthkit/autopsy/texttranslation/ui/TranslationOptionsPanel.form index 20f5daa7f5..8705086cfe 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/ui/TranslationOptionsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/ui/TranslationOptionsPanel.form @@ -19,13 +19,14 @@ - + + - + - + - + @@ -34,14 +35,16 @@ - + + + - + - + @@ -66,5 +69,12 @@ + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/ui/TranslationOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/texttranslation/ui/TranslationOptionsPanel.java index 705ca45d84..b742f51be0 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/ui/TranslationOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/ui/TranslationOptionsPanel.java @@ -145,6 +145,7 @@ public class TranslationOptionsPanel extends javax.swing.JPanel { translatorComboBox = new javax.swing.JComboBox<>(); translationServiceLabel = new javax.swing.JLabel(); translationServicePanel = new javax.swing.JPanel(); + translationOptionsDescription = new javax.swing.JLabel(); translatorComboBox.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -156,6 +157,8 @@ public class TranslationOptionsPanel extends javax.swing.JPanel { translationServicePanel.setLayout(new java.awt.BorderLayout()); + org.openide.awt.Mnemonics.setLocalizedText(translationOptionsDescription, org.openide.util.NbBundle.getMessage(TranslationOptionsPanel.class, "TranslationOptionsPanel.translationOptionsDescription.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -163,18 +166,21 @@ public class TranslationOptionsPanel extends javax.swing.JPanel { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(translationServicePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() .addComponent(translationServiceLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGap(10, 10, 10) .addComponent(translatorComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 214, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 162, Short.MAX_VALUE)) - .addComponent(translationServicePanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGap(0, 0, Short.MAX_VALUE)) + .addComponent(translationOptionsDescription, javax.swing.GroupLayout.DEFAULT_SIZE, 462, Short.MAX_VALUE)) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() + .addComponent(translationOptionsDescription, javax.swing.GroupLayout.PREFERRED_SIZE, 15, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(translatorComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(translationServiceLabel)) @@ -190,6 +196,7 @@ public class TranslationOptionsPanel extends javax.swing.JPanel { // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel translationOptionsDescription; private javax.swing.JLabel translationServiceLabel; private javax.swing.JPanel translationServicePanel; private javax.swing.JComboBox translatorComboBox; From 6b5fc4af0e96cbdcae13821a58b6081c66fc0bd5 Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 6 Jun 2019 14:46:54 -0400 Subject: [PATCH 054/115] 5079: Ingest multiple vcards from a vcf file --- .../org/sleuthkit/autopsy/thunderbirdparser/VcardParser.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/VcardParser.java b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/VcardParser.java index 15d52b536e..7e5a321313 100755 --- a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/VcardParser.java +++ b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/VcardParser.java @@ -143,8 +143,9 @@ final class VcardParser { * @throws NoCurrentCaseException If there is no open case. */ void parse(File vcardFile, AbstractFile abstractFile) throws IOException, NoCurrentCaseException { - VCard vcard = Ezvcard.parse(vcardFile).first(); - addContactArtifact(vcard, abstractFile); + for (VCard vcard: Ezvcard.parse(vcardFile).all()) { + addContactArtifact(vcard, abstractFile); + } } From a7afef0e68af25ad6e78b0d697ed5841d9056340 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 6 Jun 2019 14:47:31 -0400 Subject: [PATCH 055/115] Fixed bug which was allocating too much memory to byte buffers --- .../autopsy/texttranslation/ui/TranslatedTextViewer.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/ui/TranslatedTextViewer.java b/Core/src/org/sleuthkit/autopsy/texttranslation/ui/TranslatedTextViewer.java index e9656bb0a9..4b284c53fa 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/ui/TranslatedTextViewer.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/ui/TranslatedTextViewer.java @@ -296,8 +296,8 @@ public final class TranslatedTextViewer implements TextViewer { //Correct for UTF-8 byte[] resultInUTF8Bytes = result.getBytes("UTF8"); - byte[] trimTo1MB = Arrays.copyOfRange(resultInUTF8Bytes, 0, MAX_SIZE_1MB ); - return new String(trimTo1MB, "UTF-8"); + byte[] trimToArraySize = Arrays.copyOfRange(resultInUTF8Bytes, 0, Math.min(resultInUTF8Bytes.length, MAX_SIZE_1MB) ); + return new String(trimToArraySize, "UTF-8"); } /** @@ -343,7 +343,7 @@ public final class TranslatedTextViewer implements TextViewer { } // The trim is on here because HTML files were observed with nearly 1MB of white space at the end - return textBuilder.toString().trim(); + return textBuilder.toString(); } /** From d4514e7f3bd3f02d14ce2f072358009115329ddc Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 6 Jun 2019 15:04:49 -0400 Subject: [PATCH 056/115] 5129 reword translator instructions --- .../autopsy/texttranslation/translators/Bundle.properties | 2 +- .../texttranslation/translators/Bundle.properties-MERGED | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties index 9cc11dd938..b09c2ae682 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties @@ -13,5 +13,5 @@ GoogleTranslatorSettingsPanel.untranslatedLabel.text=Untranslated: GoogleTranslatorSettingsPanel.resultLabel.text=Result: GoogleTranslatorSettingsPanel.testResultValueLabel.text= BingTranslatorSettingsPanel.authenticationKeyLabel.text=Authentication Key: -BingTranslatorSettingsPanel.instructionsTextArea.text=You will need to provide a Microsoft Translation authenitcation key for your Microsoft Translation account. Instruction on how to create one are available here: +BingTranslatorSettingsPanel.instructionsTextArea.text=You will need to provide a Microsoft Translator authentication key for your Microsoft Translator account. Instructions on how to get one are available here: https://docs.microsoft.com/en-us/azure/cognitive-services/translator/translator-text-how-to-signup GoogleTranslatorSettingsPanel.instructionsTextArea.text=You will need a JSON credentials file which contains your service account key for your Google Translate account. Information on how to create a service account key is available here: https://cloud.google.com/iam/docs/creating-managing-service-account-keys diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED index 3cc13aa983..4c32b7abab 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/Bundle.properties-MERGED @@ -26,4 +26,5 @@ GoogleTranslatorSettingsPanel.untranslatedLabel.text=Untranslated: GoogleTranslatorSettingsPanel.resultLabel.text=Result: GoogleTranslatorSettingsPanel.testResultValueLabel.text= BingTranslatorSettingsPanel.authenticationKeyLabel.text=Authentication Key: -GoogleTranslatorSettingsPanel.jTextArea1.text=You will need a JSON credentials file which contains your service account key for your Google Translate account. Information on how to create a service account key is available here: https://cloud.google.com/iam/docs/creating-managing-service-account-keys +BingTranslatorSettingsPanel.instructionsTextArea.text=You will need to provide a Microsoft Translator authentication key for your Microsoft Translator account. Instructions on how to get one are available here: https://docs.microsoft.com/en-us/azure/cognitive-services/translator/translator-text-how-to-signup +GoogleTranslatorSettingsPanel.instructionsTextArea.text=You will need a JSON credentials file which contains your service account key for your Google Translate account. Information on how to create a service account key is available here: https://cloud.google.com/iam/docs/creating-managing-service-account-keys From e837513c91a7d94ea4715b7c13fe641807ca6ffd Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Fri, 7 Jun 2019 10:09:06 -0400 Subject: [PATCH 057/115] Removed a comment --- .../autopsy/texttranslation/ui/TranslatedTextViewer.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/ui/TranslatedTextViewer.java b/Core/src/org/sleuthkit/autopsy/texttranslation/ui/TranslatedTextViewer.java index 4b284c53fa..28c0c64a6c 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/ui/TranslatedTextViewer.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/ui/TranslatedTextViewer.java @@ -341,8 +341,7 @@ public final class TranslatedTextViewer implements TextViewer { textBuilder.append(cbuf, 0, read); bytesRead += read; } - - // The trim is on here because HTML files were observed with nearly 1MB of white space at the end + return textBuilder.toString(); } From a76fdcb68e82e5cd2f2f384e5fe91c8ccb2c8c57 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 7 Jun 2019 10:17:38 -0400 Subject: [PATCH 058/115] 5129 adjustments to ui position --- .../GoogleTranslatorSettingsPanel.form | 64 ++++++++++--------- .../GoogleTranslatorSettingsPanel.java | 46 ++++++------- 2 files changed, 58 insertions(+), 52 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.form index cf280d463c..28ab58da65 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.form @@ -23,40 +23,44 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java index 23aaf0902a..39c244be05 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslatorSettingsPanel.java @@ -265,32 +265,34 @@ public class GoogleTranslatorSettingsPanel extends javax.swing.JPanel { .addComponent(instructionsScrollPane) .addContainerGap()) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(credentialsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(targetLanguageLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(warningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 551, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(testButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(credentialsLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(targetLanguageLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(credentialsPathField) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(browseButton) - .addGap(14, 14, 14)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(credentialsPathField) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(browseButton) + .addGap(14, 14, 14)) + .addGroup(layout.createSequentialGroup() + .addComponent(targetLanguageComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 317, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, Short.MAX_VALUE)))) .addGroup(layout.createSequentialGroup() - .addComponent(targetLanguageComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 317, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE)))) - .addGroup(layout.createSequentialGroup() - .addComponent(testButton, javax.swing.GroupLayout.PREFERRED_SIZE, 83, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(untranslatedLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(testUntranslatedTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 140, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(resultLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(testResultValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addGroup(layout.createSequentialGroup() - .addComponent(warningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 551, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) + .addGap(7, 7, 7) + .addComponent(untranslatedLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(testUntranslatedTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 140, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(resultLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(testResultValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))))) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) From a2515c4cb56d813580c75db54b749450ee069ce7 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Fri, 7 Jun 2019 10:26:01 -0400 Subject: [PATCH 059/115] Implemented tagging functionality for html reports and included both the tagged thumbnail and full tagged image (as well as original). --- .../contentviewers/MediaViewImagePanel.java | 13 +- .../imagetagging/ImageTagCreator.java | 6 +- .../imagetagging/ImageTagsUtility.java | 103 ++++++++++-- .../sleuthkit/autopsy/report/ReportHTML.java | 146 +++++++++++++----- 4 files changed, 206 insertions(+), 62 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java index 3f33d8ff47..6a5643af2e 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.contentviewers; import java.awt.EventQueue; import java.awt.event.ActionEvent; +import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; @@ -864,15 +865,21 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan @Override protected Void doInBackground() { try { + //Retrieve content viewer tags List tags = Case.getCurrentCase().getServices() .getTagsManager().getContentTagsByContent(file); List> contentViewerTags = getContentViewerTags(tags); + + //Pull out image tag regions Collection regions = contentViewerTags.stream() .map(cvTag -> cvTag.getDetails()).collect(Collectors.toList()); - byte[] jpgImage = ImageTagsUtility.exportTags(file, regions, ".jpg"); + + //Apply tags to image and write to file + BufferedImage pngImage = ImageTagsUtility.writeTags(file, regions, "png"); Path output = Paths.get(exportChooser.getSelectedFile().getPath(), - FilenameUtils.getBaseName(file.getName()) + "-with_tags.jpg"); //NON-NLS - Files.write(output, jpgImage); + FilenameUtils.getBaseName(file.getName()) + "-with_tags.png"); //NON-NLS + ImageIO.write(pngImage, "png", output.toFile()); + JOptionPane.showMessageDialog(null, Bundle.MediaViewImagePanel_successfulExport()); } catch (TskCoreException | NoCurrentCaseException | IOException ex) { LOGGER.log(Level.WARNING, "Unable to export tagged image to disk", ex); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagCreator.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagCreator.java index 885dd6c18f..24421d796c 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagCreator.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagCreator.java @@ -41,7 +41,7 @@ public final class ImageTagCreator extends Rectangle { //Rectangle lines should be 1.5% of the image. This level of thickness has //a good balance between visual acuity and loss of selection at the borders //of the image. - private final static double lineThicknessAsPercent = 1.5; + private final static double LINE_THICKNESS_PERCENT = 1.5; private final double minArea; //Used to update listeners of the new tag boundaries @@ -68,11 +68,11 @@ public final class ImageTagCreator extends Rectangle { //Calculate how many pixels the stroke width should be to guarentee //a consistent % of image consumed by the rectangle border. double min = Math.min(image.getImage().getWidth(), image.getImage().getHeight()); - double lineThicknessPixels = min * lineThicknessAsPercent / 100.0; + double lineThicknessPixels = min * LINE_THICKNESS_PERCENT / 100.0; setStrokeWidth(lineThicknessPixels); minArea = lineThicknessPixels * lineThicknessPixels; setVisible(false); - + this.mousePressed = (MouseEvent event) -> { if (event.isSecondaryButtonDown()) { return; diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsUtility.java b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsUtility.java index 1d1d164e2f..3c5fccc5e6 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsUtility.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsUtility.java @@ -18,13 +18,21 @@ */ package org.sleuthkit.autopsy.contentviewers.imagetagging; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.util.Collection; +import javax.imageio.ImageIO; import org.opencv.core.Core; import org.opencv.core.Mat; import org.opencv.core.MatOfByte; +import org.opencv.core.MatOfInt; import org.opencv.core.Point; import org.opencv.core.Scalar; +import org.opencv.core.Size; import org.opencv.highgui.Highgui; +import org.opencv.imgproc.Imgproc; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TskCoreException; @@ -34,19 +42,42 @@ import org.sleuthkit.datamodel.TskCoreException; public final class ImageTagsUtility { /** - * Embeds the tag regions into an image (represented as an AbstractFile). - * + * Sizes for thumbnails + */ + public enum IconSize { + SMALL(50), + MEDIUM(100), + LARGE(200); + + private final int SIZE; + + IconSize(int size) { + this.SIZE = size; + } + + public int getSize() { + return SIZE; + } + } + + /** + * Embeds the tag regions into an image. + * * @param file Base Image * @param tagRegions Tag regions to be saved into the image - * @param outputEncoding Output file type encoding (ex. .jpg, .png) - * @return output image in byte array - * @throws TskCoreException + * @param outputEncoding Format of image (jpg, png, etc). See OpenCV for + * supported formats. Do not include a "." + * @return Output image as a BufferedImage + * + * @throws TskCoreException Cannot read from abstract file + * @throws IOException Could not create buffered image from OpenCV result */ - public static byte[] exportTags(AbstractFile file, Collection tagRegions, String outputEncoding) throws TskCoreException { + public static BufferedImage writeTags(AbstractFile file, Collection tagRegions, + String outputEncoding) throws TskCoreException, IOException { byte[] imageInMemory = new byte[(int) file.getSize()]; file.read(imageInMemory, 0, file.getSize()); Mat originalImage = Highgui.imdecode(new MatOfByte(imageInMemory), Highgui.IMREAD_UNCHANGED); - + tagRegions.forEach((region) -> { Core.rectangle( originalImage, //Matrix obj of the image @@ -56,17 +87,55 @@ public final class ImageTagsUtility { (int) Math.rint(region.getStrokeThickness()) ); }); - + MatOfByte matOfByte = new MatOfByte(); - Highgui.imencode(outputEncoding, originalImage, matOfByte); - - originalImage.release(); - byte[] output = matOfByte.toArray(); - matOfByte.release(); - - return output; + MatOfInt params = new MatOfInt(Highgui.IMWRITE_JPEG_QUALITY, 100); + Highgui.imencode("." + outputEncoding, originalImage, matOfByte, params); + + try (ByteArrayInputStream imageStream = new ByteArrayInputStream(matOfByte.toArray())) { + BufferedImage result = ImageIO.read(imageStream); + originalImage.release(); + matOfByte.release(); + return result; + } } - - private ImageTagsUtility(){ + + /** + * Creates a thumbnail version of the image with tags applied. + * + * @param file Input file to apply tags & produce thumbnail from + * @param tagRegions Tags to apply + * @param iconSize Size of the output thumbnail + * @param outputEncoding Format of thumbnail (jpg, png, etc). See OpenCV for + * supported formats. Do not include a "." + * @return BufferedImage representing the thumbnail + * + * @throws TskCoreException Could not read from file + * @throws IOException Could not create buffered image from OpenCV result + */ + public static BufferedImage makeThumbnail(AbstractFile file, Collection tagRegions, + IconSize iconSize, String outputEncoding) throws TskCoreException, IOException { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + BufferedImage result = writeTags(file, tagRegions, outputEncoding); + ImageIO.write(result, outputEncoding, baos); + Mat markedUpImage = Highgui.imdecode(new MatOfByte(baos.toByteArray()), Highgui.IMREAD_UNCHANGED); + Mat thumbnail = new Mat(); + Size resize = new Size(iconSize.getSize(), iconSize.getSize()); + + Imgproc.resize(markedUpImage, thumbnail, resize); + MatOfByte matOfByte = new MatOfByte(); + Highgui.imencode("." + outputEncoding, thumbnail, matOfByte); + + try (ByteArrayInputStream thumbnailStream = new ByteArrayInputStream(matOfByte.toArray())) { + BufferedImage thumbnailImage = ImageIO.read(thumbnailStream); + thumbnail.release(); + matOfByte.release(); + markedUpImage.release(); + return thumbnailImage; + } + } + } + + private ImageTagsUtility() { } } diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index b54af094ad..896d572b99 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -48,18 +48,18 @@ import java.util.TreeMap; import java.util.logging.Level; import javax.imageio.ImageIO; import javax.swing.JPanel; +import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringEscapeUtils; import org.openide.filesystems.FileUtil; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.casemodule.services.Services; import org.sleuthkit.autopsy.casemodule.services.TagsManager; -import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization; +import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager; +import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager.ContentViewerTag; +import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagRegion; +import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagsUtility; import org.sleuthkit.autopsy.coreutils.EscapeUtil; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; @@ -731,6 +731,29 @@ class ReportHTML implements TableReportModule { logger.log(Level.SEVERE, "Output writer is null. Page was not initialized before writing.", ex); //NON-NLS } } + + /** + * Finds all associated image tags. + * + * @param contentTags + * @return + */ + private List getTaggedRegions(List contentTags) { + ArrayList tagRegions = new ArrayList<>(); + contentTags.forEach((contentTag) -> { + try { + ContentViewerTag contentViewerTag = ContentViewerTagManager + .getTag(contentTag, ImageTagRegion.class); + if (contentViewerTag != null) { + tagRegions.add(contentViewerTag.getDetails()); + } + } catch (TskCoreException | NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Could not get content viewer tag " + + "from case db for content_tag with id %d", contentTag.getId()); + } + }); + return tagRegions; + } /** * Add the body of the thumbnails table. @@ -770,13 +793,54 @@ class ReportHTML implements TableReportModule { } AbstractFile file = (AbstractFile) content; + List contentTags = new ArrayList<>(); + + String thumbnailPath = null; + String imageWithTagsFullPath = null; + try { + //Get content tags and all image tags + contentTags = Case.getCurrentCase().getServices() + .getTagsManager().getContentTagsByContent(file); + List imageTags = getTaggedRegions(contentTags); + + if(!imageTags.isEmpty()) { + //Write the tags to the fullsize and thumbnail images + BufferedImage fullImageWithTags = ImageTagsUtility.writeTags(file, imageTags, "png"); + + BufferedImage thumbnailImageWithTags = ImageTagsUtility.makeThumbnail(file, + imageTags, ImageTagsUtility.IconSize.MEDIUM, "png"); + + String fileName = org.sleuthkit.autopsy.coreutils.FileUtil.escapeFileName(file.getName()); + + //Create paths in report to write tagged images + File thumbnailImageWithTagsFile = Paths.get(thumbsPath, FilenameUtils.removeExtension(fileName) + ".png").toFile(); + String fullImageWithTagsPath = makeCustomUniqueFilePath(file, "thumbs_fullsize"); + fullImageWithTagsPath = FilenameUtils.removeExtension(fullImageWithTagsPath) + ".png"; + File fullImageWithTagsFile = Paths.get(fullImageWithTagsPath).toFile(); + + //Save images + ImageIO.write(thumbnailImageWithTags, "png", thumbnailImageWithTagsFile); + ImageIO.write(fullImageWithTags, "png", fullImageWithTagsFile); + + thumbnailPath = THUMBS_REL_PATH + thumbnailImageWithTagsFile.getName(); + //Relative path + imageWithTagsFullPath = fullImageWithTagsPath.substring(subPath.length()); + } + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Could not get tags for file.", ex); //NON-NLS + } catch (IOException ex) { + logger.log(Level.WARNING, "Could make marked up thumbnail.", ex); //NON-NLS + } // save copies of the orginal image and thumbnail image - String thumbnailPath = prepareThumbnail(file); + if(thumbnailPath == null) { + thumbnailPath = prepareThumbnail(file); + } + if (thumbnailPath == null) { continue; } - String contentPath = saveContent(file, "thumbs_fullsize"); //NON-NLS + String contentPath = saveContent(file, "original"); //NON-NLS String nameInImage; try { nameInImage = file.getUniquePath(); @@ -787,30 +851,27 @@ class ReportHTML implements TableReportModule { StringBuilder linkToThumbnail = new StringBuilder(); linkToThumbnail.append(""); currentRow.add(linkToThumbnail.toString()); @@ -839,17 +900,8 @@ class ReportHTML implements TableReportModule { || file.getType() == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS || file.getType() == TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS; } - - /** - * Save a local copy of the given file in the reports folder. - * - * @param file File to save - * @param dirName Custom top-level folder to use to store the files in (tag - * name, etc.) - * - * @return Path to where file was stored (relative to root of HTML folder) - */ - public String saveContent(AbstractFile file, String dirName) { + + private String makeCustomUniqueFilePath(AbstractFile file, String dirName) { // clean up the dir name passed in String dirName2 = org.sleuthkit.autopsy.coreutils.FileUtil.escapeFileName(dirName); @@ -883,16 +935,32 @@ class ReportHTML implements TableReportModule { } localFilePath.append(File.separator); localFilePath.append(fileName); + + return localFilePath.toString(); + } + + /** + * Save a local copy of the given file in the reports folder. + * + * @param file File to save + * @param dirName Custom top-level folder to use to store the files in (tag + * name, etc.) + * + * @return Path to where file was stored (relative to root of HTML folder) + */ + public String saveContent(AbstractFile file, String dirName) { + + String localFilePath = makeCustomUniqueFilePath(file, dirName); // If the local file doesn't already exist, create it now. // The existence check is necessary because it is possible to apply multiple tags with the same tagName to a file. - File localFile = new File(localFilePath.toString()); + File localFile = new File(localFilePath); if (!localFile.exists()) { ExtractFscContentVisitor.extract(file, localFile, null, null); } // get the relative path - return localFilePath.toString().substring(subPath.length()); + return localFilePath.substring(subPath.length()); } /** From 605e6959921c161fcf584f32ff2d7508a833c940 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Fri, 7 Jun 2019 10:43:13 -0400 Subject: [PATCH 060/115] Use enum for SCO column names. Escape quotes. --- .../autopsy/directorytree/ExportCSVAction.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java index 4a87f72828..759078fe2b 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java @@ -47,6 +47,7 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.AbstractFilePropertyType; import org.openide.nodes.Node; import org.openide.nodes.Node.PropertySet; import org.openide.nodes.Node.Property; @@ -58,7 +59,8 @@ public final class ExportCSVAction extends AbstractAction { private static Logger logger = Logger.getLogger(ExportCSVAction.class.getName()); private final static String DEFAULT_FILENAME = "Results"; - private final static List columnsToSkip = Arrays.asList("S", "C", "O"); + private final static List columnsToSkip = Arrays.asList(AbstractFilePropertyType.SCORE.toString(), + AbstractFilePropertyType.COMMENT.toString(), AbstractFilePropertyType.OCCURRENCES.toString()); private static String userDefinedExportPath; @@ -300,7 +302,7 @@ public final class ExportCSVAction extends AbstractAction { for(PropertySet set : sets) { for (Property prop : set.getProperties()) { if ( ! columnsToSkip.contains(prop.getDisplayName())) { - values.add(prop.getValue().toString()); + values.add(escapeQuotes(prop.getValue().toString())); } } } @@ -311,6 +313,18 @@ public final class ExportCSVAction extends AbstractAction { return null; } + /** + * Escape any quotes in the string + * + * @param original + * + * @return the string with quotes escaped + */ + private String escapeQuotes(String original) { + String result = original.replaceAll("\"", "\\\\\""); + return result; + } + /** * Convert list of values to a comma separated string. * From f19a9a6c3cc6d0de5bc072194b7a37057c2e866e Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Fri, 7 Jun 2019 10:50:56 -0400 Subject: [PATCH 061/115] Codacy fixes --- .../contentviewers/MediaViewImagePanel.java | 1 - .../org/sleuthkit/autopsy/report/ReportHTML.java | 16 ++++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java index 6a5643af2e..b48460e9ba 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java @@ -25,7 +25,6 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index 896d572b99..bb5de222cb 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -849,18 +849,18 @@ class ReportHTML implements TableReportModule { } StringBuilder linkToThumbnail = new StringBuilder(); - linkToThumbnail.append("
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -281,5 +172,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LogicalImagerPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/LogicalImagerPanel.java index 1248912505..b54d468d34 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LogicalImagerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LogicalImagerPanel.java @@ -74,6 +74,7 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { private LogicalImagerPanel(String context) { this.contextName = context; initComponents(); + jScrollPane1.setBorder(null); clearImageTable(); } @@ -99,29 +100,28 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { */ // //GEN-BEGIN:initComponents private void initComponents() { + bindingGroup = new org.jdesktop.beansbinding.BindingGroup(); buttonGroup1 = new javax.swing.ButtonGroup(); - messageLabel = new javax.swing.JLabel(); browseButton = new javax.swing.JButton(); importRadioButton = new javax.swing.JRadioButton(); manualRadioButton = new javax.swing.JRadioButton(); pathTextField = new javax.swing.JTextField(); - importPanel = new javax.swing.JPanel(); + selectFolderLabel = new javax.swing.JLabel(); selectDriveLabel = new javax.swing.JLabel(); + selectFromDriveLabel = new javax.swing.JLabel(); driveListScrollPane = new javax.swing.JScrollPane(); driveList = new javax.swing.JList<>(); refreshButton = new javax.swing.JButton(); imageScrollPane = new javax.swing.JScrollPane(); imageTable = new javax.swing.JTable(); - selectFromDriveLabel = new javax.swing.JLabel(); - selectFolderLabel = new javax.swing.JLabel(); + jSeparator2 = new javax.swing.JSeparator(); + jScrollPane1 = new javax.swing.JScrollPane(); + messageTextArea = new javax.swing.JTextArea(); setMinimumSize(new java.awt.Dimension(0, 65)); setPreferredSize(new java.awt.Dimension(403, 65)); - messageLabel.setForeground(java.awt.Color.red); - org.openide.awt.Mnemonics.setLocalizedText(messageLabel, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.messageLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.browseButton.text")); // NOI18N browseButton.setEnabled(false); browseButton.addActionListener(new java.awt.event.ActionListener() { @@ -149,14 +149,19 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { }); pathTextField.setText(org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.pathTextField.text")); // NOI18N + pathTextField.setDisabledTextColor(java.awt.Color.black); pathTextField.setEnabled(false); + org.openide.awt.Mnemonics.setLocalizedText(selectFolderLabel, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.selectFolderLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(selectDriveLabel, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.selectDriveLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(selectFromDriveLabel, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.selectFromDriveLabel.text")); // NOI18N + driveList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); driveList.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseClicked(java.awt.event.MouseEvent evt) { - driveListMouseClicked(evt); + public void mouseReleased(java.awt.event.MouseEvent evt) { + driveListMouseReleased(evt); } }); driveList.addKeyListener(new java.awt.event.KeyAdapter() { @@ -190,8 +195,8 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { imageTable.getTableHeader().setReorderingAllowed(false); imageTable.setUpdateSelectionOnSort(false); imageTable.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseClicked(java.awt.event.MouseEvent evt) { - imageTableMouseClicked(evt); + public void mouseReleased(java.awt.event.MouseEvent evt) { + imageTableMouseReleased(evt); } }); imageTable.addKeyListener(new java.awt.event.KeyAdapter() { @@ -202,88 +207,94 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { imageScrollPane.setViewportView(imageTable); imageTable.getColumnModel().getSelectionModel().setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); - org.openide.awt.Mnemonics.setLocalizedText(selectFromDriveLabel, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.selectFromDriveLabel.text")); // NOI18N + jScrollPane1.setBorder(null); - javax.swing.GroupLayout importPanelLayout = new javax.swing.GroupLayout(importPanel); - importPanel.setLayout(importPanelLayout); - importPanelLayout.setHorizontalGroup( - importPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(importPanelLayout.createSequentialGroup() - .addGap(21, 21, 21) - .addGroup(importPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, importPanelLayout.createSequentialGroup() - .addGroup(importPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) - .addComponent(refreshButton) - .addComponent(driveListScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(importPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(selectFromDriveLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 305, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(imageScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addGap(22, 22, 22)) - .addGroup(importPanelLayout.createSequentialGroup() - .addComponent(selectDriveLabel) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) - ); - importPanelLayout.setVerticalGroup( - importPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(importPanelLayout.createSequentialGroup() - .addGroup(importPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(selectDriveLabel) - .addComponent(selectFromDriveLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(importPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(imageScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) - .addComponent(driveListScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 185, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(refreshButton)) - ); + messageTextArea.setBackground(new java.awt.Color(240, 240, 240)); + messageTextArea.setColumns(20); + messageTextArea.setForeground(java.awt.Color.red); + messageTextArea.setLineWrap(true); + messageTextArea.setRows(3); + messageTextArea.setText(org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.messageTextArea.text")); // NOI18N + messageTextArea.setBorder(null); + messageTextArea.setDisabledTextColor(java.awt.Color.red); + messageTextArea.setEnabled(false); + messageTextArea.setMargin(new java.awt.Insets(0, 0, 0, 0)); - org.openide.awt.Mnemonics.setLocalizedText(selectFolderLabel, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.selectFolderLabel.text")); // NOI18N + org.jdesktop.beansbinding.Binding binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, messageTextArea, org.jdesktop.beansbinding.ELProperty.create("false"), messageTextArea, org.jdesktop.beansbinding.BeanProperty.create("editable")); + bindingGroup.addBinding(binding); + + jScrollPane1.setViewportView(messageTextArea); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() + .addGap(10, 10, 10) + .addComponent(selectFolderLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 81, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(13, 13, 13) + .addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 474, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(jSeparator2, javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(manualRadioButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(browseButton)) - .addComponent(importRadioButton)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(messageLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 639, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(selectFolderLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 81, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(41, 41, 41) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(driveListScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 160, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(refreshButton)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(pathTextField))) - .addGap(25, 25, 25)) - .addComponent(importPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addComponent(imageScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 377, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addGap(20, 20, 20) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(manualRadioButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(browseButton)) + .addComponent(importRadioButton) + .addGroup(layout.createSequentialGroup() + .addGap(21, 21, 21) + .addComponent(selectDriveLabel) + .addGap(113, 113, 113) + .addComponent(selectFromDriveLabel)))))) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 568, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addContainerGap(14, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(16, 16, 16) .addComponent(importRadioButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(selectDriveLabel) + .addComponent(selectFromDriveLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(importPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGap(37, 37, 37) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(imageScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addComponent(driveListScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 186, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(refreshButton) + .addGap(18, 18, 18) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(browseButton) .addComponent(manualRadioButton)) - .addGap(3, 3, 3) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) - .addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(selectFolderLabel)) + .addGap(18, 18, 18) + .addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(selectFolderLabel) + .addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(messageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 19, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap()) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 61, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(6, 6, 6)) ); + + bindingGroup.bind(); }// //GEN-END:initComponents public static String humanReadableByteCount(long bytes, boolean si) { @@ -408,14 +419,14 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { } private void setErrorMessage(String msg) { - messageLabel.setForeground(Color.red); - messageLabel.setText(msg); + messageTextArea.setForeground(Color.red); + messageTextArea.setText(msg); pathTextField.setText(""); } private void setNormalMessage(String msg) { pathTextField.setText(msg); - messageLabel.setText(""); + messageTextArea.setText(""); } private void clearImageTable() { @@ -432,7 +443,6 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { browseButton.setEnabled(true); // disable import panel - toggleMouseAndKeyListeners(importPanel, false); toggleMouseAndKeyListeners(driveList, false); toggleMouseAndKeyListeners(driveListScrollPane, false); toggleMouseAndKeyListeners(imageScrollPane, false); @@ -448,7 +458,6 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { private void importRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importRadioButtonActionPerformed browseButton.setEnabled(false); - toggleMouseAndKeyListeners(importPanel, true); toggleMouseAndKeyListeners(driveList, true); toggleMouseAndKeyListeners(driveListScrollPane, true); toggleMouseAndKeyListeners(imageScrollPane, true); @@ -461,19 +470,6 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { refreshButton.doClick(); }//GEN-LAST:event_importRadioButtonActionPerformed - private void imageTableKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_imageTableKeyReleased - if (importRadioButton.isSelected()) { - imageTableSelect(); - firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false); - } - }//GEN-LAST:event_imageTableKeyReleased - - private void imageTableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_imageTableMouseClicked - if (importRadioButton.isSelected()) { - imageTableSelect(); - } - }//GEN-LAST:event_imageTableMouseClicked - @Messages({ "LogicalImagerPanel.messageLabel.scanningExternalDrives=Scanning external drives for sparse_image.vhd ...", "LogicalImagerPanel.messageLabel.noExternalDriveFound=No drive found" @@ -507,7 +503,7 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { if (!listData.isEmpty()) { // auto-select the first external drive, if any driveList.setSelectedIndex(firstRemovableDrive == -1 ? 0 : firstRemovableDrive); - driveListMouseClicked(null); + driveListMouseReleased(null); driveList.requestFocusInWindow(); } else { setErrorMessage(Bundle.LogicalImagerPanel_messageLabel_noExternalDriveFound()); @@ -522,13 +518,26 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { } }//GEN-LAST:event_driveListKeyReleased - private void driveListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_driveListMouseClicked + private void imageTableKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_imageTableKeyReleased + if (importRadioButton.isSelected()) { + imageTableSelect(); + } + }//GEN-LAST:event_imageTableKeyReleased + + private void imageTableMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_imageTableMouseReleased + if (importRadioButton.isSelected()) { + imageTableSelect(); + } + }//GEN-LAST:event_imageTableMouseReleased + + private void driveListMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_driveListMouseReleased if (importRadioButton.isSelected()) { driveListSelect(); firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false); } - }//GEN-LAST:event_driveListMouseClicked - + }//GEN-LAST:event_driveListMouseReleased + + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton browseButton; private javax.swing.ButtonGroup buttonGroup1; @@ -536,22 +545,28 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener { private javax.swing.JScrollPane driveListScrollPane; private javax.swing.JScrollPane imageScrollPane; private javax.swing.JTable imageTable; - private javax.swing.JPanel importPanel; private javax.swing.JRadioButton importRadioButton; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JSeparator jSeparator2; private javax.swing.JRadioButton manualRadioButton; - private javax.swing.JLabel messageLabel; + private javax.swing.JTextArea messageTextArea; private javax.swing.JTextField pathTextField; private javax.swing.JButton refreshButton; private javax.swing.JLabel selectDriveLabel; private javax.swing.JLabel selectFolderLabel; private javax.swing.JLabel selectFromDriveLabel; + private org.jdesktop.beansbinding.BindingGroup bindingGroup; // End of variables declaration//GEN-END:variables public void reset() { //reset the UI elements to default choosenImageDirPath = null; + setNormalMessage(""); driveList.setListData(EMPTY_LIST_DATA); clearImageTable(); + if (importRadioButton.isSelected()) { + refreshButton.doClick(); + } } /** From bf4604730ac62e7424e86f3fa328ef77dbb187d1 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 7 Jun 2019 16:53:15 -0400 Subject: [PATCH 083/115] 5055 include HASHSET_HIT as one of the artifacts that displays file count --- Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java b/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java index 5d81e195e2..c93d6a8822 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java @@ -72,7 +72,8 @@ class GetSCOTask implements Runnable { if (bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID() || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED.getTypeID() || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() - || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID()) { + || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID() + || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { occurrencesAttribute = fileAttribute; } else { List listOfPossibleAttributes = EamArtifactUtil.makeInstancesFromBlackboardArtifact(bbArtifact, false); From ba8da5747b022319f3f68500ffd8f6682f02f489 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Fri, 7 Jun 2019 17:15:10 -0400 Subject: [PATCH 084/115] Made file chooser start in export folder of current directory --- .../autopsy/contentviewers/MediaViewImagePanel.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java index 3f33d8ff47..5691a9891a 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java @@ -23,6 +23,7 @@ import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; +import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -67,6 +68,7 @@ import javax.swing.JSeparator; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang3.StringUtils; import org.controlsfx.control.MaskerPane; import org.openide.util.NbBundle; import org.python.google.common.collect.Lists; @@ -85,6 +87,7 @@ import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTag; import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagsGroup; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.datamodel.FileNode; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.datamodel.AbstractFile; @@ -857,9 +860,10 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan private void exportTags() { tagsGroup.clearFocus(); exportChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + //Always base chooser location to export folder + exportChooser.setCurrentDirectory(new File(Case.getCurrentCase().getExportDirectory())); int returnVal = exportChooser.showDialog(this, Bundle.MediaViewImagePanel_exportSaveText()); if (returnVal == JFileChooser.APPROVE_OPTION) { - exportChooser.setCurrentDirectory(exportChooser.getSelectedFile()); new SwingWorker() { @Override protected Void doInBackground() { From 34070d559c3d5cfce5302f556d5b39dc1ed5b2c1 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Fri, 7 Jun 2019 17:15:57 -0400 Subject: [PATCH 085/115] Removed unused imports --- .../sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java index 5691a9891a..7aeacc8f27 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java @@ -68,7 +68,6 @@ import javax.swing.JSeparator; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import org.apache.commons.io.FilenameUtils; -import org.apache.commons.lang3.StringUtils; import org.controlsfx.control.MaskerPane; import org.openide.util.NbBundle; import org.python.google.common.collect.Lists; @@ -87,7 +86,6 @@ import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTag; import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagsGroup; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.datamodel.FileNode; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.datamodel.AbstractFile; From d8f04fce98363b13a3701feb073393c9c42b19bf Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Fri, 7 Jun 2019 17:19:49 -0400 Subject: [PATCH 086/115] Warn user if a comma is present in an extension regex --- .../interestingitems/Bundle.properties-MERGED | 2 ++ .../interestingitems/FilesSetRulePanel.java | 14 +++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED index 7ca4901b1b..a1b97a0f54 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED @@ -37,6 +37,8 @@ FilesSetPanel.ingest.createNewFilter=Create/edit file ingest filters... FilesSetPanel.ingest.messages.filtersMustBeNamed=File ingest filters must be named. FilesSetPanel.rule.title=File Filter Rule FilesSetRulePanel.bytes=Bytes +#{0} - regex +FilesSetRulePanel.CommaInRegexWarning=Warning: Comma(s) in the file extension field will be interpreted as part of a regex and will not split the entry into multiple extensions (Entered: "{0}") FilesSetRulePanel.DaysIncludedEmptyError=Number of days included cannot be empty. FilesSetRulePanel.DaysIncludedInvalidError=Number of days included must be a positive integer. FilesSetRulePanel.gigaBytes=Gigabytes diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetRulePanel.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetRulePanel.java index 9744b0c5bf..12339b54f6 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetRulePanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetRulePanel.java @@ -57,7 +57,9 @@ final class FilesSetRulePanel extends javax.swing.JPanel { "FilesSetRulePanel.NoPathError=Path cannot be empty", "FilesSetRulePanel.DaysIncludedEmptyError=Number of days included cannot be empty.", "FilesSetRulePanel.DaysIncludedInvalidError=Number of days included must be a positive integer.", - "FilesSetRulePanel.ZeroFileSizeError=File size condition value must not be 0 (Unless = is selected)." + "FilesSetRulePanel.ZeroFileSizeError=File size condition value must not be 0 (Unless = is selected).", + "#{0} - regex", + "FilesSetRulePanel.CommaInRegexWarning=Warning: Comma(s) in the file extension field will be interpreted as part of a regex and will not split the entry into multiple extensions (Entered: \"{0}\")", }) private static final long serialVersionUID = 1L; @@ -358,6 +360,16 @@ final class FilesSetRulePanel extends javax.swing.JPanel { return false; } if (this.nameRegexCheckbox.isSelected()) { + + // If extension is also selected and the regex contains a comma, display a warning + // since it is unclear whether the comma is part of a regex or is separating extensions. + if (this.extensionRadioButton.isSelected() && this.nameTextField.getText().contains(",")) { + NotifyDescriptor notifyDesc = new NotifyDescriptor.Message( + Bundle.FilesSetRulePanel_CommaInRegexWarning(this.nameTextField.getText()), + NotifyDescriptor.WARNING_MESSAGE); + DialogDisplayer.getDefault().notify(notifyDesc); + } + try { Pattern.compile(this.nameTextField.getText()); } catch (PatternSyntaxException ex) { From 9af1fc4d0908c1cef6282913af8a887c171b84f8 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Fri, 7 Jun 2019 17:21:42 -0400 Subject: [PATCH 087/115] Update doc --- docs/doxygen-user/interesting_files.dox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/doxygen-user/interesting_files.dox b/docs/doxygen-user/interesting_files.dox index 080b1072af..7e4147a66f 100644 --- a/docs/doxygen-user/interesting_files.dox +++ b/docs/doxygen-user/interesting_files.dox @@ -42,7 +42,7 @@ The top line allows you to choose whether you want to match only files, only dir Each rule must have at least one condition. To create conditions, check the box to the left of the condition you want to enable. The following is a description of each condition, with some full examples after.
    -
  • Name - Enter either the full file name or one or more extensions, and select whether this is an exact match or a substring/regex match. If substring/regex match is enabled, it will automatically add wildcards to the beginning and end of the text. If you're only matching directories, this will match the directory name. If you're using a comma-separated list of extensions, make sure the regex checkbox is disabled - the two features do not work together. The following table shows some examples of what the different combinations can be used for. +
  • Name - Enter either the full file name or one or more extensions, and select whether this is an exact match or a substring/regex match. If substring/regex match is enabled, it will automatically add wildcards to the beginning and end of the text. If you're only matching directories, this will match the directory name. If you're using a comma-separated list of extensions, make sure the regex checkbox is disabled - the entire contents will be interpreted as one regex when the checkbox is selected. The following table shows some examples of what the different combinations can be used for.
From c2a0ee262dc53b9d095a9cfb7cec2e345cf83f66 Mon Sep 17 00:00:00 2001 From: Raman Date: Mon, 10 Jun 2019 09:54:19 -0400 Subject: [PATCH 088/115] 5059: tree view did not work per Group By Datasource setting --- .../autopsy/datamodel/DeletedContent.java | 2 +- .../autopsy/datamodel/EmailExtracted.java | 2 +- .../autopsy/datamodel/ExtractedContent.java | 6 +++--- .../sleuthkit/autopsy/datamodel/FileSize.java | 2 +- .../datamodel/FileTypesByExtension.java | 2 +- .../datamodel/FileTypesByMimeType.java | 2 +- .../autopsy/datamodel/HashsetHits.java | 2 +- .../autopsy/datamodel/InterestingHits.java | 2 +- .../autopsy/datamodel/KeywordHits.java | 2 +- .../org/sleuthkit/autopsy/datamodel/Tags.java | 20 +++++++++---------- .../autopsy/datamodel/accounts/Accounts.java | 2 +- 11 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java index 25069d9564..69d7597653 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java @@ -439,7 +439,7 @@ public class DeletedContent implements AutopsyVisitableItem { } - if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) { + if (filteringDSObjId > 0) { query += " AND data_source_obj_id = " + filteringDSObjId; } return query; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java index 83fcee1b65..fe88ccb90a 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java @@ -162,7 +162,7 @@ public class EmailExtracted implements AutopsyVisitableItem { + "attribute_type_id=" + pathAttrId //NON-NLS + " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS + " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS - if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) { + if (datasourceObjId > 0) { query += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId; } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index a21afff190..2baecb45a1 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -307,7 +307,7 @@ public class ExtractedContent implements AutopsyVisitableItem { protected boolean createKeys(List list) { if (skCase != null) { try { - List types = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) ? + List types = (datasourceObjId > 0) ? blackboard.getArtifactTypesInUse(datasourceObjId) : skCase.getArtifactTypesInUse() ; @@ -372,7 +372,7 @@ public class ExtractedContent implements AutopsyVisitableItem { // a performance increase might be had by adding a // "getBlackboardArtifactCount()" method to skCase try { - this.childCount = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) ? + this.childCount = (datasourceObjId > 0) ? blackboard.getArtifactsCount(type.getTypeID(), datasourceObjId) : skCase.getBlackboardArtifactsTypeCount(type.getTypeID()); } catch (TskException ex) { @@ -501,7 +501,7 @@ public class ExtractedContent implements AutopsyVisitableItem { protected List makeKeys() { if (skCase != null) { try { - return Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) + return (datasourceObjId > 0) ? blackboard.getArtifacts(type.getTypeID(), datasourceObjId) : skCase.getBlackboardArtifacts(type.getTypeID()); } catch (TskException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java index e9c49c596e..e4f2a85002 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java @@ -437,7 +437,7 @@ public class FileSize implements AutopsyVisitableItem { query = query + " AND (type != " + TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType() + ")"; //NON-NLS // filter by datasource if indicated in case preferences - if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) { + if (filteringDSObjId > 0) { query += " AND data_source_obj_id = " + filteringDSObjId; } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java index b3005c28b4..e0a887002f 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java @@ -366,7 +366,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { + (UserPreferences.hideKnownFilesInViewsTree() ? " AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")" : " ") - + (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) + + (filteringDataSourceObjId() > 0 ? " AND data_source_obj_id = " + filteringDataSourceObjId() : " ") + " AND (extension IN (" + filter.getFilter().stream() diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java index 1e4f61fc87..5a5164f519 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java @@ -103,7 +103,7 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi + TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal() + (hideSlackFilesInViewsTree() ? "" : ("," + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal())) + "))" - + ( Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) ? " AND data_source_obj_id = " + this.filteringDataSourceObjId() : " ") + + ( (filteringDataSourceObjId() > 0) ? " AND data_source_obj_id = " + this.filteringDataSourceObjId() : " ") + (hideKnownFilesInViewsTree() ? (" AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")") : ""); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java index 9d6ed53431..5d701fb400 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java @@ -142,7 +142,7 @@ public class HashsetHits implements AutopsyVisitableItem { + "attribute_type_id=" + setNameId //NON-NLS + " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS + " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS - if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) { + if (datasourceObjId > 0) { query += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId; } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java index c36833992c..7380de63d4 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java @@ -133,7 +133,7 @@ public class InterestingHits implements AutopsyVisitableItem { + "attribute_type_id=" + setNameId //NON-NLS + " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS + " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS - if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) { + if (datasourceObjId > 0) { query += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId; } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java index cb24744b0c..e78db54c01 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java @@ -344,7 +344,7 @@ public class KeywordHits implements AutopsyVisitableItem { } String queryStr = KEYWORD_HIT_ATTRIBUTES_QUERY; - if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) { + if (datasourceObjId > 0) { queryStr += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId; } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index abf77350d2..bfdf8da357 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -246,11 +246,11 @@ public class Tags implements AutopsyVisitableItem { List tagNamesInUse; if (UserPreferences.showOnlyCurrentUserTags()) { String userName = System.getProperty(USER_NAME_PROPERTY); - tagNamesInUse = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) + tagNamesInUse = (datasourceObjId > 0) ? Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUseForUser(datasourceObjId, userName) : Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUseForUser(userName); } else { - tagNamesInUse = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) + tagNamesInUse = (datasourceObjId > 0) ? Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse(datasourceObjId) : Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse(); } @@ -303,7 +303,7 @@ public class Tags implements AutopsyVisitableItem { TagsManager tm = Case.getCurrentCaseThrows().getServices().getTagsManager(); if (UserPreferences.showOnlyCurrentUserTags()) { String userName = System.getProperty(USER_NAME_PROPERTY); - if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) { + if (datasourceObjId > 0) { tagsCount = tm.getContentTagsCountByTagNameForUser(tagName, datasourceObjId, userName); tagsCount += tm.getBlackboardArtifactTagsCountByTagNameForUser(tagName, datasourceObjId, userName); } else { @@ -311,7 +311,7 @@ public class Tags implements AutopsyVisitableItem { tagsCount += tm.getBlackboardArtifactTagsCountByTagNameForUser(tagName, userName); } } else { - if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) { + if (datasourceObjId > 0) { tagsCount = tm.getContentTagsCountByTagName(tagName, datasourceObjId); tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName, datasourceObjId); } else { @@ -424,11 +424,11 @@ public class Tags implements AutopsyVisitableItem { if (UserPreferences.showOnlyCurrentUserTags()) { String userName = System.getProperty(USER_NAME_PROPERTY); - tagsCount = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) + tagsCount = (datasourceObjId > 0) ? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagNameForUser(tagName, datasourceObjId, userName) : Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagNameForUser(tagName, userName); } else { - tagsCount = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) + tagsCount = (datasourceObjId > 0) ? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName, datasourceObjId) : Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName); } @@ -486,7 +486,7 @@ public class Tags implements AutopsyVisitableItem { protected boolean createKeys(List keys) { // Use the content tags bearing the specified tag name as the keys. try { - List contentTags = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) + List contentTags = (datasourceObjId > 0) ? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName, datasourceObjId) : Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName); if (UserPreferences.showOnlyCurrentUserTags()) { @@ -544,11 +544,11 @@ public class Tags implements AutopsyVisitableItem { try { if (UserPreferences.showOnlyCurrentUserTags()) { String userName = System.getProperty(USER_NAME_PROPERTY); - tagsCount = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) + tagsCount = (datasourceObjId > 0) ? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagNameForUser(tagName, datasourceObjId, userName) : Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagNameForUser(tagName, userName); } else { - tagsCount = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) + tagsCount = (datasourceObjId > 0) ? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName, datasourceObjId) : Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName); } @@ -606,7 +606,7 @@ public class Tags implements AutopsyVisitableItem { protected boolean createKeys(List keys) { try { // Use the blackboard artifact tags bearing the specified tag name as the keys. - List artifactTags = Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) + List artifactTags = (datasourceObjId > 0) ? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName, datasourceObjId) : Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName); if (UserPreferences.showOnlyCurrentUserTags()) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java index d8e40d8a3e..f87cbb5e0c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java @@ -153,7 +153,7 @@ final public class Accounts implements AutopsyVisitableItem { * based on the CasePreferences groupItemsInTreeByDataSource setting */ private String getFilterByDataSourceClause() { - if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) { + if (datasourceObjId > 0) { return " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId + " "; } From 85bce73daf1b3566b65eaed94406ed3914eb0e72 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Mon, 10 Jun 2019 10:39:57 -0400 Subject: [PATCH 089/115] Added code to set the column width's by perc --- .../relationships/MessagesViewer.java | 3 ++- .../relationships/OutlineViewPanel.java | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesViewer.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesViewer.java index 2648ffc3b7..f81a6224b6 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesViewer.java @@ -68,7 +68,6 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer initComponents(); splitPane.setResizeWeight(0.5); -// splitPane.setDividerLocation(0.25); outlineViewPanel.hideOutlineView(Bundle.MessageViewer_no_messages()); @@ -140,6 +139,8 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer updateOutlineViewPanel(); } }); + + outlineViewPanel.setTableColumnsWidth(10,10,10,15,50,5); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/OutlineViewPanel.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/OutlineViewPanel.java index a9c977f2db..ff229960c3 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/OutlineViewPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/OutlineViewPanel.java @@ -19,7 +19,9 @@ package org.sleuthkit.autopsy.communications.relationships; import java.awt.CardLayout; +import javax.swing.JTable; import javax.swing.SwingUtilities; +import javax.swing.table.TableColumn; import org.openide.explorer.ExplorerManager; import static org.openide.explorer.ExplorerUtils.createLookup; import org.openide.explorer.view.OutlineView; @@ -99,6 +101,19 @@ public class OutlineViewPanel extends javax.swing.JPanel implements ExplorerMana outlineView.setEnabled(enabled); } + public void setTableColumnsWidth(double... percentages) { + JTable table = outlineView.getOutline(); + double total = 0; + for (int i = 0; i < table.getColumnModel().getColumnCount(); i++) { + total += percentages[i]; + } + + for (int i = 0; i < table.getColumnModel().getColumnCount(); i++) { + TableColumn column = table.getColumnModel().getColumn(i); + column.setPreferredWidth((int) (table.getPreferredSize().width * (percentages[i] / total))); + } + } + /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always From a8d180c310c3255142b3d4581a73f5bac7bb5580 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Mon, 10 Jun 2019 11:02:52 -0400 Subject: [PATCH 090/115] Added splitter to contact tab --- .../relationships/ContactsViewer.form | 34 +++++++++++++------ .../relationships/ContactsViewer.java | 25 +++++++------- .../relationships/MessagesViewer.java | 2 +- 3 files changed, 38 insertions(+), 23 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsViewer.form b/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsViewer.form index c378f085ec..308eec1a42 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsViewer.form +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsViewer.form @@ -16,19 +16,33 @@ - + + + + - + - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsViewer.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsViewer.java index aa15ec4115..4fdb400c87 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsViewer.java @@ -125,6 +125,9 @@ public final class ContactsViewer extends JPanel implements RelationshipsViewer{ updateOutlineViewPanel(); } }); + + splitPane.setResizeWeight(0.5); + splitPane.setDividerLocation(0.5); } @Override @@ -184,32 +187,30 @@ public final class ContactsViewer extends JPanel implements RelationshipsViewer{ private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; + splitPane = new javax.swing.JSplitPane(); contactPane = new org.sleuthkit.autopsy.communications.relationships.ContactDetailsPane(); outlineViewPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel(); setLayout(new java.awt.GridBagLayout()); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 1; - gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.weightx = 1.0; - gridBagConstraints.weighty = 0.25; - gridBagConstraints.insets = new java.awt.Insets(9, 0, 0, 0); - add(contactPane, gridBagConstraints); + + splitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT); + splitPane.setRightComponent(contactPane); + splitPane.setLeftComponent(outlineViewPanel); + gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.weightx = 1.0; - gridBagConstraints.weighty = 0.75; - add(outlineViewPanel, gridBagConstraints); + gridBagConstraints.weighty = 1.0; + add(splitPane, gridBagConstraints); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private org.sleuthkit.autopsy.communications.relationships.ContactDetailsPane contactPane; private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel outlineViewPanel; + private javax.swing.JSplitPane splitPane; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesViewer.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesViewer.java index f81a6224b6..f258e2c7a3 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesViewer.java @@ -140,7 +140,7 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer } }); - outlineViewPanel.setTableColumnsWidth(10,10,10,15,50,5); + outlineViewPanel.setTableColumnsWidth(5,10,10,15,50,10); } @Override From 5a94e6af393cd6a2f987bfc412da2233f0f79231 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Mon, 10 Jun 2019 13:12:13 -0400 Subject: [PATCH 091/115] Sort list of rules by name --- .../modules/interestingitems/FilesSetDefsPanel.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java index d226e6765b..25db05decb 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java @@ -22,6 +22,8 @@ import java.awt.EventQueue; import java.io.File; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -295,8 +297,14 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp FilesSetDefsPanel.this.copySetButton.setEnabled(canBeEnabled); FilesSetDefsPanel.this.exportSetButton.setEnabled(true); // Populate the rule definitions list, sorted by name. - TreeMap rules = new TreeMap<>(selectedSet.getRules()); - rules.values().forEach((rule) -> { + List rules = new ArrayList<>(selectedSet.getRules().values()); + Collections.sort(rules, new Comparator() { + @Override + public int compare(FilesSet.Rule rule1, FilesSet.Rule rule2) { + return rule1.toString().compareTo(rule2.toString()); + } + }); + rules.forEach((rule) -> { FilesSetDefsPanel.this.rulesListModel.addElement(rule); }); // Select the first rule by default. From 7a6101590a3a4e5ae288a2988858715ec7c97dfa Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 10 Jun 2019 13:48:41 -0400 Subject: [PATCH 092/115] 5055 add additional types that should display underlying file info --- Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java b/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java index c93d6a8822..7f82f7fb64 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java @@ -73,6 +73,9 @@ class GetSCOTask implements Runnable { || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED.getTypeID() || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID() + || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID() + || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID() || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { occurrencesAttribute = fileAttribute; } else { From 1ab509d428a935d3fd520c7503afc5afd4c660a8 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Mon, 10 Jun 2019 15:01:44 -0400 Subject: [PATCH 093/115] Cleaned up layout so that it resizes more cleanly --- .../DataResultViewerThumbnail.form | 461 ++++++++++-------- .../DataResultViewerThumbnail.java | 393 ++++++++++++--- 2 files changed, 582 insertions(+), 272 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.form b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.form index a042fd7de6..798b0b51bd 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.form @@ -11,217 +11,278 @@ + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - - - - - - - - - - + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java index 4f4e41d04e..fac4c95813 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java @@ -19,9 +19,14 @@ package org.sleuthkit.autopsy.corecomponents; import java.awt.Color; +import java.awt.Component; +import java.awt.Container; import java.awt.Cursor; import java.awt.Dialog; +import java.awt.Dimension; import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Insets; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.List; @@ -32,8 +37,10 @@ import java.util.logging.Level; import java.util.prefs.Preferences; import java.util.stream.Collectors; import javax.swing.JOptionPane; +import javax.swing.JScrollPane; import javax.swing.ListSelectionModel; import javax.swing.SortOrder; +import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import org.apache.commons.lang3.StringUtils; import org.netbeans.api.progress.ProgressHandle; @@ -122,6 +129,8 @@ public final class DataResultViewerThumbnail extends AbstractDataResultViewer { currentPage = -1; totalPages = 0; currentPageImages = 0; + + buttonBarPanel.setLayout(new WrapLayout(java.awt.FlowLayout.LEFT)); } /** @@ -132,33 +141,84 @@ public final class DataResultViewerThumbnail extends AbstractDataResultViewer { @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { + java.awt.GridBagConstraints gridBagConstraints; + buttonBarPanel = new javax.swing.JPanel(); + pagesPanel = new javax.swing.JPanel(); + pageNumberPane = new javax.swing.JPanel(); pageLabel = new javax.swing.JLabel(); + pageNumLabel = new javax.swing.JLabel(); + pageButtonPanel = new javax.swing.JPanel(); pagesLabel = new javax.swing.JLabel(); pagePrevButton = new javax.swing.JButton(); pageNextButton = new javax.swing.JButton(); - imagesLabel = new javax.swing.JLabel(); - imagesRangeLabel = new javax.swing.JLabel(); - pageNumLabel = new javax.swing.JLabel(); - filePathLabel = new javax.swing.JLabel(); + pageGotoPane = new javax.swing.JPanel(); goToPageLabel = new javax.swing.JLabel(); goToPageField = new javax.swing.JTextField(); + imagePane = new javax.swing.JPanel(); + imagesLabel = new javax.swing.JLabel(); + imagesRangeLabel = new javax.swing.JLabel(); thumbnailSizeComboBox = new javax.swing.JComboBox<>(); - iconView = new org.openide.explorer.view.IconView(); - sortButton = new javax.swing.JButton(); + sortPane = new javax.swing.JPanel(); sortLabel = new javax.swing.JLabel(); + sortButton = new javax.swing.JButton(); + filePathLabel = new javax.swing.JLabel(); + iconView = new org.openide.explorer.view.IconView(); + + setLayout(new java.awt.BorderLayout()); + + buttonBarPanel.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT)); + + pagesPanel.setLayout(new java.awt.GridBagLayout()); + + pageNumberPane.setLayout(new java.awt.GridBagLayout()); pageLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.pageLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; + gridBagConstraints.weighty = 1.0; + gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 9); + pageNumberPane.add(pageLabel, gridBagConstraints); + + pageNumLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.pageNumLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; + gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 15); + pageNumberPane.add(pageNumLabel, gridBagConstraints); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; + pagesPanel.add(pageNumberPane, gridBagConstraints); + + buttonBarPanel.add(pagesPanel); + + pageButtonPanel.setLayout(new java.awt.GridBagLayout()); pagesLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.pagesLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; + gridBagConstraints.weighty = 1.0; + gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 9); + pageButtonPanel.add(pagesLabel, gridBagConstraints); pagePrevButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back.png"))); // NOI18N pagePrevButton.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.pagePrevButton.text")); // NOI18N + pagePrevButton.setBorder(null); pagePrevButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png"))); // NOI18N pagePrevButton.setFocusable(false); pagePrevButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - pagePrevButton.setMargin(new java.awt.Insets(2, 0, 2, 0)); - pagePrevButton.setPreferredSize(new java.awt.Dimension(55, 23)); + pagePrevButton.setMargin(new java.awt.Insets(0, 0, 0, 0)); pagePrevButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png"))); // NOI18N pagePrevButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); pagePrevButton.addActionListener(new java.awt.event.ActionListener() { @@ -166,13 +226,20 @@ public final class DataResultViewerThumbnail extends AbstractDataResultViewer { pagePrevButtonActionPerformed(evt); } }); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 0; + gridBagConstraints.gridheight = 2; + gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; + pageButtonPanel.add(pagePrevButton, gridBagConstraints); pageNextButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png"))); // NOI18N pageNextButton.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.pageNextButton.text")); // NOI18N + pageNextButton.setBorder(null); pageNextButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png"))); // NOI18N pageNextButton.setFocusable(false); pageNextButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - pageNextButton.setMargin(new java.awt.Insets(2, 0, 2, 0)); + pageNextButton.setMargin(new java.awt.Insets(0, 0, 0, 0)); pageNextButton.setMaximumSize(new java.awt.Dimension(27, 23)); pageNextButton.setMinimumSize(new java.awt.Dimension(27, 23)); pageNextButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png"))); // NOI18N @@ -182,16 +249,27 @@ public final class DataResultViewerThumbnail extends AbstractDataResultViewer { pageNextButtonActionPerformed(evt); } }); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 2; + gridBagConstraints.gridy = 0; + gridBagConstraints.gridheight = 2; + gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; + gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 15); + pageButtonPanel.add(pageNextButton, gridBagConstraints); - imagesLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.imagesLabel.text")); // NOI18N + buttonBarPanel.add(pageButtonPanel); - imagesRangeLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.imagesRangeLabel.text")); // NOI18N - - pageNumLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.pageNumLabel.text")); // NOI18N - - filePathLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.filePathLabel.text")); // NOI18N + pageGotoPane.setLayout(new java.awt.GridBagLayout()); goToPageLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.goToPageLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; + gridBagConstraints.weighty = 1.0; + gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 9); + pageGotoPane.add(goToPageLabel, gridBagConstraints); goToPageField.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.goToPageField.text")); // NOI18N goToPageField.addActionListener(new java.awt.event.ActionListener() { @@ -199,12 +277,49 @@ public final class DataResultViewerThumbnail extends AbstractDataResultViewer { goToPageFieldActionPerformed(evt); } }); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 0; + gridBagConstraints.gridheight = 2; + gridBagConstraints.ipadx = 75; + gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 15); + pageGotoPane.add(goToPageField, gridBagConstraints); + + buttonBarPanel.add(pageGotoPane); + + imagePane.setLayout(new java.awt.GridBagLayout()); + + imagesLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.imagesLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 9); + imagePane.add(imagesLabel, gridBagConstraints); + + imagesRangeLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.imagesRangeLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 15); + imagePane.add(imagesRangeLabel, gridBagConstraints); + + buttonBarPanel.add(imagePane); thumbnailSizeComboBox.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { thumbnailSizeComboBoxActionPerformed(evt); } }); + buttonBarPanel.add(thumbnailSizeComboBox); + + sortPane.setLayout(new java.awt.GridBagLayout()); + + sortLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.sortLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; + gridBagConstraints.weighty = 1.0; + sortPane.add(sortLabel, gridBagConstraints); sortButton.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.sortButton.text")); // NOI18N sortButton.addActionListener(new java.awt.event.ActionListener() { @@ -212,65 +327,20 @@ public final class DataResultViewerThumbnail extends AbstractDataResultViewer { sortButtonActionPerformed(evt); } }); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; + gridBagConstraints.insets = new java.awt.Insets(0, 15, 0, 9); + sortPane.add(sortButton, gridBagConstraints); - sortLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.sortLabel.text")); // NOI18N + buttonBarPanel.add(sortPane); - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(iconView, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(pageLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(pageNumLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 95, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(pagesLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(pagePrevButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, 0) - .addComponent(pageNextButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(goToPageLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(goToPageField, javax.swing.GroupLayout.PREFERRED_SIZE, 54, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(12, 12, 12) - .addComponent(imagesLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(imagesRangeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 91, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(thumbnailSizeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(30, 30, 30) - .addComponent(sortButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(sortLabel)) - .addComponent(filePathLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap()) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) - .addComponent(pageLabel) - .addComponent(pageNumLabel) - .addComponent(pagesLabel) - .addComponent(pagePrevButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(pageNextButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(goToPageLabel) - .addComponent(goToPageField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(imagesLabel) - .addComponent(imagesRangeLabel) - .addComponent(thumbnailSizeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(sortButton) - .addComponent(sortLabel)) - .addGap(13, 13, 13) - .addComponent(iconView, javax.swing.GroupLayout.DEFAULT_SIZE, 322, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(filePathLabel)) - ); + add(buttonBarPanel, java.awt.BorderLayout.NORTH); + + filePathLabel.setText(org.openide.util.NbBundle.getMessage(DataResultViewerThumbnail.class, "DataResultViewerThumbnail.filePathLabel.text")); // NOI18N + add(filePathLabel, java.awt.BorderLayout.SOUTH); + add(iconView, java.awt.BorderLayout.CENTER); }// //GEN-END:initComponents private void pagePrevButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pagePrevButtonActionPerformed @@ -355,19 +425,26 @@ public final class DataResultViewerThumbnail extends AbstractDataResultViewer { // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JPanel buttonBarPanel; private javax.swing.JLabel filePathLabel; private javax.swing.JTextField goToPageField; private javax.swing.JLabel goToPageLabel; private org.openide.explorer.view.IconView iconView; + private javax.swing.JPanel imagePane; private javax.swing.JLabel imagesLabel; private javax.swing.JLabel imagesRangeLabel; + private javax.swing.JPanel pageButtonPanel; + private javax.swing.JPanel pageGotoPane; private javax.swing.JLabel pageLabel; private javax.swing.JButton pageNextButton; private javax.swing.JLabel pageNumLabel; + private javax.swing.JPanel pageNumberPane; private javax.swing.JButton pagePrevButton; private javax.swing.JLabel pagesLabel; + private javax.swing.JPanel pagesPanel; private javax.swing.JButton sortButton; private javax.swing.JLabel sortLabel; + private javax.swing.JPanel sortPane; private javax.swing.JComboBox thumbnailSizeComboBox; // End of variables declaration//GEN-END:variables @@ -680,4 +757,176 @@ public final class DataResultViewerThumbnail extends AbstractDataResultViewer { } } } + + private class WrapLayout extends FlowLayout { + + private Dimension preferredLayoutSize; + + /** + * Constructs a new WrapLayout with a left alignment and a + * default 5-unit horizontal and vertical gap. + */ + public WrapLayout() { + super(); + } + + /** + * Constructs a new FlowLayout with the specified alignment + * and a default 5-unit horizontal and vertical gap. The value of the + * alignment argument must be one of WrapLayout, + * WrapLayout, or WrapLayout. + * + * @param align the alignment value + */ + public WrapLayout(int align) { + super(align); + } + + /** + * Creates a new flow layout manager with the indicated alignment and + * the indicated horizontal and vertical gaps. + *

+ * The value of the alignment argument must be one of + * WrapLayout, WrapLayout, or + * WrapLayout. + * + * @param align the alignment value + * @param hgap the horizontal gap between components + * @param vgap the vertical gap between components + */ + public WrapLayout(int align, int hgap, int vgap) { + super(align, hgap, vgap); + } + + /** + * Returns the preferred dimensions for this layout given the + * visible components in the specified target container. + * + * @param target the component which needs to be laid out + * + * @return the preferred dimensions to lay out the subcomponents of the + * specified container + */ + @Override + public Dimension preferredLayoutSize(Container target) { + return layoutSize(target, true); + } + + /** + * Returns the minimum dimensions needed to layout the visible + * components contained in the specified target container. + * + * @param target the component which needs to be laid out + * + * @return the minimum dimensions to lay out the subcomponents of the + * specified container + */ + @Override + public Dimension minimumLayoutSize(Container target) { + Dimension minimum = layoutSize(target, false); + minimum.width -= (getHgap() + 1); + return minimum; + } + + /** + * Returns the minimum or preferred dimension needed to layout the + * target container. + * + * @param target target to get layout size for + * @param preferred should preferred size be calculated + * + * @return the dimension to layout the target container + */ + private Dimension layoutSize(Container target, boolean preferred) { + synchronized (target.getTreeLock()) { + // Each row must fit with the width allocated to the containter. + // When the container width = 0, the preferred width of the container + // has not yet been calculated so lets ask for the maximum. + + int targetWidth = target.getSize().width; + Container container = target; + + while (container.getSize().width == 0 && container.getParent() != null) { + container = container.getParent(); + } + + targetWidth = container.getSize().width; + + if (targetWidth == 0) { + targetWidth = Integer.MAX_VALUE; + } + + int hgap = getHgap(); + int vgap = getVgap(); + Insets insets = target.getInsets(); + int horizontalInsetsAndGap = insets.left + insets.right + (hgap * 2); + int maxWidth = targetWidth - horizontalInsetsAndGap; + + // Fit components into the allowed width + Dimension dim = new Dimension(0, 0); + int rowWidth = 0; + int rowHeight = 0; + + int nmembers = target.getComponentCount(); + + for (int i = 0; i < nmembers; i++) { + Component m = target.getComponent(i); + + if (m.isVisible()) { + Dimension d = preferred ? m.getPreferredSize() : m.getMinimumSize(); + + // Can't add the component to current row. Start a new row. + if (rowWidth + d.width > maxWidth) { + addRow(dim, rowWidth, rowHeight); + rowWidth = 0; + rowHeight = 0; + } + + // Add a horizontal gap for all components after the first + if (rowWidth != 0) { + rowWidth += hgap; + } + + rowWidth += d.width; + rowHeight = Math.max(rowHeight, d.height); + } + } + + addRow(dim, rowWidth, rowHeight); + + dim.width += horizontalInsetsAndGap; + dim.height += insets.top + insets.bottom + vgap * 2; + + // When using a scroll pane or the DecoratedLookAndFeel we need to + // make sure the preferred size is less than the size of the + // target containter so shrinking the container size works + // correctly. Removing the horizontal gap is an easy way to do this. + Container scrollPane = SwingUtilities.getAncestorOfClass(JScrollPane.class, target); + + if (scrollPane != null && target.isValid()) { + dim.width -= (hgap + 1); + } + + return dim; + } + } + + /* + * A new row has been completed. Use the dimensions of this row to + * update the preferred size for the container. + * + * @param dim update the width and height when appropriate @param + * rowWidth the width of the row to add @param rowHeight the height of + * the row to add + */ + private void addRow(Dimension dim, int rowWidth, int rowHeight) { + dim.width = Math.max(dim.width, rowWidth); + + if (dim.height > 0) { + dim.height += getVgap(); + } + + dim.height += rowHeight; + } + } } From 6e2495cd19577982cb1ca81b4dfd1b915d07e0bd Mon Sep 17 00:00:00 2001 From: esaunders Date: Mon, 10 Jun 2019 16:11:37 -0400 Subject: [PATCH 094/115] Disable editing of max results spinner. --- .../autopsy/corecomponents/ViewPreferencesPanel.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.java index f23caa3c61..3bc034467b 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.java @@ -23,6 +23,7 @@ import java.util.EnumSet; import java.util.Objects; import java.util.TimeZone; import javax.swing.JPanel; +import javax.swing.JSpinner; import org.netbeans.spi.options.OptionsPanelController; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.CasePreferences; @@ -55,6 +56,9 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { groupByDataSourceCheckbox.setEnabled(evt.getNewValue() != null); }); this.timeZoneList.setListData(TimeZoneUtils.createTimeZoneList().stream().toArray(String[]::new)); + + // Disable manual editing of max results spinner + ((JSpinner.DefaultEditor)maxResultsSpinner.getEditor()).getTextField().setEditable(false); } @Override From c3d66edb8c74ef23fd6cdb473c1bd7c8569fdbc3 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 10 Jun 2019 16:59:55 -0400 Subject: [PATCH 095/115] 5166 fix matisse issues with HtmlViewer panel --- .../autopsy/contentviewers/HtmlViewer.form | 26 ++----------------- .../autopsy/contentviewers/HtmlViewer.java | 24 +++-------------- 2 files changed, 5 insertions(+), 45 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.form index a08d9e9b31..bb3b76f532 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.form @@ -11,30 +11,8 @@ + - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java index a7e3e7fd11..183e61446a 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java @@ -37,7 +37,7 @@ final class HtmlViewer extends javax.swing.JPanel implements FileTypeViewer { private static final long serialVersionUID = 1L; private static final Logger logger = Logger.getLogger(HtmlViewer.class.getName()); - + private org.sleuthkit.autopsy.contentviewers.HtmlPanel htmlPanel; private static final String[] SUPPORTED_MIMETYPES = new String[]{ "text/html", "application/xhtml+xml" @@ -47,6 +47,7 @@ final class HtmlViewer extends javax.swing.JPanel implements FileTypeViewer { * Creates new form HtmlViewerPanel */ HtmlViewer() { + htmlPanel = new org.sleuthkit.autopsy.contentviewers.HtmlPanel(); initComponents(); } @@ -81,31 +82,12 @@ final class HtmlViewer extends javax.swing.JPanel implements FileTypeViewer { // //GEN-BEGIN:initComponents private void initComponents() { - htmlPanel = new org.sleuthkit.autopsy.contentviewers.HtmlPanel(); - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(htmlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addContainerGap()) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(htmlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addContainerGap()) - ); + setLayout(new java.awt.BorderLayout()); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables - private org.sleuthkit.autopsy.contentviewers.HtmlPanel htmlPanel; // End of variables declaration//GEN-END:variables - @Override public List getSupportedMIMETypes() { return Arrays.asList(SUPPORTED_MIMETYPES); From 9a719074dc515221634cc9671420e9a936fd720a Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Mon, 10 Jun 2019 17:02:58 -0400 Subject: [PATCH 096/115] Fixed off by one bug --- Core/src/org/sleuthkit/autopsy/coreutils/StringExtract.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/StringExtract.java b/Core/src/org/sleuthkit/autopsy/coreutils/StringExtract.java index aded120ac7..0f89eb2291 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/StringExtract.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/StringExtract.java @@ -221,7 +221,8 @@ public class StringExtract { StringExtractResult resWin = null; if (enableUTF8 && resUTF16 != null) { resWin = runUTF16 && resUTF16.numChars > resUTF8.numChars ? resUTF16 : resUTF8; - } else if (enableUTF16) { + } else if (runUTF16) { + //Only let resUTF16 "win" if it was actually run. resWin = resUTF16; } else if (enableUTF8) { resWin = resUTF8; From e6bbb2e457e003e2eca3377dccde04992e37ab0d Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 10 Jun 2019 17:18:21 -0400 Subject: [PATCH 097/115] 5166 fix matisse issues with MessageContentViewer --- .../contentviewers/MessageContentViewer.form | 17 +------- .../contentviewers/MessageContentViewer.java | 39 +++++++------------ 2 files changed, 15 insertions(+), 41 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.form index 1172483699..cf38160cd6 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.form @@ -271,22 +271,7 @@ - - - - - - - - - - - - - - - - + diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java index 48f7e4e82e..0f36c84b9e 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java @@ -87,7 +87,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont private static final int ATTM_TAB_INDEX = 4; private final List textAreas; - + private final org.sleuthkit.autopsy.contentviewers.HtmlPanel htmlPanel = new org.sleuthkit.autopsy.contentviewers.HtmlPanel(); /** * Artifact currently being displayed */ @@ -101,6 +101,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont @NbBundle.Messages("MessageContentViewer.AtrachmentsPanel.title=Attachments") public MessageContentViewer() { initComponents(); + htmlPane.add(htmlPanel); envelopePanel.setBackground(new Color(0, 0, 0, 38)); drp = DataResultPanel.createInstanceUninitialized(Bundle.MessageContentViewer_AtrachmentsPanel_title(), "", new TableFilterNode(Node.EMPTY, false), 0, null); attachmentsScrollPane.setViewportView(drp); @@ -153,7 +154,6 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont textbodyScrollPane = new javax.swing.JScrollPane(); textbodyTextArea = new javax.swing.JTextArea(); htmlPane = new javax.swing.JPanel(); - htmlPanel = new org.sleuthkit.autopsy.contentviewers.HtmlPanel(); rtfbodyScrollPane = new javax.swing.JScrollPane(); rtfbodyTextPane = new javax.swing.JTextPane(); attachmentsPanel = new javax.swing.JPanel(); @@ -266,17 +266,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.textbodyScrollPane.TabConstraints.tabTitle"), textbodyScrollPane); // NOI18N - javax.swing.GroupLayout htmlPaneLayout = new javax.swing.GroupLayout(htmlPane); - htmlPane.setLayout(htmlPaneLayout); - htmlPaneLayout.setHorizontalGroup( - htmlPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(htmlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 647, Short.MAX_VALUE) - ); - htmlPaneLayout.setVerticalGroup( - htmlPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(htmlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 362, Short.MAX_VALUE) - ); - + htmlPane.setLayout(new java.awt.BorderLayout()); msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.htmlPane.TabConstraints.tabTitle"), htmlPane); // NOI18N rtfbodyScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); @@ -357,7 +347,6 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont private javax.swing.JScrollPane headersScrollPane; private javax.swing.JTextArea headersTextArea; private javax.swing.JPanel htmlPane; - private org.sleuthkit.autopsy.contentviewers.HtmlPanel htmlPanel; private javax.swing.JTabbedPane msgbodyTabbedPane; private javax.swing.JScrollPane rtfbodyScrollPane; private javax.swing.JTextPane rtfbodyTextPane; @@ -534,7 +523,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont textComponent.setCaretPosition(0); //make sure we start at the top } } - + final boolean hasText = attributeText.length() > 0; msgbodyTabbedPane.setEnabledAt(index, hasText); @@ -680,18 +669,18 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont protected Sheet createSheet() { Sheet sheet = super.createSheet(); Set keepProps = new HashSet<>(Arrays.asList( - NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.nameColLbl"), - NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.score.name"), - NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.comment.name"), - NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.count.name"), - NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.sizeColLbl"), - NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.mimeType"), - NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.knownColLbl"))); - + NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.nameColLbl"), + NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.score.name"), + NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.comment.name"), + NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.count.name"), + NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.sizeColLbl"), + NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.mimeType"), + NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.knownColLbl"))); + //Remove all other props except for the ones above Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES); - for(Property p : sheetSet.getProperties()) { - if(!keepProps.contains(p.getName())){ + for (Property p : sheetSet.getProperties()) { + if (!keepProps.contains(p.getName())) { sheetSet.remove(p.getName()); } } From 7698a3e386f6fe493f95842d1b4ca28203984653 Mon Sep 17 00:00:00 2001 From: Raman Date: Mon, 10 Jun 2019 21:09:16 -0400 Subject: [PATCH 098/115] Address review comments. --- .../autopsy/datamodel/DeletedContent.java | 8 +-- .../autopsy/datamodel/EmailExtracted.java | 10 ++-- .../autopsy/datamodel/ExtractedContent.java | 18 +++--- .../sleuthkit/autopsy/datamodel/FileSize.java | 9 +-- .../datamodel/FileTypesByExtension.java | 2 - .../datamodel/FileTypesByMimeType.java | 2 - .../autopsy/datamodel/HashsetHits.java | 10 ++-- .../autopsy/datamodel/InterestingHits.java | 10 ++-- .../autopsy/datamodel/KeywordHits.java | 10 ++-- .../org/sleuthkit/autopsy/datamodel/Tags.java | 56 +++++++++---------- .../autopsy/datamodel/accounts/Accounts.java | 10 ++-- 11 files changed, 61 insertions(+), 84 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java index 69d7597653..adc5a34fa7 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java @@ -24,7 +24,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; import java.util.List; -import java.util.Objects; import java.util.Observable; import java.util.Observer; import java.util.Set; @@ -37,7 +36,6 @@ import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.CasePreferences; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; @@ -59,7 +57,7 @@ import org.sleuthkit.datamodel.VirtualDirectory; public class DeletedContent implements AutopsyVisitableItem { private SleuthkitCase skCase; - private final long datasourceObjId; + private final long filteringDSObjId; // 0 if not filtering/grouping by data source @NbBundle.Messages({"DeletedContent.fsDelFilter.text=File System", "DeletedContent.allDelFilter.text=All"}) @@ -105,11 +103,11 @@ public class DeletedContent implements AutopsyVisitableItem { public DeletedContent(SleuthkitCase skCase, long dsObjId) { this.skCase = skCase; - this.datasourceObjId = dsObjId; + this.filteringDSObjId = dsObjId; } long filteringDataSourceObjId() { - return this.datasourceObjId; + return this.filteringDSObjId; } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java index fe88ccb90a..7285b2cb8d 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java @@ -28,7 +28,6 @@ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Observable; import java.util.Observer; import java.util.Set; @@ -40,7 +39,6 @@ import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.CasePreferences; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; @@ -88,7 +86,7 @@ public class EmailExtracted implements AutopsyVisitableItem { } private SleuthkitCase skCase; private final EmailResults emailResults; - private final long datasourceObjId; + private final long filteringDSObjId; // 0 if not filtering/grouping by data source @@ -110,7 +108,7 @@ public class EmailExtracted implements AutopsyVisitableItem { */ public EmailExtracted(SleuthkitCase skCase, long objId) { this.skCase = skCase; - this.datasourceObjId = objId; + this.filteringDSObjId = objId; emailResults = new EmailResults(); } @@ -162,8 +160,8 @@ public class EmailExtracted implements AutopsyVisitableItem { + "attribute_type_id=" + pathAttrId //NON-NLS + " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS + " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS - if (datasourceObjId > 0) { - query += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId; + if (filteringDSObjId > 0) { + query += " AND blackboard_artifacts.data_source_obj_id = " + filteringDSObjId; } try (CaseDbQuery dbQuery = skCase.executeQuery(query)) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index 2baecb45a1..a51e36eb87 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -26,7 +26,6 @@ import java.util.Comparator; import java.util.EnumSet; import java.util.HashMap; import java.util.List; -import java.util.Objects; import java.util.logging.Level; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; @@ -35,7 +34,6 @@ import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.CasePreferences; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; @@ -64,7 +62,7 @@ public class ExtractedContent implements AutopsyVisitableItem { private SleuthkitCase skCase; // set to null after case has been closed private Blackboard blackboard; public static final String NAME = NbBundle.getMessage(RootNode.class, "ExtractedContentNode.name.text"); - private final long datasourceObjId; + private final long filteringDSObjId; // 0 if not filtering/grouping by data source /** * Constructs extracted content object @@ -83,7 +81,7 @@ public class ExtractedContent implements AutopsyVisitableItem { */ public ExtractedContent(SleuthkitCase skCase, long objId) { this.skCase = skCase; - this.datasourceObjId = objId; + this.filteringDSObjId = objId; this.blackboard = skCase.getBlackboard(); } @@ -307,8 +305,8 @@ public class ExtractedContent implements AutopsyVisitableItem { protected boolean createKeys(List list) { if (skCase != null) { try { - List types = (datasourceObjId > 0) ? - blackboard.getArtifactTypesInUse(datasourceObjId) : + List types = (filteringDSObjId > 0) ? + blackboard.getArtifactTypesInUse(filteringDSObjId) : skCase.getArtifactTypesInUse() ; types.removeAll(doNotShow); @@ -372,8 +370,8 @@ public class ExtractedContent implements AutopsyVisitableItem { // a performance increase might be had by adding a // "getBlackboardArtifactCount()" method to skCase try { - this.childCount = (datasourceObjId > 0) ? - blackboard.getArtifactsCount(type.getTypeID(), datasourceObjId) : + this.childCount = (filteringDSObjId > 0) ? + blackboard.getArtifactsCount(type.getTypeID(), filteringDSObjId) : skCase.getBlackboardArtifactsTypeCount(type.getTypeID()); } catch (TskException ex) { Logger.getLogger(TypeNode.class.getName()) @@ -501,8 +499,8 @@ public class ExtractedContent implements AutopsyVisitableItem { protected List makeKeys() { if (skCase != null) { try { - return (datasourceObjId > 0) - ? blackboard.getArtifacts(type.getTypeID(), datasourceObjId) + return (filteringDSObjId > 0) + ? blackboard.getArtifacts(type.getTypeID(), filteringDSObjId) : skCase.getBlackboardArtifacts(type.getTypeID()); } catch (TskException ex) { Logger.getLogger(ArtifactFactory.class.getName()).log(Level.SEVERE, "Couldn't get blackboard artifacts from database", ex); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java index e4f2a85002..9cceeb5a29 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java @@ -24,7 +24,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; import java.util.List; -import java.util.Objects; import java.util.Observable; import java.util.Observer; import java.util.Set; @@ -37,9 +36,7 @@ import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.CasePreferences; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.AbstractFile; @@ -63,7 +60,7 @@ import org.sleuthkit.datamodel.VirtualDirectory; public class FileSize implements AutopsyVisitableItem { private SleuthkitCase skCase; - private final long datasourceObjId; + private final long filteringDSObjId; // 0 if not filtering/grouping by data source public enum FileSizeFilter implements AutopsyVisitableItem { @@ -105,7 +102,7 @@ public class FileSize implements AutopsyVisitableItem { public FileSize(SleuthkitCase skCase, long dsObjId) { this.skCase = skCase; - this.datasourceObjId = dsObjId; + this.filteringDSObjId = dsObjId; } @Override @@ -118,7 +115,7 @@ public class FileSize implements AutopsyVisitableItem { } long filteringDataSourceObjId() { - return this.datasourceObjId; + return this.filteringDSObjId; } /* * Root node. Children are nodes for specific sizes. diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java index e0a887002f..34ec74280a 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java @@ -24,7 +24,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.List; -import java.util.Objects; import java.util.Observable; import java.util.Observer; import java.util.Set; @@ -39,7 +38,6 @@ import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.CasePreferences; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java index 5a5164f519..86cc42aa8c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java @@ -28,7 +28,6 @@ import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Observable; import java.util.Observer; import java.util.Set; @@ -42,7 +41,6 @@ import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.CasePreferences; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import static org.sleuthkit.autopsy.core.UserPreferences.hideKnownFilesInViewsTree; import static org.sleuthkit.autopsy.core.UserPreferences.hideSlackFilesInViewsTree; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java index 5d701fb400..03c72d2d2e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java @@ -30,7 +30,6 @@ import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Observable; import java.util.Observer; import java.util.Set; @@ -42,7 +41,6 @@ import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.CasePreferences; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; @@ -65,7 +63,7 @@ public class HashsetHits implements AutopsyVisitableItem { private static final Logger logger = Logger.getLogger(HashsetHits.class.getName()); private SleuthkitCase skCase; private final HashsetResults hashsetResults; - private final long datasourceObjId; + private final long filteringDSObjId; // 0 if not filtering/grouping by data source /** @@ -87,7 +85,7 @@ public class HashsetHits implements AutopsyVisitableItem { */ public HashsetHits(SleuthkitCase skCase, long objId) { this.skCase = skCase; - this.datasourceObjId = objId; + this.filteringDSObjId = objId; hashsetResults = new HashsetResults(); } @@ -142,8 +140,8 @@ public class HashsetHits implements AutopsyVisitableItem { + "attribute_type_id=" + setNameId //NON-NLS + " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS + " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS - if (datasourceObjId > 0) { - query += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId; + if (filteringDSObjId > 0) { + query += " AND blackboard_artifacts.data_source_obj_id = " + filteringDSObjId; } try (CaseDbQuery dbQuery = skCase.executeQuery(query)) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java index 7380de63d4..482ebf1558 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java @@ -30,7 +30,6 @@ import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Observable; import java.util.Observer; import java.util.Set; @@ -42,7 +41,6 @@ import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.CasePreferences; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; @@ -61,7 +59,7 @@ public class InterestingHits implements AutopsyVisitableItem { private static final Logger logger = Logger.getLogger(InterestingHits.class.getName()); private SleuthkitCase skCase; private final InterestingResults interestingResults = new InterestingResults(); - private final long datasourceObjId; + private final long filteringDSObjId; // 0 if not filtering/grouping by data source /** * Constructor @@ -82,7 +80,7 @@ public class InterestingHits implements AutopsyVisitableItem { */ public InterestingHits(SleuthkitCase skCase, long objId) { this.skCase = skCase; - this.datasourceObjId = objId; + this.filteringDSObjId = objId; interestingResults.update(); } @@ -133,8 +131,8 @@ public class InterestingHits implements AutopsyVisitableItem { + "attribute_type_id=" + setNameId //NON-NLS + " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS + " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS - if (datasourceObjId > 0) { - query += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId; + if (filteringDSObjId > 0) { + query += " AND blackboard_artifacts.data_source_obj_id = " + filteringDSObjId; } try (CaseDbQuery dbQuery = skCase.executeQuery(query)) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java index e78db54c01..655f0c1973 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java @@ -31,7 +31,6 @@ import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Observable; import java.util.Observer; import java.util.Set; @@ -45,7 +44,6 @@ import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.CasePreferences; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import static org.sleuthkit.autopsy.datamodel.Bundle.*; @@ -76,7 +74,7 @@ public class KeywordHits implements AutopsyVisitableItem { private SleuthkitCase skCase; private final KeywordResults keywordResults; - private final long datasourceObjId; + private final long filteringDSObjId; // 0 if not filtering/grouping by data source /** * String used in the instance MAP so that exact matches and substring can @@ -123,7 +121,7 @@ public class KeywordHits implements AutopsyVisitableItem { */ public KeywordHits(SleuthkitCase skCase, long objId) { this.skCase = skCase; - this.datasourceObjId = objId; + this.filteringDSObjId = objId; keywordResults = new KeywordResults(); } @@ -344,8 +342,8 @@ public class KeywordHits implements AutopsyVisitableItem { } String queryStr = KEYWORD_HIT_ATTRIBUTES_QUERY; - if (datasourceObjId > 0) { - queryStr += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId; + if (filteringDSObjId > 0) { + queryStr += " AND blackboard_artifacts.data_source_obj_id = " + filteringDSObjId; } try (CaseDbQuery dbQuery = skCase.executeQuery(queryStr)) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index bfdf8da357..2dfc02678b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -23,7 +23,6 @@ import java.beans.PropertyChangeListener; import java.util.Collections; import java.util.EnumSet; import java.util.List; -import java.util.Objects; import java.util.Observable; import java.util.Observer; import java.util.Set; @@ -35,7 +34,6 @@ import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.CasePreferences; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.core.UserPreferences; @@ -61,14 +59,14 @@ public class Tags implements AutopsyVisitableItem { private static final String USER_NAME_PROPERTY = "user.name"; //NON-NLS private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS - private final long datasourceObjId; + private final long filteringDSObjId; // 0 if not filtering/grouping by data source Tags() { this(0); } Tags(long dsObjId) { - this.datasourceObjId = dsObjId; + this.filteringDSObjId = dsObjId; } /** @@ -81,7 +79,7 @@ public class Tags implements AutopsyVisitableItem { } long filteringDataSourceObjId() { - return this.datasourceObjId; + return this.filteringDSObjId; } @Override @@ -156,7 +154,7 @@ public class Tags implements AutopsyVisitableItem { private class TagNameNodeFactory extends ChildFactory.Detachable implements Observer { - private final long datasourceObjId; + private final long filteringDSObjId; // 0 if not filtering/grouping by data source private final Set CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED, Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED, @@ -219,7 +217,7 @@ public class Tags implements AutopsyVisitableItem { * @param objId data source object id */ TagNameNodeFactory(long objId) { - this.datasourceObjId = objId; + this.filteringDSObjId = objId; } @@ -246,12 +244,12 @@ public class Tags implements AutopsyVisitableItem { List tagNamesInUse; if (UserPreferences.showOnlyCurrentUserTags()) { String userName = System.getProperty(USER_NAME_PROPERTY); - tagNamesInUse = (datasourceObjId > 0) - ? Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUseForUser(datasourceObjId, userName) + tagNamesInUse = (filteringDSObjId > 0) + ? Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUseForUser(filteringDSObjId, userName) : Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUseForUser(userName); } else { - tagNamesInUse = (datasourceObjId > 0) - ? Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse(datasourceObjId) + tagNamesInUse = (filteringDSObjId > 0) + ? Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse(filteringDSObjId) : Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse(); } Collections.sort(tagNamesInUse); @@ -303,17 +301,17 @@ public class Tags implements AutopsyVisitableItem { TagsManager tm = Case.getCurrentCaseThrows().getServices().getTagsManager(); if (UserPreferences.showOnlyCurrentUserTags()) { String userName = System.getProperty(USER_NAME_PROPERTY); - if (datasourceObjId > 0) { - tagsCount = tm.getContentTagsCountByTagNameForUser(tagName, datasourceObjId, userName); - tagsCount += tm.getBlackboardArtifactTagsCountByTagNameForUser(tagName, datasourceObjId, userName); + if (filteringDSObjId > 0) { + tagsCount = tm.getContentTagsCountByTagNameForUser(tagName, filteringDSObjId, userName); + tagsCount += tm.getBlackboardArtifactTagsCountByTagNameForUser(tagName, filteringDSObjId, userName); } else { tagsCount = tm.getContentTagsCountByTagNameForUser(tagName, userName); tagsCount += tm.getBlackboardArtifactTagsCountByTagNameForUser(tagName, userName); } } else { - if (datasourceObjId > 0) { - tagsCount = tm.getContentTagsCountByTagName(tagName, datasourceObjId); - tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName, datasourceObjId); + if (filteringDSObjId > 0) { + tagsCount = tm.getContentTagsCountByTagName(tagName, filteringDSObjId); + tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName, filteringDSObjId); } else { tagsCount = tm.getContentTagsCountByTagName(tagName); tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName); @@ -424,12 +422,12 @@ public class Tags implements AutopsyVisitableItem { if (UserPreferences.showOnlyCurrentUserTags()) { String userName = System.getProperty(USER_NAME_PROPERTY); - tagsCount = (datasourceObjId > 0) - ? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagNameForUser(tagName, datasourceObjId, userName) + tagsCount = (filteringDSObjId > 0) + ? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagNameForUser(tagName, filteringDSObjId, userName) : Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagNameForUser(tagName, userName); } else { - tagsCount = (datasourceObjId > 0) - ? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName, datasourceObjId) + tagsCount = (filteringDSObjId > 0) + ? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName, filteringDSObjId) : Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName); } } catch (TskCoreException | NoCurrentCaseException ex) { @@ -486,8 +484,8 @@ public class Tags implements AutopsyVisitableItem { protected boolean createKeys(List keys) { // Use the content tags bearing the specified tag name as the keys. try { - List contentTags = (datasourceObjId > 0) - ? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName, datasourceObjId) + List contentTags = (filteringDSObjId > 0) + ? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName, filteringDSObjId) : Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName); if (UserPreferences.showOnlyCurrentUserTags()) { String userName = System.getProperty(USER_NAME_PROPERTY); @@ -544,12 +542,12 @@ public class Tags implements AutopsyVisitableItem { try { if (UserPreferences.showOnlyCurrentUserTags()) { String userName = System.getProperty(USER_NAME_PROPERTY); - tagsCount = (datasourceObjId > 0) - ? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagNameForUser(tagName, datasourceObjId, userName) + tagsCount = (filteringDSObjId > 0) + ? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagNameForUser(tagName, filteringDSObjId, userName) : Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagNameForUser(tagName, userName); } else { - tagsCount = (datasourceObjId > 0) - ? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName, datasourceObjId) + tagsCount = (filteringDSObjId > 0) + ? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName, filteringDSObjId) : Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName); } } catch (TskCoreException | NoCurrentCaseException ex) { @@ -606,8 +604,8 @@ public class Tags implements AutopsyVisitableItem { protected boolean createKeys(List keys) { try { // Use the blackboard artifact tags bearing the specified tag name as the keys. - List artifactTags = (datasourceObjId > 0) - ? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName, datasourceObjId) + List artifactTags = (filteringDSObjId > 0) + ? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName, filteringDSObjId) : Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName); if (UserPreferences.showOnlyCurrentUserTags()) { String userName = System.getProperty(USER_NAME_PROPERTY); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java index f87cbb5e0c..4cd6e330e0 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java @@ -57,9 +57,7 @@ import org.openide.util.NbBundle; import org.openide.util.Utilities; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.CasePreferences; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.AutopsyItemVisitor; @@ -96,7 +94,7 @@ final public class Accounts implements AutopsyVisitableItem { final public static String NAME = Bundle.AccountsRootNode_name(); private SleuthkitCase skCase; - private final long datasourceObjId; + private final long filteringDSObjId; // 0 if not filtering/grouping by data source private final EventBus reviewStatusBus = new EventBus("ReviewStatusBus"); @@ -123,7 +121,7 @@ final public class Accounts implements AutopsyVisitableItem { */ public Accounts(SleuthkitCase skCase, long objId) { this.skCase = skCase; - this.datasourceObjId = objId; + this.filteringDSObjId = objId; this.rejectActionInstance = new RejectAccounts(); this.approveActionInstance = new ApproveAccounts(); @@ -153,8 +151,8 @@ final public class Accounts implements AutopsyVisitableItem { * based on the CasePreferences groupItemsInTreeByDataSource setting */ private String getFilterByDataSourceClause() { - if (datasourceObjId > 0) { - return " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId + " "; + if (filteringDSObjId > 0) { + return " AND blackboard_artifacts.data_source_obj_id = " + filteringDSObjId + " "; } return " "; From 1ba6ee2b2899ecfa28db08bbd7de111cba9714df Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 11 Jun 2019 08:04:00 -0400 Subject: [PATCH 099/115] Moved WrapLayout to its own public class --- .../DataResultViewerThumbnail.java | 182 +--------------- .../autopsy/corecomponents/WrapLayout.java | 205 ++++++++++++++++++ 2 files changed, 206 insertions(+), 181 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/corecomponents/WrapLayout.java diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java index fac4c95813..03b4750da4 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java @@ -19,14 +19,9 @@ package org.sleuthkit.autopsy.corecomponents; import java.awt.Color; -import java.awt.Component; -import java.awt.Container; import java.awt.Cursor; import java.awt.Dialog; -import java.awt.Dimension; import java.awt.EventQueue; -import java.awt.FlowLayout; -import java.awt.Insets; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.List; @@ -37,10 +32,7 @@ import java.util.logging.Level; import java.util.prefs.Preferences; import java.util.stream.Collectors; import javax.swing.JOptionPane; -import javax.swing.JScrollPane; import javax.swing.ListSelectionModel; -import javax.swing.SortOrder; -import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import org.apache.commons.lang3.StringUtils; import org.netbeans.api.progress.ProgressHandle; @@ -756,177 +748,5 @@ public final class DataResultViewerThumbnail extends AbstractDataResultViewer { } } } - } - - private class WrapLayout extends FlowLayout { - - private Dimension preferredLayoutSize; - - /** - * Constructs a new WrapLayout with a left alignment and a - * default 5-unit horizontal and vertical gap. - */ - public WrapLayout() { - super(); - } - - /** - * Constructs a new FlowLayout with the specified alignment - * and a default 5-unit horizontal and vertical gap. The value of the - * alignment argument must be one of WrapLayout, - * WrapLayout, or WrapLayout. - * - * @param align the alignment value - */ - public WrapLayout(int align) { - super(align); - } - - /** - * Creates a new flow layout manager with the indicated alignment and - * the indicated horizontal and vertical gaps. - *

- * The value of the alignment argument must be one of - * WrapLayout, WrapLayout, or - * WrapLayout. - * - * @param align the alignment value - * @param hgap the horizontal gap between components - * @param vgap the vertical gap between components - */ - public WrapLayout(int align, int hgap, int vgap) { - super(align, hgap, vgap); - } - - /** - * Returns the preferred dimensions for this layout given the - * visible components in the specified target container. - * - * @param target the component which needs to be laid out - * - * @return the preferred dimensions to lay out the subcomponents of the - * specified container - */ - @Override - public Dimension preferredLayoutSize(Container target) { - return layoutSize(target, true); - } - - /** - * Returns the minimum dimensions needed to layout the visible - * components contained in the specified target container. - * - * @param target the component which needs to be laid out - * - * @return the minimum dimensions to lay out the subcomponents of the - * specified container - */ - @Override - public Dimension minimumLayoutSize(Container target) { - Dimension minimum = layoutSize(target, false); - minimum.width -= (getHgap() + 1); - return minimum; - } - - /** - * Returns the minimum or preferred dimension needed to layout the - * target container. - * - * @param target target to get layout size for - * @param preferred should preferred size be calculated - * - * @return the dimension to layout the target container - */ - private Dimension layoutSize(Container target, boolean preferred) { - synchronized (target.getTreeLock()) { - // Each row must fit with the width allocated to the containter. - // When the container width = 0, the preferred width of the container - // has not yet been calculated so lets ask for the maximum. - - int targetWidth = target.getSize().width; - Container container = target; - - while (container.getSize().width == 0 && container.getParent() != null) { - container = container.getParent(); - } - - targetWidth = container.getSize().width; - - if (targetWidth == 0) { - targetWidth = Integer.MAX_VALUE; - } - - int hgap = getHgap(); - int vgap = getVgap(); - Insets insets = target.getInsets(); - int horizontalInsetsAndGap = insets.left + insets.right + (hgap * 2); - int maxWidth = targetWidth - horizontalInsetsAndGap; - - // Fit components into the allowed width - Dimension dim = new Dimension(0, 0); - int rowWidth = 0; - int rowHeight = 0; - - int nmembers = target.getComponentCount(); - - for (int i = 0; i < nmembers; i++) { - Component m = target.getComponent(i); - - if (m.isVisible()) { - Dimension d = preferred ? m.getPreferredSize() : m.getMinimumSize(); - - // Can't add the component to current row. Start a new row. - if (rowWidth + d.width > maxWidth) { - addRow(dim, rowWidth, rowHeight); - rowWidth = 0; - rowHeight = 0; - } - - // Add a horizontal gap for all components after the first - if (rowWidth != 0) { - rowWidth += hgap; - } - - rowWidth += d.width; - rowHeight = Math.max(rowHeight, d.height); - } - } - - addRow(dim, rowWidth, rowHeight); - - dim.width += horizontalInsetsAndGap; - dim.height += insets.top + insets.bottom + vgap * 2; - - // When using a scroll pane or the DecoratedLookAndFeel we need to - // make sure the preferred size is less than the size of the - // target containter so shrinking the container size works - // correctly. Removing the horizontal gap is an easy way to do this. - Container scrollPane = SwingUtilities.getAncestorOfClass(JScrollPane.class, target); - - if (scrollPane != null && target.isValid()) { - dim.width -= (hgap + 1); - } - - return dim; - } - } - - /* - * A new row has been completed. Use the dimensions of this row to - * update the preferred size for the container. - * - * @param dim update the width and height when appropriate @param - * rowWidth the width of the row to add @param rowHeight the height of - * the row to add - */ - private void addRow(Dimension dim, int rowWidth, int rowHeight) { - dim.width = Math.max(dim.width, rowWidth); - - if (dim.height > 0) { - dim.height += getVgap(); - } - - dim.height += rowHeight; - } - } + } } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/WrapLayout.java b/Core/src/org/sleuthkit/autopsy/corecomponents/WrapLayout.java new file mode 100755 index 0000000000..91235149a9 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/WrapLayout.java @@ -0,0 +1,205 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 Basis Technology Corp. + * Contact: carrier sleuthkit 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.corecomponents; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Insets; +import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; + +/** +* FlowLayout subclass that fully supports wrapping of components. +* +* Originally written by Rob Camick +* https://tips4java.wordpress.com/2008/11/06/wrap-layout/ +*/ +public class WrapLayout extends FlowLayout { + + private Dimension preferredLayoutSize; + + /** + * Constructs a new WrapLayout with a left alignment and a + * default 5-unit horizontal and vertical gap. + */ + public WrapLayout() { + super(); + } + + /** + * Constructs a new FlowLayout with the specified alignment + * and a default 5-unit horizontal and vertical gap. The value of the + * alignment argument must be one of WrapLayout, + * WrapLayout, or WrapLayout. + * + * @param align the alignment value + */ + public WrapLayout(int align) { + super(align); + } + + /** + * Creates a new flow layout manager with the indicated alignment and + * the indicated horizontal and vertical gaps. + *

+ * The value of the alignment argument must be one of + * WrapLayout, WrapLayout, or + * WrapLayout. + * + * @param align the alignment value + * @param hgap the horizontal gap between components + * @param vgap the vertical gap between components + */ + public WrapLayout(int align, int hgap, int vgap) { + super(align, hgap, vgap); + } + + /** + * Returns the preferred dimensions for this layout given the + * visible components in the specified target container. + * + * @param target the component which needs to be laid out + * + * @return the preferred dimensions to lay out the subcomponents of the + * specified container + */ + @Override + public Dimension preferredLayoutSize(Container target) { + return layoutSize(target, true); + } + + /** + * Returns the minimum dimensions needed to layout the visible + * components contained in the specified target container. + * + * @param target the component which needs to be laid out + * + * @return the minimum dimensions to lay out the subcomponents of the + * specified container + */ + @Override + public Dimension minimumLayoutSize(Container target) { + Dimension minimum = layoutSize(target, false); + minimum.width -= (getHgap() + 1); + return minimum; + } + + /** + * Returns the minimum or preferred dimension needed to layout the + * target container. + * + * @param target target to get layout size for + * @param preferred should preferred size be calculated + * + * @return the dimension to layout the target container + */ + private Dimension layoutSize(Container target, boolean preferred) { + synchronized (target.getTreeLock()) { + // Each row must fit with the width allocated to the containter. + // When the container width = 0, the preferred width of the container + // has not yet been calculated so lets ask for the maximum. + + int targetWidth = target.getSize().width; + Container container = target; + + while (container.getSize().width == 0 && container.getParent() != null) { + container = container.getParent(); + } + + targetWidth = container.getSize().width; + + if (targetWidth == 0) { + targetWidth = Integer.MAX_VALUE; + } + + int hgap = getHgap(); + int vgap = getVgap(); + Insets insets = target.getInsets(); + int horizontalInsetsAndGap = insets.left + insets.right + (hgap * 2); + int maxWidth = targetWidth - horizontalInsetsAndGap; + + // Fit components into the allowed width + Dimension dim = new Dimension(0, 0); + int rowWidth = 0; + int rowHeight = 0; + + int nmembers = target.getComponentCount(); + + for (int i = 0; i < nmembers; i++) { + Component m = target.getComponent(i); + + if (m.isVisible()) { + Dimension d = preferred ? m.getPreferredSize() : m.getMinimumSize(); + + // Can't add the component to current row. Start a new row. + if (rowWidth + d.width > maxWidth) { + addRow(dim, rowWidth, rowHeight); + rowWidth = 0; + rowHeight = 0; + } + + // Add a horizontal gap for all components after the first + if (rowWidth != 0) { + rowWidth += hgap; + } + + rowWidth += d.width; + rowHeight = Math.max(rowHeight, d.height); + } + } + + addRow(dim, rowWidth, rowHeight); + + dim.width += horizontalInsetsAndGap; + dim.height += insets.top + insets.bottom + vgap * 2; + + // When using a scroll pane or the DecoratedLookAndFeel we need to + // make sure the preferred size is less than the size of the + // target containter so shrinking the container size works + // correctly. Removing the horizontal gap is an easy way to do this. + Container scrollPane = SwingUtilities.getAncestorOfClass(JScrollPane.class, target); + + if (scrollPane != null && target.isValid()) { + dim.width -= (hgap + 1); + } + + return dim; + } + } + + /* + * A new row has been completed. Use the dimensions of this row to + * update the preferred size for the container. + * + * @param dim update the width and height when appropriate @param + * rowWidth the width of the row to add @param rowHeight the height of + * the row to add + */ + private void addRow(Dimension dim, int rowWidth, int rowHeight) { + dim.width = Math.max(dim.width, rowWidth); + + if (dim.height > 0) { + dim.height += getVgap(); + } + + dim.height += rowHeight; + } + } \ No newline at end of file From 374c20edde5a3f788debd2ffdf005f29e721156e Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 11 Jun 2019 08:10:28 -0400 Subject: [PATCH 100/115] Added missing import --- .../autopsy/actions/Bundle.properties-MERGED | 14 ------- .../casemodule/Bundle.properties-MERGED | 42 ++++--------------- .../Bundle.properties-MERGED | 11 ----- .../contentviewers/Bundle.properties-MERGED | 2 +- .../autopsy/core/Bundle.properties-MERGED | 8 +--- .../corecomponents/Bundle.properties-MERGED | 6 +-- .../DataResultViewerThumbnail.java | 4 ++ .../coreutils/Bundle.properties-MERGED | 4 +- .../datamodel/Bundle.properties-MERGED | 9 ++-- .../filesearch/Bundle.properties-MERGED | 4 +- .../autopsy/ingest/Bundle.properties-MERGED | 2 +- .../Bundle.properties-MERGED | 7 +--- .../modules/exif/Bundle.properties-MERGED | 4 +- .../fileextmismatch/Bundle.properties-MERGED | 18 ++++---- .../hashdatabase/Bundle.properties-MERGED | 10 +---- .../interestingitems/Bundle.properties-MERGED | 5 +-- .../photoreccarver/Bundle.properties-MERGED | 2 +- .../autopsy/report/Bundle.properties-MERGED | 8 ++-- .../timeline/ui/Bundle.properties-MERGED | 6 +-- 19 files changed, 48 insertions(+), 118 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties-MERGED index 506786c42d..bb34c94363 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties-MERGED @@ -1,35 +1,25 @@ AddBlackboardArtifactTagAction.pluralTagResult=Add Result Tags AddBlackboardArtifactTagAction.singularTagResult=Add Result Tag AddBlackboardArtifactTagAction.taggingErr=Tagging Error -# {0} - artifactName AddBlackboardArtifactTagAction.unableToTag.msg=Unable to tag {0}. AddContentTagAction.cannotApplyTagErr=Cannot Apply Tag AddContentTagAction.pluralTagFile=Add File Tags AddContentTagAction.singularTagFile=Add File Tag -# {0} - fileName -# {1} - tagName AddContentTagAction.tagExists={0} has been tagged as {1}. Cannot reapply the same tag. AddContentTagAction.taggingErr=Tagging Error -# {0} - fileName AddContentTagAction.unableToTag.msg=Unable to tag {0}, not a regular file. -# {0} - fileName AddContentTagAction.unableToTag.msg2=Unable to tag {0}. CTL_ShowIngestProgressSnapshotAction=Ingest Status Details DeleteBlackboardArtifactTagAction.deleteTag=Remove Selected Tag(s) DeleteBlackboardArtifactTagAction.tagDelErr=Tag Deletion Error -# {0} - tagName DeleteBlackboardArtifactTagAction.unableToDelTag.msg=Unable to delete tag {0}. DeleteContentTagAction.deleteTag=Remove Selected Tag(s) DeleteContentTagAction.tagDelErr=Tag Deletion Error -# {0} - tagName DeleteContentTagAction.unableToDelTag.msg=Unable to delete tag {0}. DeleteFileBlackboardArtifactTagAction.deleteTag=Remove Result Tag -# {0} - artifactID DeleteFileBlackboardArtifactTagAction.deleteTag.alert=Unable to untag artifact {0}. -# {0} - artifactID DeleteFileBlackboardArtifactTagAction.deleteTags.alert=Unable to untag artifact {0}. DeleteFileContentTagAction.deleteTag=Remove File Tag -# {0} - fileID DeleteFileContentTagAction.deleteTag.alert=Unable to untag file {0}. ExitAction.confirmationDialog.message=Ingest is running, are you sure you want to exit? ExitAction.confirmationDialog.title=Ingest is Running @@ -83,11 +73,7 @@ CTL_OpenOutputFolder=Open Output Folder OpenOutputFolder.error1=Output Folder Not Found: {0} OpenOutputFolder.noCaseOpen=No open case, therefore no current output folder available. OpenOutputFolder.CouldNotOpenOutputFolder=Could not open output folder -# {0} - old tag name -# {1} - artifactID ReplaceBlackboardArtifactTagAction.replaceTag.alert=Unable to replace tag {0} for artifact {1}. -# {0} - old tag name -# {1} - content obj id ReplaceContentTagAction.replaceTag.alert=Unable to replace tag {0} for {1}. ReplaceTagAction.replaceTag=Replace Selected Tag(s) With ShowIngestProgressSnapshotAction.actionName.text=Get Ingest Progress Snapshot diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED index 5ad9042e9f..bcaa9d1d28 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED @@ -1,18 +1,10 @@ AddImageWizardIngestConfigPanel.name.text=Configure Ingest Modules AddImageWizardSelectDspVisual.multiUserWarning.text=This type of Data Source Processor is not available in multi-user mode -# {0} - file AddLogicalImageTask.addingToReport=Adding {0} to report -# {0} - src -# {1} - dest AddLogicalImageTask.copyingImageFromTo=Copying image from {0} to {1} -# {0} - file AddLogicalImageTask.doneAddingToReport=Done adding {0} to report AddLogicalImageTask.doneCopying=Done copying -# {0} - file -# {1} - exception message AddLogicalImageTask.failedToAddReport=Failed to add report {0}. Reason= {1} -# {0} - src -# {1} - dest AddLogicalImageTask.failedToCopyDirectory=Failed to copy directory {0} to {1} # {0} - exception message Case.closeException.couldNotCloseCase=Error closing case: {0} @@ -20,7 +12,6 @@ Case.creationException.couldNotAcquireDirLock=Failed to get lock on case directo Case.creationException.couldNotAcquireResourcesLock=Failed to get lock on case resources Case.deleteCaseConfirmationDialog.message=Are you sure you want to close and delete the current case? Case.deleteCaseConfirmationDialog.title=Delete Current Case? -# {0} - exception message Case.deleteCaseFailureMessageBox.message=Error deleting case: {0} Case.deleteCaseFailureMessageBox.title=Failed to Delete Case Case.exceptionMessage.cancelledByUser=Cancelled by user. @@ -183,19 +174,13 @@ LogicalEvidenceFilePanel.validatePanel.nonL01Error.text=Only files with the .l01 LogicalFilesDspPanel.subTypeComboBox.l01FileOption.text=Logical evidence file (L01) LogicalFilesDspPanel.subTypeComboBox.localFilesOption.text=Local files and folders LogicalImagerDSProcessor.dataSourceType=Autopsy Imager -# {0} - directory LogicalImagerDSProcessor.directoryAlreadyExists=Directory {0} already exists -# {0} - directory LogicalImagerDSProcessor.failToCreateDirectory=Failed to create directory {0} -# {0} - imageDirPath LogicalImagerDSProcessor.imageDirPathNotFound={0} not found.\nUSB drive has been ejected. LogicalImagerPanel.imageTable.columnModel.title0=Hostname LogicalImagerPanel.imageTable.columnModel.title1=Extracted Date LogicalImagerPanel.messageLabel.clickScanOrBrowse=Click SCAN or BROWSE button to find images -# {0} - sparseImageDirectory -# {1} - image LogicalImagerPanel.messageLabel.directoryDoesNotContainSparseImage=Directory {0} does not contain {1} -# {0} - invalidFormatDirectory LogicalImagerPanel.messageLabel.directoryFormatInvalid=Directory {0} does not match format Logical_Imager_HOSTNAME_yyyymmdd_HH_MM_SS LogicalImagerPanel.messageLabel.driveHasNoImages=Drive has no images LogicalImagerPanel.messageLabel.noExternalDriveFound=No drive found @@ -266,15 +251,10 @@ AddImageWizardIngestConfigPanel.dsProcDone.errs.text=*Errors encountered in addi AddImageWizardIngestConfigVisual.getName.text=Configure Ingest Modules AddImageWizardIterator.stepXofN=Step {0} of {1} AddLocalFilesTask.localFileAdd.progress.text=Adding: {0}/{1} -Case.getCurCase.exception.noneOpen=Cannot get the current case; there is no case open\! +Case.getCurCase.exception.noneOpen=Cannot get the current case; there is no case open! Case.open.msgDlg.updated.msg=Updated case database schema.\nA backup copy of the database with the following path has been made:\n {0} Case.open.msgDlg.updated.title=Case Database Schema Update -Case.checkImgExist.confDlg.doesntExist.msg=One of the images associated with \n\ -this case are missing. Would you like to search for them now?\n\ -Previously, the image was located at:\n\ -{0}\n\ -Please note that you will still be able to browse directories and generate reports\n\ -if you choose No, but you will not be able to view file content or run the ingest process. +Case.checkImgExist.confDlg.doesntExist.msg=One of the images associated with \nthis case are missing. Would you like to search for them now?\nPreviously, the image was located at:\n{0}\nPlease note that you will still be able to browse directories and generate reports\nif you choose No, but you will not be able to view file content or run the ingest process. Case.checkImgExist.confDlg.doesntExist.title=Missing Image Case.addImg.exception.msg=Error adding image to the case Case.updateCaseName.exception.msg=Error while trying to update the case name. @@ -293,12 +273,9 @@ Case.GetCaseTypeGivenPath.Failure=Unable to get case type Case.metaDataFileCorrupt.exception.msg=The case metadata file (.aut) is corrupted. Case.deleteReports.deleteFromDiskException.log.msg=Unable to delete the report from the disk. Case.deleteReports.deleteFromDiskException.msg=Unable to delete the report {0} from the disk.\nYou may manually delete it from {1} -CaseDeleteAction.closeConfMsg.text=Are you sure want to close and delete this case? \n\ - Case Name: {0}\n\ - Case Directory: {1} +CaseDeleteAction.closeConfMsg.text=Are you sure want to close and delete this case? \nCase Name: {0}\nCase Directory: {1} CaseDeleteAction.closeConfMsg.title=Warning: Closing the Current Case -CaseDeleteAction.msgDlg.fileInUse.msg=The delete action cannot be fully completed because the folder or file in it is open by another program.\n\n\ -Close the folder and file and try again or you can delete the case manually. +CaseDeleteAction.msgDlg.fileInUse.msg=The delete action cannot be fully completed because the folder or file in it is open by another program.\n\nClose the folder and file and try again or you can delete the case manually. CaseDeleteAction.msgDlg.fileInUse.title=Error: Folder In Use CaseDeleteAction.msgDlg.caseDelete.msg=Case {0} has been deleted. CaseOpenAction.autFilter.title={0} Case File ( {1}) @@ -330,8 +307,7 @@ NewCaseWizardAction.databaseProblem1.text=Cannot open database. Cancelling case NewCaseWizardAction.databaseProblem2.text=Error NewCaseWizardPanel1.validate.errMsg.invalidSymbols=The Case Name cannot contain any of the following symbols: \\ / : * ? " < > | NewCaseWizardPanel1.validate.errMsg.dirExists=Case directory ''{0}'' already exists. -NewCaseWizardPanel1.validate.confMsg.createDir.msg=The base directory "{0}" does not exist. \n\n\ - Do you want to create that directory? +NewCaseWizardPanel1.validate.confMsg.createDir.msg=The base directory "{0}" does not exist. \n\nDo you want to create that directory? NewCaseWizardPanel1.validate.confMsg.createDir.title=Create directory NewCaseWizardPanel1.validate.errMsg.cantCreateParDir.msg=Error: Could not create case parent directory {0} NewCaseWizardPanel1.validate.errMsg.prevCreateBaseDir.msg=Prevented from creating base directory {0} @@ -360,14 +336,12 @@ OptionalCasePropertiesPanel.lbPointOfContactPhoneLabel.text=Phone: OptionalCasePropertiesPanel.orgainizationPanel.border.title=Organization RecentCases.exception.caseIdxOutOfRange.msg=Recent case index {0} is out of range. RecentCases.getName.text=Clear Recent Cases -# {0} - case name RecentItems.openRecentCase.msgDlg.text=Case {0} no longer exists. SelectDataSourceProcessorPanel.name.text=Select Type of Data Source To Add StartupWindow.title.text=Welcome UnpackagePortableCaseDialog.title.text=Unpackage Portable Case UnpackagePortableCaseDialog.UnpackagePortableCaseDialog.extensions=Portable case package (.zip, .zip.001) UnpackagePortableCaseDialog.validatePaths.badExtension=File extension must be .zip or .zip.001 -# {0} - case folder UnpackagePortableCaseDialog.validatePaths.caseFolderExists=Folder {0} already exists UnpackagePortableCaseDialog.validatePaths.caseIsNotFile=Selected path is not a file UnpackagePortableCaseDialog.validatePaths.caseNotFound=File does not exist @@ -381,15 +355,15 @@ UnpackageWorker.doInBackground.errorFinding7zip=Could not locate 7-Zip executabl UpdateRecentCases.menuItem.clearRecentCases.text=Clear Recent Cases UpdateRecentCases.menuItem.empty=-Empty- AddImageWizardIngestConfigPanel.CANCEL_BUTTON.text=Cancel -NewCaseVisualPanel1.CaseFolderOnCDriveError.text=Warning: Path to multi-user case folder is on \"C:\" drive -NewCaseVisualPanel1.CaseFolderOnInternalDriveWindowsError.text=Warning: Path to case folder is on \"C:\" drive. Case folder is created on the target system +NewCaseVisualPanel1.CaseFolderOnCDriveError.text=Warning: Path to multi-user case folder is on "C:" drive +NewCaseVisualPanel1.CaseFolderOnInternalDriveWindowsError.text=Warning: Path to case folder is on "C:" drive. Case folder is created on the target system NewCaseVisualPanel1.CaseFolderOnInternalDriveLinuxError.text=Warning: Path to case folder is on the target system. Create case folder in mounted drive. CollaborationMonitor.addingDataSourceStatus.msg={0} adding data source CollaborationMonitor.analyzingDataSourceStatus.msg={0} analyzing {1} MissingImageDialog.lbWarning.text= MissingImageDialog.lbWarning.toolTipText= NewCaseVisualPanel1.caseParentDirWarningLabel.text= -NewCaseVisualPanel1.multiUserCaseRadioButton.text=Multi-user +NewCaseVisualPanel1.multiUserCaseRadioButton.text=Multi-user\t\t NewCaseVisualPanel1.singleUserCaseRadioButton.text=Single-user NewCaseVisualPanel1.caseTypeLabel.text=Case Type: SingleUserCaseConverter.BadDatabaseFileName=Database file does not exist! diff --git a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/Bundle.properties-MERGED index d164529639..9cd17f566f 100755 --- a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/Bundle.properties-MERGED @@ -1,13 +1,8 @@ AbstractCommonFilesMetadataBuilder.buildCategorySelectionString.all=All File Categories AbstractCommonFilesMetadataBuilder.buildCategorySelectionString.doc=Documents AbstractCommonFilesMetadataBuilder.buildCategorySelectionString.media=Media -# {0} - threshold percent AbstractCommonFilesMetadataBuilder.getPercentFilter.thresholdPercent=, Threshold {0}% -# {0} - attr type -# {1} - threshold string AllInterCaseCommonAttributeSearcher.buildTabTitle.titleInterAll=Common Properties (All Central Repository Cases, {0}{1}) -# {0} - build category -# {1} - threshold string AllIntraCaseCommonAttributeSearcher.buildTabTitle.titleIntraAll=Common Properties (All Data Sources, {0}{1}) # {0} - number of datasources CommonAttributePanel.dataSourcesLabel.text=The current Central Repository contains {0} data source(s). @@ -103,13 +98,7 @@ CommonAttributePanel.organizeByCountRadio.text=Number of occurrences CommonAttributePanel.caseResultsRadioButton.text=Case CommonAttributePanel.countResultsRadioButton.text=Number of data sources CommonAttributePanel.displayResultsLabel.text_2=Display results organized by: -# {0} - case name -# {1} - attr type -# {2} - threshold string SingleInterCaseCommonAttributeSearcher.buildTabTitle.titleInterSingle=Common Properties (Central Repository Case: {0}, {1}{2}) -# {0} - data source name -# {1} - build category -# {2} - threshold string SingleIntraCaseCommonAttributeSearcher.buildTabTitle.titleIntraSingle=Common Properties (Data Source: {0}, {1}{2}) UserInputErrorManager.categories=No file categories are included in the search. UserInputErrorManager.frequency=Invalid Frequency Percentage: 0 < % < 100. diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED index 7b8fa6ad6b..dc0ae90960 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED @@ -147,7 +147,7 @@ MediaViewImagePanel.rotationTextField.text= MediaViewImagePanel.rotateLeftButton.toolTipText= HtmlPanel.showImagesToggleButton.text=Download Images MediaPlayerPanel.audioSlider.toolTipText= -MediaPlayerPanel.VolumeIcon.text=\ \ \ \ \ Volume +MediaPlayerPanel.VolumeIcon.text=\ Volume MediaPlayerPanel.progressLabel.text=00:00:00/00:00:00 MediaPlayerPanel.playButton.text=\u25ba MediaPlayerPanel.infoLabel.text=No Errors diff --git a/Core/src/org/sleuthkit/autopsy/core/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/core/Bundle.properties-MERGED index 087eaec314..f7039ab4ce 100755 --- a/Core/src/org/sleuthkit/autopsy/core/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/core/Bundle.properties-MERGED @@ -3,13 +3,7 @@ Installer.closing.confirmationDialog.title=Ingest is Running # {0} - exception message Installer.closing.messageBox.caseCloseExceptionMessage=Error closing case: {0} OpenIDE-Module-Display-Category=Infrastructure -OpenIDE-Module-Long-Description=\ - This is the core Autopsy module.\n\n\ - The module contains the core components needed for the bare application to run; the RCP platform, windowing GUI, sleuthkit bindings, datamodel / storage, explorer, result viewers, content viewers, ingest framework, reporting, and core tools, such as the file search.\n\n\ - The framework included in the module contains APIs for developing modules for ingest, viewers and reporting. \ - The modules can be deployed as Plugins using the Autopsy plugin installer.\n\ - This module should not be uninstalled - without it, Autopsy will not run.\n\n\ - For more information, see http://www.sleuthkit.org/autopsy/ +OpenIDE-Module-Long-Description=This is the core Autopsy module.\n\nThe module contains the core components needed for the bare application to run; the RCP platform, windowing GUI, sleuthkit bindings, datamodel / storage, explorer, result viewers, content viewers, ingest framework, reporting, and core tools, such as the file search.\n\nThe framework included in the module contains APIs for developing modules for ingest, viewers and reporting. The modules can be deployed as Plugins using the Autopsy plugin installer.\nThis module should not be uninstalled - without it, Autopsy will not run.\n\nFor more information, see http://www.sleuthkit.org/autopsy/ OpenIDE-Module-Name=Autopsy-Core OpenIDE-Module-Short-Description=Autopsy Core Module org_sleuthkit_autopsy_core_update_center=http://sleuthkit.org/autopsy/updates.xml diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED index b0e36da986..d4794e7dc3 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED @@ -63,9 +63,9 @@ DataContentViewerHex.totalPageLabel.text_1=100 DataContentViewerHex.pageLabel2.text=Page # Product Information panel -LBL_Description=

\n Product Version: {0} ({9})
Sleuth Kit Version: {7}
Netbeans RCP Build: {8}
Java: {1}; {2}
System: {3}; {4}; {5}
Userdir: {6}
+LBL_Description=
\n Product Version: {0} ({9})
Sleuth Kit Version: {7}
Netbeans RCP Build: {8}
Java: {1}; {2}
System: {3}; {4}; {5}
Userdir: {6}
Format_OperatingSystem_Value={0} version {1} running on {2} -LBL_Copyright=
Autopsy™ is a digital forensics platform based on The Sleuth Kit™ and other tools.
Copyright © 2003-2018.
+LBL_Copyright=
Autopsy™ is a digital forensics platform based on The Sleuth Kit™ and other tools.
Copyright © 2003-2018.
SortChooser.dialogTitle=Choose Sort Criteria ThumbnailViewChildren.progress.cancelling=(Cancelling) # {0} - file name @@ -95,7 +95,7 @@ DataResultViewerThumbnail.pageNextButton.text= DataResultViewerThumbnail.imagesLabel.text=Images: DataResultViewerThumbnail.imagesRangeLabel.text=- DataResultViewerThumbnail.pageNumLabel.text=- -DataResultViewerThumbnail.filePathLabel.text=\ \ \ +DataResultViewerThumbnail.filePathLabel.text=\ DataResultViewerThumbnail.goToPageLabel.text=Go to Page: DataResultViewerThumbnail.goToPageField.text= AdvancedConfigurationDialog.cancelButton.text=Cancel diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java index 03b4750da4..3199dbd7e8 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java @@ -33,6 +33,7 @@ import java.util.prefs.Preferences; import java.util.stream.Collectors; import javax.swing.JOptionPane; import javax.swing.ListSelectionModel; +import javax.swing.SortOrder; import javax.swing.SwingWorker; import org.apache.commons.lang3.StringUtils; import org.netbeans.api.progress.ProgressHandle; @@ -122,6 +123,9 @@ public final class DataResultViewerThumbnail extends AbstractDataResultViewer { totalPages = 0; currentPageImages = 0; + // The GUI builder is using FlowLayout therefore this change so have no + // impact on the initally designed layout. This change will just effect + // how the components are laid out as size of the window changes. buttonBarPanel.setLayout(new WrapLayout(java.awt.FlowLayout.LEFT)); } diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/coreutils/Bundle.properties-MERGED index 17791d159d..702b726e08 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/coreutils/Bundle.properties-MERGED @@ -23,9 +23,7 @@ PlatformUtil.getProcVmUsed.sigarNotInit.msg=Cannot get virt mem used, sigar not PlatformUtil.getProcVmUsed.gen.msg=Cannot get virt mem used, {0} PlatformUtil.getJvmMemInfo.usageText=JVM heap usage: {0}, JVM non-heap usage: {1} PlatformUtil.getPhysicalMemInfo.usageText=Physical memory usage (max, total, free): {0}, {1}, {2} -PlatformUtil.getAllMemUsageInfo.usageText={0}\n\ -{1}\n\ -Process Virtual Memory: {2} +PlatformUtil.getAllMemUsageInfo.usageText={0}\n{1}\nProcess Virtual Memory: {2} # {0} - file name ReadImageTask.mesageText=Reading image: {0} StringExtract.illegalStateException.cannotInit.msg=Unicode table not properly initialized, cannot instantiate StringExtract diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED index 0386b0fef2..8c2c553ad0 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED @@ -44,7 +44,6 @@ ArtifactStringContent.attrsTableHeader.type=Type ArtifactStringContent.attrsTableHeader.value=Value ArtifactStringContent.failedToGetAttributes.message=Failed to get some or all attributes from case database ArtifactStringContent.failedToGetSourcePath.message=Failed to get source file path from case database -# {0} - node name BaseChildFactory.NoSuchEventBusException.message=No event bus for node: {0} BlackboardArtifactNode.createSheet.artifactDetails.displayName=Result Details BlackboardArtifactNode.createSheet.artifactDetails.name=Result Details @@ -261,10 +260,10 @@ ImageNode.getActions.viewInNewWin.text=View in New Window ImageNode.createSheet.name.name=Name ImageNode.createSheet.name.displayName=Name ImageNode.createSheet.name.desc=no description -Installer.exception.tskVerStringNull.msg=Sleuth Kit JNI test call returned without error, but version string was null\! -Installer.exception.taskVerStringBang.msg=Sleuth Kit JNI test call returned without error, but version string was ""\! -Installer.tskLibErr.msg=Problem with Sleuth Kit JNI. Test call failed\!\n\nDetails: {0} -Installer.tskLibErr.err=Fatal Error\! +Installer.exception.tskVerStringNull.msg=Sleuth Kit JNI test call returned without error, but version string was null! +Installer.exception.taskVerStringBang.msg=Sleuth Kit JNI test call returned without error, but version string was ""! +Installer.tskLibErr.msg=Problem with Sleuth Kit JNI. Test call failed!\n\nDetails: {0} +Installer.tskLibErr.err=Fatal Error! InterestingHits.interestingItems.text=INTERESTING ITEMS InterestingHits.displayName.text=Interesting Items InterestingHits.createSheet.name.name=Name diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties-MERGED index 08cc69c39c..7ab8ecbe04 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties-MERGED @@ -14,7 +14,7 @@ KnownStatusSearchPanel.knownCheckBox.text=Known Status: KnownStatusSearchPanel.knownBadOptionCheckBox.text=Notable KnownStatusSearchPanel.knownOptionCheckBox.text=Known (NSRL or other) KnownStatusSearchPanel.unknownOptionCheckBox.text=Unknown -DateSearchFilter.noneSelectedMsg.text=At least one date type must be selected\! +DateSearchFilter.noneSelectedMsg.text=At least one date type must be selected! DateSearchPanel.dateCheckBox.text=Date: DateSearchPanel.jLabel4.text=Timezone: DateSearchPanel.jLabel3.text=*The date format is mm/dd/yyyy @@ -56,7 +56,7 @@ FileSearchPanel.search.results.details=Large number of matches may impact perfor FileSearchPanel.search.exception.noFilterSelected.msg=At least one filter must be selected. FileSearchPanel.search.validationErr.msg=Validation Error: {0} FileSearchPanel.emptyWhereClause.text=Invalid options, nothing to show. -KnownStatusSearchFilter.noneSelectedMsg.text=At least one known status must be selected\! +KnownStatusSearchFilter.noneSelectedMsg.text=At least one known status must be selected! NameSearchFilter.emptyNameMsg.text=Must enter something for name search. SearchNode.getName.text=Search Result SizeSearchPanel.sizeCompareComboBox.equalTo=equal to diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED index 9e4f612b6b..6be3e48e71 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED @@ -140,7 +140,7 @@ IngestJob.cancelReason.outOfDiskSpace.text=Out of disk space IngestJob.cancelReason.servicesDown.text=Services Down IngestJob.cancelReason.caseClosed.text=Case closed IngestJobSettingsPanel.globalSettingsButton.text=Global Settings -gest +gest= IngestJobSettingsPanel.globalSettingsButton.actionCommand=Advanced IngestJobSettingsPanel.globalSettingsButton.text=Global Settings IngestJobSettingsPanel.pastJobsButton.text=History diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties-MERGED index d73865ac3e..4729293fb9 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties-MERGED @@ -11,12 +11,7 @@ ExtractArchiveWithPasswordAction.progress.text=Unpacking contents of archive: {0 ExtractArchiveWithPasswordAction.prompt.text=Enter Password ExtractArchiveWithPasswordAction.prompt.title=Enter Password OpenIDE-Module-Display-Category=Ingest Module -OpenIDE-Module-Long-Description=\ - Embedded File Extraction Ingest Module\n\nThe Embedded File Extraction Ingest Module processes document files (such as doc, docx, ppt, pptx, xls, xlsx) and archive files (such as zip and others archive types supported by the 7zip extractor).\n\ - Contents of these files are extracted and the derived files are added back to the current ingest to be processed by the configured ingest modules.\n\ - If the derived file happens to be an archive file, it will be re-processed by the 7zip extractor - the extractor will process archive files N-levels deep.\n\n\ - The extracted files are navigable in the directory tree.\n\n\ - The module is supported on Windows, Linux and Mac operating systems. +OpenIDE-Module-Long-Description=Embedded File Extraction Ingest Module\n\nThe Embedded File Extraction Ingest Module processes document files (such as doc, docx, ppt, pptx, xls, xlsx) and archive files (such as zip and others archive types supported by the 7zip extractor).\nContents of these files are extracted and the derived files are added back to the current ingest to be processed by the configured ingest modules.\nIf the derived file happens to be an archive file, it will be re-processed by the 7zip extractor - the extractor will process archive files N-levels deep.\n\nThe extracted files are navigable in the directory tree.\n\nThe module is supported on Windows, Linux and Mac operating systems. OpenIDE-Module-Name=Embedded File Extraction OpenIDE-Module-Short-Description=Embedded File Extraction Ingest Module EmbeddedFileExtractorIngestModule.SevenZipContentReadStream.seek.exception.invalidOrigin=Invalid seek origin: {0} diff --git a/Core/src/org/sleuthkit/autopsy/modules/exif/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/exif/Bundle.properties-MERGED index 9905159d99..ee788daf61 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/exif/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/exif/Bundle.properties-MERGED @@ -1,9 +1,7 @@ CannotRunFileTypeDetection=Cannot run file type detection. ExifParserFileIngestModule.indexError.message=Failed to index EXIF Metadata artifact for keyword search. OpenIDE-Module-Display-Category=Ingest Module -OpenIDE-Module-Long-Description=\ - Exif metadata ingest module. \n\n\ - The ingest module analyzes image files, extracts Exif information and posts the Exif data as results. +OpenIDE-Module-Long-Description=Exif metadata ingest module. \n\nThe ingest module analyzes image files, extracts Exif information and posts the Exif data as results. OpenIDE-Module-Name=ExifParser OpenIDE-Module-Short-Description=Exif metadata ingest module ExifParserFileIngestModule.moduleName.text=Exif Parser diff --git a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/Bundle.properties-MERGED index cfaadf1635..5063bd55fa 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/Bundle.properties-MERGED @@ -36,27 +36,27 @@ FileExtMismatchSettingsPanel.jLabel1.text=File Types: FileExtMismatchSettingsPanel.newExtButton.text=New Extension FileExtMismatchSettingsPanel.newMimePrompt.message=Add a new MIME file type: FileExtMismatchSettingsPanel.newMimePrompt.title=New MIME -FileExtMismatchSettingsPanel.newMimePrompt.emptyMime.message=MIME type text is empty\! +FileExtMismatchSettingsPanel.newMimePrompt.emptyMime.message=MIME type text is empty! FileExtMismatchSettingsPanel.newMimePrompt.emptyMime.title=Empty type -FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotSupported.message=MIME type not supported\! +FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotSupported.message=MIME type not supported! FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotSupported.title=Type not supported -FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeExists.message=MIME type already exists\! +FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeExists.message=MIME type already exists! FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeExists.title=Type already exists FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotDetectable.message=MIME type is not detectable by this module. FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotDetectable.title=Type not detectable -FileExtMismatchSettingsPanel.removeTypeButton.noneSelected.message=No MIME type selected\! +FileExtMismatchSettingsPanel.removeTypeButton.noneSelected.message=No MIME type selected! FileExtMismatchSettingsPanel.removeTypeButton.noneSelected.title=No type selected FileExtMismatchSettingsPanel.newExtPrompt.message=Add an allowed extension: FileExtMismatchSettingsPanel.newExtPrompt.title=New allowed extension -FileExtMismatchSettingsPanel.newExtPrompt.empty.message=Extension text is empty\! +FileExtMismatchSettingsPanel.newExtPrompt.empty.message=Extension text is empty! FileExtMismatchSettingsPanel.newExtPrompt.empty.title=Extension text empty -FileExtMismatchSettingsPanel.newExtPrompt.noMimeType.message=No MIME type selected\! +FileExtMismatchSettingsPanel.newExtPrompt.noMimeType.message=No MIME type selected! FileExtMismatchSettingsPanel.newExtPrompt.noMimeType.title=No MIME type selected -FileExtMismatchSettingsPanel.newExtPrompt.extExists.message=Extension already exists\! +FileExtMismatchSettingsPanel.newExtPrompt.extExists.message=Extension already exists! FileExtMismatchSettingsPanel.newExtPrompt.extExists.title=Extension already exists -FileExtMismatchSettingsPanel.removeExtButton.noneSelected.message=No extension selected\! +FileExtMismatchSettingsPanel.removeExtButton.noneSelected.message=No extension selected! FileExtMismatchSettingsPanel.removeExtButton.noneSelected.title=No extension selected -FileExtMismatchSettingsPanel.removeExtButton.noMimeTypeSelected.message=No MIME type selected\! +FileExtMismatchSettingsPanel.removeExtButton.noMimeTypeSelected.message=No MIME type selected! FileExtMismatchSettingsPanel.removeExtButton.noMimeTypeSelected.title=No MIME type selected FileExtMismatchSettingsPanel.removeTypeButton.toolTipText= FileExtMismatchModuleSettingsPanel.checkAllRadioButton.text=Check all file types diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties-MERGED index 2d105bc3a9..ed79db018d 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties-MERGED @@ -40,10 +40,7 @@ ImportCentralRepoDbProgressDialog.errorParsingFile.message=Error parsing hash se ImportCentralRepoDbProgressDialog.linesProcessed.message=\ hashes processed ImportCentralRepoDbProgressDialog.title.text=Central Repository Import Progress OpenIDE-Module-Display-Category=Ingest Module -OpenIDE-Module-Long-Description=\ - Hash Set ingest module. \n\n\ - The ingest module analyzes files in the disk image and marks them as "known" (based on NSRL hashset lookup for "known" files) and "bad / interesting" (based on one or more hash sets supplied by the user).\n\n\ - The module also contains additional non-ingest tools that are integrated in the GUI, such as file lookup by hash and hash set configuration. +OpenIDE-Module-Long-Description=Hash Set ingest module. \n\nThe ingest module analyzes files in the disk image and marks them as "known" (based on NSRL hashset lookup for "known" files) and "bad / interesting" (based on one or more hash sets supplied by the user).\n\nThe module also contains additional non-ingest tools that are integrated in the GUI, such as file lookup by hash and hash set configuration. OpenIDE-Module-Name=HashDatabases OptionsCategory_Name_HashDatabase=Hash Sets OptionsCategory_Keywords_HashDatabase=Hash Sets @@ -172,10 +169,7 @@ HashDbSearchThread.name.searching=Searching HashDbSearchThread.noMoreFilesWithMD5Msg=No other files with the same MD5 hash were found. ModalNoButtons.indexingDbsTitle=Indexing hash sets ModalNoButtons.indexingDbTitle=Indexing hash set -ModalNoButtons.exitHashDbIndexingMsg=You are about to exit out of indexing your hash sets. \n\ -The generated index will be left unusable. If you choose to continue,\n\ - please delete the corresponding -md5.idx file in the hash folder.\n\ - Exit indexing? +ModalNoButtons.exitHashDbIndexingMsg=You are about to exit out of indexing your hash sets. \nThe generated index will be left unusable. If you choose to continue,\nplease delete the corresponding -md5.idx file in the hash folder.\nExit indexing? ModalNoButtons.dlgTitle.unfinishedIndexing=Unfinished Indexing ModalNoButtons.indexThis.currentlyIndexing1Db=Currently indexing 1 hash set ModalNoButtons.indexThese.currentlyIndexing1OfNDbs=Currently indexing 1 of {0} diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED index 7ca4901b1b..e960a709d8 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED @@ -2,7 +2,6 @@ FilesIdentifierIngestJobSettingsPanel.getError=Error getting interesting files s FilesIdentifierIngestJobSettingsPanel.updateError=Error updating interesting files sets settings file. FilesIdentifierIngestModule.getFilesError=Error getting interesting files sets from file. FilesIdentifierIngestModule.indexError.message=Failed to index interesting file hit artifact for keyword search. -# {0} - daysIncluded FilesSet.rule.dateRule.toString=(modified within {0} day(s)) FilesSetDefsPanel.bytes=Bytes FilesSetDefsPanel.cancelImportMsg=Cancel import @@ -81,8 +80,8 @@ FilesSetRulePanel.nameTextField.text= FilesSetRulePanel.ruleNameLabel.text=Rule Name (Optional): FilesSetRulePanel.messages.emptyNameCondition=You must specify a name pattern for this rule. FilesSetRulePanel.messages.invalidNameRegex=The name regular expression is not valid:\n\n{0} -FilesSetRulePanel.messages.invalidCharInName=The name cannot contain \\, /, :, *, ?, \", <, or > unless it is a regular expression. -FilesSetRulePanel.messages.invalidCharInPath=The path cannot contain \\, :, *, ?, \", <, or > unless it is a regular expression. +FilesSetRulePanel.messages.invalidCharInName=The name cannot contain \\, /, :, *, ?, ", <, or > unless it is a regular expression. +FilesSetRulePanel.messages.invalidCharInPath=The path cannot contain \\, :, *, ?, ", <, or > unless it is a regular expression. FilesSetRulePanel.messages.invalidPathRegex=The path regular expression is not valid:\n\n{0} FilesSetDefsPanel.doFileSetsDialog.duplicateRuleSet.text=Rule set with name {0} already exists. FilesSetRulePanel.pathSeparatorInfoLabel.text=Use / as path separator diff --git a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties-MERGED index 87dacfc16c..2dc971a40d 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties-MERGED @@ -21,7 +21,7 @@ PhotoRecIngestModule.complete.totalParsetime=Total Parsing Time: PhotoRecIngestModule.complete.photoRecResults=PhotoRec Results PhotoRecIngestModule.NotEnoughDiskSpace.detail.msg=PhotoRec error processing {0} with {1} Not enough space on primary disk to save unallocated space. PhotoRecIngestModule.cancelledByUser=PhotoRec cancelled by user. -PhotoRecIngestModule.error.exitValue=PhotoRec carver returned error exit value \= {0} when scanning {1} +PhotoRecIngestModule.error.exitValue=PhotoRec carver returned error exit value = {0} when scanning {1} PhotoRecIngestModule.error.msg=Error processing {0} with PhotoRec carver. PhotoRecIngestModule.complete.numberOfErrors=Number of Errors while Carving: PhotoRecCarverIngestJobSettingsPanel.detectionSettingsLabel.text=PhotoRec Settings diff --git a/Core/src/org/sleuthkit/autopsy/report/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/Bundle.properties-MERGED index f9813728d5..6444541518 100644 --- a/Core/src/org/sleuthkit/autopsy/report/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/report/Bundle.properties-MERGED @@ -99,7 +99,7 @@ FileReportDataTypes.path.text=Full Path FileReportText.getName.text=Files - Text FileReportText.getDesc.text=A delimited text file containing information about individual files in the case. ReportBodyFile.progress.querying=Querying files... -ReportBodyFile.ingestWarning.text=Warning, this report was run before ingest services completed\! +ReportBodyFile.ingestWarning.text=Warning, this report was run before ingest services completed! ReportBodyFile.progress.loading=Loading files... ReportBodyFile.progress.processing=Now processing {0}... ReportBodyFile.getName.text=TSK Body File @@ -241,13 +241,13 @@ ReportHTML.getName.text=HTML Report ReportHTML.getDesc.text=A report about results and tagged items in HTML format. ReportHTML.writeIndex.title=for case {0} ReportHTML.writeIndex.noFrames.msg=Your browser is not compatible with our frame setup. -ReportHTML.writeIndex.noFrames.seeNav=Please see the navigation page for artifact links, -ReportHTML.writeIndex.seeSum=and the summary page for a case summary. +ReportHTML.writeIndex.noFrames.seeNav=Please see the navigation page for artifact links, +ReportHTML.writeIndex.seeSum=and the summary page for a case summary. ReportHTML.writeNav.title=Report Navigation ReportHTML.writeNav.h1=Report Navigation ReportHTML.writeNav.summary=Case Summary ReportHTML.writeSum.title=Case Summary -ReportHTML.writeSum.warningMsg=Warning, this report was run before ingest services completed\! +ReportHTML.writeSum.warningMsg=Warning, this report was run before ingest services completed! # # autopsy/test/scripts/regression.py._html_report_diff() uses reportGenOn.text, caseName, caseNum, # examiner as a regex signature to skip report.html and summary.html diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/timeline/ui/Bundle.properties-MERGED index 3255e82f2b..ed3e6724d8 100755 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/Bundle.properties-MERGED @@ -1,4 +1,4 @@ -/* +/*= * Autopsy Forensic Browser * * Copyright 2013-15 Basis Technology Corp. @@ -14,8 +14,8 @@ * 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. - */ +*=limitations under the License. +*/= AbstractTimelineChart.defaultTooltip.text=Drag the mouse to select a time interval to zoom into.\nRight-click for more actions. HistoryToolBar.historyLabel.text=History From 2cd04e99a51d15768aca4ff4f5642db7bbf8afdf Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 11 Jun 2019 08:47:52 -0400 Subject: [PATCH 101/115] changed WrapLayout to package scope instead of public --- Core/src/org/sleuthkit/autopsy/corecomponents/WrapLayout.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/WrapLayout.java b/Core/src/org/sleuthkit/autopsy/corecomponents/WrapLayout.java index 91235149a9..d4f9ea5e2f 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/WrapLayout.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/WrapLayout.java @@ -32,7 +32,7 @@ import javax.swing.SwingUtilities; * Originally written by Rob Camick * https://tips4java.wordpress.com/2008/11/06/wrap-layout/ */ -public class WrapLayout extends FlowLayout { +class WrapLayout extends FlowLayout { private Dimension preferredLayoutSize; From 958139a7a5aae0c1efc1c76c6e2a019ec6c0bc0f Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 11 Jun 2019 11:30:35 -0400 Subject: [PATCH 102/115] Fixed filter panel layouts and added scroll bar --- .../communications/CVTTopComponent.form | 10 +- .../communications/CVTTopComponent.java | 4 +- .../autopsy/communications/FiltersPanel.form | 890 +++++++++--------- .../autopsy/communications/FiltersPanel.java | 470 +++++---- 4 files changed, 718 insertions(+), 656 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/CVTTopComponent.form b/Core/src/org/sleuthkit/autopsy/communications/CVTTopComponent.form index 77fc276f83..bc16bb6da2 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/CVTTopComponent.form +++ b/Core/src/org/sleuthkit/autopsy/communications/CVTTopComponent.form @@ -11,6 +11,7 @@ + @@ -28,7 +29,7 @@ - + @@ -65,14 +66,9 @@ - - - - - - + diff --git a/Core/src/org/sleuthkit/autopsy/communications/CVTTopComponent.java b/Core/src/org/sleuthkit/autopsy/communications/CVTTopComponent.java index 8e8365436c..0032793584 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/CVTTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/communications/CVTTopComponent.java @@ -112,18 +112,18 @@ public final class CVTTopComponent extends TopComponent { gridBagConstraints.gridy = 0; gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; - gridBagConstraints.weightx = 1.0; + gridBagConstraints.weightx = 0.75; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new Insets(15, 0, 15, 15); add(browseVisualizeTabPane, gridBagConstraints); browseVisualizeTabPane.getAccessibleContext().setAccessibleName(NbBundle.getMessage(CVTTopComponent.class, "CVTTopComponent.browseVisualizeTabPane.AccessibleContext.accessibleName")); // NOI18N - filtersPane.setMinimumSize(new Dimension(256, 495)); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 0.25; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new Insets(15, 15, 15, 5); add(filtersPane, gridBagConstraints); diff --git a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form index 8bd260ea4b..2a656008c2 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form +++ b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form @@ -11,493 +11,487 @@ + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - + - + - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - - - - - - + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + - - - - + + - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java index a6cdf63b63..5ba6b9b89a 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java @@ -394,135 +394,123 @@ final public class FiltersPanel extends JPanel { @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { + java.awt.GridBagConstraints gridBagConstraints; - applyFiltersButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/tick.png"))); // NOI18N - applyFiltersButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.applyFiltersButton.text")); // NOI18N - applyFiltersButton.setPreferredSize(null); + setLayout(new java.awt.GridBagLayout()); + + topPane.setLayout(new java.awt.GridBagLayout()); filtersTitleLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/funnel.png"))); // NOI18N filtersTitleLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.filtersTitleLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + topPane.add(filtersTitleLabel, gridBagConstraints); - unCheckAllAccountTypesButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.unCheckAllAccountTypesButton.text")); // NOI18N - unCheckAllAccountTypesButton.addActionListener(new java.awt.event.ActionListener() { + refreshButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/arrow-circle-double-135.png"))); // NOI18N + refreshButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.refreshButton.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 2; + gridBagConstraints.gridy = 0; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST; + topPane.add(refreshButton, gridBagConstraints); + + applyFiltersButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/tick.png"))); // NOI18N + applyFiltersButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.applyFiltersButton.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 0; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST; + topPane.add(applyFiltersButton, gridBagConstraints); + + needsRefreshLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.needsRefreshLabel.text")); // NOI18N + needsRefreshLabel.setForeground(new java.awt.Color(255, 0, 0)); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 1; + gridBagConstraints.gridwidth = 3; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + topPane.add(needsRefreshLabel, gridBagConstraints); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_END; + gridBagConstraints.weightx = 1.0; + add(topPane, gridBagConstraints); + + scrollPane.setBorder(null); + + mainPanel.setLayout(new java.awt.GridBagLayout()); + + limitPane.setLayout(new java.awt.GridBagLayout()); + + mostRecentLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.mostRecentLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 1; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(0, 9, 0, 9); + limitPane.add(mostRecentLabel, gridBagConstraints); + + limitComboBox.setEditable(true); + limitComboBox.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "All", "10000", "5000", "1000", "500", "100" })); + limitComboBox.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - unCheckAllAccountTypesButtonActionPerformed(evt); + limitComboBoxActionPerformed(evt); } }); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 1; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + limitPane.add(limitComboBox, gridBagConstraints); - accountTypesLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/accounts.png"))); // NOI18N - accountTypesLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.accountTypesLabel.text")); // NOI18N + limitTitlePanel.setLayout(new java.awt.GridBagLayout()); - checkAllAccountTypesButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.checkAllAccountTypesButton.text")); // NOI18N - checkAllAccountTypesButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - checkAllAccountTypesButtonActionPerformed(evt); - } - }); + limitHeaderLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.limitHeaderLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + limitTitlePanel.add(limitHeaderLabel, gridBagConstraints); - accountTypesScrollPane.setPreferredSize(new java.awt.Dimension(2, 200)); + limitErrorMsgLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/error-icon-16.png"))); // NOI18N + limitErrorMsgLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.limitErrorMsgLabel.text")); // NOI18N + limitErrorMsgLabel.setForeground(new java.awt.Color(255, 0, 0)); + limitErrorMsgLabel.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 0; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST; + limitTitlePanel.add(limitErrorMsgLabel, gridBagConstraints); - accountTypeListPane.setLayout(new javax.swing.BoxLayout(accountTypeListPane, javax.swing.BoxLayout.Y_AXIS)); - accountTypesScrollPane.setViewportView(accountTypeListPane); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.gridwidth = 2; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(0, 0, 9, 0); + limitPane.add(limitTitlePanel, gridBagConstraints); - accountTypeRequiredLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/error-icon-16.png"))); // NOI18N - accountTypeRequiredLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.accountTypeRequiredLabel.text")); // NOI18N - accountTypeRequiredLabel.setForeground(new java.awt.Color(255, 0, 0)); - accountTypeRequiredLabel.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT); - - javax.swing.GroupLayout accountTypesPaneLayout = new javax.swing.GroupLayout(accountTypesPane); - accountTypesPane.setLayout(accountTypesPaneLayout); - accountTypesPaneLayout.setHorizontalGroup( - accountTypesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, accountTypesPaneLayout.createSequentialGroup() - .addGroup(accountTypesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(accountTypesPaneLayout.createSequentialGroup() - .addComponent(accountTypesLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(accountTypeRequiredLabel)) - .addGroup(accountTypesPaneLayout.createSequentialGroup() - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(unCheckAllAccountTypesButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(checkAllAccountTypesButton)) - .addGroup(accountTypesPaneLayout.createSequentialGroup() - .addGap(10, 10, 10) - .addComponent(accountTypesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) - .addGap(0, 0, 0)) - ); - accountTypesPaneLayout.setVerticalGroup( - accountTypesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(accountTypesPaneLayout.createSequentialGroup() - .addGroup(accountTypesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(accountTypesLabel) - .addComponent(accountTypeRequiredLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(accountTypesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(accountTypesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(checkAllAccountTypesButton) - .addComponent(unCheckAllAccountTypesButton))) - ); - - unCheckAllDevicesButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.unCheckAllDevicesButton.text")); // NOI18N - unCheckAllDevicesButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - unCheckAllDevicesButtonActionPerformed(evt); - } - }); - - devicesLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/image.png"))); // NOI18N - devicesLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.devicesLabel.text")); // NOI18N - - checkAllDevicesButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.checkAllDevicesButton.text")); // NOI18N - checkAllDevicesButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - checkAllDevicesButtonActionPerformed(evt); - } - }); - - devicesScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); - devicesScrollPane.setMinimumSize(new java.awt.Dimension(27, 75)); - - devicesListPane.setMinimumSize(new java.awt.Dimension(4, 100)); - devicesListPane.setLayout(new javax.swing.BoxLayout(devicesListPane, javax.swing.BoxLayout.Y_AXIS)); - devicesScrollPane.setViewportView(devicesListPane); - - deviceRequiredLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/error-icon-16.png"))); // NOI18N - deviceRequiredLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.deviceRequiredLabel.text")); // NOI18N - deviceRequiredLabel.setForeground(new java.awt.Color(255, 0, 0)); - deviceRequiredLabel.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT); - - javax.swing.GroupLayout devicesPaneLayout = new javax.swing.GroupLayout(devicesPane); - devicesPane.setLayout(devicesPaneLayout); - devicesPaneLayout.setHorizontalGroup( - devicesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(devicesPaneLayout.createSequentialGroup() - .addComponent(devicesLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(deviceRequiredLabel)) - .addGroup(devicesPaneLayout.createSequentialGroup() - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(unCheckAllDevicesButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(checkAllDevicesButton)) - .addGroup(devicesPaneLayout.createSequentialGroup() - .addGap(10, 10, 10) - .addComponent(devicesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - devicesPaneLayout.setVerticalGroup( - devicesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(devicesPaneLayout.createSequentialGroup() - .addGroup(devicesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(devicesLabel) - .addComponent(deviceRequiredLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(devicesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 94, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(devicesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(checkAllDevicesButton) - .addComponent(unCheckAllDevicesButton)) - .addGap(5, 5, 5)) - ); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 3; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.weighty = 1.0; + gridBagConstraints.insets = new java.awt.Insets(15, 0, 15, 0); + mainPanel.add(limitPane, gridBagConstraints); startDatePicker.setEnabled(false); @@ -582,97 +570,177 @@ final public class FiltersPanel extends JPanel { .addComponent(endCheckBox))) ); - refreshButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/arrow-circle-double-135.png"))); // NOI18N - refreshButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.refreshButton.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 2; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(15, 0, 0, 0); + mainPanel.add(dateRangePane, gridBagConstraints); - needsRefreshLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.needsRefreshLabel.text")); // NOI18N - needsRefreshLabel.setForeground(new java.awt.Color(255, 0, 0)); + devicesPane.setLayout(new java.awt.GridBagLayout()); - limitHeaderLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.limitHeaderLabel.text")); // NOI18N - - mostRecentLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.mostRecentLabel.text")); // NOI18N - - limitComboBox.setEditable(true); - limitComboBox.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "All", "10000", "5000", "1000", "500", "100" })); - limitComboBox.addActionListener(new java.awt.event.ActionListener() { + unCheckAllDevicesButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.unCheckAllDevicesButton.text")); // NOI18N + unCheckAllDevicesButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - limitComboBoxActionPerformed(evt); + unCheckAllDevicesButtonActionPerformed(evt); } }); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 2; + gridBagConstraints.gridwidth = 2; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(9, 0, 0, 9); + devicesPane.add(unCheckAllDevicesButton, gridBagConstraints); - limitErrorMsgLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/error-icon-16.png"))); // NOI18N - limitErrorMsgLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.limitErrorMsgLabel.text")); // NOI18N - limitErrorMsgLabel.setForeground(new java.awt.Color(255, 0, 0)); - limitErrorMsgLabel.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING); + devicesLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/image.png"))); // NOI18N + devicesLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.devicesLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(0, 0, 9, 0); + devicesPane.add(devicesLabel, gridBagConstraints); - javax.swing.GroupLayout limitPaneLayout = new javax.swing.GroupLayout(limitPane); - limitPane.setLayout(limitPaneLayout); - limitPaneLayout.setHorizontalGroup( - limitPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(limitPaneLayout.createSequentialGroup() - .addComponent(limitHeaderLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(limitErrorMsgLabel) - .addContainerGap()) - .addGroup(limitPaneLayout.createSequentialGroup() - .addContainerGap() - .addComponent(mostRecentLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(limitComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - limitPaneLayout.setVerticalGroup( - limitPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(limitPaneLayout.createSequentialGroup() - .addContainerGap() - .addGroup(limitPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(limitHeaderLabel) - .addComponent(limitErrorMsgLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(limitPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(mostRecentLabel) - .addComponent(limitComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(0, 32, Short.MAX_VALUE)) - ); + checkAllDevicesButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.checkAllDevicesButton.text")); // NOI18N + checkAllDevicesButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + checkAllDevicesButtonActionPerformed(evt); + } + }); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 2; + gridBagConstraints.gridy = 2; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST; + gridBagConstraints.insets = new java.awt.Insets(9, 0, 0, 0); + devicesPane.add(checkAllDevicesButton, gridBagConstraints); - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(devicesPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(accountTypesPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(layout.createSequentialGroup() - .addComponent(filtersTitleLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(applyFiltersButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(refreshButton)) - .addComponent(dateRangePane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(needsRefreshLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addComponent(limitPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGap(0, 0, 0) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(filtersTitleLabel) - .addComponent(applyFiltersButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(refreshButton)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(needsRefreshLabel) - .addGap(4, 4, 4) - .addComponent(devicesPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(accountTypesPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(dateRangePane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(limitPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); + devicesScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + devicesScrollPane.setMinimumSize(new java.awt.Dimension(27, 75)); + + devicesListPane.setMinimumSize(new java.awt.Dimension(4, 100)); + devicesListPane.setLayout(new javax.swing.BoxLayout(devicesListPane, javax.swing.BoxLayout.Y_AXIS)); + devicesScrollPane.setViewportView(devicesListPane); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 1; + gridBagConstraints.gridwidth = 3; + gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.weighty = 1.0; + devicesPane.add(devicesScrollPane, gridBagConstraints); + + deviceRequiredLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/error-icon-16.png"))); // NOI18N + deviceRequiredLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.deviceRequiredLabel.text")); // NOI18N + deviceRequiredLabel.setForeground(new java.awt.Color(255, 0, 0)); + deviceRequiredLabel.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 0; + gridBagConstraints.gridwidth = 2; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST; + gridBagConstraints.insets = new java.awt.Insets(0, 0, 9, 0); + devicesPane.add(deviceRequiredLabel, gridBagConstraints); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.ipady = 100; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(15, 0, 0, 0); + mainPanel.add(devicesPane, gridBagConstraints); + + accountTypesPane.setLayout(new java.awt.GridBagLayout()); + + unCheckAllAccountTypesButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.unCheckAllAccountTypesButton.text")); // NOI18N + unCheckAllAccountTypesButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + unCheckAllAccountTypesButtonActionPerformed(evt); + } + }); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 2; + gridBagConstraints.gridwidth = 2; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(9, 0, 0, 9); + accountTypesPane.add(unCheckAllAccountTypesButton, gridBagConstraints); + + accountTypesLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/accounts.png"))); // NOI18N + accountTypesLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.accountTypesLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + accountTypesPane.add(accountTypesLabel, gridBagConstraints); + + checkAllAccountTypesButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.checkAllAccountTypesButton.text")); // NOI18N + checkAllAccountTypesButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + checkAllAccountTypesButtonActionPerformed(evt); + } + }); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 2; + gridBagConstraints.gridy = 2; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST; + gridBagConstraints.insets = new java.awt.Insets(9, 0, 0, 0); + accountTypesPane.add(checkAllAccountTypesButton, gridBagConstraints); + + accountTypesScrollPane.setPreferredSize(new java.awt.Dimension(2, 200)); + + accountTypeListPane.setLayout(new javax.swing.BoxLayout(accountTypeListPane, javax.swing.BoxLayout.Y_AXIS)); + accountTypesScrollPane.setViewportView(accountTypeListPane); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 1; + gridBagConstraints.gridwidth = 3; + gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.weighty = 1.0; + gridBagConstraints.insets = new java.awt.Insets(9, 0, 0, 0); + accountTypesPane.add(accountTypesScrollPane, gridBagConstraints); + + accountTypeRequiredLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/error-icon-16.png"))); // NOI18N + accountTypeRequiredLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.accountTypeRequiredLabel.text")); // NOI18N + accountTypeRequiredLabel.setForeground(new java.awt.Color(255, 0, 0)); + accountTypeRequiredLabel.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 0; + gridBagConstraints.gridwidth = 2; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST; + accountTypesPane.add(accountTypeRequiredLabel, gridBagConstraints); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 1; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(15, 0, 0, 0); + mainPanel.add(accountTypesPane, gridBagConstraints); + + scrollPane.setViewportView(mainPanel); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 1; + gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.weighty = 1.0; + add(scrollPane, gridBagConstraints); }// //GEN-END:initComponents /** @@ -933,11 +1001,15 @@ final public class FiltersPanel extends JPanel { private final javax.swing.JLabel limitErrorMsgLabel = new javax.swing.JLabel(); private final javax.swing.JLabel limitHeaderLabel = new javax.swing.JLabel(); private final javax.swing.JPanel limitPane = new javax.swing.JPanel(); + private final javax.swing.JPanel limitTitlePanel = new javax.swing.JPanel(); + private final javax.swing.JPanel mainPanel = new javax.swing.JPanel(); private final javax.swing.JLabel mostRecentLabel = new javax.swing.JLabel(); private final javax.swing.JLabel needsRefreshLabel = new javax.swing.JLabel(); private final javax.swing.JButton refreshButton = new javax.swing.JButton(); + private final javax.swing.JScrollPane scrollPane = new javax.swing.JScrollPane(); private final javax.swing.JCheckBox startCheckBox = new javax.swing.JCheckBox(); private final com.github.lgooddatepicker.components.DatePicker startDatePicker = new com.github.lgooddatepicker.components.DatePicker(); + private final javax.swing.JPanel topPane = new javax.swing.JPanel(); private final javax.swing.JButton unCheckAllAccountTypesButton = new javax.swing.JButton(); private final javax.swing.JButton unCheckAllDevicesButton = new javax.swing.JButton(); // End of variables declaration//GEN-END:variables From e572e2c71830cceebe669a857a1a216335fbc1fc Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 11 Jun 2019 11:53:35 -0400 Subject: [PATCH 103/115] Removed the unused field --- Core/src/org/sleuthkit/autopsy/corecomponents/WrapLayout.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/WrapLayout.java b/Core/src/org/sleuthkit/autopsy/corecomponents/WrapLayout.java index d4f9ea5e2f..be35ea0581 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/WrapLayout.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/WrapLayout.java @@ -34,8 +34,6 @@ import javax.swing.SwingUtilities; */ class WrapLayout extends FlowLayout { - private Dimension preferredLayoutSize; - /** * Constructs a new WrapLayout with a left alignment and a * default 5-unit horizontal and vertical gap. From cf4d06f9bd40b7dd099145caec8fc9e2763969e7 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 11 Jun 2019 13:11:18 -0400 Subject: [PATCH 104/115] Fixed accoutbrowswer aoob exception --- .../org/sleuthkit/autopsy/communications/AccountsBrowser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.java b/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.java index 54ab3fba23..fe66b2fa6e 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.java +++ b/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.java @@ -122,7 +122,7 @@ public final class AccountsBrowser extends JPanel implements ExplorerManager.Pro final int rows = Math.min(100, outline.getRowCount()); - for (int column = 0; column < outline.getModel().getColumnCount(); column++) { + for (int column = 0; column < outline.getColumnCount(); column++) { int columnWidthLimit = 500; int columnWidth = 0; From 5718d34376e7d14b2653a8cc4f458c903efcc832 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 11 Jun 2019 13:14:02 -0400 Subject: [PATCH 105/115] 5166 add htmlPanel to htmlviewer again --- Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java index 183e61446a..fb88ed9312 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java @@ -37,18 +37,18 @@ final class HtmlViewer extends javax.swing.JPanel implements FileTypeViewer { private static final long serialVersionUID = 1L; private static final Logger logger = Logger.getLogger(HtmlViewer.class.getName()); - private org.sleuthkit.autopsy.contentviewers.HtmlPanel htmlPanel; private static final String[] SUPPORTED_MIMETYPES = new String[]{ "text/html", "application/xhtml+xml" }; + private final org.sleuthkit.autopsy.contentviewers.HtmlPanel htmlPanel = new org.sleuthkit.autopsy.contentviewers.HtmlPanel(); /** * Creates new form HtmlViewerPanel */ HtmlViewer() { - htmlPanel = new org.sleuthkit.autopsy.contentviewers.HtmlPanel(); initComponents(); + this.add(htmlPanel); } /** From 3400f1dff9cef4394b9e21bab1d314329e33eaa3 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 11 Jun 2019 15:25:10 -0400 Subject: [PATCH 106/115] 5138 change path substring to be less confusing --- .../autopsy/modules/interestingitems/Bundle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties index 35378ab1a3..f12f1cd396 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties @@ -31,13 +31,13 @@ FilesSetRulePanel.messages.invalidCharInName=The name cannot contain \\, /, :, * FilesSetRulePanel.messages.invalidCharInPath=The path cannot contain \\, :, *, ?, \", <, or > unless it is a regular expression. FilesSetRulePanel.messages.invalidPathRegex=The path regular expression is not valid:\n\n{0} FilesSetDefsPanel.doFileSetsDialog.duplicateRuleSet.text=Rule set with name {0} already exists. -FilesSetRulePanel.pathSeparatorInfoLabel.text=Use / as path separator +FilesSetRulePanel.pathSeparatorInfoLabel.text=Folder must be in parent path. Use '/' to give consecutive names FilesIdentifierIngestJobSettingsPanel.border.title=Select interesting files sets to enable during ingest: FilesSetRulePanel.jLabel1.text=Type: FilesSetRulePanel.interesting.jLabel5.text=Enter information about files that you want to find. FilesSetRulePanel.ingest.jLabel5.text=Enter information about files that you want to run ingest on. FilesSetRulePanel.nameCheck.text=Name: -FilesSetRulePanel.pathCheck.text=Path Substring: +FilesSetRulePanel.pathCheck.text=Folder Name: FilesSetRulePanel.filesRadioButton.text=Files FilesSetRulePanel.dirsRadioButton.text=Directories FilesSetDefsPanel.interesting.setsListLabel.text=Rule Sets: From f2457cd20d00d1a24349d4c9ff3c2527c10cbea5 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 11 Jun 2019 15:33:03 -0400 Subject: [PATCH 107/115] 5138 merged properties change --- .../autopsy/modules/interestingitems/Bundle.properties-MERGED | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED index 7ca4901b1b..a401ae2021 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED @@ -85,13 +85,13 @@ FilesSetRulePanel.messages.invalidCharInName=The name cannot contain \\, /, :, * FilesSetRulePanel.messages.invalidCharInPath=The path cannot contain \\, :, *, ?, \", <, or > unless it is a regular expression. FilesSetRulePanel.messages.invalidPathRegex=The path regular expression is not valid:\n\n{0} FilesSetDefsPanel.doFileSetsDialog.duplicateRuleSet.text=Rule set with name {0} already exists. -FilesSetRulePanel.pathSeparatorInfoLabel.text=Use / as path separator +FilesSetRulePanel.pathSeparatorInfoLabel.text=Folder must be in parent path. Use '/' to give consecutive names FilesIdentifierIngestJobSettingsPanel.border.title=Select interesting files sets to enable during ingest: FilesSetRulePanel.jLabel1.text=Type: FilesSetRulePanel.interesting.jLabel5.text=Enter information about files that you want to find. FilesSetRulePanel.ingest.jLabel5.text=Enter information about files that you want to run ingest on. FilesSetRulePanel.nameCheck.text=Name: -FilesSetRulePanel.pathCheck.text=Path Substring: +FilesSetRulePanel.pathCheck.text=Folder Name: FilesSetRulePanel.filesRadioButton.text=Files FilesSetRulePanel.dirsRadioButton.text=Directories FilesSetDefsPanel.interesting.setsListLabel.text=Rule Sets: From cb0d58ee4320f4998ab5006118393ce37cedb057 Mon Sep 17 00:00:00 2001 From: Raman Date: Tue, 11 Jun 2019 15:34:50 -0400 Subject: [PATCH 108/115] 5108: NPE in LuceneQuery.postKeywordHitToBlackboard --- .../src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java index 66d0803812..fe1e9083dd 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java @@ -217,10 +217,10 @@ class QueryResults { SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase(); content = tskCase.getContentById(hit.getContentID()); } catch (TskCoreException | NoCurrentCaseException tskCoreException) { - logger.log(Level.SEVERE, "Failed to get text source object for ", tskCoreException); //NON-NLS + logger.log(Level.SEVERE, "Failed to get text source object for keyword hit", tskCoreException); //NON-NLS } - if (saveResults) { + if ((content != null) && saveResults) { /* * Post an artifact for the hit to the blackboard. */ From 30a36c2a08966c87edf5f4d3db187c84c1325109 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 11 Jun 2019 18:35:06 -0400 Subject: [PATCH 109/115] 5019 fix intra case search results O column displaying count --- .../datamodel/AbstractAbstractFileNode.java | 8 ++++---- .../datamodel/AbstractContentNode.java | 6 ++++-- .../datamodel/BlackboardArtifactNode.java | 19 +++++++++++-------- .../autopsy/datamodel/GetSCOTask.java | 16 +++++++++++----- .../autopsy/datamodel/ImageNode.java | 5 +++-- .../autopsy/datamodel/VolumeNode.java | 5 +++-- 6 files changed, 36 insertions(+), 23 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java index 34f498d050..e9b395f292 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java @@ -396,15 +396,15 @@ public abstract class AbstractAbstractFileNode extends A "# {0} - occurenceCount", "AbstractAbstractFileNode.createSheet.count.description=There were {0} datasource(s) found with occurences of the MD5 correlation value"}) @Override - protected Pair getCountPropertyAndDescription(CorrelationAttributeInstance attribute, String defaultDescription) { + protected Pair getCountPropertyAndDescription(CorrelationAttributeInstance.Type attributeType, String attributeValue, String defaultDescription) { Long count = -1L; //The column renderer will not display negative values, negative value used when count unavailble to preserve sorting String description = defaultDescription; try { //don't perform the query if there is no correlation value - if (attribute != null && StringUtils.isNotBlank(attribute.getCorrelationValue())) { - count = EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(attribute.getCorrelationType(), attribute.getCorrelationValue()); + if (attributeType != null && StringUtils.isNotBlank(attributeValue)) { + count = EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(attributeType, attributeValue); description = Bundle.AbstractAbstractFileNode_createSheet_count_description(count); - } else if (attribute != null) { + } else if (attributeType != null) { description = Bundle.AbstractAbstractFileNode_createSheet_count_hashLookupNotRun_description(); } } catch (EamDbException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java index 428509c54e..8b1d22d349 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java @@ -35,6 +35,7 @@ import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance.Type; import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; @@ -353,11 +354,12 @@ public abstract class AbstractContentNode extends ContentNode /** * Returns occurrences/count property for the node. * - * @param attribute correlation attribute instance + * @param attributeType the type of the attribute to count + * @param attributeValue the value of the attribute to count * @param defaultDescription a description to use when none is determined by * the getCountPropertyAndDescription method * * @return count property for the underlying content of the node. */ - abstract protected Pair getCountPropertyAndDescription(CorrelationAttributeInstance attribute, String defaultDescription); + abstract protected Pair getCountPropertyAndDescription(Type attributeType, String attributeValue, String defaultDescription); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java index 9444605b7c..ef96097391 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java @@ -52,6 +52,7 @@ import org.sleuthkit.autopsy.casemodule.events.CommentChangedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance.Type; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException; import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; @@ -751,7 +752,7 @@ public class BlackboardArtifactNode extends AbstractContentNode countAndDescription = getCountPropertyAndDescription(attribute, Bundle.BlackboardArtifactNode_createSheet_count_noCorrelationAttributes_description()); + Pair countAndDescription = getCountPropertyAndDescription(attribute.getCorrelationType(), attribute.getCorrelationValue(), Bundle.BlackboardArtifactNode_createSheet_count_noCorrelationAttributes_description()); sheetSet.put( new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_count_name(), Bundle.BlackboardArtifactNode_createSheet_count_displayName(), countAndDescription.getRight(), countAndDescription.getLeft())); } @@ -759,22 +760,24 @@ public class BlackboardArtifactNode extends AbstractContentNode getCountPropertyAndDescription(CorrelationAttributeInstance attribute, String defaultDescription) { + protected Pair getCountPropertyAndDescription(Type attributeType, String attributeValue, String defaultDescription) { Long count = -1L; String description = defaultDescription; try { //don't perform the query if there is no correlation value - if (attribute != null && StringUtils.isNotBlank(attribute.getCorrelationValue())) { - count = EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(attribute.getCorrelationType(), attribute.getCorrelationValue()); - description = Bundle.BlackboardArtifactNode_createSheet_count_description(count, attribute.getCorrelationType().getDisplayName()); - } else if (attribute != null) { + if (attributeType != null && StringUtils.isNotBlank(attributeValue)) { + count = EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(attributeType, attributeValue); + description = Bundle.BlackboardArtifactNode_createSheet_count_description(count, attributeType.getDisplayName()); + } else if (attributeType != null) { description = Bundle.BlackboardArtifactNode_createSheet_count_noCorrelationValues_description(); } } catch (EamDbException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java b/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java index 7f82f7fb64..f78e45461e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java @@ -24,6 +24,7 @@ import java.lang.ref.WeakReference; import java.util.List; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance.Type; import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.events.AutopsyEvent; @@ -63,8 +64,10 @@ class GetSCOTask implements Runnable { SCOData scoData = new SCOData(); scoData.setScoreAndDescription(contentNode.getScorePropertyAndDescription(tags)); scoData.setComment(contentNode.getCommentProperty(tags, fileAttribute)); + if (!UserPreferences.hideCentralRepoCommentsAndOccurrences()) { - CorrelationAttributeInstance occurrencesAttribute = null; + Type type = null; + String value = null; String description = Bundle.GetSCOTask_occurrences_defaultDescription(); if (contentNode instanceof BlackboardArtifactNode) { BlackboardArtifact bbArtifact = ((BlackboardArtifactNode) contentNode).getArtifact(); @@ -77,7 +80,8 @@ class GetSCOTask implements Runnable { || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID() || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID() || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { - occurrencesAttribute = fileAttribute; + type = fileAttribute.getCorrelationType(); + value = fileAttribute.getCorrelationValue(); } else { List listOfPossibleAttributes = EamArtifactUtil.makeInstancesFromBlackboardArtifact(bbArtifact, false); if (listOfPossibleAttributes.size() > 1) { @@ -85,14 +89,16 @@ class GetSCOTask implements Runnable { description = Bundle.GetSCOTask_occurrences_multipleProperties(); } else if (!listOfPossibleAttributes.isEmpty()) { //there should only be one item in the list - occurrencesAttribute = listOfPossibleAttributes.get(0); + type = listOfPossibleAttributes.get(0).getCorrelationType(); + value = listOfPossibleAttributes.get(0).getCorrelationValue(); } } } else { //use the file instance correlation attribute if the node is not a BlackboardArtifactNode - occurrencesAttribute = fileAttribute; + type = fileAttribute.getCorrelationType(); + value = fileAttribute.getCorrelationValue(); } - scoData.setCountAndDescription(contentNode.getCountPropertyAndDescription(occurrencesAttribute, description)); + scoData.setCountAndDescription(contentNode.getCountPropertyAndDescription(type, value, description)); } // signal SCO data is available. diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java index dbf58b2a84..da82c315b5 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java @@ -314,14 +314,15 @@ public class ImageNode extends AbstractContentNode { * * Null implementation of an abstract method. * - * @param attribute correlation attribute instance + * @param attributeType the type of the attribute to count + * @param attributeValue the value of the attribute to coun * @param defaultDescription a description to use when none is determined by * the getCountPropertyAndDescription method * * @return count property for the underlying content of the node. */ @Override - protected Pair getCountPropertyAndDescription(CorrelationAttributeInstance attribute, String defaultDescription) { + protected Pair getCountPropertyAndDescription(CorrelationAttributeInstance.Type attributeType, String attributeValue, String defaultDescription) { return Pair.of(-1L, NO_DESCR); } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/VolumeNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/VolumeNode.java index 8e825ed24c..307013136f 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/VolumeNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/VolumeNode.java @@ -279,14 +279,15 @@ public class VolumeNode extends AbstractContentNode { * * Null implementation of an abstract method. * - * @param attribute correlation attribute instance + * @param attributeType the type of the attribute to count + * @param attributeValue the value of the attribute to coun * @param defaultDescription a description to use when none is determined by * the getCountPropertyAndDescription method * * @return count property for the underlying content of the node. */ @Override - protected Pair getCountPropertyAndDescription(CorrelationAttributeInstance attribute, String defaultDescription) { + protected Pair getCountPropertyAndDescription(CorrelationAttributeInstance.Type attributeType, String attributeValue, String defaultDescription) { return Pair.of(-1L, NO_DESCR); } } From bc1eb083503d0570ae69f0cec0e37d026a5a3b02 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 11 Jun 2019 19:03:31 -0400 Subject: [PATCH 110/115] 5019 use correlation value and type independent of correlation attributes existence --- .../autopsy/datamodel/GetSCOTask.java | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java b/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java index f78e45461e..bcdca8632e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java @@ -22,14 +22,19 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.lang.ref.WeakReference; import java.util.List; +import java.util.logging.Level; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance.Type; import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; import org.sleuthkit.autopsy.core.UserPreferences; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.AutopsyEvent; +import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.Tag; +import org.sleuthkit.datamodel.TskCoreException; /** * Background task to get Score, Comment and Occurrences values for an Abstract @@ -40,6 +45,7 @@ class GetSCOTask implements Runnable { private final WeakReference> weakNodeRef; private final PropertyChangeListener listener; + private static final Logger logger = Logger.getLogger(GetSCOTask.class.getName()); GetSCOTask(WeakReference> weakContentRef, PropertyChangeListener listener) { this.weakNodeRef = weakContentRef; @@ -80,8 +86,14 @@ class GetSCOTask implements Runnable { || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID() || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID() || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { - type = fileAttribute.getCorrelationType(); - value = fileAttribute.getCorrelationValue(); + try { + if (bbArtifact.getParent() instanceof AbstractFile) { + type = CorrelationAttributeInstance.getDefaultCorrelationTypes().get(CorrelationAttributeInstance.FILES_TYPE_ID); + value = ((AbstractFile) bbArtifact.getParent()).getMd5Hash(); + } + } catch (TskCoreException | EamDbException ex) { + logger.log(Level.WARNING, "Unable to get correlation type or value to determine value for O column for artifact", ex); + } } else { List listOfPossibleAttributes = EamArtifactUtil.makeInstancesFromBlackboardArtifact(bbArtifact, false); if (listOfPossibleAttributes.size() > 1) { @@ -93,16 +105,21 @@ class GetSCOTask implements Runnable { value = listOfPossibleAttributes.get(0).getCorrelationValue(); } } - } else { - //use the file instance correlation attribute if the node is not a BlackboardArtifactNode - type = fileAttribute.getCorrelationType(); - value = fileAttribute.getCorrelationValue(); + } else if (contentNode.getContent() instanceof AbstractFile) { + //use the file instance correlation attribute if the node is not a BlackboardArtifactNode + try { + type = CorrelationAttributeInstance.getDefaultCorrelationTypes().get(CorrelationAttributeInstance.FILES_TYPE_ID); + value = ((AbstractFile) contentNode.getContent()).getMd5Hash(); + } catch (EamDbException ex) { + logger.log(Level.WARNING, "Unable to get correlation type to determine value for O column for file", ex); + } } scoData.setCountAndDescription(contentNode.getCountPropertyAndDescription(type, value, description)); } // signal SCO data is available. - if (listener != null) { + if (listener + != null) { listener.propertyChange(new PropertyChangeEvent( AutopsyEvent.SourceType.LOCAL.toString(), AbstractAbstractFileNode.NodeSpecificEvents.SCO_AVAILABLE.toString(), From 1684b62823f5e8454906b54f33133b6feb020705 Mon Sep 17 00:00:00 2001 From: Raman Date: Wed, 12 Jun 2019 11:28:28 -0400 Subject: [PATCH 111/115] 5105: Erroneous "new case" wizard behavior if case name ends with empty space character --- .../org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java index 8b551ce4ec..aedbb3671f 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java @@ -88,7 +88,7 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener { * @return caseName the case name from the case name text field */ String getCaseName() { - return this.caseNameTextField.getText(); + return this.caseNameTextField.getText().trim(); } /** @@ -109,7 +109,7 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener { * @return baseDirectory the base directory from the case dir text field */ String getCaseParentDir() { - String parentDir = this.caseParentDirTextField.getText(); + String parentDir = this.caseParentDirTextField.getText().trim(); if (parentDir.endsWith(File.separator) == false) { parentDir = parentDir + File.separator; } From 0c15fc140415bde96fb8279948383d35e071c558 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 12 Jun 2019 11:30:26 -0400 Subject: [PATCH 112/115] Add a merged files which have new bundle properties --- .../autopsy/actions/Bundle.properties-MERGED | 14 +++++++ .../casemodule/Bundle.properties-MERGED | 42 +++++++++++++++---- .../Bundle.properties-MERGED | 11 +++++ .../datamodel/Bundle.properties-MERGED | 9 ++-- 4 files changed, 64 insertions(+), 12 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties-MERGED index bb34c94363..506786c42d 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties-MERGED @@ -1,25 +1,35 @@ AddBlackboardArtifactTagAction.pluralTagResult=Add Result Tags AddBlackboardArtifactTagAction.singularTagResult=Add Result Tag AddBlackboardArtifactTagAction.taggingErr=Tagging Error +# {0} - artifactName AddBlackboardArtifactTagAction.unableToTag.msg=Unable to tag {0}. AddContentTagAction.cannotApplyTagErr=Cannot Apply Tag AddContentTagAction.pluralTagFile=Add File Tags AddContentTagAction.singularTagFile=Add File Tag +# {0} - fileName +# {1} - tagName AddContentTagAction.tagExists={0} has been tagged as {1}. Cannot reapply the same tag. AddContentTagAction.taggingErr=Tagging Error +# {0} - fileName AddContentTagAction.unableToTag.msg=Unable to tag {0}, not a regular file. +# {0} - fileName AddContentTagAction.unableToTag.msg2=Unable to tag {0}. CTL_ShowIngestProgressSnapshotAction=Ingest Status Details DeleteBlackboardArtifactTagAction.deleteTag=Remove Selected Tag(s) DeleteBlackboardArtifactTagAction.tagDelErr=Tag Deletion Error +# {0} - tagName DeleteBlackboardArtifactTagAction.unableToDelTag.msg=Unable to delete tag {0}. DeleteContentTagAction.deleteTag=Remove Selected Tag(s) DeleteContentTagAction.tagDelErr=Tag Deletion Error +# {0} - tagName DeleteContentTagAction.unableToDelTag.msg=Unable to delete tag {0}. DeleteFileBlackboardArtifactTagAction.deleteTag=Remove Result Tag +# {0} - artifactID DeleteFileBlackboardArtifactTagAction.deleteTag.alert=Unable to untag artifact {0}. +# {0} - artifactID DeleteFileBlackboardArtifactTagAction.deleteTags.alert=Unable to untag artifact {0}. DeleteFileContentTagAction.deleteTag=Remove File Tag +# {0} - fileID DeleteFileContentTagAction.deleteTag.alert=Unable to untag file {0}. ExitAction.confirmationDialog.message=Ingest is running, are you sure you want to exit? ExitAction.confirmationDialog.title=Ingest is Running @@ -73,7 +83,11 @@ CTL_OpenOutputFolder=Open Output Folder OpenOutputFolder.error1=Output Folder Not Found: {0} OpenOutputFolder.noCaseOpen=No open case, therefore no current output folder available. OpenOutputFolder.CouldNotOpenOutputFolder=Could not open output folder +# {0} - old tag name +# {1} - artifactID ReplaceBlackboardArtifactTagAction.replaceTag.alert=Unable to replace tag {0} for artifact {1}. +# {0} - old tag name +# {1} - content obj id ReplaceContentTagAction.replaceTag.alert=Unable to replace tag {0} for {1}. ReplaceTagAction.replaceTag=Replace Selected Tag(s) With ShowIngestProgressSnapshotAction.actionName.text=Get Ingest Progress Snapshot diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED index bcaa9d1d28..5ad9042e9f 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED @@ -1,10 +1,18 @@ AddImageWizardIngestConfigPanel.name.text=Configure Ingest Modules AddImageWizardSelectDspVisual.multiUserWarning.text=This type of Data Source Processor is not available in multi-user mode +# {0} - file AddLogicalImageTask.addingToReport=Adding {0} to report +# {0} - src +# {1} - dest AddLogicalImageTask.copyingImageFromTo=Copying image from {0} to {1} +# {0} - file AddLogicalImageTask.doneAddingToReport=Done adding {0} to report AddLogicalImageTask.doneCopying=Done copying +# {0} - file +# {1} - exception message AddLogicalImageTask.failedToAddReport=Failed to add report {0}. Reason= {1} +# {0} - src +# {1} - dest AddLogicalImageTask.failedToCopyDirectory=Failed to copy directory {0} to {1} # {0} - exception message Case.closeException.couldNotCloseCase=Error closing case: {0} @@ -12,6 +20,7 @@ Case.creationException.couldNotAcquireDirLock=Failed to get lock on case directo Case.creationException.couldNotAcquireResourcesLock=Failed to get lock on case resources Case.deleteCaseConfirmationDialog.message=Are you sure you want to close and delete the current case? Case.deleteCaseConfirmationDialog.title=Delete Current Case? +# {0} - exception message Case.deleteCaseFailureMessageBox.message=Error deleting case: {0} Case.deleteCaseFailureMessageBox.title=Failed to Delete Case Case.exceptionMessage.cancelledByUser=Cancelled by user. @@ -174,13 +183,19 @@ LogicalEvidenceFilePanel.validatePanel.nonL01Error.text=Only files with the .l01 LogicalFilesDspPanel.subTypeComboBox.l01FileOption.text=Logical evidence file (L01) LogicalFilesDspPanel.subTypeComboBox.localFilesOption.text=Local files and folders LogicalImagerDSProcessor.dataSourceType=Autopsy Imager +# {0} - directory LogicalImagerDSProcessor.directoryAlreadyExists=Directory {0} already exists +# {0} - directory LogicalImagerDSProcessor.failToCreateDirectory=Failed to create directory {0} +# {0} - imageDirPath LogicalImagerDSProcessor.imageDirPathNotFound={0} not found.\nUSB drive has been ejected. LogicalImagerPanel.imageTable.columnModel.title0=Hostname LogicalImagerPanel.imageTable.columnModel.title1=Extracted Date LogicalImagerPanel.messageLabel.clickScanOrBrowse=Click SCAN or BROWSE button to find images +# {0} - sparseImageDirectory +# {1} - image LogicalImagerPanel.messageLabel.directoryDoesNotContainSparseImage=Directory {0} does not contain {1} +# {0} - invalidFormatDirectory LogicalImagerPanel.messageLabel.directoryFormatInvalid=Directory {0} does not match format Logical_Imager_HOSTNAME_yyyymmdd_HH_MM_SS LogicalImagerPanel.messageLabel.driveHasNoImages=Drive has no images LogicalImagerPanel.messageLabel.noExternalDriveFound=No drive found @@ -251,10 +266,15 @@ AddImageWizardIngestConfigPanel.dsProcDone.errs.text=*Errors encountered in addi AddImageWizardIngestConfigVisual.getName.text=Configure Ingest Modules AddImageWizardIterator.stepXofN=Step {0} of {1} AddLocalFilesTask.localFileAdd.progress.text=Adding: {0}/{1} -Case.getCurCase.exception.noneOpen=Cannot get the current case; there is no case open! +Case.getCurCase.exception.noneOpen=Cannot get the current case; there is no case open\! Case.open.msgDlg.updated.msg=Updated case database schema.\nA backup copy of the database with the following path has been made:\n {0} Case.open.msgDlg.updated.title=Case Database Schema Update -Case.checkImgExist.confDlg.doesntExist.msg=One of the images associated with \nthis case are missing. Would you like to search for them now?\nPreviously, the image was located at:\n{0}\nPlease note that you will still be able to browse directories and generate reports\nif you choose No, but you will not be able to view file content or run the ingest process. +Case.checkImgExist.confDlg.doesntExist.msg=One of the images associated with \n\ +this case are missing. Would you like to search for them now?\n\ +Previously, the image was located at:\n\ +{0}\n\ +Please note that you will still be able to browse directories and generate reports\n\ +if you choose No, but you will not be able to view file content or run the ingest process. Case.checkImgExist.confDlg.doesntExist.title=Missing Image Case.addImg.exception.msg=Error adding image to the case Case.updateCaseName.exception.msg=Error while trying to update the case name. @@ -273,9 +293,12 @@ Case.GetCaseTypeGivenPath.Failure=Unable to get case type Case.metaDataFileCorrupt.exception.msg=The case metadata file (.aut) is corrupted. Case.deleteReports.deleteFromDiskException.log.msg=Unable to delete the report from the disk. Case.deleteReports.deleteFromDiskException.msg=Unable to delete the report {0} from the disk.\nYou may manually delete it from {1} -CaseDeleteAction.closeConfMsg.text=Are you sure want to close and delete this case? \nCase Name: {0}\nCase Directory: {1} +CaseDeleteAction.closeConfMsg.text=Are you sure want to close and delete this case? \n\ + Case Name: {0}\n\ + Case Directory: {1} CaseDeleteAction.closeConfMsg.title=Warning: Closing the Current Case -CaseDeleteAction.msgDlg.fileInUse.msg=The delete action cannot be fully completed because the folder or file in it is open by another program.\n\nClose the folder and file and try again or you can delete the case manually. +CaseDeleteAction.msgDlg.fileInUse.msg=The delete action cannot be fully completed because the folder or file in it is open by another program.\n\n\ +Close the folder and file and try again or you can delete the case manually. CaseDeleteAction.msgDlg.fileInUse.title=Error: Folder In Use CaseDeleteAction.msgDlg.caseDelete.msg=Case {0} has been deleted. CaseOpenAction.autFilter.title={0} Case File ( {1}) @@ -307,7 +330,8 @@ NewCaseWizardAction.databaseProblem1.text=Cannot open database. Cancelling case NewCaseWizardAction.databaseProblem2.text=Error NewCaseWizardPanel1.validate.errMsg.invalidSymbols=The Case Name cannot contain any of the following symbols: \\ / : * ? " < > | NewCaseWizardPanel1.validate.errMsg.dirExists=Case directory ''{0}'' already exists. -NewCaseWizardPanel1.validate.confMsg.createDir.msg=The base directory "{0}" does not exist. \n\nDo you want to create that directory? +NewCaseWizardPanel1.validate.confMsg.createDir.msg=The base directory "{0}" does not exist. \n\n\ + Do you want to create that directory? NewCaseWizardPanel1.validate.confMsg.createDir.title=Create directory NewCaseWizardPanel1.validate.errMsg.cantCreateParDir.msg=Error: Could not create case parent directory {0} NewCaseWizardPanel1.validate.errMsg.prevCreateBaseDir.msg=Prevented from creating base directory {0} @@ -336,12 +360,14 @@ OptionalCasePropertiesPanel.lbPointOfContactPhoneLabel.text=Phone: OptionalCasePropertiesPanel.orgainizationPanel.border.title=Organization RecentCases.exception.caseIdxOutOfRange.msg=Recent case index {0} is out of range. RecentCases.getName.text=Clear Recent Cases +# {0} - case name RecentItems.openRecentCase.msgDlg.text=Case {0} no longer exists. SelectDataSourceProcessorPanel.name.text=Select Type of Data Source To Add StartupWindow.title.text=Welcome UnpackagePortableCaseDialog.title.text=Unpackage Portable Case UnpackagePortableCaseDialog.UnpackagePortableCaseDialog.extensions=Portable case package (.zip, .zip.001) UnpackagePortableCaseDialog.validatePaths.badExtension=File extension must be .zip or .zip.001 +# {0} - case folder UnpackagePortableCaseDialog.validatePaths.caseFolderExists=Folder {0} already exists UnpackagePortableCaseDialog.validatePaths.caseIsNotFile=Selected path is not a file UnpackagePortableCaseDialog.validatePaths.caseNotFound=File does not exist @@ -355,15 +381,15 @@ UnpackageWorker.doInBackground.errorFinding7zip=Could not locate 7-Zip executabl UpdateRecentCases.menuItem.clearRecentCases.text=Clear Recent Cases UpdateRecentCases.menuItem.empty=-Empty- AddImageWizardIngestConfigPanel.CANCEL_BUTTON.text=Cancel -NewCaseVisualPanel1.CaseFolderOnCDriveError.text=Warning: Path to multi-user case folder is on "C:" drive -NewCaseVisualPanel1.CaseFolderOnInternalDriveWindowsError.text=Warning: Path to case folder is on "C:" drive. Case folder is created on the target system +NewCaseVisualPanel1.CaseFolderOnCDriveError.text=Warning: Path to multi-user case folder is on \"C:\" drive +NewCaseVisualPanel1.CaseFolderOnInternalDriveWindowsError.text=Warning: Path to case folder is on \"C:\" drive. Case folder is created on the target system NewCaseVisualPanel1.CaseFolderOnInternalDriveLinuxError.text=Warning: Path to case folder is on the target system. Create case folder in mounted drive. CollaborationMonitor.addingDataSourceStatus.msg={0} adding data source CollaborationMonitor.analyzingDataSourceStatus.msg={0} analyzing {1} MissingImageDialog.lbWarning.text= MissingImageDialog.lbWarning.toolTipText= NewCaseVisualPanel1.caseParentDirWarningLabel.text= -NewCaseVisualPanel1.multiUserCaseRadioButton.text=Multi-user\t\t +NewCaseVisualPanel1.multiUserCaseRadioButton.text=Multi-user NewCaseVisualPanel1.singleUserCaseRadioButton.text=Single-user NewCaseVisualPanel1.caseTypeLabel.text=Case Type: SingleUserCaseConverter.BadDatabaseFileName=Database file does not exist! diff --git a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/Bundle.properties-MERGED index 9cd17f566f..d164529639 100755 --- a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/Bundle.properties-MERGED @@ -1,8 +1,13 @@ AbstractCommonFilesMetadataBuilder.buildCategorySelectionString.all=All File Categories AbstractCommonFilesMetadataBuilder.buildCategorySelectionString.doc=Documents AbstractCommonFilesMetadataBuilder.buildCategorySelectionString.media=Media +# {0} - threshold percent AbstractCommonFilesMetadataBuilder.getPercentFilter.thresholdPercent=, Threshold {0}% +# {0} - attr type +# {1} - threshold string AllInterCaseCommonAttributeSearcher.buildTabTitle.titleInterAll=Common Properties (All Central Repository Cases, {0}{1}) +# {0} - build category +# {1} - threshold string AllIntraCaseCommonAttributeSearcher.buildTabTitle.titleIntraAll=Common Properties (All Data Sources, {0}{1}) # {0} - number of datasources CommonAttributePanel.dataSourcesLabel.text=The current Central Repository contains {0} data source(s). @@ -98,7 +103,13 @@ CommonAttributePanel.organizeByCountRadio.text=Number of occurrences CommonAttributePanel.caseResultsRadioButton.text=Case CommonAttributePanel.countResultsRadioButton.text=Number of data sources CommonAttributePanel.displayResultsLabel.text_2=Display results organized by: +# {0} - case name +# {1} - attr type +# {2} - threshold string SingleInterCaseCommonAttributeSearcher.buildTabTitle.titleInterSingle=Common Properties (Central Repository Case: {0}, {1}{2}) +# {0} - data source name +# {1} - build category +# {2} - threshold string SingleIntraCaseCommonAttributeSearcher.buildTabTitle.titleIntraSingle=Common Properties (Data Source: {0}, {1}{2}) UserInputErrorManager.categories=No file categories are included in the search. UserInputErrorManager.frequency=Invalid Frequency Percentage: 0 < % < 100. diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED index 31fd8b9ce0..04173f9689 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED @@ -43,6 +43,7 @@ ArtifactStringContent.attrsTableHeader.type=Type ArtifactStringContent.attrsTableHeader.value=Value ArtifactStringContent.failedToGetAttributes.message=Failed to get some or all attributes from case database ArtifactStringContent.failedToGetSourcePath.message=Failed to get source file path from case database +# {0} - node name BaseChildFactory.NoSuchEventBusException.message=No event bus for node: {0} BlackboardArtifactNode.createSheet.artifactDetails.displayName=Result Details BlackboardArtifactNode.createSheet.artifactDetails.name=Result Details @@ -262,10 +263,10 @@ ImageNode.getActions.viewInNewWin.text=View in New Window ImageNode.createSheet.name.name=Name ImageNode.createSheet.name.displayName=Name ImageNode.createSheet.name.desc=no description -Installer.exception.tskVerStringNull.msg=Sleuth Kit JNI test call returned without error, but version string was null! -Installer.exception.taskVerStringBang.msg=Sleuth Kit JNI test call returned without error, but version string was ""! -Installer.tskLibErr.msg=Problem with Sleuth Kit JNI. Test call failed!\n\nDetails: {0} -Installer.tskLibErr.err=Fatal Error! +Installer.exception.tskVerStringNull.msg=Sleuth Kit JNI test call returned without error, but version string was null\! +Installer.exception.taskVerStringBang.msg=Sleuth Kit JNI test call returned without error, but version string was ""\! +Installer.tskLibErr.msg=Problem with Sleuth Kit JNI. Test call failed\!\n\nDetails: {0} +Installer.tskLibErr.err=Fatal Error\! InterestingHits.interestingItems.text=INTERESTING ITEMS InterestingHits.displayName.text=Interesting Items InterestingHits.createSheet.name.name=Name From b0b7010116c060617f23e45072aa16ab56ba929b Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 12 Jun 2019 16:02:10 -0400 Subject: [PATCH 114/115] 5138 change interest files set rule dialog title --- .../autopsy/modules/interestingitems/Bundle.properties | 2 +- .../autopsy/modules/interestingitems/Bundle.properties-MERGED | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties index f12f1cd396..b3732ce149 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties @@ -6,7 +6,7 @@ OptionsCategory_Name_InterestingItemDefinitions=Interesting Files OptionsCategory_Keywords_InterestingItemDefinitions=InterestingItemDefinitions InterestingItemsIdentifierIngestModule.moduleName=Interesting Files Identifier InterestingItemsIdentifierIngestModule.moduleDescription=Identifies interesting items as defined by interesting item rule sets. -FilesSetPanel.interesting.title=Interesting Files Set +FilesSetPanel.interesting.title=Interesting Files Set Rule FilesSetPanel.interesting.messages.filesSetsMustBeNamed=Interesting files sets must be named. FilesSetPanel.messages.filesSetsReservedName=You have chosen a name reserved by the software, please choose a different name. FilesSetPanel.ignoreKnownFilesCheckbox.text=Ignore Known Files diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED index a401ae2021..20c1eae05f 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED @@ -60,7 +60,7 @@ OptionsCategory_Name_InterestingItemDefinitions=Interesting Files OptionsCategory_Keywords_InterestingItemDefinitions=InterestingItemDefinitions InterestingItemsIdentifierIngestModule.moduleName=Interesting Files Identifier InterestingItemsIdentifierIngestModule.moduleDescription=Identifies interesting items as defined by interesting item rule sets. -FilesSetPanel.interesting.title=Interesting Files Set +FilesSetPanel.interesting.title=Interesting Files Set Rule FilesSetPanel.interesting.messages.filesSetsMustBeNamed=Interesting files sets must be named. FilesSetPanel.messages.filesSetsReservedName=You have chosen a name reserved by the software, please choose a different name. FilesSetPanel.ignoreKnownFilesCheckbox.text=Ignore Known Files From e45e385cf79d59f5a08175c643abaacee189b836 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 13 Jun 2019 14:59:03 -0400 Subject: [PATCH 115/115] Update bundle.properties.MERGED files --- .../casemodule/Bundle.properties-MERGED | 2 +- .../contentviewers/Bundle.properties-MERGED | 2 +- .../autopsy/core/Bundle.properties-MERGED | 8 +++++++- .../corecomponents/Bundle.properties-MERGED | 6 +++--- .../autopsy/coreutils/Bundle.properties-MERGED | 4 +++- .../filesearch/Bundle.properties-MERGED | 4 ++-- .../autopsy/ingest/Bundle.properties-MERGED | 2 +- .../Bundle.properties-MERGED | 7 ++++++- .../modules/exif/Bundle.properties-MERGED | 4 +++- .../fileextmismatch/Bundle.properties-MERGED | 18 +++++++++--------- .../hashdatabase/Bundle.properties-MERGED | 10 ++++++++-- .../interestingitems/Bundle.properties-MERGED | 5 +++-- .../photoreccarver/Bundle.properties-MERGED | 2 +- .../autopsy/report/Bundle.properties-MERGED | 8 ++++---- .../timeline/ui/Bundle.properties-MERGED | 6 +++--- 15 files changed, 55 insertions(+), 33 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED index eda66f0e20..1a55b465df 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED @@ -497,4 +497,4 @@ LogicalImagerPanel.selectFolderLabel.text=Selected Folder: LogicalImagerPanel.refreshButton.text=Refresh LogicalImagerPanel.selectFromDriveLabel.text=Select Acquisition From Drive LogicalImagerPanel.selectDriveLabel.text=Select Drive -LogicalImagerPanel.messageTextArea.text=test +LogicalImagerPanel.messageTextArea.text= diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED index bb26f40a65..b9f5986b41 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED @@ -151,7 +151,7 @@ MediaViewImagePanel.rotationTextField.text= MediaViewImagePanel.rotateLeftButton.toolTipText= HtmlPanel.showImagesToggleButton.text=Download Images MediaPlayerPanel.audioSlider.toolTipText= -MediaPlayerPanel.VolumeIcon.text=\ Volume +MediaPlayerPanel.VolumeIcon.text=\ \ \ \ \ Volume MediaPlayerPanel.progressLabel.text=00:00:00/00:00:00 MediaPlayerPanel.playButton.text=\u25ba MediaPlayerPanel.infoLabel.text=No Errors diff --git a/Core/src/org/sleuthkit/autopsy/core/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/core/Bundle.properties-MERGED index f7039ab4ce..087eaec314 100755 --- a/Core/src/org/sleuthkit/autopsy/core/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/core/Bundle.properties-MERGED @@ -3,7 +3,13 @@ Installer.closing.confirmationDialog.title=Ingest is Running # {0} - exception message Installer.closing.messageBox.caseCloseExceptionMessage=Error closing case: {0} OpenIDE-Module-Display-Category=Infrastructure -OpenIDE-Module-Long-Description=This is the core Autopsy module.\n\nThe module contains the core components needed for the bare application to run; the RCP platform, windowing GUI, sleuthkit bindings, datamodel / storage, explorer, result viewers, content viewers, ingest framework, reporting, and core tools, such as the file search.\n\nThe framework included in the module contains APIs for developing modules for ingest, viewers and reporting. The modules can be deployed as Plugins using the Autopsy plugin installer.\nThis module should not be uninstalled - without it, Autopsy will not run.\n\nFor more information, see http://www.sleuthkit.org/autopsy/ +OpenIDE-Module-Long-Description=\ + This is the core Autopsy module.\n\n\ + The module contains the core components needed for the bare application to run; the RCP platform, windowing GUI, sleuthkit bindings, datamodel / storage, explorer, result viewers, content viewers, ingest framework, reporting, and core tools, such as the file search.\n\n\ + The framework included in the module contains APIs for developing modules for ingest, viewers and reporting. \ + The modules can be deployed as Plugins using the Autopsy plugin installer.\n\ + This module should not be uninstalled - without it, Autopsy will not run.\n\n\ + For more information, see http://www.sleuthkit.org/autopsy/ OpenIDE-Module-Name=Autopsy-Core OpenIDE-Module-Short-Description=Autopsy Core Module org_sleuthkit_autopsy_core_update_center=http://sleuthkit.org/autopsy/updates.xml diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED index d4794e7dc3..b0e36da986 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED @@ -63,9 +63,9 @@ DataContentViewerHex.totalPageLabel.text_1=100 DataContentViewerHex.pageLabel2.text=Page # Product Information panel -LBL_Description=
\n Product Version: {0} ({9})
Sleuth Kit Version: {7}
Netbeans RCP Build: {8}
Java: {1}; {2}
System: {3}; {4}; {5}
Userdir: {6}
+LBL_Description=
\n Product Version: {0} ({9})
Sleuth Kit Version: {7}
Netbeans RCP Build: {8}
Java: {1}; {2}
System: {3}; {4}; {5}
Userdir: {6}
Format_OperatingSystem_Value={0} version {1} running on {2} -LBL_Copyright=
Autopsy™ is a digital forensics platform based on The Sleuth Kit™ and other tools.
Copyright © 2003-2018.
+LBL_Copyright=
Autopsy™ is a digital forensics platform based on The Sleuth Kit™ and other tools.
Copyright © 2003-2018.
SortChooser.dialogTitle=Choose Sort Criteria ThumbnailViewChildren.progress.cancelling=(Cancelling) # {0} - file name @@ -95,7 +95,7 @@ DataResultViewerThumbnail.pageNextButton.text= DataResultViewerThumbnail.imagesLabel.text=Images: DataResultViewerThumbnail.imagesRangeLabel.text=- DataResultViewerThumbnail.pageNumLabel.text=- -DataResultViewerThumbnail.filePathLabel.text=\ +DataResultViewerThumbnail.filePathLabel.text=\ \ \ DataResultViewerThumbnail.goToPageLabel.text=Go to Page: DataResultViewerThumbnail.goToPageField.text= AdvancedConfigurationDialog.cancelButton.text=Cancel diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/coreutils/Bundle.properties-MERGED index 702b726e08..17791d159d 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/coreutils/Bundle.properties-MERGED @@ -23,7 +23,9 @@ PlatformUtil.getProcVmUsed.sigarNotInit.msg=Cannot get virt mem used, sigar not PlatformUtil.getProcVmUsed.gen.msg=Cannot get virt mem used, {0} PlatformUtil.getJvmMemInfo.usageText=JVM heap usage: {0}, JVM non-heap usage: {1} PlatformUtil.getPhysicalMemInfo.usageText=Physical memory usage (max, total, free): {0}, {1}, {2} -PlatformUtil.getAllMemUsageInfo.usageText={0}\n{1}\nProcess Virtual Memory: {2} +PlatformUtil.getAllMemUsageInfo.usageText={0}\n\ +{1}\n\ +Process Virtual Memory: {2} # {0} - file name ReadImageTask.mesageText=Reading image: {0} StringExtract.illegalStateException.cannotInit.msg=Unicode table not properly initialized, cannot instantiate StringExtract diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties-MERGED index 7ab8ecbe04..08cc69c39c 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties-MERGED @@ -14,7 +14,7 @@ KnownStatusSearchPanel.knownCheckBox.text=Known Status: KnownStatusSearchPanel.knownBadOptionCheckBox.text=Notable KnownStatusSearchPanel.knownOptionCheckBox.text=Known (NSRL or other) KnownStatusSearchPanel.unknownOptionCheckBox.text=Unknown -DateSearchFilter.noneSelectedMsg.text=At least one date type must be selected! +DateSearchFilter.noneSelectedMsg.text=At least one date type must be selected\! DateSearchPanel.dateCheckBox.text=Date: DateSearchPanel.jLabel4.text=Timezone: DateSearchPanel.jLabel3.text=*The date format is mm/dd/yyyy @@ -56,7 +56,7 @@ FileSearchPanel.search.results.details=Large number of matches may impact perfor FileSearchPanel.search.exception.noFilterSelected.msg=At least one filter must be selected. FileSearchPanel.search.validationErr.msg=Validation Error: {0} FileSearchPanel.emptyWhereClause.text=Invalid options, nothing to show. -KnownStatusSearchFilter.noneSelectedMsg.text=At least one known status must be selected! +KnownStatusSearchFilter.noneSelectedMsg.text=At least one known status must be selected\! NameSearchFilter.emptyNameMsg.text=Must enter something for name search. SearchNode.getName.text=Search Result SizeSearchPanel.sizeCompareComboBox.equalTo=equal to diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED index 6be3e48e71..9e4f612b6b 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED @@ -140,7 +140,7 @@ IngestJob.cancelReason.outOfDiskSpace.text=Out of disk space IngestJob.cancelReason.servicesDown.text=Services Down IngestJob.cancelReason.caseClosed.text=Case closed IngestJobSettingsPanel.globalSettingsButton.text=Global Settings -gest= +gest IngestJobSettingsPanel.globalSettingsButton.actionCommand=Advanced IngestJobSettingsPanel.globalSettingsButton.text=Global Settings IngestJobSettingsPanel.pastJobsButton.text=History diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties-MERGED index 4729293fb9..d73865ac3e 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties-MERGED @@ -11,7 +11,12 @@ ExtractArchiveWithPasswordAction.progress.text=Unpacking contents of archive: {0 ExtractArchiveWithPasswordAction.prompt.text=Enter Password ExtractArchiveWithPasswordAction.prompt.title=Enter Password OpenIDE-Module-Display-Category=Ingest Module -OpenIDE-Module-Long-Description=Embedded File Extraction Ingest Module\n\nThe Embedded File Extraction Ingest Module processes document files (such as doc, docx, ppt, pptx, xls, xlsx) and archive files (such as zip and others archive types supported by the 7zip extractor).\nContents of these files are extracted and the derived files are added back to the current ingest to be processed by the configured ingest modules.\nIf the derived file happens to be an archive file, it will be re-processed by the 7zip extractor - the extractor will process archive files N-levels deep.\n\nThe extracted files are navigable in the directory tree.\n\nThe module is supported on Windows, Linux and Mac operating systems. +OpenIDE-Module-Long-Description=\ + Embedded File Extraction Ingest Module\n\nThe Embedded File Extraction Ingest Module processes document files (such as doc, docx, ppt, pptx, xls, xlsx) and archive files (such as zip and others archive types supported by the 7zip extractor).\n\ + Contents of these files are extracted and the derived files are added back to the current ingest to be processed by the configured ingest modules.\n\ + If the derived file happens to be an archive file, it will be re-processed by the 7zip extractor - the extractor will process archive files N-levels deep.\n\n\ + The extracted files are navigable in the directory tree.\n\n\ + The module is supported on Windows, Linux and Mac operating systems. OpenIDE-Module-Name=Embedded File Extraction OpenIDE-Module-Short-Description=Embedded File Extraction Ingest Module EmbeddedFileExtractorIngestModule.SevenZipContentReadStream.seek.exception.invalidOrigin=Invalid seek origin: {0} diff --git a/Core/src/org/sleuthkit/autopsy/modules/exif/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/exif/Bundle.properties-MERGED index ee788daf61..9905159d99 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/exif/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/exif/Bundle.properties-MERGED @@ -1,7 +1,9 @@ CannotRunFileTypeDetection=Cannot run file type detection. ExifParserFileIngestModule.indexError.message=Failed to index EXIF Metadata artifact for keyword search. OpenIDE-Module-Display-Category=Ingest Module -OpenIDE-Module-Long-Description=Exif metadata ingest module. \n\nThe ingest module analyzes image files, extracts Exif information and posts the Exif data as results. +OpenIDE-Module-Long-Description=\ + Exif metadata ingest module. \n\n\ + The ingest module analyzes image files, extracts Exif information and posts the Exif data as results. OpenIDE-Module-Name=ExifParser OpenIDE-Module-Short-Description=Exif metadata ingest module ExifParserFileIngestModule.moduleName.text=Exif Parser diff --git a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/Bundle.properties-MERGED index 5063bd55fa..cfaadf1635 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/Bundle.properties-MERGED @@ -36,27 +36,27 @@ FileExtMismatchSettingsPanel.jLabel1.text=File Types: FileExtMismatchSettingsPanel.newExtButton.text=New Extension FileExtMismatchSettingsPanel.newMimePrompt.message=Add a new MIME file type: FileExtMismatchSettingsPanel.newMimePrompt.title=New MIME -FileExtMismatchSettingsPanel.newMimePrompt.emptyMime.message=MIME type text is empty! +FileExtMismatchSettingsPanel.newMimePrompt.emptyMime.message=MIME type text is empty\! FileExtMismatchSettingsPanel.newMimePrompt.emptyMime.title=Empty type -FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotSupported.message=MIME type not supported! +FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotSupported.message=MIME type not supported\! FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotSupported.title=Type not supported -FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeExists.message=MIME type already exists! +FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeExists.message=MIME type already exists\! FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeExists.title=Type already exists FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotDetectable.message=MIME type is not detectable by this module. FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotDetectable.title=Type not detectable -FileExtMismatchSettingsPanel.removeTypeButton.noneSelected.message=No MIME type selected! +FileExtMismatchSettingsPanel.removeTypeButton.noneSelected.message=No MIME type selected\! FileExtMismatchSettingsPanel.removeTypeButton.noneSelected.title=No type selected FileExtMismatchSettingsPanel.newExtPrompt.message=Add an allowed extension: FileExtMismatchSettingsPanel.newExtPrompt.title=New allowed extension -FileExtMismatchSettingsPanel.newExtPrompt.empty.message=Extension text is empty! +FileExtMismatchSettingsPanel.newExtPrompt.empty.message=Extension text is empty\! FileExtMismatchSettingsPanel.newExtPrompt.empty.title=Extension text empty -FileExtMismatchSettingsPanel.newExtPrompt.noMimeType.message=No MIME type selected! +FileExtMismatchSettingsPanel.newExtPrompt.noMimeType.message=No MIME type selected\! FileExtMismatchSettingsPanel.newExtPrompt.noMimeType.title=No MIME type selected -FileExtMismatchSettingsPanel.newExtPrompt.extExists.message=Extension already exists! +FileExtMismatchSettingsPanel.newExtPrompt.extExists.message=Extension already exists\! FileExtMismatchSettingsPanel.newExtPrompt.extExists.title=Extension already exists -FileExtMismatchSettingsPanel.removeExtButton.noneSelected.message=No extension selected! +FileExtMismatchSettingsPanel.removeExtButton.noneSelected.message=No extension selected\! FileExtMismatchSettingsPanel.removeExtButton.noneSelected.title=No extension selected -FileExtMismatchSettingsPanel.removeExtButton.noMimeTypeSelected.message=No MIME type selected! +FileExtMismatchSettingsPanel.removeExtButton.noMimeTypeSelected.message=No MIME type selected\! FileExtMismatchSettingsPanel.removeExtButton.noMimeTypeSelected.title=No MIME type selected FileExtMismatchSettingsPanel.removeTypeButton.toolTipText= FileExtMismatchModuleSettingsPanel.checkAllRadioButton.text=Check all file types diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties-MERGED index ed79db018d..2d105bc3a9 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties-MERGED @@ -40,7 +40,10 @@ ImportCentralRepoDbProgressDialog.errorParsingFile.message=Error parsing hash se ImportCentralRepoDbProgressDialog.linesProcessed.message=\ hashes processed ImportCentralRepoDbProgressDialog.title.text=Central Repository Import Progress OpenIDE-Module-Display-Category=Ingest Module -OpenIDE-Module-Long-Description=Hash Set ingest module. \n\nThe ingest module analyzes files in the disk image and marks them as "known" (based on NSRL hashset lookup for "known" files) and "bad / interesting" (based on one or more hash sets supplied by the user).\n\nThe module also contains additional non-ingest tools that are integrated in the GUI, such as file lookup by hash and hash set configuration. +OpenIDE-Module-Long-Description=\ + Hash Set ingest module. \n\n\ + The ingest module analyzes files in the disk image and marks them as "known" (based on NSRL hashset lookup for "known" files) and "bad / interesting" (based on one or more hash sets supplied by the user).\n\n\ + The module also contains additional non-ingest tools that are integrated in the GUI, such as file lookup by hash and hash set configuration. OpenIDE-Module-Name=HashDatabases OptionsCategory_Name_HashDatabase=Hash Sets OptionsCategory_Keywords_HashDatabase=Hash Sets @@ -169,7 +172,10 @@ HashDbSearchThread.name.searching=Searching HashDbSearchThread.noMoreFilesWithMD5Msg=No other files with the same MD5 hash were found. ModalNoButtons.indexingDbsTitle=Indexing hash sets ModalNoButtons.indexingDbTitle=Indexing hash set -ModalNoButtons.exitHashDbIndexingMsg=You are about to exit out of indexing your hash sets. \nThe generated index will be left unusable. If you choose to continue,\nplease delete the corresponding -md5.idx file in the hash folder.\nExit indexing? +ModalNoButtons.exitHashDbIndexingMsg=You are about to exit out of indexing your hash sets. \n\ +The generated index will be left unusable. If you choose to continue,\n\ + please delete the corresponding -md5.idx file in the hash folder.\n\ + Exit indexing? ModalNoButtons.dlgTitle.unfinishedIndexing=Unfinished Indexing ModalNoButtons.indexThis.currentlyIndexing1Db=Currently indexing 1 hash set ModalNoButtons.indexThese.currentlyIndexing1OfNDbs=Currently indexing 1 of {0} diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED index 506674aa5b..ad6fe6f1c9 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED @@ -2,6 +2,7 @@ FilesIdentifierIngestJobSettingsPanel.getError=Error getting interesting files s FilesIdentifierIngestJobSettingsPanel.updateError=Error updating interesting files sets settings file. FilesIdentifierIngestModule.getFilesError=Error getting interesting files sets from file. FilesIdentifierIngestModule.indexError.message=Failed to index interesting file hit artifact for keyword search. +# {0} - daysIncluded FilesSet.rule.dateRule.toString=(modified within {0} day(s)) FilesSetDefsPanel.bytes=Bytes FilesSetDefsPanel.cancelImportMsg=Cancel import @@ -82,8 +83,8 @@ FilesSetRulePanel.nameTextField.text= FilesSetRulePanel.ruleNameLabel.text=Rule Name (Optional): FilesSetRulePanel.messages.emptyNameCondition=You must specify a name pattern for this rule. FilesSetRulePanel.messages.invalidNameRegex=The name regular expression is not valid:\n\n{0} -FilesSetRulePanel.messages.invalidCharInName=The name cannot contain \\, /, :, *, ?, ", <, or > unless it is a regular expression. -FilesSetRulePanel.messages.invalidCharInPath=The path cannot contain \\, :, *, ?, ", <, or > unless it is a regular expression. +FilesSetRulePanel.messages.invalidCharInName=The name cannot contain \\, /, :, *, ?, \", <, or > unless it is a regular expression. +FilesSetRulePanel.messages.invalidCharInPath=The path cannot contain \\, :, *, ?, \", <, or > unless it is a regular expression. FilesSetRulePanel.messages.invalidPathRegex=The path regular expression is not valid:\n\n{0} FilesSetDefsPanel.doFileSetsDialog.duplicateRuleSet.text=Rule set with name {0} already exists. FilesSetRulePanel.pathSeparatorInfoLabel.text=Folder must be in parent path. Use '/' to give consecutive names diff --git a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties-MERGED index 2dc971a40d..87dacfc16c 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties-MERGED @@ -21,7 +21,7 @@ PhotoRecIngestModule.complete.totalParsetime=Total Parsing Time: PhotoRecIngestModule.complete.photoRecResults=PhotoRec Results PhotoRecIngestModule.NotEnoughDiskSpace.detail.msg=PhotoRec error processing {0} with {1} Not enough space on primary disk to save unallocated space. PhotoRecIngestModule.cancelledByUser=PhotoRec cancelled by user. -PhotoRecIngestModule.error.exitValue=PhotoRec carver returned error exit value = {0} when scanning {1} +PhotoRecIngestModule.error.exitValue=PhotoRec carver returned error exit value \= {0} when scanning {1} PhotoRecIngestModule.error.msg=Error processing {0} with PhotoRec carver. PhotoRecIngestModule.complete.numberOfErrors=Number of Errors while Carving: PhotoRecCarverIngestJobSettingsPanel.detectionSettingsLabel.text=PhotoRec Settings diff --git a/Core/src/org/sleuthkit/autopsy/report/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/Bundle.properties-MERGED index 6444541518..f9813728d5 100644 --- a/Core/src/org/sleuthkit/autopsy/report/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/report/Bundle.properties-MERGED @@ -99,7 +99,7 @@ FileReportDataTypes.path.text=Full Path FileReportText.getName.text=Files - Text FileReportText.getDesc.text=A delimited text file containing information about individual files in the case. ReportBodyFile.progress.querying=Querying files... -ReportBodyFile.ingestWarning.text=Warning, this report was run before ingest services completed! +ReportBodyFile.ingestWarning.text=Warning, this report was run before ingest services completed\! ReportBodyFile.progress.loading=Loading files... ReportBodyFile.progress.processing=Now processing {0}... ReportBodyFile.getName.text=TSK Body File @@ -241,13 +241,13 @@ ReportHTML.getName.text=HTML Report ReportHTML.getDesc.text=A report about results and tagged items in HTML format. ReportHTML.writeIndex.title=for case {0} ReportHTML.writeIndex.noFrames.msg=Your browser is not compatible with our frame setup. -ReportHTML.writeIndex.noFrames.seeNav=Please see the navigation page for artifact links, -ReportHTML.writeIndex.seeSum=and the summary page for a case summary. +ReportHTML.writeIndex.noFrames.seeNav=Please see the navigation page for artifact links, +ReportHTML.writeIndex.seeSum=and the summary page for a case summary. ReportHTML.writeNav.title=Report Navigation ReportHTML.writeNav.h1=Report Navigation ReportHTML.writeNav.summary=Case Summary ReportHTML.writeSum.title=Case Summary -ReportHTML.writeSum.warningMsg=Warning, this report was run before ingest services completed! +ReportHTML.writeSum.warningMsg=Warning, this report was run before ingest services completed\! # # autopsy/test/scripts/regression.py._html_report_diff() uses reportGenOn.text, caseName, caseNum, # examiner as a regex signature to skip report.html and summary.html diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/timeline/ui/Bundle.properties-MERGED index ed3e6724d8..3255e82f2b 100755 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/Bundle.properties-MERGED @@ -1,4 +1,4 @@ -/*= +/* * Autopsy Forensic Browser * * Copyright 2013-15 Basis Technology Corp. @@ -14,8 +14,8 @@ * 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. -*/= + * limitations under the License. + */ AbstractTimelineChart.defaultTooltip.text=Drag the mouse to select a time interval to zoom into.\nRight-click for more actions. HistoryToolBar.historyLabel.text=History
TypeSubstring/RegexTextDescriptionSample match