Autopsy  4.19.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-2020 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.cancelSearch();
264  discDialog.setVisible(true);
265  discDialog.validateDialog();
266  }//GEN-LAST:event_newSearchButtonActionPerformed
267 
268  @Override
269  public List<Mode> availableModes(List<Mode> modes) {
270  /*
271  * This looks like the right thing to do, but online discussions seems
272  * to indicate this method is effectively deprecated. A break point
273  * placed here was never hit.
274  */
275  return modes.stream().filter(mode -> mode.getName().equals("discovery"))
276  .collect(Collectors.toList());
277  }
278 
286  @Subscribe
287  void handleDetailsVisibleEvent(DiscoveryEventUtils.DetailsVisibleEvent detailsVisibleEvent) {
288  SwingUtilities.invokeLater(() -> {
289  if (animator != null && animator.isRunning()) {
290  animator.stop();
291  animator = null;
292  }
293  dividerLocation = rightSplitPane.getDividerLocation();
294  if (detailsVisibleEvent.isShowDetailsArea()) {
295  animator = new SwingAnimator(new ShowDetailsAreaCallback());
296  } else {
297  animator = new SwingAnimator(new HideDetailsAreaCallback());
298  }
299  animator.start();
300  });
301  }
302 
309  @Messages({"DiscoveryTopComponent.cancelButton.text=Cancel Search",
310  "# {0} - searchType",
311  "DiscoveryTopComponent.searchInProgress.text=Performing search for results of type {0}. Please wait.",
312  "DiscoveryTopComponent.searchError.text=Error no type specified for search."})
313  @Subscribe
314  void handleSearchStartedEvent(DiscoveryEventUtils.SearchStartedEvent searchStartedEvent) {
315  SwingUtilities.invokeLater(() -> {
316  newSearchButton.setText(Bundle.DiscoveryTopComponent_cancelButton_text());
317  progressMessageTextArea.setForeground(Color.red);
318  searchType = searchStartedEvent.getType();
319  progressMessageTextArea.setText(Bundle.DiscoveryTopComponent_searchInProgress_text(searchType.name()));
320  });
321  }
322 
329  @Subscribe
330  @Messages({"DiscoveryTopComponent.newSearch.text=New Search",
331  "# {0} - search",
332  "DiscoveryTopComponent.searchComplete.text=Results with {0}",
333  "DiscoveryTopComponent.domainSearch.text=Type: Domain",
334  "DiscoveryTopComponent.additionalFilters.text=; "})
335  void handleSearchCompleteEvent(DiscoveryEventUtils.SearchCompleteEvent searchCompleteEvent) {
336  SwingUtilities.invokeLater(() -> {
337  newSearchButton.setText(Bundle.DiscoveryTopComponent_newSearch_text());
338  progressMessageTextArea.setForeground(Color.black);
339  String descriptionText = "";
340  if (searchType == DOMAIN) {
341  //domain does not have a file type filter to add the type information so it is manually added
342  descriptionText = Bundle.DiscoveryTopComponent_domainSearch_text();
343  if (!searchCompleteEvent.getFilters().isEmpty()) {
344  descriptionText += Bundle.DiscoveryTopComponent_additionalFilters_text();
345  }
346  selectedDomainTabName = validateLastSelectedType(searchCompleteEvent);
347  DomainDetailsPanel domainDetailsPanel = new DomainDetailsPanel();
348  domainDetailsPanel.configureArtifactTabs(selectedDomainTabName);
349  detailsPanel = domainDetailsPanel;
350  } else {
351  detailsPanel = new FileDetailsPanel();
352  }
353  rightSplitPane.setBottomComponent(detailsPanel);
354  DiscoveryEventUtils.getDiscoveryEventBus().register(detailsPanel);
355  descriptionText += searchCompleteEvent.getFilters().stream().map(AbstractFilter::getDesc).collect(Collectors.joining("; "));
356  progressMessageTextArea.setText(Bundle.DiscoveryTopComponent_searchComplete_text(descriptionText));
357  progressMessageTextArea.setCaretPosition(0);
358  });
359  }
360 
369  @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
370  private String validateLastSelectedType(DiscoveryEventUtils.SearchCompleteEvent searchCompleteEvent) {
371  String typeFilteredOn = selectedDomainTabName;
372 
373  for (AbstractFilter filter : searchCompleteEvent.getFilters()) {
374  if (filter instanceof ArtifactTypeFilter) {
375  for (ARTIFACT_TYPE type : ((ArtifactTypeFilter) filter).getTypes()) {
376  typeFilteredOn = type.getDisplayName();
377  if (selectedDomainTabName == null || typeFilteredOn.equalsIgnoreCase(selectedDomainTabName)) {
378  break;
379  }
380  }
381  break;
382  }
383  }
384  return typeFilteredOn;
385  }
386 
393  @Messages({"DiscoveryTopComponent.searchCancelled.text=Search has been cancelled."})
394  @Subscribe
395  void handleSearchCancelledEvent(DiscoveryEventUtils.SearchCancelledEvent searchCancelledEvent) {
396  SwingUtilities.invokeLater(() -> {
397  newSearchButton.setText(Bundle.DiscoveryTopComponent_newSearch_text());
398  progressMessageTextArea.setForeground(Color.red);
399  progressMessageTextArea.setText(Bundle.DiscoveryTopComponent_searchCancelled_text());
400  });
401 
402  }
403 
407  private final class ShowDetailsAreaCallback implements SwingAnimatorCallback {
408 
410  @Override
411  public void callback(Object caller) {
412  dividerLocation -= ANIMATION_INCREMENT;
413  repaint();
414  }
415 
417  @Override
418  public boolean hasTerminated() {
419  if (dividerLocation != JSplitPane.UNDEFINED_CONDITION && dividerLocation < previousDividerLocation) {
420  dividerLocation = previousDividerLocation;
421  animator = null;
422  return true;
423  }
424  return false;
425  }
426 
427  }
428 
432  private final class HideDetailsAreaCallback implements SwingAnimatorCallback {
433 
435  @Override
436  public void callback(Object caller) {
437  dividerLocation += ANIMATION_INCREMENT;
438  repaint();
439  }
440 
442  @Override
443  public boolean hasTerminated() {
444  if (dividerLocation > rightSplitPane.getHeight() || dividerLocation == JSplitPane.UNDEFINED_CONDITION) {
445  dividerLocation = rightSplitPane.getHeight();
446  animator = null;
447  return true;
448  }
449  return false;
450  }
451 
452  }
453  // Variables declaration - do not modify//GEN-BEGIN:variables
454  private javax.swing.JSplitPane mainSplitPane;
455  private javax.swing.JButton newSearchButton;
456  private javax.swing.JTextArea progressMessageTextArea;
457  private javax.swing.JSplitPane rightSplitPane;
458  // End of variables declaration//GEN-END:variables
459 
463  private final class AnimatedSplitPane extends JSplitPane {
464 
465  private static final long serialVersionUID = 1L;
466 
468  @Override
469  public void paintComponent(Graphics g) {
470  if (animator != null && animator.isRunning() && (dividerLocation == JSplitPane.UNDEFINED_CONDITION
471  || (dividerLocation <= getHeight() && dividerLocation >= previousDividerLocation))) {
472  setDividerLocation(dividerLocation);
473  }
474  super.paintComponent(g);
475  }
476 
477  }
478 
479 }
void newSearchButtonActionPerformed(java.awt.event.ActionEvent evt)
String validateLastSelectedType(DiscoveryEventUtils.SearchCompleteEvent searchCompleteEvent)

Copyright © 2012-2021 Basis Technology. Generated on: Fri Aug 6 2021
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.