From c3156be65bd730b8eae664da176acbf91245d297 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 12 May 2020 01:09:47 -0400 Subject: [PATCH] 6305 animation tools --- .../discovery/Bundle.properties-MERGED | 11 +- .../autopsy/discovery/DetailsPanel.form | 43 ++++ .../autopsy/discovery/DetailsPanel.java | 60 ++++++ .../autopsy/discovery/ResultsPanel.form | 12 +- .../autopsy/discovery/ResultsPanel.java | 179 +++++++++++++++- .../autopsy/discovery/SwingAnimator.java | 193 ++++++++++++++++++ .../discovery/SwingAnimatorCallback.java | 35 ++++ 7 files changed, 509 insertions(+), 24 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/DetailsPanel.form create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/DetailsPanel.java create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/SwingAnimator.java create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/SwingAnimatorCallback.java diff --git a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED index 2aced0f0a0..f69686a0ea 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED @@ -139,7 +139,6 @@ FileSearchFiltering.TagsFilter.or=\ or FileSearchFiltering.UserCreatedFilter.desc=Files that contain EXIF data FileSearchPanel.dialogTitle.text=Test file search FileSearchPanel.sortingPanel.border.title=Grouping -FileSearchPanel.searchButton.text=Show FileSearchPanel.addButton.text=Add FileSearchPanel.steptwo.documents=Step 2: Filter which documents to show FileSearchPanel.steptwo.images=Step 2: Filter which images to show @@ -165,7 +164,6 @@ FileSearchDialog.objCheckBox.text=Objects FileSearchDialog.exifCheckBox.text=Must contain EXIF data FileSearchDialog.notableCheckBox.text=Must have been tagged as notable FileSearchDialog.scoreCheckBox.text=Has score -FileSearchPanel.cancelButton.text=Cancel FileSearchPanel.hashSetCheckbox.text=Hash Set: FileSearchPanel.tagsCheckbox.text=Tag: FileSearchPanel.interestingItemsCheckbox.text=Interesting Item: @@ -209,16 +207,17 @@ FileSearchPanel.excludeRadioButton.text=Exclude FileSearchPanel.knownFilesCheckbox.toolTipText= FileSearchPanel.knownFilesCheckbox.text=Hide known files GroupListPanel.groupKeyList.border.title=Groups -DiscoveryTopComponent.imagesButton.text=Images -DiscoveryTopComponent.videosButton.text=Videos ResultsPanel.resultsSplitPane.toolTipText= FileSearchPanel.stepThreeLabel.text=Step 3: Choose display settings -DiscoveryTopComponent.stepOneLabel.text=Step 1: Pick File Type -DiscoveryTopComponent.documentsButton.text=Documents DocumentPanel.fileSizeLabel.toolTipText= DocumentPanel.isDeletedLabel.toolTipText= ImageThumbnailPanel.isDeletedLabel.toolTipText= FileSearchPanel.userCreatedCheckbox.text=Possibly User Created +DiscoveryDialog.documentsButton.text=Documents +DiscoveryDialog.videosButton.text=Videos +DiscoveryDialog.imagesButton.text=Images +DiscoveryDialog.searchButton.text=Show +DiscoveryDialog.cancelButton.text=Cancel ResultsPanel.unableToCreate.text=Unable to create summary. ResultsPanel.viewFileInDir.name=View File in Directory VideoThumbnailPanel.bytes.text=bytes diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DetailsPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/DetailsPanel.form new file mode 100644 index 0000000000..058ed2dd31 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/DetailsPanel.form @@ -0,0 +1,43 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DetailsPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DetailsPanel.java new file mode 100644 index 0000000000..c49cbe0edc --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/DetailsPanel.java @@ -0,0 +1,60 @@ +/* + * 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.discovery; + +import org.sleuthkit.autopsy.corecomponents.DataContentPanel; + +/** + * + * @author wschaefer + */ +public class DetailsPanel extends javax.swing.JPanel { + + private final DataContentPanel dataContentPanel; + + /** + * Creates new form DetailsPanel + */ + public DetailsPanel() { + initComponents(); + dataContentPanel = DataContentPanel.createInstance(); + detailsSplitPane.setBottomComponent(dataContentPanel); + } + + /** + * 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() { + + detailsSplitPane = new javax.swing.JSplitPane(); + + detailsSplitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 667, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(detailsSplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 667, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 402, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(detailsSplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 402, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JSplitPane detailsSplitPane; + // End of variables declaration//GEN-END:variables +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ResultsPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ResultsPanel.form index bc265187e9..407e17c946 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ResultsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ResultsPanel.form @@ -30,7 +30,7 @@ - + @@ -312,22 +312,16 @@ - - - - - - @@ -358,11 +352,11 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ResultsPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ResultsPanel.java index 9a22418fb7..7bd732d18a 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ResultsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ResultsPanel.java @@ -56,10 +56,11 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.textsummarizer.TextSummary; +import java.awt.Graphics; /** - * Panel for displaying of Discovery results and handling the paging of - * those results. + * Panel for displaying of Discovery results and handling the paging of those + * results. */ public class ResultsPanel extends javax.swing.JPanel { @@ -82,6 +83,14 @@ public class ResultsPanel extends javax.swing.JPanel { private final DefaultListModel instancesListModel = new DefaultListModel<>(); private ListSelectionListener listener = null; + private int dividerLocation = 1; + + private static final int ANIMATION_INCREMENT = 10; + + private SwingAnimator fadeInAnimator = null; + + private SwingAnimator fadeOutAnimator = null; + /** * Creates new form ResultsPanel. */ @@ -164,6 +173,7 @@ public class ResultsPanel extends javax.swing.JPanel { if (files.isEmpty()) { //if there are no files currently remove the current items without removing listener to cause content viewer to reset instancesListModel.removeAllElements(); + fadeOut(); } else { //remove listener so content viewer node is not set multiple times instancesList.removeListSelectionListener(listener); @@ -176,10 +186,12 @@ public class ResultsPanel extends javax.swing.JPanel { if (!instancesListModel.isEmpty()) { instancesList.setSelectedIndex(0); } + fadeIn(); } }); } + /** * Get the AbstractFile for the item currently selected in the instances * list. @@ -425,7 +437,7 @@ public class ResultsPanel extends javax.swing.JPanel { javax.swing.Box.Filler filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0)); javax.swing.Box.Filler filler3 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0)); javax.swing.Box.Filler filler4 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0)); - javax.swing.JSplitPane resultsSplitPane = new javax.swing.JSplitPane(); + resultsSplitPane = new javax.swing.JSplitPane(); javax.swing.JPanel instancesPanel = new javax.swing.JPanel(); javax.swing.JScrollPane instancesScrollPane = new javax.swing.JScrollPane(); instancesList = new javax.swing.JList<>(); @@ -580,11 +592,9 @@ public class ResultsPanel extends javax.swing.JPanel { gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; pagingPanel.add(filler4, gridBagConstraints); - resultsSplitPane.setDividerLocation(380); resultsSplitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT); resultsSplitPane.setResizeWeight(1.0); resultsSplitPane.setToolTipText(org.openide.util.NbBundle.getMessage(ResultsPanel.class, "ResultsPanel.resultsSplitPane.toolTipText")); // NOI18N - resultsSplitPane.setLastDividerLocation(180); resultsSplitPane.setOpaque(false); resultsSplitPane.setPreferredSize(new java.awt.Dimension(777, 440)); @@ -609,11 +619,11 @@ public class ResultsPanel extends javax.swing.JPanel { ); instancesPanelLayout.setVerticalGroup( instancesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 68, Short.MAX_VALUE) + .addGap(0, 433, Short.MAX_VALUE) .addGroup(instancesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, instancesPanelLayout.createSequentialGroup() .addGap(0, 0, 0) - .addComponent(instancesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addComponent(instancesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 433, Short.MAX_VALUE))) ); resultsSplitPane.setRightComponent(instancesPanel); @@ -627,14 +637,14 @@ public class ResultsPanel extends javax.swing.JPanel { layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(pagingPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) - .addComponent(resultsSplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(resultsSplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 29, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addComponent(pagingPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(0, 0, 0) - .addComponent(resultsSplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 436, Short.MAX_VALUE) + .addComponent(resultsSplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 34, Short.MAX_VALUE) .addGap(0, 0, 0)) ); }// //GEN-END:initComponents @@ -723,6 +733,7 @@ public class ResultsPanel extends javax.swing.JPanel { private javax.swing.JButton nextPageButton; private javax.swing.JComboBox pageSizeComboBox; private javax.swing.JButton previousPageButton; + private javax.swing.JSplitPane resultsSplitPane; private javax.swing.JPanel resultsViewerPanel; // End of variables declaration//GEN-END:variables @@ -878,4 +889,154 @@ public class ResultsPanel extends javax.swing.JPanel { } } + + /** + * + * Sets the alpha value + * + * @param a + * + */ + public void setDividerLocation(int a) { + + this.dividerLocation = a; + + } + + /** + * + * Fades this JPanel in. * + */ + public void fadeIn() { + + stop(); + + fadeInAnimator = new SwingAnimator(new FadeInCallback()); + + fadeInAnimator.start(); + + } + + /** + * + * Fades this JPanel out + * + */ + public void fadeOut() { + + stop(); + + fadeOutAnimator = new SwingAnimator(new FadeOutCallback()); + + fadeOutAnimator.start(); + + } + + /** + * + * Stops all animators. * + */ + private void stop() { + + if (fadeOutAnimator != null && fadeOutAnimator.isRunning()) { + + fadeOutAnimator.stop(); + + } + + if (fadeInAnimator != null && fadeInAnimator.isRunning()) { + + fadeInAnimator.stop(); + + } + + } + + @Override + public void paintComponent(Graphics g) { + + if (dividerLocation <= resultsSplitPane.getHeight() && dividerLocation >= (resultsSplitPane.getHeight() - 100)) { + resultsSplitPane.setDividerLocation(dividerLocation); + } + + super.paintComponent(g); + + } + + /** + * + * Callback implementation for fading in + * + * @author Greg Cope + * + * + * + */ + private class FadeInCallback implements SwingAnimatorCallback { + + @Override + + public void callback(Object caller) { + + dividerLocation -= ANIMATION_INCREMENT; + + repaint(); + + } + + @Override + + public boolean hasTerminated() { + + if (dividerLocation <= (resultsSplitPane.getHeight() - 100)) { + + dividerLocation = resultsSplitPane.getHeight() - 100; + System.out.println("FADE IN COMPLETE"); + return true; + + } + + return false; + + } + + } + + /** + * + * Callback implementation to fade out + * + * @author Greg Cope + * + * + * + */ + private class FadeOutCallback implements SwingAnimatorCallback { + + @Override + + public void callback(Object caller) { + + dividerLocation += ANIMATION_INCREMENT; + + repaint(); + + } + + @Override + + public boolean hasTerminated() { + + if (dividerLocation >= resultsSplitPane.getHeight()) { + + dividerLocation = resultsSplitPane.getHeight(); + System.out.println("FADE OUT COMPLETE"); + return true; + } + + return false; + } + + } + } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/SwingAnimator.java b/Core/src/org/sleuthkit/autopsy/discovery/SwingAnimator.java new file mode 100644 index 0000000000..d744f5c3d8 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/SwingAnimator.java @@ -0,0 +1,193 @@ +/* + * 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.discovery; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.Timer; + +/** + * + * Class to animate Layouts and Fades for a given component. + * + * + * @author Greg Cope + * + * + * + */ +public final class SwingAnimator { + + //callback object + private final SwingAnimatorCallback callback; + + //Timer to animate on the EDT + private Timer timer = null; + + //duration in milliseconds betweeen each firing of the Timer + private static final int INITIAL_DURATION = 10; + private static int duration = INITIAL_DURATION; + + /** + * + * Constructs a new SwingAnimator. + * + * + * @param callback The object to callback to + * + */ + public SwingAnimator(SwingAnimatorCallback callback) { + + this(callback, false); + + } + + /** + * + * + * + * @param callback The object to callback to + * + * @param start true to automatically start the animation, false + * otherwise + * + */ + public SwingAnimator(SwingAnimatorCallback callback, boolean start) { + + this(callback, INITIAL_DURATION, start); + + } + + /** + * + * + * + * @param callback The object to callback to + * + * @param frameTiming Timing between each call to callback. + * + * @param start true to automatically start the animation, false + * otherwise + * + */ + public SwingAnimator(SwingAnimatorCallback callback, int frameTiming, boolean start) { + + this.callback = callback; + + duration = frameTiming; + + if (start) { + + start(); + + } + + } + + /** + * + * + * + * @param callback The object to callback to + * + * @param frameTiming Timing between each call to callback. + * + */ + public SwingAnimator(SwingAnimatorCallback callback, int frameTiming) { + + this(callback, frameTiming, false); + + } + + /** + * + * Checks if this animator is running. + * + * @return + * + */ + public boolean isRunning() { + + if (timer == null) { + + return false; + + } + + return timer.isRunning(); + + } + + /** + * + * Stops the timer + * + */ + public void stop() { + + if (timer != null) { + + timer.stop(); + + } + + } + + /** + * + * Starts the timer to fire. If the current timer is non-null and running, + * this method will first + * + * stop the timer before beginning a new one. * + */ + public void start() { + + if (timer != null && timer.isRunning()) { + + stop(); + + } + + timer = new Timer(duration, new CallbackListener()); + + timer.start(); + + } + + /** + * + * ActionListener implements to be passed to the internal timer instance + * + * @author Greg Cope + * + * + * + */ + private class CallbackListener implements ActionListener { + + @Override + + public void actionPerformed(ActionEvent e) { + + if (callback.hasTerminated()) { + + if (timer == null) { + + throw new IllegalStateException("Callback listener should not be fired outside of SwingAnimator timer control"); + + } + + timer.stop(); + + } + + callback.callback(SwingAnimator.this); + + } + + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/SwingAnimatorCallback.java b/Core/src/org/sleuthkit/autopsy/discovery/SwingAnimatorCallback.java new file mode 100644 index 0000000000..31a8fdba0d --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/SwingAnimatorCallback.java @@ -0,0 +1,35 @@ +/* + * 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.discovery; + +/** + * + * Callback interface to be notified by a SwingAnimator of a new time frame. * + * @author Greg Cope + * + * + * + */ +public interface SwingAnimatorCallback { + + /** + * + * Callback method for the SwingAnimator + * + * @param caller + * + */ + public void callback(Object caller); + + /** + * + * Returns true if the SwingAnimator should terminate. * + * @return + * + */ + public boolean hasTerminated(); + +}