Autopsy  4.20.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
ExtractedContentPanel.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-2023 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.keywordsearch;
20 
21 import java.awt.ComponentOrientation;
22 import java.awt.EventQueue;
23 import java.awt.Font;
24 import java.awt.event.ActionListener;
25 import java.awt.event.ItemEvent;
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.List;
29 import java.util.concurrent.CancellationException;
30 import java.util.concurrent.ExecutionException;
31 import java.util.logging.Level;
32 import javax.swing.SizeRequirements;
33 import javax.swing.SwingUtilities;
34 import javax.swing.SwingWorker;
35 import javax.swing.UIManager;
36 import javax.swing.text.Element;
37 import javax.swing.text.View;
38 import javax.swing.text.ViewFactory;
39 import javax.swing.text.html.HTMLEditorKit;
40 import javax.swing.text.html.HTMLEditorKit.HTMLFactory;
41 import javax.swing.text.html.InlineView;
42 import javax.swing.text.html.ParagraphView;
43 import javax.swing.text.html.StyleSheet;
44 import org.apache.commons.lang3.StringUtils;
45 import org.netbeans.api.progress.ProgressHandle;
46 import org.openide.util.NbBundle;
51 
56 @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
57 class ExtractedContentPanel extends javax.swing.JPanel implements ResizableTextPanel {
58 
59  private static final Logger logger = Logger.getLogger(ExtractedContentPanel.class.getName());
60 
61  // set font as close as possible to default
62  private static final Font DEFAULT_FONT = UIManager.getDefaults().getFont("Label.font");
63 
64  private static final long serialVersionUID = 1L;
65  private String contentName;
66  private int curSize;
67 
68  private final StyleSheet styleSheet;
69  private final HTMLEditorKit editorKit;
70  private String lastKnownAnchor = null;
71 
72  ExtractedContentPanel() {
73  initComponents();
74  additionalInit();
75  hitPreviousButton.setEnabled(false);
76  hitNextButton.setEnabled(false);
77 
78  /*
79  * This appears to be an attempt to modify the wrapping behavior of the
80  * extractedTextPane taken form this website:
81  * http://java-sl.com/tip_html_letter_wrap.html.
82  */
83  editorKit = new HTMLEditorKit() {
84  private static final long serialVersionUID = 1L;
85 
86  @Override
87  public ViewFactory getViewFactory() {
88 
89  return new HTMLFactory() {
90  @Override
91  public View create(Element e) {
92  View v = super.create(e);
93  if (v instanceof InlineView) {
94  return new InlineView(e) {
95  @Override
96  public int getBreakWeight(int axis, float pos, float len) {
97  return GoodBreakWeight;
98  }
99 
100  @Override
101  public View breakView(int axis, int p0, float pos, float len) {
102  if (axis == View.X_AXIS) {
103  checkPainter();
104  int p1 = getGlyphPainter().getBoundedPosition(this, p0, pos, len);
105  if (p0 == getStartOffset() && p1 == getEndOffset()) {
106  return this;
107  }
108  return createFragment(p0, p1);
109  }
110  return this;
111  }
112  };
113  } else if (v instanceof ParagraphView) {
114  return new ParagraphView(e) {
115  @Override
116  protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) {
117  SizeRequirements requirements = r;
118  if (requirements == null) {
119  requirements = new SizeRequirements();
120  }
121  float pref = layoutPool.getPreferredSpan(axis);
122  float min = layoutPool.getMinimumSpan(axis);
123  // Don't include insets, Box.getXXXSpan will include them.
124  requirements.minimum = (int) min;
125  requirements.preferred = Math.max(requirements.minimum, (int) pref);
126  requirements.maximum = Integer.MAX_VALUE;
127  requirements.alignment = 0.5f;
128  return requirements;
129  }
130  };
131  }
132  return v;
133  }
134  };
135  }
136  };
137  // set new style sheet to clear default styles
138  styleSheet = editorKit.getStyleSheet();
139 
140  sourceComboBox.addItemListener(itemEvent -> {
141  if (itemEvent.getStateChange() == ItemEvent.SELECTED) {
142  refreshCurrentMarkup();
143  }
144  });
145  extractedTextPane.setComponentPopupMenu(rightClickMenu);
146 
147  copyMenuItem.addActionListener(actionEvent -> extractedTextPane.copy());
148  selectAllMenuItem.addActionListener(actionEvent -> extractedTextPane.selectAll());
149 
150  // TextZoomPanel could not be directly instantiated in Swing WYSIWYG editor
151  // (because it was package private, couldn't use constructor, etc.)
152  // so it was identified as a JPanel for the WYSIWYG. This function is called for
153  // initial setup so the font size of this panel as well as the font size indicated
154  // in the TextZoomPanel are correct
155  SwingUtilities.invokeLater(() -> {
156  if (zoomPanel instanceof TextZoomPanel)
157  ((TextZoomPanel) this.zoomPanel).resetSize();
158  });
159 
160  setSources("", new ArrayList<>());
161  }
162 
163 
164  private void setStyleSheetSize(StyleSheet styleSheet, int size) {
165  styleSheet.addRule(
166  "body { font-family:\"" + DEFAULT_FONT.getFamily() + "\"; font-size:" + size + "pt; } " +
167  "pre { font-family:\"" + DEFAULT_FONT.getFamily() + "\"; font-size:" + size + "pt; } "
168  );
169  }
170 
171 
172  @Override
173  public int getTextSize() {
174  return curSize;
175  }
176 
177  @Override
178  public void setTextSize(int newSize) {
179  curSize = newSize;
180 
181  String curText = extractedTextPane.getText();
182 
183  setStyleSheetSize(styleSheet, curSize);
184 
185  editorKit.setStyleSheet(styleSheet);
186  extractedTextPane.setEditorKit(editorKit);
187 
188  extractedTextPane.setText(curText);
189  if (lastKnownAnchor != null)
190  scrollToAnchor(lastKnownAnchor);
191  }
192 
193 
194  private void additionalInit() {
195  // use wrap layout for better component wrapping
196  WrapLayout layout = new WrapLayout(0,5);
197  layout.setOppositeAligned(Arrays.asList(textSourcePanel));
198  controlPanel.setLayout(layout);
199  }
200 
201 
207  @SuppressWarnings("unchecked")
208  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
209  private void initComponents() {
210 
211  rightClickMenu = new javax.swing.JPopupMenu();
212  copyMenuItem = new javax.swing.JMenuItem();
213  selectAllMenuItem = new javax.swing.JMenuItem();
214  controlPanel = new javax.swing.JPanel();
215  javax.swing.JPanel pagePanel = new javax.swing.JPanel();
216  pagesLabel = new javax.swing.JLabel();
217  javax.swing.Box.Filler fillerSmall1 = new javax.swing.Box.Filler(new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 32767));
218  pageCurLabel = new javax.swing.JLabel();
219  javax.swing.Box.Filler fillerSmall2 = new javax.swing.Box.Filler(new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 32767));
220  pageOfLabel = new javax.swing.JLabel();
221  javax.swing.Box.Filler fillerSmall3 = new javax.swing.Box.Filler(new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 32767));
222  pageTotalLabel = new javax.swing.JLabel();
223  javax.swing.Box.Filler fillerSmall4 = new javax.swing.Box.Filler(new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 32767));
224  pageButtonsLabel = new javax.swing.JLabel();
225  javax.swing.Box.Filler fillerMed1 = new javax.swing.Box.Filler(new java.awt.Dimension(10, 0), new java.awt.Dimension(10, 0), new java.awt.Dimension(10, 32767));
226  pagePreviousButton = new javax.swing.JButton();
227  pageNextButton = new javax.swing.JButton();
228  javax.swing.Box.Filler fillerSmall6 = new javax.swing.Box.Filler(new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 32767));
229  jSeparator2 = new javax.swing.JSeparator();
230  javax.swing.JPanel matchesPanel = new javax.swing.JPanel();
231  hitLabel = new javax.swing.JLabel();
232  hitCountLabel = new javax.swing.JLabel();
233  hitOfLabel = new javax.swing.JLabel();
234  hitTotalLabel = new javax.swing.JLabel();
235  hitButtonsLabel = new javax.swing.JLabel();
236  javax.swing.Box.Filler fillerMed2 = new javax.swing.Box.Filler(new java.awt.Dimension(10, 0), new java.awt.Dimension(10, 0), new java.awt.Dimension(10, 32767));
237  hitPreviousButton = new javax.swing.JButton();
238  hitNextButton = new javax.swing.JButton();
239  javax.swing.Box.Filler fillerSmall11 = new javax.swing.Box.Filler(new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 32767));
240  jSeparator3 = new javax.swing.JSeparator();
241  javax.swing.JPanel zoomPanelWrapper = new javax.swing.JPanel();
242  zoomPanel = new TextZoomPanel(this);
243  javax.swing.Box.Filler fillerSmall14 = new javax.swing.Box.Filler(new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 32767));
244  jSeparator4 = new javax.swing.JSeparator();
245  textSourcePanel = new javax.swing.JPanel();
246  jLabel1 = new javax.swing.JLabel();
247  javax.swing.Box.Filler fillerSmall12 = new javax.swing.Box.Filler(new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 32767));
248  sourceComboBox = new javax.swing.JComboBox<>();
249  extractedScrollPane = new javax.swing.JScrollPane();
250  extractedTextPane = new javax.swing.JTextPane();
251 
252  copyMenuItem.setText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.copyMenuItem.text")); // NOI18N
253  rightClickMenu.add(copyMenuItem);
254 
255  selectAllMenuItem.setText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.selectAllMenuItem.text")); // NOI18N
256  rightClickMenu.add(selectAllMenuItem);
257 
258  setMinimumSize(new java.awt.Dimension(250, 0));
259  setPreferredSize(new java.awt.Dimension(250, 58));
260  setLayout(new java.awt.BorderLayout());
261 
262  controlPanel.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT, 0, 0));
263 
264  pagePanel.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT, 0, 0));
265 
266  pagesLabel.setText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.pagesLabel.text")); // NOI18N
267  pagePanel.add(pagesLabel);
268  pagePanel.add(fillerSmall1);
269 
270  pageCurLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
271  pageCurLabel.setText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.pageCurLabel.text")); // NOI18N
272  pagePanel.add(pageCurLabel);
273  pagePanel.add(fillerSmall2);
274 
275  pageOfLabel.setText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.pageOfLabel.text")); // NOI18N
276  pagePanel.add(pageOfLabel);
277  pagePanel.add(fillerSmall3);
278 
279  pageTotalLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
280  pageTotalLabel.setText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.pageTotalLabel.text")); // NOI18N
281  pagePanel.add(pageTotalLabel);
282  pagePanel.add(fillerSmall4);
283 
284  pageButtonsLabel.setText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.pageButtonsLabel.text")); // NOI18N
285  pagePanel.add(pageButtonsLabel);
286  pagePanel.add(fillerMed1);
287 
288  pagePreviousButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/keywordsearch/btn_step_back.png"))); // NOI18N
289  pagePreviousButton.setText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.pagePreviousButton.text")); // NOI18N
290  pagePreviousButton.setActionCommand(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.pagePreviousButton.actionCommand")); // NOI18N
291  pagePreviousButton.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1));
292  pagePreviousButton.setBorderPainted(false);
293  pagePreviousButton.setContentAreaFilled(false);
294  pagePreviousButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/keywordsearch/btn_step_back_disabled.png"))); // NOI18N
295  pagePreviousButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
296  pagePanel.add(pagePreviousButton);
297 
298  pageNextButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/keywordsearch/btn_step_forward.png"))); // NOI18N
299  pageNextButton.setText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.pageNextButton.text")); // NOI18N
300  pageNextButton.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1));
301  pageNextButton.setBorderPainted(false);
302  pageNextButton.setContentAreaFilled(false);
303  pageNextButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/keywordsearch/btn_step_forward_disabled.png"))); // NOI18N
304  pageNextButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
305  pageNextButton.setPreferredSize(new java.awt.Dimension(23, 23));
306  pagePanel.add(pageNextButton);
307  pagePanel.add(fillerSmall6);
308 
309  jSeparator2.setOrientation(javax.swing.SwingConstants.VERTICAL);
310  jSeparator2.setMaximumSize(new java.awt.Dimension(2, 25));
311  jSeparator2.setMinimumSize(new java.awt.Dimension(2, 25));
312  jSeparator2.setPreferredSize(new java.awt.Dimension(2, 25));
313  pagePanel.add(jSeparator2);
314 
315  controlPanel.add(pagePanel);
316 
317  matchesPanel.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT, 0, 0));
318 
319  hitLabel.setText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.hitLabel.text")); // NOI18N
320  hitLabel.setToolTipText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.hitLabel.toolTipText")); // NOI18N
321  matchesPanel.add(hitLabel);
322 
323  hitCountLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
324  hitCountLabel.setText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.hitCountLabel.text")); // NOI18N
325  hitCountLabel.setMaximumSize(new java.awt.Dimension(18, 14));
326  hitCountLabel.setMinimumSize(new java.awt.Dimension(18, 14));
327  hitCountLabel.setPreferredSize(new java.awt.Dimension(18, 14));
328  matchesPanel.add(hitCountLabel);
329 
330  hitOfLabel.setText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.hitOfLabel.text")); // NOI18N
331  matchesPanel.add(hitOfLabel);
332 
333  hitTotalLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
334  hitTotalLabel.setText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.hitTotalLabel.text")); // NOI18N
335  hitTotalLabel.setMaximumSize(new java.awt.Dimension(18, 14));
336  hitTotalLabel.setMinimumSize(new java.awt.Dimension(18, 14));
337  hitTotalLabel.setPreferredSize(new java.awt.Dimension(18, 14));
338  matchesPanel.add(hitTotalLabel);
339 
340  hitButtonsLabel.setText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.hitButtonsLabel.text")); // NOI18N
341  matchesPanel.add(hitButtonsLabel);
342  matchesPanel.add(fillerMed2);
343 
344  hitPreviousButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/keywordsearch/btn_step_back.png"))); // NOI18N
345  hitPreviousButton.setText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.hitPreviousButton.text")); // NOI18N
346  hitPreviousButton.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1));
347  hitPreviousButton.setBorderPainted(false);
348  hitPreviousButton.setContentAreaFilled(false);
349  hitPreviousButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/keywordsearch/btn_step_back_disabled.png"))); // NOI18N
350  hitPreviousButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
351  hitPreviousButton.setPreferredSize(new java.awt.Dimension(23, 23));
352  hitPreviousButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/keywordsearch/btn_step_back_hover.png"))); // NOI18N
353  matchesPanel.add(hitPreviousButton);
354 
355  hitNextButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/keywordsearch/btn_step_forward.png"))); // NOI18N
356  hitNextButton.setText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.hitNextButton.text")); // NOI18N
357  hitNextButton.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1));
358  hitNextButton.setBorderPainted(false);
359  hitNextButton.setContentAreaFilled(false);
360  hitNextButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/keywordsearch/btn_step_forward_disabled.png"))); // NOI18N
361  hitNextButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
362  hitNextButton.setPreferredSize(new java.awt.Dimension(23, 23));
363  hitNextButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/keywordsearch/btn_step_forward_hover.png"))); // NOI18N
364  matchesPanel.add(hitNextButton);
365  matchesPanel.add(fillerSmall11);
366 
367  jSeparator3.setOrientation(javax.swing.SwingConstants.VERTICAL);
368  jSeparator3.setMaximumSize(new java.awt.Dimension(2, 25));
369  jSeparator3.setMinimumSize(new java.awt.Dimension(2, 25));
370  jSeparator3.setName(""); // NOI18N
371  jSeparator3.setPreferredSize(new java.awt.Dimension(2, 25));
372  matchesPanel.add(jSeparator3);
373 
374  controlPanel.add(matchesPanel);
375 
376  zoomPanelWrapper.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT, 0, 0));
377 
378  zoomPanel.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT, 0, 0));
379  zoomPanelWrapper.add(zoomPanel);
380  zoomPanel.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.AccessibleContext.accessibleName")); // NOI18N
381 
382  zoomPanelWrapper.add(fillerSmall14);
383 
384  jSeparator4.setOrientation(javax.swing.SwingConstants.VERTICAL);
385  jSeparator4.setMaximumSize(new java.awt.Dimension(2, 25));
386  jSeparator4.setMinimumSize(new java.awt.Dimension(2, 25));
387  jSeparator4.setName(""); // NOI18N
388  jSeparator4.setPreferredSize(new java.awt.Dimension(2, 25));
389  zoomPanelWrapper.add(jSeparator4);
390 
391  controlPanel.add(zoomPanelWrapper);
392 
393  textSourcePanel.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.CENTER, 0, 0));
394 
395  jLabel1.setText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.jLabel1.text")); // NOI18N
396  textSourcePanel.add(jLabel1);
397  textSourcePanel.add(fillerSmall12);
398 
399  sourceComboBox.setModel(new javax.swing.DefaultComboBoxModel<org.sleuthkit.autopsy.keywordsearch.ExtractedText>());
400  sourceComboBox.setMaximumSize(new java.awt.Dimension(150, 32767));
401  sourceComboBox.setMinimumSize(new java.awt.Dimension(150, 25));
402  sourceComboBox.setPreferredSize(new java.awt.Dimension(150, 25));
403  textSourcePanel.add(sourceComboBox);
404 
405  controlPanel.add(textSourcePanel);
406 
407  add(controlPanel, java.awt.BorderLayout.NORTH);
408 
409  extractedScrollPane.setBackground(new java.awt.Color(255, 255, 255));
410  extractedScrollPane.setPreferredSize(new java.awt.Dimension(640, 29));
411 
412  extractedTextPane.setEditable(false);
413  extractedTextPane.setAutoscrolls(false);
414  extractedTextPane.setInheritsPopupMenu(true);
415  extractedTextPane.setMaximumSize(new java.awt.Dimension(2000, 2000));
416  extractedTextPane.setPreferredSize(new java.awt.Dimension(600, 29));
417  extractedScrollPane.setViewportView(extractedTextPane);
418 
419  add(extractedScrollPane, java.awt.BorderLayout.CENTER);
420  }// </editor-fold>//GEN-END:initComponents
421  // Variables declaration - do not modify//GEN-BEGIN:variables
422  private javax.swing.JPanel controlPanel;
423  private javax.swing.JMenuItem copyMenuItem;
424  private javax.swing.JScrollPane extractedScrollPane;
425  private javax.swing.JTextPane extractedTextPane;
426  private javax.swing.JLabel hitButtonsLabel;
427  private javax.swing.JLabel hitCountLabel;
428  private javax.swing.JLabel hitLabel;
429  private javax.swing.JButton hitNextButton;
430  private javax.swing.JLabel hitOfLabel;
431  private javax.swing.JButton hitPreviousButton;
432  private javax.swing.JLabel hitTotalLabel;
433  private javax.swing.JLabel jLabel1;
434  private javax.swing.JSeparator jSeparator2;
435  private javax.swing.JSeparator jSeparator3;
436  private javax.swing.JSeparator jSeparator4;
437  private javax.swing.JLabel pageButtonsLabel;
438  private javax.swing.JLabel pageCurLabel;
439  private javax.swing.JButton pageNextButton;
440  private javax.swing.JLabel pageOfLabel;
441  private javax.swing.JButton pagePreviousButton;
442  private javax.swing.JLabel pageTotalLabel;
443  private javax.swing.JLabel pagesLabel;
444  private javax.swing.JPopupMenu rightClickMenu;
445  private javax.swing.JMenuItem selectAllMenuItem;
446  private javax.swing.JComboBox<org.sleuthkit.autopsy.keywordsearch.ExtractedText> sourceComboBox;
447  private javax.swing.JPanel textSourcePanel;
448  private javax.swing.JPanel zoomPanel;
449  // End of variables declaration//GEN-END:variables
450 
451  void refreshCurrentMarkup() {
452  setMarkup(getSelectedSource());
453  }
454 
463  final void setSources(String contentName, List<ExtractedText> sources) {
464  this.lastKnownAnchor = null;
465  this.contentName = contentName;
466  setPanelText(null, false);
467 
468  sourceComboBox.removeAllItems();
469  sources.forEach(sourceComboBox::addItem);
470  if (false == sources.isEmpty()) {
471  sourceComboBox.setEnabled(true);
472  sourceComboBox.setSelectedIndex(0);
473  } else {
474  sourceComboBox.setEnabled(false);
475  }
476  }
477 
483  public ExtractedText getSelectedSource() {
484  return (ExtractedText) sourceComboBox.getSelectedItem();
485  }
486 
487  private void setPanelText(String text, boolean detectDirection) {
488  String safeText = StringUtils.defaultString(text);
489 
490  if (detectDirection) {
491  //detect text direction using first 1024 chars and set it
492  //get first up to 1024 chars, strip <pre> tag and unescape html to get the string on which to detect
493  final int len = safeText.length();
494  final int prefixLen = "<pre>".length(); //NON-NLS
495  if (len > prefixLen) {
496  final int maxOrientChars = Math.min(len, 1024);
497  final String orientDetectText = EscapeUtil.unEscapeHtml(safeText.substring(prefixLen, maxOrientChars));
498  ComponentOrientation direction = TextUtil.getTextDirection(orientDetectText);
499  extractedTextPane.applyComponentOrientation(direction);
500  } else {
501  extractedTextPane.applyComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
502  }
503  } else {
504  extractedTextPane.applyComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
505  }
506 
507  // refresh style
508  setStyleSheetSize(styleSheet, curSize);
509  extractedTextPane.setText(safeText);
510  extractedTextPane.setCaretPosition(0);
511  }
512 
513  void scrollToAnchor(String anchor) {
514  lastKnownAnchor = anchor;
515  extractedTextPane.scrollToReference(anchor);
516  }
517 
523  void updateCurrentMatchDisplay(int current) {
524  if (current == 0) {
525  hitCountLabel.setText("-");
526  } else {
527  hitCountLabel.setText(Integer.toString(current));
528  }
529  }
530 
536  void updateTotaMatcheslDisplay(int total) {
537  if (total == 0) {
538  hitTotalLabel.setText("-");
539  } else {
540  hitTotalLabel.setText(Integer.toString(total));
541  }
542  }
543 
549  void updateCurrentPageDisplay(int current) {
550  pageCurLabel.setText(Integer.toString(current));
551  }
552 
558  void updateTotalPagesDisplay(int total) {
559  if (total >= 0) {
560  pageTotalLabel.setText(Integer.toString(total));
561  } else {
562  pageTotalLabel.setText("-");
563  }
564  }
565 
570  void resetDisplay() {
571  setSources("", new ArrayList<>());
572  hitTotalLabel.setText("-");
573  hitCountLabel.setText("-");
574  pageCurLabel.setText("-");
575  pageTotalLabel.setText("-");
576  }
577 
583  void enablePrevMatchControl(boolean enable) {
584  hitPreviousButton.setEnabled(enable);
585  }
586 
592  void enableNextMatchControl(boolean enable) {
593  hitNextButton.setEnabled(enable);
594  }
595 
596  void addPrevMatchControlListener(ActionListener l) {
597  hitPreviousButton.addActionListener(l);
598  }
599 
600  void addNextMatchControlListener(ActionListener l) {
601  hitNextButton.addActionListener(l);
602  }
603 
609  void enablePrevPageControl(boolean enable) {
610  pagePreviousButton.setEnabled(enable);
611  }
612 
618  void enableNextPageControl(boolean enable) {
619  pageNextButton.setEnabled(enable);
620  }
621 
622  void addPrevPageControlListener(ActionListener l) {
623  pagePreviousButton.addActionListener(l);
624  }
625 
626  void addNextPageControlListener(ActionListener l) {
627  pageNextButton.addActionListener(l);
628  }
629 
630  void addSourceComboControlListener(ActionListener l) {
631  sourceComboBox.addActionListener(l);
632  }
633 
639  void updateControls(ExtractedText source) {
640  updatePageControls(source);
641  updateSearchControls(source);
642  }
643 
649  void updatePageControls(ExtractedText source) {
650  if (source == null) {
651  enableNextPageControl(false);
652  enablePrevPageControl(false);
653  updateCurrentPageDisplay(0);
654  updateTotalPagesDisplay(0);
655  return;
656  }
657 
658  updateCurrentPageDisplay(source.getCurrentPage());
659  int totalPages = source.getNumberPages();
660  updateTotalPagesDisplay(totalPages);
661 
662  enableNextPageControl(source.hasNextPage());
663  enablePrevPageControl(source.hasPreviousPage());
664  }
665 
671  void updateSearchControls(ExtractedText source) {
672  //setup search controls
673  if (source != null && source.isSearchable()) {
674  updateCurrentMatchDisplay(source.currentItem());
675  updateTotaMatcheslDisplay(source.getNumberHits());
676  enableNextMatchControl(source.hasNextItem() || source.hasNextPage());
677  enablePrevMatchControl(source.hasPreviousItem() || source.hasPreviousPage());
678  } else {
679  enableNextMatchControl(false);
680  enablePrevMatchControl(false);
681  updateCurrentMatchDisplay(0);
682  updateTotaMatcheslDisplay(0);
683  }
684  }
685 
691  private void scrollToCurrentHit(final ExtractedText source) {
692  if (source == null || !source.isSearchable()) {
693  return;
694  }
695 
696  //scrolling required invokeLater to enqueue in EDT
697  EventQueue.invokeLater(() -> scrollToAnchor(source.getAnchorPrefix() + source.currentItem()));
698 
699  }
700 
706  @NbBundle.Messages("ExtractedContentPanel.setMarkup.panelTxt=<span style='font-style:italic'>Loading text... Please wait</span>")
707  private void setMarkup(ExtractedText source) {
708  setPanelText(Bundle.ExtractedContentPanel_setMarkup_panelTxt(), false);
709  new SetMarkupWorker(contentName, source).execute();
710  }
711 
717  private final class SetMarkupWorker extends SwingWorker<String, Void> {
718 
719  private final String contentName;
720 
721  private final ExtractedText source;
722 
723  private ProgressHandle progress;
724 
725  SetMarkupWorker(String contentName, ExtractedText source) {
726  this.contentName = contentName;
727  this.source = source;
728  }
729 
730  @Override
731  @NbBundle.Messages({"# {0} - Content name",
732  "ExtractedContentPanel.SetMarkup.progress.loading=Loading text for {0}"})
733  protected String doInBackground() throws Exception {
734  progress = ProgressHandle.createHandle(Bundle.ExtractedContentPanel_SetMarkup_progress_loading(contentName));
735  progress.start();
736  progress.switchToIndeterminate();
737 
738  return source.getText();
739  }
740 
741  @Override
742  protected void done() {
743  super.done();
744  progress.finish();
745 
746  // see if there are any errors
747  try {
748  String markup = get();
749  if (markup != null) {
750  setPanelText(markup, true);
751  } else {
752  setPanelText("", false);
753  }
754  } catch (InterruptedException | CancellationException | ExecutionException ex) {
755  logger.log(Level.SEVERE, "Error getting marked up text", ex); //NON-NLS
756  setPanelText(Bundle.ExtractedText_errorMessage_errorGettingText(), true);
757  }
758 
759  updateControls(source);
760  scrollToCurrentHit(source);
761  }
762  }
763 }

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.