mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-17 10:17:41 +00:00
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:
commit
003a1f6662
@ -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>
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="currentCaseSettingsPanel">
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -69,7 +69,6 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(ContentNodeVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)));
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
49
Core/src/org/sleuthkit/autopsy/texttranslation/TranslationCallback.java
Executable file
49
Core/src/org/sleuthkit/autopsy/texttranslation/TranslationCallback.java
Executable 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);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user