Merged in TTS to changes to AAFN, now we have reduction in public api changes and support for translation column

This commit is contained in:
U-BASIS\dsmyda 2018-10-30 15:38:45 -04:00
commit 003a1f6662
15 changed files with 412 additions and 39 deletions

View File

@ -338,6 +338,10 @@
<package>org.sleuthkit.autopsy.modules.vmextractor</package>
<package>org.sleuthkit.autopsy.progress</package>
<package>org.sleuthkit.autopsy.report</package>
<<<<<<< HEAD
=======
<package>org.sleuthkit.autopsy.tabulardatareader</package>
>>>>>>> 4316-text-translation-service
<package>org.sleuthkit.autopsy.texttranslation</package>
<package>org.sleuthkit.datamodel</package>
</public-packages>

View File

@ -72,7 +72,8 @@ public final class UserPreferences {
public static final String GROUP_ITEMS_IN_TREE_BY_DATASOURCE = "GroupItemsInTreeByDataSource"; //NON-NLS
public static final String SHOW_ONLY_CURRENT_USER_TAGS = "ShowOnlyCurrentUserTags";
public static final String HIDE_CENTRAL_REPO_COMMENTS_AND_OCCURRENCES = "HideCentralRepoCommentsAndOccurrences";
public static final String DISPLAY_TRANSLATED_NAMES = "DisplayTranslatedNames";
// Prevent instantiation.
private UserPreferences() {
}
@ -244,6 +245,14 @@ public final class UserPreferences {
public static void setHideCentralRepoCommentsAndOccurrences(boolean value) {
preferences.putBoolean(HIDE_CENTRAL_REPO_COMMENTS_AND_OCCURRENCES, value);
}
public static void setDisplayTranslationFileNames(boolean value) {
preferences.putBoolean(DISPLAY_TRANSLATED_NAMES, value);
}
public static boolean displayTranslationFileNames() {
return preferences.getBoolean(DISPLAY_TRANSLATED_NAMES, false);
}
/**
* Reads persisted case database connection info.

View File

@ -192,3 +192,5 @@ ViewPreferencesPanel.centralRepoLabel.text=Do not use Central Repository for:
ViewPreferencesPanel.commentsOccurencesColumnsCheckbox.text=C(omments) and O(ccurences) columns to reduce loading times
ViewPreferencesPanel.deletedFilesLimitCheckbox.text=Limit to 10,000
ViewPreferencesPanel.deletedFilesLimitLabel.text=Limit number of deleted files displayed:
ViewPreferencesPanel.fileDisplayLabel.text=Translate text in the:
ViewPreferencesPanel.translatedNamesButton.text=Table

View File

@ -92,6 +92,8 @@
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="centralRepoLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="deletedFilesLimitLabel" alignment="0" min="-2" pref="215" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="hideKnownFilesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
@ -114,9 +116,11 @@
</Group>
</Group>
</Group>
<Component id="hideOtherUsersTagsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="fileDisplayLabel" min="-2" max="-2" attributes="0"/>
<Component id="displayTimeLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
@ -125,14 +129,12 @@
<Component id="useBestViewerRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="useGMTTimeRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="useLocalTimeRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="translatedNamesButton" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Component id="selectFileLabel" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Component id="hideOtherUsersTagsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="centralRepoLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="deletedFilesLimitLabel" alignment="0" min="-2" pref="215" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="10" max="32767" attributes="0"/>
</Group>
@ -174,9 +176,15 @@
</Group>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="hideOtherUsersTagsLabel" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="fileDisplayLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="hideOtherUsersTagsLabel" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="hideOtherUsersTagsCheckbox" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="hideOtherUsersTagsCheckbox" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="translatedNamesButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="centralRepoLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
@ -356,6 +364,23 @@
</Property>
</Properties>
</Component>
<Component class="javax.swing.JRadioButton" name="translatedNamesButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.translatedNamesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="translatedNamesButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="fileDisplayLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.fileDisplayLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="currentCaseSettingsPanel">

View File

@ -27,6 +27,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.deletedFiles.DeletedFilePreferences;
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
/**
* Panel for configuring view preferences.
@ -44,6 +45,14 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
public ViewPreferencesPanel(boolean immediateUpdates) {
initComponents();
this.immediateUpdates = immediateUpdates;
//If there is not Text Translator implementation, then hide these buttons
//from the user.
TextTranslationService tts = TextTranslationService.getInstance();
if(!tts.hasProvider()) {
translatedNamesButton.setVisible(false);
fileDisplayLabel.setVisible(false);
}
}
@Override
@ -67,6 +76,7 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
commentsOccurencesColumnsCheckbox.setSelected(UserPreferences.hideCentralRepoCommentsAndOccurrences());
deletedFilesLimitCheckbox.setSelected(DeletedFilePreferences.getDefault().getShouldLimitDeletedFiles());
translatedNamesButton.setSelected(UserPreferences.displayTranslationFileNames());
// Current Case Settings
boolean caseIsOpen = Case.isCaseOpen();
@ -90,6 +100,7 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
UserPreferences.setHideSlackFilesInViewsTree(viewsHideSlackCheckbox.isSelected());
UserPreferences.setShowOnlyCurrentUserTags(hideOtherUsersTagsCheckbox.isSelected());
UserPreferences.setHideCentralRepoCommentsAndOccurrences(commentsOccurencesColumnsCheckbox.isSelected());
UserPreferences.setDisplayTranslationFileNames(translatedNamesButton.isSelected());
storeGroupItemsInTreeByDataSource();
@ -142,6 +153,8 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
centralRepoLabel = new javax.swing.JLabel();
deletedFilesLimitCheckbox = new javax.swing.JCheckBox();
deletedFilesLimitLabel = new javax.swing.JLabel();
translatedNamesButton = new javax.swing.JRadioButton();
fileDisplayLabel = new javax.swing.JLabel();
currentCaseSettingsPanel = new javax.swing.JPanel();
groupByDataSourceCheckbox = new javax.swing.JCheckBox();
currentSessionSettingsPanel = new javax.swing.JPanel();
@ -244,6 +257,15 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
org.openide.awt.Mnemonics.setLocalizedText(deletedFilesLimitLabel, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.deletedFilesLimitLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(translatedNamesButton, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.translatedNamesButton.text")); // NOI18N
translatedNamesButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
translatedNamesButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(fileDisplayLabel, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.fileDisplayLabel.text")); // NOI18N
javax.swing.GroupLayout globalSettingsPanelLayout = new javax.swing.GroupLayout(globalSettingsPanel);
globalSettingsPanel.setLayout(globalSettingsPanelLayout);
globalSettingsPanelLayout.setHorizontalGroup(
@ -259,6 +281,8 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
.addComponent(deletedFilesLimitCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(centralRepoLabel)
.addComponent(deletedFilesLimitLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(hideKnownFilesLabel)
@ -274,9 +298,11 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
.addGap(10, 10, 10)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(dataSourcesHideKnownCheckbox)
.addComponent(viewsHideKnownCheckbox)))))
.addComponent(viewsHideKnownCheckbox))))
.addComponent(hideOtherUsersTagsLabel))
.addGap(18, 18, 18)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(fileDisplayLabel)
.addComponent(displayTimeLabel)
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGap(10, 10, 10)
@ -284,11 +310,9 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
.addComponent(keepCurrentViewerRadioButton)
.addComponent(useBestViewerRadioButton)
.addComponent(useGMTTimeRadioButton)
.addComponent(useLocalTimeRadioButton)))
.addComponent(selectFileLabel)))
.addComponent(hideOtherUsersTagsLabel)
.addComponent(centralRepoLabel)
.addComponent(deletedFilesLimitLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(useLocalTimeRadioButton)
.addComponent(translatedNamesButton)))
.addComponent(selectFileLabel))))
.addGap(0, 10, Short.MAX_VALUE)))
.addContainerGap())
);
@ -322,9 +346,13 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(useGMTTimeRadioButton)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(hideOtherUsersTagsLabel)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(fileDisplayLabel)
.addComponent(hideOtherUsersTagsLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(hideOtherUsersTagsCheckbox)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(hideOtherUsersTagsCheckbox)
.addComponent(translatedNamesButton))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(centralRepoLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
@ -535,6 +563,14 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
}
}//GEN-LAST:event_deletedFilesLimitCheckboxActionPerformed
private void translatedNamesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_translatedNamesButtonActionPerformed
if (immediateUpdates) {
UserPreferences.setDisplayTranslationFileNames(translatedNamesButton.isSelected());
} else {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}
}//GEN-LAST:event_translatedNamesButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel centralRepoLabel;
@ -546,6 +582,7 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
private javax.swing.JCheckBox deletedFilesLimitCheckbox;
private javax.swing.JLabel deletedFilesLimitLabel;
private javax.swing.JLabel displayTimeLabel;
private javax.swing.JLabel fileDisplayLabel;
private javax.swing.JPanel globalSettingsPanel;
private javax.swing.JCheckBox groupByDataSourceCheckbox;
private javax.swing.JLabel hideKnownFilesLabel;
@ -555,6 +592,7 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
private javax.swing.JLabel hideSlackFilesLabel;
private javax.swing.JRadioButton keepCurrentViewerRadioButton;
private javax.swing.JLabel selectFileLabel;
private javax.swing.JRadioButton translatedNamesButton;
private javax.swing.JRadioButton useBestViewerRadioButton;
private javax.swing.JRadioButton useGMTTimeRadioButton;
private javax.swing.JRadioButton useLocalTimeRadioButton;

View File

@ -30,6 +30,7 @@ import java.util.Optional;
import java.util.Set;
import java.util.logging.Level;
import java.util.stream.Collectors;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.openide.nodes.Children;
@ -52,8 +53,13 @@ import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable.Score;
import org.sleuthkit.autopsy.coreutils.Logger;
import static org.sleuthkit.autopsy.datamodel.Bundle.*;
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable.HasCommentStatus;
import org.sleuthkit.autopsy.events.AutopsyEvent;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
import org.sleuthkit.autopsy.texttranslation.NoServiceProviderException;
import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
import org.sleuthkit.autopsy.texttranslation.TranslationCallback;
import org.sleuthkit.autopsy.texttranslation.TranslationException;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.Content;
@ -71,10 +77,15 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
private static final Logger logger = Logger.getLogger(AbstractAbstractFileNode.class.getName());
@NbBundle.Messages("AbstractAbstractFileNode.addFileProperty.desc=no description")
private static final String NO_DESCR = AbstractAbstractFileNode_addFileProperty_desc();
private static final String TRANSLATION_AVAILABLE_EVENT = "TRANSLATION_AVAILABLE";
private static final String NO_TRANSLATION = "";
private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.CURRENT_CASE,
Case.Events.CONTENT_TAG_ADDED, Case.Events.CONTENT_TAG_DELETED, Case.Events.CR_COMMENT_CHANGED);
private String translatedFileName;
/**
* @param abstractFile file to wrap
*/
@ -89,6 +100,7 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
IngestManager.getInstance().addIngestModuleEventListener(weakPcl);
}
}
translatedFileName = null;
// Listen for case events so that we can detect when the case is closed
// or when tags are added.
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, weakPcl);
@ -165,6 +177,9 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
if (event.getContentID() == content.getId()) {
updateSheet();
}
} else if (eventType.equals(TRANSLATION_AVAILABLE_EVENT)) {
this.translatedFileName = (String) evt.getNewValue();
updateSheet();
}
};
@ -211,6 +226,7 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
"AbstractAbstractFileNode.createSheet.score.name=S",
"AbstractAbstractFileNode.createSheet.comment.name=C",
"AbstractAbstractFileNode.createSheet.count.name=O",
"AbstractAbstractFileNode.translateFileName=Translated Name",
"AbstractAbstractFileNode.locationColLbl=Location",
"AbstractAbstractFileNode.modifiedTimeColLbl=Modified Time",
"AbstractAbstractFileNode.changeTimeColLbl=Change Time",
@ -454,6 +470,41 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
}
}
/**
* Attempts translation on the file name by kicking off a background task to do the
* translation. Once the background task is done, it will fire a PropertyChangeEvent,
* which will force this node to refresh itself, thus updating its translated name
* column.
*
* @return The file names translation.
*/
protected String getTranslatedFileName() {
//If already in complete English, don't translate.
if (this.content.getName().matches("^\\p{ASCII}+$")) {
return NO_TRANSLATION;
}
//If we already have a translation use that one.
if (translatedFileName != null) {
return translatedFileName;
}
//If not, lets fire off a background translation that will update the UI
//when it is done.
TextTranslationService tts = TextTranslationService.getInstance();
if (tts.hasProvider()) {
//Seperate out the base and ext from the contents file name.
String base = FilenameUtils.getBaseName(this.content.getName());
//Send only the base file name to be translated. Once the translation comes
//back fire a PropertyChangeEvent on this nodes PropertyChangeListener.
tts.translateAsynchronously(base, new TranslateFileNameCallback(this.content, weakPcl));
}
//In the mean time, return a blank translation.
return NO_TRANSLATION;
}
/**
* Fill map with AbstractFile properties
*
@ -659,4 +710,72 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
return "";
}
}
/**
* Implements the TranslationCallback interface so that the TextTranslationService
* can call these methods when an asynchronous translation task is complete.
*/
private class TranslateFileNameCallback implements TranslationCallback {
private final String ext;
private final String originalFileName;
private final PropertyChangeListener listener;
public TranslateFileNameCallback(AbstractFile file, PropertyChangeListener listener) {
this.ext = FilenameUtils.getExtension(content.getName());
this.originalFileName = content.getName();
this.listener = listener;
}
/**
* Fires a PropertyChangeEvent on this nodes PropertyChangeListener
* when the translation is finished. Reconstruct the file name so we
* can properly display the translation.
*
* @param translation Result from the translation job submitted to
* Text translation service.
*/
@Override
public void onTranslationResult(String translation) {
//If we have no extension, then we shouldn't add the .
String extensionDelimiter = (ext.isEmpty()) ? "" : ".";
//Talk directly to this nodes pcl, fire an update when the translation
//is complete.
if (translation.isEmpty()) {
listener.propertyChange(new PropertyChangeEvent(
AutopsyEvent.SourceType.LOCAL.toString(),
TRANSLATION_AVAILABLE_EVENT, null, translation));
} else {
listener.propertyChange(new PropertyChangeEvent(
AutopsyEvent.SourceType.LOCAL.toString(),
TRANSLATION_AVAILABLE_EVENT, null,
translation + extensionDelimiter + ext));
}
}
/**
* Do nothing on a translation exception except log, the column will remain empty
* and there is nothing we can do as a fallback.
*
* @param ex Exception caught while translating.
*/
@Override
public void onTranslationException(TranslationException noTranslationEx) {
logger.log(Level.WARNING, "Could not successfully translate file name " + originalFileName, noTranslationEx);
}
/**
* Do nothing on a no service provider exception except log, in this implemention we
* are only calling for translation to be done if we know that a TextTranslator
* service provider is already defined.
*
* @param ex
*/
@Override
public void onNoServiceProviderException(NoServiceProviderException noServiceEx) {
logger.log(Level.WARNING, "Translate unsuccessful because no TextTranslator "
+ "implementation was provided.", noServiceEx);
}
}
}

View File

@ -320,7 +320,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
}
return srcName;
}
@NbBundle.Messages({
"BlackboardArtifactNode.createSheet.artifactType.displayName=Artifact Type",
"BlackboardArtifactNode.createSheet.artifactType.name=Artifact Type",

View File

@ -69,7 +69,6 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
}
}
@Override
public <T> T accept(ContentNodeVisitor<T> visitor) {
return visitor.visit(this);
}

View File

@ -38,6 +38,59 @@ public class LocalDirectoryNode extends SpecialDirectoryNode {
}
@Override
<<<<<<< HEAD
=======
@NbBundle.Messages({
"LocalDirectoryNode.createSheet.name.name=Name",
"LocalDirectoryNode.createSheet.name.displayName=Name",
"LocalDirectoryNode.createSheet.name.desc=no description",
"LocalDirectoryNode.createSheet.noDesc=no description"})
protected Sheet createSheet() {
Sheet sheet = super.createSheet();
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
if (sheetSet == null) {
sheetSet = Sheet.createPropertiesSet();
sheet.put(sheetSet);
}
List<ContentTag> tags = getContentTagsFromDatabase();
sheetSet.put(new NodeProperty<>(Bundle.LocalDirectoryNode_createSheet_name_name(),
Bundle.LocalDirectoryNode_createSheet_name_displayName(),
Bundle.LocalDirectoryNode_createSheet_name_desc(),
getName()));
final String NO_DESCR = Bundle.LocalDirectoryNode_createSheet_noDesc();
if(UserPreferences.displayTranslationFileNames()) {
String translation = getTranslatedFileName();
sheetSet.put(new NodeProperty<>(Bundle.AbstractAbstractFileNode_translateFileName(),
Bundle.AbstractAbstractFileNode_translateFileName(), NO_DESCR, translation));
}
addScoreProperty(sheetSet, tags);
CorrelationAttributeInstance correlationAttribute = null;
if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) {
correlationAttribute = getCorrelationAttributeInstance();
}
addCommentProperty(sheetSet, tags, correlationAttribute);
if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) {
addCountProperty(sheetSet, correlationAttribute);
}
// At present, a LocalDirectory will never be a datasource - the top level of a logical
// file set is a VirtualDirectory
Map<String, Object> map = new LinkedHashMap<>();
fillPropertyMap(map, getContent());
for (Map.Entry<String, Object> entry : map.entrySet()) {
sheetSet.put(new NodeProperty<>(entry.getKey(), entry.getKey(), NO_DESCR, entry.getValue()));
}
return sheet;
}
@Override
>>>>>>> 4316-text-translation-service
public <T> T accept(ContentNodeVisitor<T> visitor) {
return visitor.visit(this);
}

View File

@ -61,7 +61,6 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
}
@Override
public Action[] getActions(boolean context) {
List<Action> actionsList = new ArrayList<>();
actionsList.addAll(Arrays.asList(super.getActions(true)));

View File

@ -170,6 +170,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
case UserPreferences.HIDE_KNOWN_FILES_IN_DATA_SRCS_TREE:
case UserPreferences.HIDE_SLACK_FILES_IN_DATA_SRCS_TREE:
case UserPreferences.HIDE_CENTRAL_REPO_COMMENTS_AND_OCCURRENCES:
case UserPreferences.DISPLAY_TRANSLATED_NAMES:
case UserPreferences.KEEP_PREFERRED_VIEWER:
refreshContentTreeSafe();
break;

View File

@ -0,0 +1,30 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.texttranslation;
/**
* Exception to indicate that no Service Provider could be found during the
* Lookup action.
*/
public class NoServiceProviderException extends Exception {
public NoServiceProviderException(String msg) {
super(msg);
}
}

View File

@ -18,27 +18,41 @@
*/
package org.sleuthkit.autopsy.texttranslation;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import org.openide.util.Lookup;
/**
* Service for finding and running TextTranslator implementations
* Performs a lookup for a TextTranslator service provider and if present,
* will use this provider to run translation on the input.
*/
public class TextTranslationService {
public final class TextTranslationService {
private final static TextTranslationService tts = new TextTranslationService();
private final Optional<TextTranslator> translator;
/**
*
*/
public TextTranslationService() {
private static ExecutorService pool;
private final static Integer MAX_POOL_SIZE = 10;
private TextTranslationService(){
//Perform look up for Text Translation implementations ONLY ONCE during
//class loading.
translator = Optional.ofNullable(Lookup.getDefault()
.lookup(TextTranslator.class));
}
public static TextTranslationService getInstance() {
return tts;
}
/**
* Performs a lookup for a TextTranslator service provider and if present,
* will use this provider to run translation on the input.
* Translates the input string using whichever TextTranslator Service Provider
* was found during lookup.
*
* @param input Input string to be translated
*
@ -59,13 +73,51 @@ public class TextTranslationService {
}
/**
* Exception to indicate that no Service Provider could be found during the
* Lookup action.
* Makes the call to translate(String) happen asynchronously on a background
* thread. When it is done, it will use the appropriate TranslationCallback
* method.
*
* @param input String to be translated
* @param tcb Interface for handling the translation result or any
* exceptions thrown while running translate.
*
*/
public class NoServiceProviderException extends Exception {
public void translateAsynchronously(String input, TranslationCallback tcb) {
if (translator.isPresent()) {
//Delay thread pool initialization until an asynchronous task is first called.
//That way we don't have threads sitting parked in the background for no reason.
if (pool == null) {
ThreadFactory translationFactory = new ThreadFactoryBuilder()
.setNameFormat("translation-thread-%d")
.build();
pool = Executors.newFixedThreadPool(MAX_POOL_SIZE, translationFactory);
}
public NoServiceProviderException(String msg) {
super(msg);
//Submit the task to the pool, calling the appropriate method depending
//on the result of the translate operation.
pool.submit(() -> {
try {
String translation = translate(input);
tcb.onTranslationResult(translation);
} catch (NoServiceProviderException ex) {
tcb.onNoServiceProviderException(ex);
} catch (TranslationException ex) {
tcb.onTranslationException(ex);
}
});
}
tcb.onNoServiceProviderException(new NoServiceProviderException(
"Could not find a TextTranslator service provider"));
}
/**
* Returns if a TextTranslator lookup successfully found an implementing
* class.
*
* @return
*/
public boolean hasProvider() {
return translator.isPresent();
}
}

View File

@ -24,13 +24,6 @@ package org.sleuthkit.autopsy.texttranslation;
*/
public interface TextTranslator {
public String translate(String input) throws TranslationException;
String translate(String input) throws TranslationException;
public default String[] translate(String[] inputs) throws TranslationException {
String[] outputs = new String[inputs.length];
for(int i = 0; i < inputs.length; i++) {
outputs[i] = translate(inputs[i]);
}
return outputs;
}
}

View File

@ -0,0 +1,49 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.texttranslation;
/**
* This callback interface will be used by TextTranslationService when doing
* translations on background tasks. When the translation is done, it's result will
* be delegated to one of the following methods. It can either be successful or fail with
* exceptions.
*/
public interface TranslationCallback {
/**
* Provides a method to handle the translation result
*
* @param translation result of calling TextTranslationService.
*/
void onTranslationResult(String translation);
/**
* Provides a way to handle Translation Exceptions.
*
* @param noTranslationEx
*/
void onTranslationException(TranslationException noTranslationEx);
/**
* Provides a way to handle NoServiceProviderExceptions.
*
* @param noServiceEx
*/
void onNoServiceProviderException(NoServiceProviderException noServiceEx);
}