19 package org.sleuthkit.autopsy.texttranslation.ui;
21 import com.google.common.collect.Lists;
22 import com.google.common.util.concurrent.ThreadFactoryBuilder;
23 import java.awt.Component;
24 import java.awt.ComponentOrientation;
26 import java.awt.event.ActionEvent;
27 import java.awt.event.ActionListener;
28 import java.io.IOException;
29 import java.io.Reader;
30 import java.util.Arrays;
31 import java.util.concurrent.ExecutorService;
32 import java.util.concurrent.Executors;
33 import java.util.concurrent.ThreadFactory;
34 import org.openide.nodes.Node;
35 import org.openide.util.lookup.ServiceProvider;
38 import org.openide.util.Lookup;
39 import org.openide.util.NbBundle;
40 import org.openide.util.lookup.Lookups;
48 import java.util.List;
49 import java.util.logging.Level;
50 import javax.swing.SwingUtilities;
58 @ServiceProvider(service =
TextViewer.class, position = 4)
63 private static final boolean OCR_ENABLED =
true;
64 private static final boolean OCR_DISABLED =
false;
65 private static final int MAX_EXTRACT_SIZE_BYTES = 25600;
69 private volatile Node
node;
71 private final ThreadFactory translationThreadFactory
72 =
new ThreadFactoryBuilder().setNameFormat(
"translation-content-viewer-%d").build();
73 private final ExecutorService executorService = Executors.newSingleThreadExecutor(translationThreadFactory);
76 "TranslatedTextViewer.maxPayloadSize=Up to the first %dKB of text will be translated"
82 panel.addDisplayTextActionListener(displayDropDownListener);
86 if (source instanceof AbstractFile) {
87 boolean isImage = ((AbstractFile) source).getMIMEType().toLowerCase().startsWith(
"image/");
89 panel.enableOCRSelection(OCR_ENABLED);
90 panel.addLanguagePackNames(INSTALLED_LANGUAGE_PACKS);
95 panel.setWarningLabelMsg(String.format(Bundle.TranslatedTextViewer_maxPayloadSize(), payloadMaxInKB));
101 @NbBundle.Messages({
"TranslatedTextViewer.title=Translation"})
104 return Bundle.TranslatedTextViewer_title();
107 @NbBundle.Messages({
"TranslatedTextViewer.toolTip=Displays translated file text."})
110 return Bundle.TranslatedTextViewer_toolTip();
127 if (backgroundTask != null) {
128 backgroundTask.cancel(
true);
130 backgroundTask = null;
143 AbstractFile file = node.getLookup().lookup(AbstractFile.class);
159 private final AbstractFile
file;
162 super(translateText, String.format(
"%s (objId=%d)", file.getName(), file.getId()));
174 "TranslatedContentViewer.extractingText=Extracting text, please wait...",
175 "# {0} - exception message",
"TranslatedContentViewer.errorExtractingText=An error occurred while extracting the text ({0}).",
177 protected String
retrieveText()
throws IOException, InterruptedException, IllegalStateException {
178 SwingUtilities.invokeLater(() -> {
179 onProgressDisplay(Bundle.TranslatedContentViewer_extractingText(), ComponentOrientation.LEFT_TO_RIGHT, Font.ITALIC);
183 return getFileText(file);
185 logger.log(Level.WARNING, String.format(
"Error extracting text for file %s (objId=%d)", file.getName(), file.getId()), ex);
187 throw new IllegalStateException(Bundle.TranslatedContentViewer_errorExtractingText(ex.getMessage()), ex);
205 final boolean isImage = file.getMIMEType().toLowerCase().startsWith(
"image/");
208 result = extractText(file, OCR_ENABLED);
210 result = extractText(file, OCR_DISABLED);
214 byte[] resultInUTF8Bytes = result.getBytes(
"UTF8");
215 byte[] trimToArraySize = Arrays.copyOfRange(resultInUTF8Bytes, 0,
216 Math.min(resultInUTF8Bytes.length, MAX_EXTRACT_SIZE_BYTES));
217 return new String(trimToArraySize,
"UTF-8");
234 Reader textExtractor = getTextExtractor(source, ocrEnabled);
236 char[] cbuf =
new char[8096];
237 StringBuilder textBuilder =
new StringBuilder();
244 while ((read = textExtractor.read(cbuf)) != -1) {
245 if (this.isCancelled()) {
246 throw new InterruptedException();
251 int bytesLeft = MAX_EXTRACT_SIZE_BYTES - bytesRead;
253 if (bytesLeft < read) {
254 textBuilder.append(cbuf, 0, bytesLeft);
255 return textBuilder.toString();
258 textBuilder.append(cbuf, 0, read);
262 return textBuilder.toString();
280 Lookup context = null;
286 String ocrSelection = panel.getSelectedOcrLanguagePack();
287 if (!ocrSelection.isEmpty()) {
294 context = Lookups.fixed(imageConfig, terminator);
307 protected void onTextDisplay(String text, ComponentOrientation orientation,
int font) {
308 panel.
display(text, orientation, font);
321 abstract String getSelection();
325 String selection = getSelection();
326 if (!selection.equals(currentSelection)) {
327 currentSelection = selection;
329 if (backgroundTask != null && !backgroundTask.isDone()) {
330 backgroundTask.cancel(
true);
333 AbstractFile file = node.getLookup().lookup(AbstractFile.class);
334 String textDisplaySelection = panel.getDisplayDropDownSelection();
335 boolean translateText = !textDisplaySelection.equals(DisplayDropdownOptions.ORIGINAL_TEXT.toString());
340 executorService.execute(backgroundTask);
351 String getSelection() {
352 return panel.getDisplayDropDownSelection();
362 String getSelection() {
363 return panel.getSelectedOcrLanguagePack();
void setNode(final Node node)
volatile ExtractAndTranslateTextTask backgroundTask
synchronized int getMaxTextChars()
static Content getDefaultContent(Node node)
void onTextDisplay(String text, ComponentOrientation orientation, int font)
String extractText(AbstractFile source, boolean ocrEnabled)
String getFileText(AbstractFile file)
void display(String text, ComponentOrientation direction, int font)
ExtractAndTranslateTextTask(AbstractFile file, boolean translateText)
Reader getTextExtractor(AbstractFile file, boolean ocrEnabled)
boolean isSupported(Node node)
final void actionPerformed(ActionEvent e)
static TextTranslationService getInstance()
synchronized boolean hasProvider()
synchronized static Logger getLogger(String name)
TextViewer createInstance()
int isPreferred(Node node)