Autopsy  4.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
Reports.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-2015 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.datamodel;
20 
21 import java.awt.Desktop;
22 import java.awt.event.ActionEvent;
23 import java.beans.PropertyChangeEvent;
24 import java.beans.PropertyChangeListener;
25 import java.io.File;
26 import java.io.IOException;
27 import java.text.SimpleDateFormat;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.Collection;
31 import java.util.List;
32 import java.util.logging.Level;
33 import javax.swing.AbstractAction;
34 import javax.swing.Action;
35 import javax.swing.JCheckBox;
36 import javax.swing.JOptionPane;
37 import org.openide.nodes.ChildFactory;
38 import org.openide.nodes.Children;
39 import org.openide.nodes.Node;
40 import org.openide.nodes.Sheet;
41 import org.openide.util.NbBundle;
42 import org.openide.util.Utilities;
43 import org.openide.util.lookup.Lookups;
47 import org.sleuthkit.datamodel.Report;
48 import org.sleuthkit.datamodel.TskCoreException;
49 
53 public final class Reports implements AutopsyVisitableItem {
54 
55  private static final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
56 
57  @Override
58  public <T> T accept(AutopsyItemVisitor<T> visitor) {
59  // CreateAutopsyNodeVisitor.visit() constructs a ReportsListNode.
60  return visitor.visit(this);
61  }
62 
66  public static final class ReportsListNode extends DisplayableItemNode {
67 
68  private static final String DISPLAY_NAME = NbBundle.getMessage(ReportsListNode.class, "ReportsListNode.displayName");
69  private static final String ICON_PATH = "org/sleuthkit/autopsy/images/report_16.png"; //NON-NLS
70 
71  public ReportsListNode() {
72  super(Children.create(new ReportNodeFactory(), true));
73  setName(DISPLAY_NAME);
74  setDisplayName(DISPLAY_NAME);
75  this.setIconBaseWithExtension(ICON_PATH);
76  }
77 
78  @Override
79  public boolean isLeafTypeNode() {
80  return true;
81  }
82 
83  @Override
84  public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
85  // - GetPopupActionsDisplayableItemNodeVisitor.visit() returns null.
86  // - GetPreferredActionsDisplayableItemNodeVisitor.visit() returns null.
87  // - IsLeafItemVisitor.visit() returns false.
88  // - ShowItemVisitor.visit() returns true.
89  return visitor.visit(this);
90  }
91 
92  /*
93  * TODO (AUT-1849): Correct or remove peristent column reordering code
94  *
95  * Added to support this feature.
96  */
97 // @Override
98 // public String getItemType() {
99 // return "ReportsList"; //NON-NLS
100 // }
101  }
102 
107  private static final class ReportNodeFactory extends ChildFactory<Report> {
108 
110  Case.addPropertyChangeListener(new PropertyChangeListener() {
111  @Override
112  public void propertyChange(PropertyChangeEvent evt) {
113  String eventType = evt.getPropertyName();
114  if (eventType.equals(Case.Events.REPORT_ADDED.toString())) {
121  try {
123  ReportNodeFactory.this.refresh(true);
124  } catch (IllegalStateException notUsed) {
128  }
129  }
130  }
131  });
132  }
133 
134  @Override
135  protected boolean createKeys(List<Report> keys) {
136  try {
137  keys.addAll(Case.getCurrentCase().getAllReports());
138  } catch (TskCoreException ex) {
139  Logger.getLogger(Reports.ReportNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get reports", ex); //NON-NLS
140  }
141  return true;
142  }
143 
144  @Override
145  protected Node createNodeForKey(Report key) {
146  return new ReportNode(key);
147  }
148  }
149 
154  public static final class ReportNode extends DisplayableItemNode {
155 
156  private static final String ICON_PATH = "org/sleuthkit/autopsy/images/report_16.png"; //NON-NLS
157  private final Report report;
158 
159  ReportNode(Report report) {
160  super(Children.LEAF, Lookups.fixed(report));
161  this.report = report;
162  super.setName(this.report.getSourceModuleName());
163  super.setDisplayName(this.report.getSourceModuleName());
164  this.setIconBaseWithExtension(ICON_PATH);
165  }
166 
167  @Override
168  public boolean isLeafTypeNode() {
169  return true;
170  }
171 
172  @Override
173  public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
174  // - GetPopupActionsDisplayableItemNodeVisitor.visit() calls getActions().
175  // - GetPreferredActionsDisplayableItemNodeVisitor.visit() calls getPreferredAction().
176  // - IsLeafItemVisitor.visit() returns true.
177  // - ShowItemVisitor.visit() returns true.
178  return visitor.visit(this);
179  }
180 
181  @Override
182  protected Sheet createSheet() {
183  Sheet sheet = super.createSheet();
184  Sheet.Set propertiesSet = sheet.get(Sheet.PROPERTIES);
185  if (propertiesSet == null) {
186  propertiesSet = Sheet.createPropertiesSet();
187  sheet.put(propertiesSet);
188  }
189  propertiesSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ReportNode.sourceModuleNameProperty.name"),
190  NbBundle.getMessage(this.getClass(), "ReportNode.sourceModuleNameProperty.displayName"),
191  NbBundle.getMessage(this.getClass(), "ReportNode.sourceModuleNameProperty.desc"),
192  this.report.getSourceModuleName()));
193  propertiesSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ReportNode.reportNameProperty.name"),
194  NbBundle.getMessage(this.getClass(), "ReportNode.reportNameProperty.displayName"),
195  NbBundle.getMessage(this.getClass(), "ReportNode.reportNameProperty.desc"),
196  this.report.getReportName()));
197  propertiesSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ReportNode.createdTimeProperty.name"),
198  NbBundle.getMessage(this.getClass(), "ReportNode.createdTimeProperty.displayName"),
199  NbBundle.getMessage(this.getClass(), "ReportNode.createdTimeProperty.desc"),
200  dateFormatter.format(new java.util.Date(this.report.getCreatedTime() * 1000))));
201  propertiesSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ReportNode.pathProperty.name"),
202  NbBundle.getMessage(this.getClass(), "ReportNode.pathProperty.displayName"),
203  NbBundle.getMessage(this.getClass(), "ReportNode.pathProperty.desc"),
204  this.report.getPath()));
205  return sheet;
206  }
207 
208  @Override
209  public Action[] getActions(boolean popup) {
210  List<Action> actions = new ArrayList<>();
211  actions.addAll(Arrays.asList(super.getActions(true)));
212  actions.add(new OpenReportAction());
213  actions.add(DeleteReportAction.getInstance());
214  return actions.toArray(new Action[actions.size()]);
215  }
216 
217  @Override
218  public AbstractAction getPreferredAction() {
219  return new OpenReportAction();
220  }
221 
222  /*
223  * TODO (AUT-1849): Correct or remove peristent column reordering code
224  *
225  * Added to support this feature.
226  */
227 // @Override
228 // public String getItemType() {
229 // return "Reports"; //NON-NLS
230 // }
231  private static class DeleteReportAction extends AbstractAction {
232 
233  private static DeleteReportAction instance;
234 
235  // This class is a singleton to support multi-selection of nodes,
236  // since org.openide.nodes.NodeOp.findActions(Node[] nodes) will
237  // only pick up an Action if every node in the array returns a
238  // reference to the same action object from Node.getActions(boolean).
239  private static DeleteReportAction getInstance() {
240  if (instance == null) {
241  instance = new DeleteReportAction();
242  }
243  if (Utilities.actionsGlobalContext().lookupAll(Report.class).size() == 1) {
244  instance.putValue(Action.NAME, NbBundle.getMessage(Reports.class, "DeleteReportAction.actionDisplayName.singleReport"));
245  } else {
246  instance.putValue(Action.NAME, NbBundle.getMessage(Reports.class, "DeleteReportAction.actionDisplayName.multipleReports"));
247  }
248  return instance;
249  }
250 
255  private DeleteReportAction() {
256  }
257 
258  @Override
259  public void actionPerformed(ActionEvent e) {
260  Collection<? extends Report> selectedReportsCollection = Utilities.actionsGlobalContext().lookupAll(Report.class);
261 
262  String jOptionPaneMessage = selectedReportsCollection.size() > 1
263  ? NbBundle.getMessage(Reports.class, "DeleteReportAction.actionPerformed.showConfirmDialog.multiple.msg", selectedReportsCollection.size())
264  : NbBundle.getMessage(Reports.class, "DeleteReportAction.actionPerformed.showConfirmDialog.single.msg");
265  JCheckBox checkbox = new JCheckBox(NbBundle.getMessage(Reports.class, "DeleteReportAction.actionPerformed.showConfirmDialog.checkbox.msg"));
266  checkbox.setSelected(false);
267 
268  Object[] jOptionPaneContent = {jOptionPaneMessage, checkbox};
269 
270  if (JOptionPane.showConfirmDialog(null, jOptionPaneContent,
271  NbBundle.getMessage(Reports.class, "DeleteReportAction.actionPerformed.showConfirmDialog.title"),
272  JOptionPane.YES_NO_OPTION) == 0) {
273  try {
274  Case.getCurrentCase().deleteReports(selectedReportsCollection, checkbox.isSelected());
276  } catch (TskCoreException | IllegalStateException ex) {
277  Logger.getLogger(DeleteReportAction.class.getName()).log(Level.INFO, "Error deleting the reports. ", ex); // NON-NLS - Provide solution to the user?
278  }
279  }
280  }
281  }
282 
283  private final class OpenReportAction extends AbstractAction {
284 
285  private OpenReportAction() {
286  super(NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionDisplayName"));
287  }
288 
289  @Override
290  public void actionPerformed(ActionEvent e) {
291  File file = new File(ReportNode.this.report.getPath());
292  try {
293  Desktop.getDesktop().open(file);
294  } catch (IOException ex) {
295  JOptionPane.showMessageDialog(null,
296  NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionPerformed.NoAssociatedEditorMessage"),
297  NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionPerformed.MessageBoxTitle"),
298  JOptionPane.ERROR_MESSAGE);
299  } catch (UnsupportedOperationException ex) {
300  JOptionPane.showMessageDialog(null,
301  NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionPerformed.NoOpenInEditorSupportMessage"),
302  NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionPerformed.MessageBoxTitle"),
303  JOptionPane.ERROR_MESSAGE);
304  } catch (IllegalArgumentException ex) {
305  JOptionPane.showMessageDialog(null,
306  NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionPerformed.MissingReportFileMessage"),
307  NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionPerformed.MessageBoxTitle"),
308  JOptionPane.ERROR_MESSAGE);
309  } catch (SecurityException ex) {
310  JOptionPane.showMessageDialog(null,
311  NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionPerformed.ReportFileOpenPermissionDeniedMessage"),
312  NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionPerformed.MessageBoxTitle"),
313  JOptionPane.ERROR_MESSAGE);
314  }
315  }
316  }
317  }
318 }
void deleteReports(Collection<?extends Report > reports, boolean deleteFromDisk)
Definition: Case.java:1713
static synchronized DataContentTopComponent findInstance()
static final SimpleDateFormat dateFormatter
Definition: Reports.java:55
static synchronized void addPropertyChangeListener(PropertyChangeListener listener)
Definition: Case.java:1292
synchronized static Logger getLogger(String name)
Definition: Logger.java:166

Copyright © 2012-2015 Basis Technology. Generated on: Wed Apr 6 2016
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.