19 package org.sleuthkit.autopsy.contentviewers;
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;
40 class TranslatablePanel
extends JPanel {
47 class TranslatablePanelException
extends Exception {
48 public static final long serialVersionUID = 1L;
50 TranslatablePanelException(String message) {
54 TranslatablePanelException(String message, Throwable cause) {
55 super(message, cause);
64 interface ContentComponent {
69 Component getRootComponent();
77 void setContent(String content, ComponentOrientation orientation)
throws TranslatablePanelException;
103 boolean shouldTranslate() {
125 ComponentOrientation getOrientation() {
143 return retrieveTranslation(input);
148 setStatus(text,
false);
152 protected void onErrorDisplay(String text, ComponentOrientation orientation,
int font) {
153 setStatus(text,
true);
157 protected String
retrieveText() throws IOException, InterruptedException, IllegalStateException {
158 return content == null ?
"" : content;
162 protected void onTextDisplay(String text, ComponentOrientation orientation,
int font) {
165 setChildComponentContent(text, orientation);
172 private static final long serialVersionUID = 1L;
173 private static final ComponentOrientation DEFAULT_ORIENTATION = ComponentOrientation.LEFT_TO_RIGHT;
175 private final ImageIcon warningIcon =
new ImageIcon(TranslatablePanel.class.getResource(
"/org/sleuthkit/autopsy/images/warning16.png"));
177 private final ContentComponent contentComponent;
179 private final ThreadFactory translationThreadFactory =
new ThreadFactoryBuilder().setNameFormat(
"translatable-panel-%d").build();
180 private final ExecutorService executorService = Executors.newSingleThreadExecutor(translationThreadFactory);
182 private final Object cachedTranslatedLock =
new Object();
183 private final Object backgroundTaskLock =
new Object();
185 private String content;
186 private String contentDescriptor;
187 private boolean prevTranslateSelection;
189 private volatile TranslatedText cachedTranslated;
190 private volatile OnTranslation backgroundTask = null;
192 @Messages({
"TranslatablePanel.comboBoxOption.originalText=Original Text",
193 "TranslatablePanel.comboBoxOption.translatedText=Translated Text"})
194 TranslatablePanel(ContentComponent contentComponent) {
197 Bundle.TranslatablePanel_comboBoxOption_originalText(),
198 Bundle.TranslatablePanel_comboBoxOption_translatedText(),
200 TextTranslationService.getInstance());
206 TranslatablePanel(ContentComponent contentComponent, String origOptionText, String translatedOptionText, String origContent,
207 TextTranslationService translationService) {
208 this.contentComponent = contentComponent;
209 this.translationService = translationService;
212 additionalInit(contentComponent.getRootComponent(), origOptionText, translatedOptionText);
221 private TranslatedText getCachedTranslated() {
222 synchronized (cachedTranslatedLock) {
223 return cachedTranslated;
230 private void setCachedTranslated(TranslatedText translated) {
231 synchronized (cachedTranslatedLock) {
232 this.cachedTranslated = translated;
239 private void cancelPendingTranslation() {
240 synchronized (backgroundTaskLock) {
241 if (backgroundTask != null && !backgroundTask.isDone()) {
242 backgroundTask.cancel(
true);
244 backgroundTask = null;
251 private void runTranslationTask() {
252 synchronized (backgroundTaskLock) {
253 cancelPendingTranslation();
254 backgroundTask =
new OnTranslation();
258 executorService.execute(backgroundTask);
267 setContent(null, null);
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;
283 setCachedTranslated(null);
284 setChildComponentContent(content);
296 protected String retrieveTranslation(String input)
throws TranslationException, NoServiceProviderException {
297 return translationService.translate(input);
303 private void clearStatus() {
304 setStatus(null,
false);
312 private synchronized void setStatus(String msg,
boolean showWarningIcon) {
313 statusLabel.setText(msg);
314 statusLabel.setIcon(showWarningIcon ? warningIcon : null);
320 private void setTranslationEnabled() {
321 translateComboBox.setEnabled(this.translationService.hasProvider());
328 private void setChildComponentContent(String content) {
329 setChildComponentContent(content, DEFAULT_ORIENTATION);
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(() -> {
341 contentComponent.setContent(content, orientation);
342 }
catch (TranslatablePanelException ex) {
343 setStatus(Bundle.TranslatablePanel_onSetContentError_text(ex.getMessage()),
true);
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));
362 private void handleComboBoxChange(TranslateOption translateOption) {
363 boolean curTranslateSelection = translateOption.shouldTranslate();
364 if (curTranslateSelection != this.prevTranslateSelection) {
365 this.prevTranslateSelection = curTranslateSelection;
367 cancelPendingTranslation();
370 if (curTranslateSelection) {
371 TranslatedText translated = getCachedTranslated();
372 if (translated != null) {
373 setChildComponentContent(translated.getText(), translated.getOrientation());
375 runTranslationTask();
378 setChildComponentContent(content);
388 @SuppressWarnings(
"unchecked")
390 private
void initComponents() {
392 translationBar =
new javax.swing.JPanel();
393 translateComboBox =
new javax.swing.JComboBox<>();
394 statusLabel =
new javax.swing.JLabel();
396 setMaximumSize(
new java.awt.Dimension(2000, 2000));
397 setMinimumSize(
new java.awt.Dimension(2, 2));
399 setPreferredSize(
new java.awt.Dimension(100, 58));
400 setVerifyInputWhenFocusTarget(
false);
401 setLayout(
new java.awt.BorderLayout());
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());
408 translateComboBox.setMaximumSize(
new java.awt.Dimension(200, 20));
409 translateComboBox.setMinimumSize(
new java.awt.Dimension(200, 20));
410 translateComboBox.setName(
"");
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);
417 translationBar.add(translateComboBox, java.awt.BorderLayout.LINE_END);
419 statusLabel.setMaximumSize(
new java.awt.Dimension(32767, 32767));
420 translationBar.add(statusLabel, java.awt.BorderLayout.CENTER);
422 add(translationBar, java.awt.BorderLayout.NORTH);
425 private void translateComboBoxActionPerformed(java.awt.event.ActionEvent evt) {
426 handleComboBoxChange((TranslateOption) translateComboBox.getSelectedItem());
430 private javax.swing.JLabel statusLabel;
431 private javax.swing.JComboBox<TranslateOption> translateComboBox;
432 private javax.swing.JPanel translationBar;
void onTextDisplay(String text, ComponentOrientation orientation, int font)
void onErrorDisplay(String text, ComponentOrientation orientation, int font)
final String contentDescriptor
void onProgressDisplay(String text, ComponentOrientation orientation, int font)
String translate(String input)
final ComponentOrientation orientation