Autopsy  4.20.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
DiscoveryTopComponent.java
Go to the documentation of this file.
1 /*
2  * Autopsy
3  *
4  * Copyright 2019-2021 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.discovery.ui;
20 
22 import com.google.common.eventbus.Subscribe;
23 import java.awt.BorderLayout;
24 import java.awt.Color;
25 import java.awt.Graphics;
26 import java.beans.PropertyChangeEvent;
27 import java.beans.PropertyChangeListener;
28 import java.util.List;
29 import java.util.stream.Collectors;
30 import javax.swing.JPanel;
31 import javax.swing.JSplitPane;
32 import javax.swing.SwingUtilities;
33 import javax.swing.plaf.basic.BasicSplitPaneDivider;
34 import javax.swing.plaf.basic.BasicSplitPaneUI;
35 import org.openide.util.NbBundle;
36 import org.openide.util.NbBundle.Messages;
37 import org.openide.windows.Mode;
38 import org.openide.windows.RetainLocation;
39 import org.openide.windows.TopComponent;
40 import org.openide.windows.WindowManager;
46 import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
47 
51 @TopComponent.Description(preferredID = "DiscoveryTc", persistenceType = TopComponent.PERSISTENCE_NEVER)
52 @TopComponent.Registration(mode = "discovery", openAtStartup = false)
53 @RetainLocation("discovery")
54 @NbBundle.Messages("DiscoveryTopComponent.name= Discovery")
55 public final class DiscoveryTopComponent extends TopComponent {
56 
57  private static final long serialVersionUID = 1L;
58  private static final String PREFERRED_ID = "DiscoveryTc"; // NON-NLS
59  private static final int ANIMATION_INCREMENT = 30;
60  private volatile static int previousDividerLocation = 250;
61  private final GroupListPanel groupListPanel;
62  private final ResultsPanel resultsPanel;
63  private JPanel detailsPanel = new JPanel();
64  private String selectedDomainTabName;
65  private Type searchType;
66  private int dividerLocation = JSplitPane.UNDEFINED_CONDITION;
67 
68  private SwingAnimator animator = null;
69 
76  setName(Bundle.DiscoveryTopComponent_name());
77  groupListPanel = new GroupListPanel();
78  resultsPanel = new ResultsPanel();
79  mainSplitPane.setLeftComponent(groupListPanel);
80  //set color of divider
81  rightSplitPane.setUI(new BasicSplitPaneUI() {
82  @Override
83  public BasicSplitPaneDivider createDefaultDivider() {
84  return new BasicSplitPaneDividerImpl(this);
85 
86  }
87  });
88  rightSplitPane.setTopComponent(resultsPanel);
90  rightSplitPane.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, new PropertyChangeListener() {
91  @Override
92  public void propertyChange(PropertyChangeEvent evt) {
93  if (evt.getPropertyName().equalsIgnoreCase(JSplitPane.DIVIDER_LOCATION_PROPERTY)
94  && ((animator == null || !animator.isRunning())
95  && evt.getNewValue() instanceof Integer
96  && evt.getOldValue() instanceof Integer
97  && ((int) evt.getNewValue() + 5) < (rightSplitPane.getHeight() - rightSplitPane.getDividerSize())
98  && (JSplitPane.UNDEFINED_CONDITION != (int) evt.getNewValue())
99  && ((int) evt.getOldValue() != JSplitPane.UNDEFINED_CONDITION))) {
100  //Only change the saved location when it was a manual change by the user and not the animation or the window opening initially
101  previousDividerLocation = (int) evt.getNewValue();
102  }
103  }
104  }
105  );
106 
107  }
108 
112  private final class BasicSplitPaneDividerImpl extends BasicSplitPaneDivider {
113 
121  BasicSplitPaneDividerImpl(BasicSplitPaneUI ui) {
122  super(ui);
123  this.setLayout(new BorderLayout());
124  this.add(new ResultsSplitPaneDivider());
125  }
126 
127  private static final long serialVersionUID = 1L;
128  }
129 
136  DiscoveryTopComponent discoveryTopComp = (DiscoveryTopComponent) WindowManager.getDefault().findTopComponent(PREFERRED_ID);
137  return discoveryTopComp;
138  }
139 
144  public void resetTopComponent() {
145  resultsPanel.resetResultViewer();
146  groupListPanel.resetGroupList();
147  }
148 
150  @Override
151  public void componentOpened() {
152  super.componentOpened();
153  WindowManager.getDefault().setTopComponentFloating(this, true);
154  DiscoveryEventUtils.getDiscoveryEventBus().register(this);
155  DiscoveryEventUtils.getDiscoveryEventBus().register(resultsPanel);
156  DiscoveryEventUtils.getDiscoveryEventBus().register(groupListPanel);
157  }
158 
159  private void resetBottomComponent() {
160  rightSplitPane.setBottomComponent(new JPanel());
161  rightSplitPane.setDividerLocation(JSplitPane.UNDEFINED_CONDITION);
162  }
163 
165  @Override
166  protected void componentClosed() {
167  DiscoveryDialog.getDiscoveryDialogInstance().cancelSearch();
170  DiscoveryEventUtils.getDiscoveryEventBus().unregister(this);
171  DiscoveryEventUtils.getDiscoveryEventBus().unregister(groupListPanel);
172  DiscoveryEventUtils.getDiscoveryEventBus().unregister(resultsPanel);
173  DiscoveryEventUtils.getDiscoveryEventBus().unregister(detailsPanel);
174  if (detailsPanel instanceof DomainDetailsPanel) {
175  ((DomainDetailsPanel) detailsPanel).unregister();
176  selectedDomainTabName = ((DomainDetailsPanel) detailsPanel).getSelectedTabName();
177  }
179  super.componentClosed();
180  }
181 
187  @SuppressWarnings("unchecked")
188  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
189  private void initComponents() {
190 
191  mainSplitPane = new javax.swing.JSplitPane();
193  javax.swing.JPanel searchDetailsPanel = new javax.swing.JPanel();
194  newSearchButton = new javax.swing.JButton();
195  javax.swing.JScrollPane progressMessageScrollPane = new javax.swing.JScrollPane();
196  progressMessageTextArea = new javax.swing.JTextArea();
197 
198  setMinimumSize(new java.awt.Dimension(199, 200));
199  setPreferredSize(new java.awt.Dimension(1100, 700));
200  setLayout(new java.awt.BorderLayout());
201 
202  mainSplitPane.setDividerLocation(250);
203  mainSplitPane.setPreferredSize(new java.awt.Dimension(1100, 700));
204 
205  rightSplitPane.setDividerSize(35);
206  rightSplitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
207  rightSplitPane.setResizeWeight(1.0);
208  rightSplitPane.setPreferredSize(new java.awt.Dimension(800, 700));
209  mainSplitPane.setRightComponent(rightSplitPane);
210 
211  add(mainSplitPane, java.awt.BorderLayout.CENTER);
212 
213  org.openide.awt.Mnemonics.setLocalizedText(newSearchButton, Bundle.DiscoveryTopComponent_cancelButton_text());
214  newSearchButton.setMaximumSize(new java.awt.Dimension(110, 26));
215  newSearchButton.setMinimumSize(new java.awt.Dimension(110, 26));
216  newSearchButton.setPreferredSize(new java.awt.Dimension(110, 26));
217  newSearchButton.addActionListener(new java.awt.event.ActionListener() {
218  public void actionPerformed(java.awt.event.ActionEvent evt) {
220  }
221  });
222 
223  progressMessageScrollPane.setBorder(null);
224 
225  progressMessageTextArea.setBackground(new java.awt.Color(240, 240, 240));
226  progressMessageTextArea.setColumns(20);
227  progressMessageTextArea.setLineWrap(true);
228  progressMessageTextArea.setRows(2);
229  progressMessageTextArea.setWrapStyleWord(true);
230  progressMessageTextArea.setBorder(null);
231  progressMessageScrollPane.setViewportView(progressMessageTextArea);
232 
233  javax.swing.GroupLayout searchDetailsPanelLayout = new javax.swing.GroupLayout(searchDetailsPanel);
234  searchDetailsPanel.setLayout(searchDetailsPanelLayout);
235  searchDetailsPanelLayout.setHorizontalGroup(
236  searchDetailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
237  .addGroup(searchDetailsPanelLayout.createSequentialGroup()
238  .addContainerGap()
239  .addComponent(newSearchButton, javax.swing.GroupLayout.PREFERRED_SIZE, 110, javax.swing.GroupLayout.PREFERRED_SIZE)
240  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
241  .addComponent(progressMessageScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 954, Short.MAX_VALUE)
242  .addContainerGap())
243  );
244  searchDetailsPanelLayout.setVerticalGroup(
245  searchDetailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
246  .addGroup(searchDetailsPanelLayout.createSequentialGroup()
247  .addGroup(searchDetailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
248  .addGroup(searchDetailsPanelLayout.createSequentialGroup()
249  .addGap(8, 8, 8)
250  .addComponent(progressMessageScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 44, javax.swing.GroupLayout.PREFERRED_SIZE))
251  .addGroup(searchDetailsPanelLayout.createSequentialGroup()
252  .addGap(17, 17, 17)
253  .addComponent(newSearchButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
254  .addContainerGap())
255  );
256 
257  add(searchDetailsPanel, java.awt.BorderLayout.PAGE_START);
258  }// </editor-fold>//GEN-END:initComponents
259 
260  private void newSearchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newSearchButtonActionPerformed
261  close();
262  final DiscoveryDialog discDialog = DiscoveryDialog.getDiscoveryDialogInstance();
263  discDialog.setVisible(true);
264  discDialog.validateDialog();
265  }//GEN-LAST:event_newSearchButtonActionPerformed
266 
267  @Override
268  public List<Mode> availableModes(List<Mode> modes) {
269  /*
270  * This looks like the right thing to do, but online discussions seems
271  * to indicate this method is effectively deprecated. A break point
272  * placed here was never hit.
273  */
274  return modes.stream().filter(mode -> mode.getName().equals("discovery"))
275  .collect(Collectors.toList());
276  }
277 
285  @Subscribe
286  void handleDetailsVisibleEvent(DiscoveryEventUtils.DetailsVisibleEvent detailsVisibleEvent) {
287  SwingUtilities.invokeLater(() -> {
288  if (animator != null && animator.isRunning()) {
289  animator.stop();
290  animator = null;
291  }
292  dividerLocation = rightSplitPane.getDividerLocation();
293  if (detailsVisibleEvent.isShowDetailsArea()) {
294  animator = new SwingAnimator(new ShowDetailsAreaCallback());
295  } else {
296  animator = new SwingAnimator(new HideDetailsAreaCallback());
297  }
298  animator.start();
299  });
300  }
301 
308  @Messages({"DiscoveryTopComponent.cancelButton.text=Cancel Search",
309  "# {0} - searchType",
310  "DiscoveryTopComponent.searchInProgress.text=Performing search for results of type {0}. Please wait.",
311  "DiscoveryTopComponent.searchError.text=Error no type specified for search."})
312  @Subscribe
313  void handleSearchStartedEvent(DiscoveryEventUtils.SearchStartedEvent searchStartedEvent) {
314  SwingUtilities.invokeLater(() -> {
315  newSearchButton.setText(Bundle.DiscoveryTopComponent_cancelButton_text());
316  progressMessageTextArea.setForeground(Color.red);
317  searchType = searchStartedEvent.getType();
318  progressMessageTextArea.setText(Bundle.DiscoveryTopComponent_searchInProgress_text(searchType.name()));
319  });
320  }
321 
328  @Subscribe
329  @Messages({"DiscoveryTopComponent.newSearch.text=New Search",
330  "# {0} - search",
331  "DiscoveryTopComponent.searchComplete.text=Results with {0}",
332  "DiscoveryTopComponent.domainSearch.text=Type: Domain",
333  "DiscoveryTopComponent.additionalFilters.text=; "})
334  void handleSearchCompleteEvent(DiscoveryEventUtils.SearchCompleteEvent searchCompleteEvent) {
335  SwingUtilities.invokeLater(() -> {
336  newSearchButton.setText(Bundle.DiscoveryTopComponent_newSearch_text());
337  progressMessageTextArea.setForeground(Color.black);
338  String descriptionText = "";
339  if (searchType == DOMAIN) {
340  //domain does not have a file type filter to add the type information so it is manually added
341  descriptionText = Bundle.DiscoveryTopComponent_domainSearch_text();
342  if (!searchCompleteEvent.getFilters().isEmpty()) {
343  descriptionText += Bundle.DiscoveryTopComponent_additionalFilters_text();
344  }
345  selectedDomainTabName = validateLastSelectedType(searchCompleteEvent);
346  DomainDetailsPanel domainDetailsPanel = new DomainDetailsPanel();
347  domainDetailsPanel.configureArtifactTabs(selectedDomainTabName);
348  detailsPanel = domainDetailsPanel;
349  } else {
350  detailsPanel = new FileDetailsPanel();
351  }
352  rightSplitPane.setBottomComponent(detailsPanel);
353  DiscoveryEventUtils.getDiscoveryEventBus().register(detailsPanel);
354  descriptionText += searchCompleteEvent.getFilters().stream().map(AbstractFilter::getDesc).collect(Collectors.joining("; "));
355  progressMessageTextArea.setText(Bundle.DiscoveryTopComponent_searchComplete_text(descriptionText));
356  progressMessageTextArea.setCaretPosition(0);
357  });
358  }
359 
368  @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
369  private String validateLastSelectedType(DiscoveryEventUtils.SearchCompleteEvent searchCompleteEvent) {
370  String typeFilteredOn = selectedDomainTabName;
371 
372  for (AbstractFilter filter : searchCompleteEvent.getFilters()) {
373  if (filter instanceof ArtifactTypeFilter) {
374  for (ARTIFACT_TYPE type : ((ArtifactTypeFilter) filter).getTypes()) {
375  typeFilteredOn = type.getDisplayName();
376  if (selectedDomainTabName == null || typeFilteredOn.equalsIgnoreCase(selectedDomainTabName)) {
377  break;
378  }
379  }
380  break;
381  }
382  }
383  return typeFilteredOn;
384  }
385 
392  @Messages({"DiscoveryTopComponent.searchCancelled.text=Search has been cancelled."})
393  @Subscribe
394  void handleSearchCancelledEvent(DiscoveryEventUtils.SearchCancelledEvent searchCancelledEvent) {
395  SwingUtilities.invokeLater(() -> {
396  newSearchButton.setText(Bundle.DiscoveryTopComponent_newSearch_text());
397  progressMessageTextArea.setForeground(Color.red);
398  progressMessageTextArea.setText(Bundle.DiscoveryTopComponent_searchCancelled_text());
399  });
400 
401  }
402 
406  private final class ShowDetailsAreaCallback implements SwingAnimatorCallback {
407 
409  @Override
410  public void callback(Object caller) {
411  dividerLocation -= ANIMATION_INCREMENT;
412  repaint();
413  }
414 
416  @Override
417  public boolean hasTerminated() {
418  if (dividerLocation != JSplitPane.UNDEFINED_CONDITION && dividerLocation < previousDividerLocation) {
419  dividerLocation = previousDividerLocation;
420  animator = null;
421  return true;
422  }
423  return false;
424  }
425 
426  }
427 
431  private final class HideDetailsAreaCallback implements SwingAnimatorCallback {
432 
434  @Override
435  public void callback(Object caller) {
436  dividerLocation += ANIMATION_INCREMENT;
437  repaint();
438  }
439 
441  @Override
442  public boolean hasTerminated() {
443  if (dividerLocation > rightSplitPane.getHeight() || dividerLocation == JSplitPane.UNDEFINED_CONDITION) {
444  dividerLocation = rightSplitPane.getHeight();
445  animator = null;
446  return true;
447  }
448  return false;
449  }
450 
451  }
452  // Variables declaration - do not modify//GEN-BEGIN:variables
453  private javax.swing.JSplitPane mainSplitPane;
454  private javax.swing.JButton newSearchButton;
455  private javax.swing.JTextArea progressMessageTextArea;
456  private javax.swing.JSplitPane rightSplitPane;
457  // End of variables declaration//GEN-END:variables
458 
462  private final class AnimatedSplitPane extends JSplitPane {
463 
464  private static final long serialVersionUID = 1L;
465 
467  @Override
468  public void paintComponent(Graphics g) {
469  if (animator != null && animator.isRunning() && (dividerLocation == JSplitPane.UNDEFINED_CONDITION
470  || (dividerLocation <= getHeight() && dividerLocation >= previousDividerLocation))) {
471  setDividerLocation(dividerLocation);
472  }
473  super.paintComponent(g);
474  }
475 
476  }
477 
478 }
void newSearchButtonActionPerformed(java.awt.event.ActionEvent evt)
String validateLastSelectedType(DiscoveryEventUtils.SearchCompleteEvent searchCompleteEvent)

Copyright © 2012-2022 Basis Technology. Generated on: Tue Aug 1 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.