Autopsy  4.19.3
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 public class TranslatablePanel extends JPanel {
41 
47  public 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  public 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 
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 
190  private volatile OnTranslation backgroundTask = null;
191 
192  @Messages({"TranslatablePanel.comboBoxOption.originalText=Original Text",
193  "TranslatablePanel.comboBoxOption.translatedText=Translated Text"})
194  public TranslatablePanel(ContentComponent contentComponent) {
195  this(
197  Bundle.TranslatablePanel_comboBoxOption_originalText(),
198  Bundle.TranslatablePanel_comboBoxOption_translatedText(),
199  null,
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 
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) {
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  public final void reset() {
267  setContent(null, null);
268  }
269 
275  public void setContent(String content, String contentDescriptor) {
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 
368  clearStatus();
369 
370  if (curTranslateSelection) {
371  TranslatedText translated = getCachedTranslated();
372  if (translated != null) {
373  setChildComponentContent(translated.getText(), translated.getOrientation());
374  } else {
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) {
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
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)
synchronized void setChildComponentContent(String content, ComponentOrientation orientation)
void setContent(String content, ComponentOrientation orientation)
void setContent(String content, String contentDescriptor)
void additionalInit(Component rootComponent, String origOptionText, String translatedOptionText)
void translateComboBoxActionPerformed(java.awt.event.ActionEvent evt)
void onProgressDisplay(String text, ComponentOrientation orientation, int font)
void handleComboBoxChange(TranslateOption translateOption)
javax.swing.JComboBox< TranslateOption > translateComboBox
synchronized void setStatus(String msg, boolean showWarningIcon)

Copyright © 2012-2022 Basis Technology. Generated on: Tue Jun 27 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.