Autopsy  4.14.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
TranslatablePanel.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 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.contentviewers;
20 
21 import com.google.common.util.concurrent.ThreadFactoryBuilder;
22 import java.awt.Component;
23 import java.awt.ComponentOrientation;
24 import java.io.IOException;
25 import java.util.concurrent.ExecutorService;
26 import java.util.concurrent.Executors;
27 import java.util.concurrent.ThreadFactory;
28 import javax.swing.ImageIcon;
29 import javax.swing.JPanel;
30 import javax.swing.SwingUtilities;
31 import org.openide.util.NbBundle.Messages;
36 
40 class TranslatablePanel extends JPanel {
41 
47  class TranslatablePanelException extends Exception {
48  public static final long serialVersionUID = 1L;
49 
50  TranslatablePanelException(String message) {
51  super(message);
52  }
53 
54  TranslatablePanelException(String message, Throwable cause) {
55  super(message, cause);
56  }
57  }
58 
59 
64  interface ContentComponent {
69  Component getRootComponent();
70 
77  void setContent(String content, ComponentOrientation orientation) throws TranslatablePanelException;
78  }
79 
80 
84  private static class TranslateOption {
85 
86  private final String text;
87  private final boolean translate;
88 
89  TranslateOption(String text, boolean translate) {
90  this.text = text;
91  this.translate = translate;
92  }
93 
94  String getText() {
95  return text;
96  }
97 
98  @Override
99  public String toString() {
100  return text;
101  }
102 
103  boolean shouldTranslate() {
104  return translate;
105  }
106  }
107 
111  private static class TranslatedText {
112 
113  private final String text;
114  private final ComponentOrientation orientation;
115 
116  TranslatedText(String text, ComponentOrientation orientation) {
117  this.text = text;
118  this.orientation = orientation;
119  }
120 
121  String getText() {
122  return text;
123  }
124 
125  ComponentOrientation getOrientation() {
126  return orientation;
127  }
128  }
129 
134  private class OnTranslation extends TranslateTextTask {
135 
136  OnTranslation() {
137  super(true, contentDescriptor == null ? "" : contentDescriptor);
138  }
139 
140  @Override
141  protected String translate(String input) throws NoServiceProviderException, TranslationException {
142  // This defers to the outer class method so that it can be overridden for items like html, rtf, etc.
143  return retrieveTranslation(input);
144  }
145 
146  @Override
147  protected void onProgressDisplay(String text, ComponentOrientation orientation, int font) {
148  setStatus(text, false);
149  }
150 
151  @Override
152  protected void onErrorDisplay(String text, ComponentOrientation orientation, int font) {
153  setStatus(text, true);
154  }
155 
156  @Override
157  protected String retrieveText() throws IOException, InterruptedException, IllegalStateException {
158  return content == null ? "" : content;
159  }
160 
161  @Override
162  protected void onTextDisplay(String text, ComponentOrientation orientation, int font) {
163  // On successful acquire, this caches the result and set the text.
164  setCachedTranslated(new TranslatedText(text, orientation));
165  setChildComponentContent(text, orientation);
166 
167  // This clears any status that may be present.
168  clearStatus();
169  }
170  }
171 
172  private static final long serialVersionUID = 1L;
173  private static final ComponentOrientation DEFAULT_ORIENTATION = ComponentOrientation.LEFT_TO_RIGHT;
174 
175  private final ImageIcon warningIcon = new ImageIcon(TranslatablePanel.class.getResource("/org/sleuthkit/autopsy/images/warning16.png"));
176 
177  private final ContentComponent contentComponent;
178  private final TextTranslationService translationService;
179  private final ThreadFactory translationThreadFactory = new ThreadFactoryBuilder().setNameFormat("translatable-panel-%d").build();
180  private final ExecutorService executorService = Executors.newSingleThreadExecutor(translationThreadFactory);
181 
182  private final Object cachedTranslatedLock = new Object();
183  private final Object backgroundTaskLock = new Object();
184 
185  private String content;
186  private String contentDescriptor;
187  private boolean prevTranslateSelection;
188 
189  private volatile TranslatedText cachedTranslated;
190  private volatile OnTranslation backgroundTask = null;
191 
192  @Messages({"TranslatablePanel.comboBoxOption.originalText=Original Text",
193  "TranslatablePanel.comboBoxOption.translatedText=Translated Text"})
194  TranslatablePanel(ContentComponent contentComponent) {
195  this(
196  contentComponent,
197  Bundle.TranslatablePanel_comboBoxOption_originalText(),
198  Bundle.TranslatablePanel_comboBoxOption_translatedText(),
199  null,
200  TextTranslationService.getInstance());
201  }
202 
206  TranslatablePanel(ContentComponent contentComponent, String origOptionText, String translatedOptionText, String origContent,
207  TextTranslationService translationService) {
208  this.contentComponent = contentComponent;
209  this.translationService = translationService;
210 
211  initComponents();
212  additionalInit(contentComponent.getRootComponent(), origOptionText, translatedOptionText);
213  reset();
214  }
215 
216 
217 
221  private TranslatedText getCachedTranslated() {
222  synchronized (cachedTranslatedLock) {
223  return cachedTranslated;
224  }
225  }
226 
230  private void setCachedTranslated(TranslatedText translated) {
231  synchronized (cachedTranslatedLock) {
232  this.cachedTranslated = translated;
233  }
234  }
235 
239  private void cancelPendingTranslation() {
240  synchronized (backgroundTaskLock) {
241  if (backgroundTask != null && !backgroundTask.isDone()) {
242  backgroundTask.cancel(true);
243  }
244  backgroundTask = null;
245  }
246  }
247 
251  private void runTranslationTask() {
252  synchronized (backgroundTaskLock) {
253  cancelPendingTranslation();
254  backgroundTask = new OnTranslation();
255 
256  //Pass the background task to a single threaded pool to keep
257  //the number of jobs running to one.
258  executorService.execute(backgroundTask);
259  }
260  }
261 
266  final void reset() {
267  setContent(null, null);
268  }
269 
275  void setContent(String content, String contentDescriptor) {
276  cancelPendingTranslation();
277  setTranslationEnabled();
278  this.translateComboBox.setSelectedIndex(0);
279  this.prevTranslateSelection = false;
280  this.content = content;
281  this.contentDescriptor = contentDescriptor;
282  clearStatus();
283  setCachedTranslated(null);
284  setChildComponentContent(content);
285  }
286 
296  protected String retrieveTranslation(String input) throws TranslationException, NoServiceProviderException {
297  return translationService.translate(input);
298  }
299 
303  private void clearStatus() {
304  setStatus(null, false);
305  }
306 
312  private synchronized void setStatus(String msg, boolean showWarningIcon) {
313  statusLabel.setText(msg);
314  statusLabel.setIcon(showWarningIcon ? warningIcon : null);
315  }
316 
320  private void setTranslationEnabled() {
321  translateComboBox.setEnabled(this.translationService.hasProvider());
322  }
323 
328  private void setChildComponentContent(String content) {
329  setChildComponentContent(content, DEFAULT_ORIENTATION);
330  }
331 
337  @Messages({"# {0} - exception message", "TranslatablePanel.onSetContentError.text=There was an error displaying the text: {0}"})
338  private synchronized void setChildComponentContent(String content, ComponentOrientation orientation) {
339  SwingUtilities.invokeLater(() -> {
340  try {
341  contentComponent.setContent(content, orientation);
342  } catch (TranslatablePanelException ex) {
343  setStatus(Bundle.TranslatablePanel_onSetContentError_text(ex.getMessage()), true);
344  }
345  });
346  }
347 
351  private void additionalInit(Component rootComponent, String origOptionText, String translatedOptionText) {
352  add(rootComponent, java.awt.BorderLayout.CENTER);
353  translateComboBox.removeAllItems();
354  translateComboBox.addItem(new TranslateOption(origOptionText, false));
355  translateComboBox.addItem(new TranslateOption(translatedOptionText, true));
356  }
357 
362  private void handleComboBoxChange(TranslateOption translateOption) {
363  boolean curTranslateSelection = translateOption.shouldTranslate();
364  if (curTranslateSelection != this.prevTranslateSelection) {
365  this.prevTranslateSelection = curTranslateSelection;
366 
367  cancelPendingTranslation();
368  clearStatus();
369 
370  if (curTranslateSelection) {
371  TranslatedText translated = getCachedTranslated();
372  if (translated != null) {
373  setChildComponentContent(translated.getText(), translated.getOrientation());
374  } else {
375  runTranslationTask();
376  }
377  } else {
378  setChildComponentContent(content);
379  }
380  }
381  }
382 
388  @SuppressWarnings("unchecked")
389  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
390  private void initComponents() {
391 
392  translationBar = new javax.swing.JPanel();
393  translateComboBox = new javax.swing.JComboBox<>();
394  statusLabel = new javax.swing.JLabel();
395 
396  setMaximumSize(new java.awt.Dimension(2000, 2000));
397  setMinimumSize(new java.awt.Dimension(2, 2));
398  setName(""); // NOI18N
399  setPreferredSize(new java.awt.Dimension(100, 58));
400  setVerifyInputWhenFocusTarget(false);
401  setLayout(new java.awt.BorderLayout());
402 
403  translationBar.setBorder(javax.swing.BorderFactory.createEtchedBorder());
404  translationBar.setMaximumSize(new java.awt.Dimension(182, 24));
405  translationBar.setPreferredSize(new java.awt.Dimension(182, 24));
406  translationBar.setLayout(new java.awt.BorderLayout());
407 
408  translateComboBox.setMaximumSize(new java.awt.Dimension(200, 20));
409  translateComboBox.setMinimumSize(new java.awt.Dimension(200, 20));
410  translateComboBox.setName(""); // NOI18N
411  translateComboBox.setPreferredSize(new java.awt.Dimension(200, 20));
412  translateComboBox.addActionListener(new java.awt.event.ActionListener() {
413  public void actionPerformed(java.awt.event.ActionEvent evt) {
414  translateComboBoxActionPerformed(evt);
415  }
416  });
417  translationBar.add(translateComboBox, java.awt.BorderLayout.LINE_END);
418 
419  statusLabel.setMaximumSize(new java.awt.Dimension(32767, 32767));
420  translationBar.add(statusLabel, java.awt.BorderLayout.CENTER);
421 
422  add(translationBar, java.awt.BorderLayout.NORTH);
423  }// </editor-fold>//GEN-END:initComponents
424 
425  private void translateComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_translateComboBoxActionPerformed
426  handleComboBoxChange((TranslateOption) translateComboBox.getSelectedItem());
427  }//GEN-LAST:event_translateComboBoxActionPerformed
428 
429  // Variables declaration - do not modify//GEN-BEGIN:variables
430  private javax.swing.JLabel statusLabel;
431  private javax.swing.JComboBox<TranslateOption> translateComboBox;
432  private javax.swing.JPanel translationBar;
433  // End of variables declaration//GEN-END:variables
434 }
void onTextDisplay(String text, ComponentOrientation orientation, int font)
void onErrorDisplay(String text, ComponentOrientation orientation, int font)
void onProgressDisplay(String text, ComponentOrientation orientation, int font)

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