Autopsy  4.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
DataContentViewerArtifact.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-2013 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.corecomponents;
20 
21 import java.awt.*;
22 import java.awt.event.ActionEvent;
23 import java.awt.event.ActionListener;
24 import java.util.ArrayList;
25 import java.util.List;
26 import java.util.concurrent.ExecutionException;
27 import java.util.logging.Level;
28 import javax.swing.JMenuItem;
29 import javax.swing.JTextPane;
30 import javax.swing.SwingWorker;
31 import org.openide.nodes.Node;
32 import org.openide.util.Lookup;
33 import org.openide.util.NbBundle;
34 import org.openide.util.lookup.ServiceProvider;
40 import org.sleuthkit.datamodel.BlackboardArtifact;
41 import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
42 import org.sleuthkit.datamodel.BlackboardAttribute;
43 import org.sleuthkit.datamodel.Content;
44 import org.sleuthkit.datamodel.SleuthkitCase;
45 import org.sleuthkit.datamodel.TskCoreException;
46 import org.sleuthkit.datamodel.TskException;
47 
53 @ServiceProvider(service = DataContentViewer.class, position = 3)
54 public class DataContentViewerArtifact extends javax.swing.JPanel implements DataContentViewer {
55 
56  private final static Logger logger = Logger.getLogger(DataContentViewerArtifact.class.getName());
57  private final static String WAIT_TEXT = NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.waitText");
58  private final static String ERROR_TEXT = NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.errorText");
59  private Node currentNode; // @@@ Remove this when the redundant setNode() calls problem is fixed.
60  private int currentPage = 1;
61  private final Object lock = new Object();
62  private List<ArtifactStringContent> artifactContentStrings; // Accessed by multiple threads, use getArtifactContentStrings() and setArtifactContentStrings()
63  SwingWorker<ViewUpdate, Void> currentTask; // Accessed by multiple threads, use startNewTask()
64 
66  initComponents();
67  customizeComponents();
68  resetComponents();
69  }
70 
76  @SuppressWarnings("unchecked")
77  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
78  private void initComponents() {
79 
80  rightClickMenu = new javax.swing.JPopupMenu();
81  copyMenuItem = new javax.swing.JMenuItem();
82  selectAllMenuItem = new javax.swing.JMenuItem();
83  jPanel1 = new javax.swing.JPanel();
84  jScrollPane1 = new javax.swing.JScrollPane();
85  outputViewPane = new JTextPane(){
86  public boolean getScrollableTracksViewportWidth() {
87  return (getSize().width < 400);
88  }};
89  totalPageLabel = new javax.swing.JLabel();
90  ofLabel = new javax.swing.JLabel();
91  currentPageLabel = new javax.swing.JLabel();
92  pageLabel = new javax.swing.JLabel();
93  nextPageButton = new javax.swing.JButton();
94  pageLabel2 = new javax.swing.JLabel();
95  prevPageButton = new javax.swing.JButton();
96 
97  copyMenuItem.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.copyMenuItem.text")); // NOI18N
98  rightClickMenu.add(copyMenuItem);
99 
100  selectAllMenuItem.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.selectAllMenuItem.text")); // NOI18N
101  rightClickMenu.add(selectAllMenuItem);
102 
103  setPreferredSize(new java.awt.Dimension(622, 424));
104 
105  jPanel1.setPreferredSize(new java.awt.Dimension(622, 424));
106 
107  outputViewPane.setEditable(false);
108  outputViewPane.setPreferredSize(new java.awt.Dimension(700, 400));
109  jScrollPane1.setViewportView(outputViewPane);
110 
111  totalPageLabel.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.totalPageLabel.text")); // NOI18N
112 
113  ofLabel.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.ofLabel.text")); // NOI18N
114 
115  currentPageLabel.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.currentPageLabel.text")); // NOI18N
116  currentPageLabel.setMaximumSize(new java.awt.Dimension(18, 14));
117  currentPageLabel.setMinimumSize(new java.awt.Dimension(18, 14));
118  currentPageLabel.setPreferredSize(new java.awt.Dimension(18, 14));
119 
120  pageLabel.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.pageLabel.text")); // NOI18N
121  pageLabel.setMaximumSize(new java.awt.Dimension(33, 14));
122  pageLabel.setMinimumSize(new java.awt.Dimension(33, 14));
123  pageLabel.setPreferredSize(new java.awt.Dimension(33, 14));
124 
125  nextPageButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png"))); // NOI18N NON-NLS
126  nextPageButton.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.nextPageButton.text")); // NOI18N
127  nextPageButton.setBorderPainted(false);
128  nextPageButton.setContentAreaFilled(false);
129  nextPageButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png"))); // NOI18N NON-NLS
130  nextPageButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
131  nextPageButton.setPreferredSize(new java.awt.Dimension(23, 23));
132  nextPageButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png"))); // NOI18N NON-NLS
133  nextPageButton.addActionListener(new java.awt.event.ActionListener() {
134  public void actionPerformed(java.awt.event.ActionEvent evt) {
135  nextPageButtonActionPerformed(evt);
136  }
137  });
138 
139  pageLabel2.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.pageLabel2.text")); // NOI18N
140  pageLabel2.setMaximumSize(new java.awt.Dimension(29, 14));
141  pageLabel2.setMinimumSize(new java.awt.Dimension(29, 14));
142  pageLabel2.setPreferredSize(new java.awt.Dimension(29, 14));
143 
144  prevPageButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back.png"))); // NOI18N NON-NLS
145  prevPageButton.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.prevPageButton.text")); // NOI18N
146  prevPageButton.setBorderPainted(false);
147  prevPageButton.setContentAreaFilled(false);
148  prevPageButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png"))); // NOI18N NON-NLS
149  prevPageButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
150  prevPageButton.setPreferredSize(new java.awt.Dimension(23, 23));
151  prevPageButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png"))); // NOI18N NON-NLS
152  prevPageButton.addActionListener(new java.awt.event.ActionListener() {
153  public void actionPerformed(java.awt.event.ActionEvent evt) {
154  prevPageButtonActionPerformed(evt);
155  }
156  });
157 
158  javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
159  jPanel1.setLayout(jPanel1Layout);
160  jPanel1Layout.setHorizontalGroup(
161  jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
162  .addGroup(jPanel1Layout.createSequentialGroup()
163  .addContainerGap()
164  .addComponent(pageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE)
165  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
166  .addComponent(currentPageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
167  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
168  .addComponent(ofLabel)
169  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
170  .addComponent(totalPageLabel)
171  .addGap(41, 41, 41)
172  .addComponent(pageLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 38, javax.swing.GroupLayout.PREFERRED_SIZE)
173  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
174  .addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
175  .addGap(0, 0, 0)
176  .addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
177  .addContainerGap(366, Short.MAX_VALUE))
178  .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 622, Short.MAX_VALUE)
179  );
180  jPanel1Layout.setVerticalGroup(
181  jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
182  .addGroup(jPanel1Layout.createSequentialGroup()
183  .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
184  .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
185  .addComponent(pageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
186  .addComponent(currentPageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
187  .addComponent(ofLabel)
188  .addComponent(totalPageLabel))
189  .addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
190  .addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
191  .addComponent(pageLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
192  .addGap(0, 0, 0)
193  .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 401, Short.MAX_VALUE))
194  );
195 
196  javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
197  this.setLayout(layout);
198  layout.setHorizontalGroup(
199  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
200  .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
201  );
202  layout.setVerticalGroup(
203  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
204  .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
205  );
206  }// </editor-fold>//GEN-END:initComponents
207 
208  private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed
209  currentPage = currentPage + 1;
210  currentPageLabel.setText(Integer.toString(currentPage));
211  startNewTask(new SelectedArtifactChangedTask(currentPage));
212  }//GEN-LAST:event_nextPageButtonActionPerformed
213 
214  private void prevPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prevPageButtonActionPerformed
215  currentPage = currentPage - 1;
216  currentPageLabel.setText(Integer.toString(currentPage));
217  startNewTask(new SelectedArtifactChangedTask(currentPage));
218  }//GEN-LAST:event_prevPageButtonActionPerformed
219 
220  // Variables declaration - do not modify//GEN-BEGIN:variables
221  private javax.swing.JMenuItem copyMenuItem;
222  private javax.swing.JLabel currentPageLabel;
223  private javax.swing.JPanel jPanel1;
224  private javax.swing.JScrollPane jScrollPane1;
225  private javax.swing.JButton nextPageButton;
226  private javax.swing.JLabel ofLabel;
227  private javax.swing.JTextPane outputViewPane;
228  private javax.swing.JLabel pageLabel;
229  private javax.swing.JLabel pageLabel2;
230  private javax.swing.JButton prevPageButton;
231  private javax.swing.JPopupMenu rightClickMenu;
232  private javax.swing.JMenuItem selectAllMenuItem;
233  private javax.swing.JLabel totalPageLabel;
234  // End of variables declaration//GEN-END:variables
235 
236  private void customizeComponents() {
237  outputViewPane.setComponentPopupMenu(rightClickMenu);
238  ActionListener actList = new ActionListener() {
239  @Override
240  public void actionPerformed(ActionEvent e) {
241  JMenuItem jmi = (JMenuItem) e.getSource();
242  if (jmi.equals(copyMenuItem)) {
243  outputViewPane.copy();
244  } else if (jmi.equals(selectAllMenuItem)) {
245  outputViewPane.selectAll();
246  }
247  }
248  };
249  copyMenuItem.addActionListener(actList);
250  selectAllMenuItem.addActionListener(actList);
251 
252  Utilities.configureTextPaneAsHtml(outputViewPane);
253  }
254 
258  private void resetComponents() {
259  currentPage = 1;
260  currentPageLabel.setText("");
261  totalPageLabel.setText("");
262  outputViewPane.setText("");
263  prevPageButton.setEnabled(false);
264  nextPageButton.setEnabled(false);
265  currentNode = null;
266  }
267 
268  @Override
269  public void setNode(Node selectedNode) {
270  if (currentNode == selectedNode) {
271  return;
272  }
273  currentNode = selectedNode;
274 
275  // Make sure there is a node. Null might be passed to reset the viewer.
276  if (selectedNode == null) {
277  return;
278  }
279 
280  // Make sure the node is of the correct type.
281  Lookup lookup = selectedNode.getLookup();
282  Content content = lookup.lookup(Content.class);
283  if (content == null) {
284  return;
285  }
286 
287  startNewTask(new SelectedNodeChangedTask(selectedNode));
288  }
289 
290  @Override
291  public String getTitle() {
292  return NbBundle.getMessage(this.getClass(), "DataContentViewerArtifact.title");
293  }
294 
295  @Override
296  public String getToolTip() {
297  return NbBundle.getMessage(this.getClass(), "DataContentViewerArtifact.toolTip");
298  }
299 
300  @Override
301  public DataContentViewer createInstance() {
302  return new DataContentViewerArtifact();
303  }
304 
305  @Override
306  public Component getComponent() {
307  return this;
308  }
309 
310  @Override
311  public void resetComponent() {
312  resetComponents();
313  }
314 
315  @Override
316  public boolean isSupported(Node node) {
317  if (node == null) {
318  return false;
319  }
320 
321  Content content = node.getLookup().lookup(Content.class);
322  if (content != null) {
323  try {
324  return content.getAllArtifactsCount() > 0;
325  } catch (TskException ex) {
326  logger.log(Level.WARNING, "Couldn't get count of BlackboardArtifacts for content", ex); //NON-NLS
327  }
328  }
329  return false;
330  }
331 
332  @Override
333  public int isPreferred(Node node) {
334  BlackboardArtifact artifact = node.getLookup().lookup(BlackboardArtifact.class);
335  // low priority if node doesn't have an artifact (meaning it was found from normal directory
336  // browsing, or if the artifact is something that means the user really wants to see the original
337  // file and not more details about the artifact
338  if ((artifact == null)
339  || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID())
340  || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID())) {
341  return 3;
342  } else {
343  return 5;
344  }
345  }
346 
351  private class ViewUpdate {
352 
353  int numberOfPages;
354  int currentPage;
355  String text;
356 
357  ViewUpdate(int numberOfPages, int currentPage, String text) {
358  this.currentPage = currentPage;
359  this.numberOfPages = numberOfPages;
360  this.text = text;
361  }
362  }
363 
371  private void updateView(ViewUpdate viewUpdate) {
372  this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
373 
374  nextPageButton.setEnabled(viewUpdate.currentPage < viewUpdate.numberOfPages);
375  prevPageButton.setEnabled(viewUpdate.currentPage > 1);
376  currentPage = viewUpdate.currentPage;
377  totalPageLabel.setText(Integer.toString(viewUpdate.numberOfPages));
378  currentPageLabel.setText(Integer.toString(currentPage));
379 
380  // @@@ This can take a long time. Perhaps a faster HTML renderer can be found.
381  // Note that the rendering appears to be done on a background thread, since the
382  // wait cursor reset below happens before the new text hits the JTextPane. On the
383  // other hand, the UI is unresponsive...
384  outputViewPane.setText(viewUpdate.text);
385  outputViewPane.moveCaretPosition(0);
386 
387  this.setCursor(null);
388  }
389 
396  private synchronized void startNewTask(SwingWorker<ViewUpdate, Void> task) {
397  outputViewPane.setText(WAIT_TEXT);
398  outputViewPane.moveCaretPosition(0);
399 
400  // The output of the previous task is no longer relevant.
401  if (currentTask != null) {
402  // This call sets a cancellation flag. It does not terminate the background thread running the task.
403  // The task must check the cancellation flag and react appropriately.
404  currentTask.cancel(false);
405  }
406 
407  // Start the new task.
408  currentTask = task;
409  currentTask.execute();
410  }
411 
417  private void setArtifactContentStrings(List<ArtifactStringContent> artifactStrings) {
418  synchronized (lock) {
419  this.artifactContentStrings = artifactStrings;
420  }
421  }
422 
428  private List<ArtifactStringContent> getArtifactContentStrings() {
429  synchronized (lock) {
430  return artifactContentStrings;
431  }
432  }
433 
439  private class SelectedNodeChangedTask extends SwingWorker<ViewUpdate, Void> {
440 
441  private final Node selectedNode;
442 
443  SelectedNodeChangedTask(Node selectedNode) {
444  this.selectedNode = selectedNode;
445  }
446 
447  @Override
449  // Get the lookup for the node for access to its underlying content and
450  // blackboard artifact, if any.
451  Lookup lookup = selectedNode.getLookup();
452 
453  // Get the content.
454  Content content = lookup.lookup(Content.class);
455  if (content == null) {
456  return new ViewUpdate(getArtifactContentStrings().size(), currentPage, ERROR_TEXT);
457  }
458 
459  // Get all of the blackboard artifacts associated with the content. These are what this
460  // viewer displays.
461  ArrayList<BlackboardArtifact> artifacts;
462  try {
463  artifacts = content.getAllArtifacts();
464  } catch (TskException ex) {
465  logger.log(Level.WARNING, "Couldn't get artifacts", ex); //NON-NLS
466  return new ViewUpdate(getArtifactContentStrings().size(), currentPage, ERROR_TEXT);
467  }
468 
469  if (isCancelled()) {
470  return null;
471  }
472 
473  // Build the new artifact strings cache.
474  ArrayList<ArtifactStringContent> artifactStrings = new ArrayList<>();
475  for (BlackboardArtifact artifact : artifacts) {
476  artifactStrings.add(new ArtifactStringContent(artifact));
477  }
478 
479  // If the node has an underlying blackboard artifact, show it. If not,
480  // show the first artifact.
481  int index = 0;
482  BlackboardArtifact artifact = lookup.lookup(BlackboardArtifact.class);
483  if (artifact != null) {
484  index = artifacts.indexOf(artifact);
485  if (index == -1) {
486  index = 0;
487  } else {
488  // if the artifact has an ASSOCIATED ARTIFACT, then we display the associated artifact instead
489  try {
490  for (BlackboardAttribute attr : artifact.getAttributes()) {
491  if (attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) {
492  long assocArtifactId = attr.getValueLong();
493  int assocArtifactIndex = -1;
494  for (BlackboardArtifact art : artifacts) {
495  if (assocArtifactId == art.getArtifactID()) {
496  assocArtifactIndex = artifacts.indexOf(art);
497  break;
498  }
499  }
500  if (assocArtifactIndex >= 0) {
501  index = assocArtifactIndex;
502  }
503  break;
504  }
505  }
506  } catch (TskCoreException ex) {
507  logger.log(Level.WARNING, "Couldn't get associated artifact to display in Content Viewer.", ex); //NON-NLS
508  }
509  }
510 
511  }
512 
513  if (isCancelled()) {
514  return null;
515  }
516 
517  // Add one to the index of the artifact string for the corresponding page index. Note that the getString() method
518  // of ArtifactStringContent does a lazy fetch of the attributes of the correspoding artifact and represents them as
519  // HTML.
520  ViewUpdate viewUpdate = new ViewUpdate(artifactStrings.size(), index + 1, artifactStrings.get(index).getString());
521 
522  // It may take a considerable amount of time to fetch the attributes of the selected artifact and render them
523  // as HTML, so check for cancellation.
524  if (isCancelled()) {
525  return null;
526  }
527 
528  // Update the artifact strings cache.
529  setArtifactContentStrings(artifactStrings);
530 
531  return viewUpdate;
532  }
533 
534  @Override
535  protected void done() {
536  if (!isCancelled()) {
537  try {
538  ViewUpdate viewUpdate = get();
539  if (viewUpdate != null) {
540  updateView(viewUpdate);
541  }
542  } catch (InterruptedException | ExecutionException ex) {
543  logger.log(Level.WARNING, "Artifact display task unexpectedly interrupted or failed", ex); //NON-NLS
544  }
545  }
546  }
547  }
548 
554  private class SelectedArtifactChangedTask extends SwingWorker<ViewUpdate, Void> {
555 
556  private final int pageIndex;
557 
558  SelectedArtifactChangedTask(final int pageIndex) {
559  this.pageIndex = pageIndex;
560  }
561 
562  @Override
564  // Get the artifact string to display from the cache. Note that one must be subtracted from the
565  // page index to get the corresponding artifact string index.
566  List<ArtifactStringContent> artifactStrings = getArtifactContentStrings();
567  ArtifactStringContent artifactStringContent = artifactStrings.get(pageIndex - 1);
568 
569  // The getString() method of ArtifactStringContent does a lazy fetch of the attributes of the
570  // correspoding artifact and represents them as HTML.
571  String artifactString = artifactStringContent.getString();
572 
573  // It may take a considerable amount of time to fetch the attributes of the selected artifact and render them
574  // as HTML, so check for cancellation.
575  if (isCancelled()) {
576  return null;
577  }
578 
579  return new ViewUpdate(artifactStrings.size(), pageIndex, artifactString);
580  }
581 
582  @Override
583  protected void done() {
584  if (!isCancelled()) {
585  try {
586  ViewUpdate viewUpdate = get();
587  if (viewUpdate != null) {
588  updateView(viewUpdate);
589  }
590  } catch (InterruptedException | ExecutionException ex) {
591  logger.log(Level.WARNING, "Artifact display task unexpectedly interrupted or failed", ex); //NON-NLS
592  }
593  }
594  }
595  }
596 }
void setArtifactContentStrings(List< ArtifactStringContent > artifactStrings)
synchronized void startNewTask(SwingWorker< ViewUpdate, Void > task)
static void configureTextPaneAsHtml(JTextPane pane)
Definition: Utilities.java:31
synchronized static Logger getLogger(String name)
Definition: Logger.java:161

Copyright © 2012-2016 Basis Technology. Generated on: Tue Oct 25 2016
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.