mirror of
https://github.com/elisspace/autopsy.git
synced 2026-09-29 05:49:50 +00:00
Merge pull request #5722 from rcordovano/6032-translated-file-name-columns-in-results-view
6032 translated file name columns in results view
This commit is contained in:
@@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.datamodel;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
@@ -28,7 +29,6 @@ import java.util.Map;
|
||||
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.Sheet;
|
||||
@@ -66,6 +66,7 @@ import org.sleuthkit.datamodel.Tag;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
|
||||
import org.sleuthkit.autopsy.texttranslation.utils.FileNameTranslationUtil;
|
||||
|
||||
/**
|
||||
* An abstract node that encapsulates AbstractFile data
|
||||
@@ -94,15 +95,15 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
||||
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, weakPcl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
//See JIRA-5971
|
||||
//Attempt to cache file path during construction of this UI component.
|
||||
this.content.getUniquePath();
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Failed attempt to cache the "
|
||||
+ "unique path of the abstract file instance. Name: %s (objID=%d)",
|
||||
this.content.getName(), this.content.getId()), ex);
|
||||
+ "unique path of the abstract file instance. Name: %s (objID=%d)",
|
||||
this.content.getName(), this.content.getId()), ex);
|
||||
}
|
||||
|
||||
if (TextTranslationService.getInstance().hasProvider() && UserPreferences.displayTranslatedFileNames()) {
|
||||
@@ -490,39 +491,18 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates this nodes content name. Doesn't attempt translation if the
|
||||
* name is in english or if there is now translation service available.
|
||||
* Translates the name of the file this node represents. An empty string
|
||||
* will be returned if the translation fails for any reason.
|
||||
*
|
||||
* @return The translated file name or the empty string.
|
||||
*/
|
||||
String getTranslatedFileName() {
|
||||
//If already in complete English, don't translate.
|
||||
if (content.getName().matches("^\\p{ASCII}+$")) {
|
||||
try {
|
||||
return FileNameTranslationUtil.translate(content.getName());
|
||||
} catch (NoServiceProviderException | TranslationException ex) {
|
||||
logger.log(Level.WARNING, MessageFormat.format("Error translating file name (objID={0}))", content.getId()), ex);
|
||||
return "";
|
||||
}
|
||||
TextTranslationService tts = TextTranslationService.getInstance();
|
||||
if (tts.hasProvider()) {
|
||||
//Seperate out the base and ext from the contents file name.
|
||||
String base = FilenameUtils.getBaseName(content.getName());
|
||||
try {
|
||||
String translation = tts.translate(base);
|
||||
String ext = FilenameUtils.getExtension(content.getName());
|
||||
|
||||
//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()) {
|
||||
return translation + extensionDelimiter + ext;
|
||||
}
|
||||
} catch (NoServiceProviderException noServiceEx) {
|
||||
logger.log(Level.WARNING, "Translate unsuccessful because no TextTranslator "
|
||||
+ "implementation was provided.", noServiceEx.getMessage());
|
||||
} catch (TranslationException noTranslationEx) {
|
||||
logger.log(Level.WARNING, "Could not successfully translate file name "
|
||||
+ content.getName(), noTranslationEx.getMessage());
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -76,6 +76,9 @@ import org.sleuthkit.datamodel.Tag;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
|
||||
import static org.sleuthkit.autopsy.datamodel.AbstractContentNode.NO_DESCR;
|
||||
import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
|
||||
import org.sleuthkit.autopsy.datamodel.utils.FileNameTransTask;
|
||||
|
||||
/**
|
||||
* A BlackboardArtifactNode is an AbstractNode implementation that can be used
|
||||
@@ -124,7 +127,8 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
};
|
||||
|
||||
private final BlackboardArtifact artifact;
|
||||
private Content srcContent; // May be null.
|
||||
private Content srcContent;
|
||||
private volatile String translatedSourceName;
|
||||
|
||||
/*
|
||||
* A method has been provided to allow the injection of properties into this
|
||||
@@ -133,7 +137,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
*/
|
||||
private List<NodeProperty<? extends Object>> customProperties;
|
||||
|
||||
private final PropertyChangeListener appEventListener = new PropertyChangeListener() {
|
||||
private final PropertyChangeListener listener = new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
String eventType = evt.getPropertyName();
|
||||
@@ -148,25 +152,19 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
updateSheet();
|
||||
}
|
||||
} else if (eventType.equals(Case.Events.CONTENT_TAG_ADDED.toString())) {
|
||||
if (srcContent != null) {
|
||||
ContentTagAddedEvent event = (ContentTagAddedEvent) evt;
|
||||
if (event.getAddedTag().getContent().equals(srcContent)) {
|
||||
updateSheet();
|
||||
}
|
||||
ContentTagAddedEvent event = (ContentTagAddedEvent) evt;
|
||||
if (event.getAddedTag().getContent().equals(srcContent)) {
|
||||
updateSheet();
|
||||
}
|
||||
} else if (eventType.equals(Case.Events.CONTENT_TAG_DELETED.toString())) {
|
||||
if (srcContent != null) {
|
||||
ContentTagDeletedEvent event = (ContentTagDeletedEvent) evt;
|
||||
if (event.getDeletedTagInfo().getContentID() == srcContent.getId()) {
|
||||
updateSheet();
|
||||
}
|
||||
ContentTagDeletedEvent event = (ContentTagDeletedEvent) evt;
|
||||
if (event.getDeletedTagInfo().getContentID() == srcContent.getId()) {
|
||||
updateSheet();
|
||||
}
|
||||
} else if (eventType.equals(Case.Events.CR_COMMENT_CHANGED.toString())) {
|
||||
if (srcContent != null) {
|
||||
CommentChangedEvent event = (CommentChangedEvent) evt;
|
||||
if (event.getContentID() == srcContent.getId()) {
|
||||
updateSheet();
|
||||
}
|
||||
CommentChangedEvent event = (CommentChangedEvent) evt;
|
||||
if (event.getContentID() == srcContent.getId()) {
|
||||
updateSheet();
|
||||
}
|
||||
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
|
||||
if (evt.getNewValue() == null) {
|
||||
@@ -179,14 +177,41 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
} else if (eventType.equals(NodeSpecificEvents.SCO_AVAILABLE.toString()) && !UserPreferences.getHideSCOColumns()) {
|
||||
SCOData scoData = (SCOData) evt.getNewValue();
|
||||
if (scoData.getScoreAndDescription() != null) {
|
||||
updateSheet(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_score_name(), Bundle.BlackboardArtifactNode_createSheet_score_displayName(), scoData.getScoreAndDescription().getRight(), scoData.getScoreAndDescription().getLeft()));
|
||||
updateSheet(new NodeProperty<>(
|
||||
Bundle.BlackboardArtifactNode_createSheet_score_name(),
|
||||
Bundle.BlackboardArtifactNode_createSheet_score_displayName(),
|
||||
scoData.getScoreAndDescription().getRight(),
|
||||
scoData.getScoreAndDescription().getLeft()));
|
||||
}
|
||||
if (scoData.getComment() != null) {
|
||||
updateSheet(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_comment_name(), Bundle.BlackboardArtifactNode_createSheet_comment_displayName(), NO_DESCR, scoData.getComment()));
|
||||
updateSheet(new NodeProperty<>(
|
||||
Bundle.BlackboardArtifactNode_createSheet_comment_name(),
|
||||
Bundle.BlackboardArtifactNode_createSheet_comment_displayName(),
|
||||
NO_DESCR, scoData.getComment()));
|
||||
}
|
||||
if (scoData.getCountAndDescription() != null) {
|
||||
updateSheet(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_count_name(), Bundle.BlackboardArtifactNode_createSheet_count_displayName(), scoData.getCountAndDescription().getRight(), scoData.getCountAndDescription().getLeft()));
|
||||
updateSheet(new NodeProperty<>(
|
||||
Bundle.BlackboardArtifactNode_createSheet_count_name(),
|
||||
Bundle.BlackboardArtifactNode_createSheet_count_displayName(),
|
||||
scoData.getCountAndDescription().getRight(),
|
||||
scoData.getCountAndDescription().getLeft()));
|
||||
}
|
||||
} else if (eventType.equals(FileNameTransTask.getPropertyName())) {
|
||||
/*
|
||||
* Replace the value of the Source File property with the
|
||||
* translated name via setDisplayName (see note in createSheet),
|
||||
* and put the untranslated name in the Original Name property
|
||||
* and in the tooltip.
|
||||
*/
|
||||
String originalName = evt.getOldValue().toString();
|
||||
translatedSourceName = evt.getNewValue().toString();
|
||||
setDisplayName(translatedSourceName);
|
||||
setShortDescription(originalName);
|
||||
updateSheet(new NodeProperty<>(
|
||||
Bundle.BlackboardArtifactNode_createSheet_srcFile_origName(),
|
||||
Bundle.BlackboardArtifactNode_createSheet_srcFile_origDisplayName(),
|
||||
NO_DESCR,
|
||||
originalName));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -198,7 +223,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
* listener held by event publishers prevents garbage collection of this
|
||||
* node.
|
||||
*/
|
||||
private final PropertyChangeListener weakAppEventListener = WeakListeners.propertyChange(appEventListener, null);
|
||||
private final PropertyChangeListener weakListener = WeakListeners.propertyChange(listener, null);
|
||||
|
||||
/**
|
||||
* Constructs a BlackboardArtifactNode, an AbstractNode implementation that
|
||||
@@ -207,7 +232,6 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
* @param artifact The artifact to represent.
|
||||
* @param iconPath The path to the icon for the artifact type.
|
||||
*/
|
||||
@NbBundle.Messages({"# {0} - artifactDisplayName", "BlackboardArtifactNode.displayName.artifact={0} Artifact"})
|
||||
public BlackboardArtifactNode(BlackboardArtifact artifact, String iconPath) {
|
||||
super(artifact, createLookup(artifact));
|
||||
this.artifact = artifact;
|
||||
@@ -218,20 +242,25 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
/*
|
||||
* Calling this getter causes the unique path of the source
|
||||
* content to be cached in the Content object. This is
|
||||
* advantageous if this node is constructed in a background
|
||||
* thread instead of a UI thread.
|
||||
* advantageous as long as this node is constructed in a
|
||||
* background thread instead of a UI thread.
|
||||
*/
|
||||
srcContent.getUniquePath();
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, MessageFormat.format("Error getting the unique path of the source content (artifact objID={0})", artifact.getId()), ex);
|
||||
logger.log(Level.WARNING, MessageFormat.format("Error getting the unique path of the source content (artifact objID={0})", artifact.getId()), ex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (srcContent == null) {
|
||||
throw new IllegalArgumentException(MessageFormat.format("Artifact missing source content (artifact objID={0})", artifact));
|
||||
}
|
||||
setName(Long.toString(artifact.getArtifactID()));
|
||||
setDisplayName(Bundle.BlackboardArtifactNode_displayName_artifact(artifact.getDisplayName()));
|
||||
String displayName = srcContent.getName();
|
||||
setDisplayName(displayName);
|
||||
setShortDescription(displayName);
|
||||
setIconBaseWithExtension(iconPath);
|
||||
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, weakAppEventListener);
|
||||
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, weakListener);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -286,7 +315,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
* Unregisters this node's application event listener.
|
||||
*/
|
||||
private void unregisterListener() {
|
||||
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, weakAppEventListener);
|
||||
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, weakListener);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -327,13 +356,15 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, MessageFormat.format("Error getting linked file of artifact (artifact objID={0})", artifact.getId()), ex); //NON-NLS
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* If the source content of the artifact represented by this node is a
|
||||
* file, add an action to view the file in the data source tree.
|
||||
*/
|
||||
AbstractFile file = getLookup().lookup(AbstractFile.class);
|
||||
AbstractFile file = getLookup().lookup(AbstractFile.class
|
||||
);
|
||||
if (null != file) {
|
||||
actionsList.add(ViewFileInTimelineAction.createViewSourceFileAction(file));
|
||||
}
|
||||
@@ -348,14 +379,14 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
* @return The source content name.
|
||||
*/
|
||||
public String getSourceName() {
|
||||
String name = "";
|
||||
if (srcContent != null) {
|
||||
name = srcContent.getName();
|
||||
}
|
||||
return name;
|
||||
return srcContent.getName();
|
||||
}
|
||||
|
||||
@NbBundle.Messages({
|
||||
"BlackboardArtifactNode.createSheet.srcFile.name=Source File",
|
||||
"BlackboardArtifactNode.createSheet.srcFile.displayName=Source File",
|
||||
"BlackboardArtifactNode.createSheet.srcFile.origName=Original Name",
|
||||
"BlackboardArtifactNode.createSheet.srcFile.origDisplayName=Original Name",
|
||||
"BlackboardArtifactNode.createSheet.artifactType.displayName=Result Type",
|
||||
"BlackboardArtifactNode.createSheet.artifactType.name=Result Type",
|
||||
"BlackboardArtifactNode.createSheet.artifactDetails.displayName=Result Details",
|
||||
@@ -381,12 +412,34 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
|
||||
/*
|
||||
* Add the name of the source content of the artifact represented by
|
||||
* this node to the sheet.
|
||||
* this node to the sheet. The value of this property is the same as the
|
||||
* display name of the node and this a "special" property that displays
|
||||
* the node's icon as well as the display name.
|
||||
*/
|
||||
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.srcFile.name"),
|
||||
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.srcFile.displayName"),
|
||||
sheetSet.put(new NodeProperty<>(
|
||||
Bundle.BlackboardArtifactNode_createSheet_srcFile_name(),
|
||||
Bundle.BlackboardArtifactNode_createSheet_srcFile_displayName(),
|
||||
NO_DESCR,
|
||||
this.getSourceName()));
|
||||
getDisplayName()));
|
||||
|
||||
if (TextTranslationService.getInstance().hasProvider() && UserPreferences.displayTranslatedFileNames()) {
|
||||
/*
|
||||
* If machine translation is configured, add the original name of
|
||||
* the of the source content of the artifact represented by this
|
||||
* node to the sheet.
|
||||
*/
|
||||
sheetSet.put(new NodeProperty<>(
|
||||
Bundle.BlackboardArtifactNode_createSheet_srcFile_origName(),
|
||||
Bundle.BlackboardArtifactNode_createSheet_srcFile_origDisplayName(),
|
||||
NO_DESCR,
|
||||
translatedSourceName != null ? srcContent.getName() : ""));
|
||||
if (translatedSourceName == null) {
|
||||
/*
|
||||
* NOTE: The task makes its own weak reference to the listener.
|
||||
*/
|
||||
new FileNameTransTask(srcContent.getName(), this, listener).submit();
|
||||
}
|
||||
}
|
||||
|
||||
if (!UserPreferences.getHideSCOColumns()) {
|
||||
/*
|
||||
@@ -396,12 +449,24 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
* will fire a PropertyChangeEvent when the computation is completed
|
||||
* and this node's PropertyChangeListener will update the sheet.
|
||||
*/
|
||||
sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_score_name(), Bundle.BlackboardArtifactNode_createSheet_score_displayName(), VALUE_LOADING, ""));
|
||||
sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_comment_name(), Bundle.BlackboardArtifactNode_createSheet_comment_displayName(), VALUE_LOADING, ""));
|
||||
sheetSet.put(new NodeProperty<>(
|
||||
Bundle.BlackboardArtifactNode_createSheet_score_name(),
|
||||
Bundle.BlackboardArtifactNode_createSheet_score_displayName(),
|
||||
VALUE_LOADING,
|
||||
""));
|
||||
sheetSet.put(new NodeProperty<>(
|
||||
Bundle.BlackboardArtifactNode_createSheet_comment_name(),
|
||||
Bundle.BlackboardArtifactNode_createSheet_comment_displayName(),
|
||||
VALUE_LOADING,
|
||||
""));
|
||||
if (CentralRepository.isEnabled()) {
|
||||
sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_count_name(), Bundle.BlackboardArtifactNode_createSheet_count_displayName(), VALUE_LOADING, ""));
|
||||
sheetSet.put(new NodeProperty<>(
|
||||
Bundle.BlackboardArtifactNode_createSheet_count_name(),
|
||||
Bundle.BlackboardArtifactNode_createSheet_count_displayName(),
|
||||
VALUE_LOADING,
|
||||
""));
|
||||
}
|
||||
backgroundTasksPool.submit(new GetSCOTask(new WeakReference<>(this), weakAppEventListener));
|
||||
backgroundTasksPool.submit(new GetSCOTask(new WeakReference<>(this), weakListener));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -414,11 +479,13 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
|
||||
if (attribute != null) {
|
||||
BlackboardArtifact associatedArtifact = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(attribute.getValueLong());
|
||||
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactType.name"),
|
||||
sheetSet.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactType.name"),
|
||||
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactType.displayName"),
|
||||
NO_DESCR,
|
||||
associatedArtifact.getDisplayName()));
|
||||
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactDetails.name"),
|
||||
sheetSet.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactDetails.name"),
|
||||
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactDetails.displayName"),
|
||||
NO_DESCR,
|
||||
associatedArtifact.getShortDescription()));
|
||||
@@ -459,15 +526,17 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID()) {
|
||||
String ext = ""; //NON-NLS
|
||||
String actualMimeType = ""; //NON-NLS
|
||||
if (srcContent != null && srcContent instanceof AbstractFile) {
|
||||
if (srcContent instanceof AbstractFile) {
|
||||
AbstractFile file = (AbstractFile) srcContent;
|
||||
ext = file.getNameExtension();
|
||||
actualMimeType = file.getMIMEType();
|
||||
if (actualMimeType == null) {
|
||||
actualMimeType = ""; //NON-NLS
|
||||
|
||||
}
|
||||
}
|
||||
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.ext.name"),
|
||||
sheetSet.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.ext.name"),
|
||||
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.ext.displayName"),
|
||||
NO_DESCR,
|
||||
ext));
|
||||
@@ -484,12 +553,11 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
*/
|
||||
if (Arrays.asList(SHOW_UNIQUE_PATH).contains(artifactTypeId)) {
|
||||
String sourcePath = ""; //NON-NLS
|
||||
if (srcContent != null) {
|
||||
try {
|
||||
sourcePath = srcContent.getUniquePath();
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, MessageFormat.format("Error getting unique path of source content (artifact objID={0})", artifact.getId()), ex); //NON-NLS
|
||||
}
|
||||
try {
|
||||
sourcePath = srcContent.getUniquePath();
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, MessageFormat.format("Error getting unique path of source content (artifact objID={0})", artifact.getId()), ex); //NON-NLS
|
||||
|
||||
}
|
||||
|
||||
if (sourcePath.isEmpty() == false) {
|
||||
@@ -506,45 +574,50 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
* sheet. Otherwise, add the data source to the sheet.
|
||||
*/
|
||||
if (Arrays.asList(SHOW_FILE_METADATA).contains(artifactTypeId)) {
|
||||
AbstractFile file = srcContent != null && srcContent instanceof AbstractFile ? (AbstractFile) srcContent : null;
|
||||
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileModifiedTime.name"),
|
||||
AbstractFile file = srcContent instanceof AbstractFile ? (AbstractFile) srcContent : null;
|
||||
sheetSet.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileModifiedTime.name"),
|
||||
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileModifiedTime.displayName"),
|
||||
"",
|
||||
file == null ? "" : ContentUtils.getStringTime(file.getMtime(), file)));
|
||||
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileChangedTime.name"),
|
||||
sheetSet.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileChangedTime.name"),
|
||||
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileChangedTime.displayName"),
|
||||
"",
|
||||
file == null ? "" : ContentUtils.getStringTime(file.getCtime(), file)));
|
||||
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileAccessedTime.name"),
|
||||
sheetSet.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileAccessedTime.name"),
|
||||
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileAccessedTime.displayName"),
|
||||
"",
|
||||
file == null ? "" : ContentUtils.getStringTime(file.getAtime(), file)));
|
||||
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileCreatedTime.name"),
|
||||
sheetSet.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileCreatedTime.name"),
|
||||
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileCreatedTime.displayName"),
|
||||
"",
|
||||
file == null ? "" : ContentUtils.getStringTime(file.getCrtime(), file)));
|
||||
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileSize.name"),
|
||||
sheetSet.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileSize.name"),
|
||||
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileSize.displayName"),
|
||||
"",
|
||||
file == null ? "" : file.getSize()));
|
||||
sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_artifactMD5_name(),
|
||||
sheetSet.put(new NodeProperty<>(
|
||||
Bundle.BlackboardArtifactNode_createSheet_artifactMD5_name(),
|
||||
Bundle.BlackboardArtifactNode_createSheet_artifactMD5_displayName(),
|
||||
"",
|
||||
file == null ? "" : StringUtils.defaultString(file.getMd5Hash())));
|
||||
}
|
||||
} else {
|
||||
String dataSourceStr = "";
|
||||
if (srcContent != null) {
|
||||
try {
|
||||
Content dataSource = srcContent.getDataSource();
|
||||
if (dataSource != null) {
|
||||
dataSourceStr = dataSource.getName();
|
||||
} else {
|
||||
dataSourceStr = getRootAncestorName();
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, MessageFormat.format("Error getting source data source name (artifact objID={0})", artifact.getId()), ex); //NON-NLS
|
||||
try {
|
||||
Content dataSource = srcContent.getDataSource();
|
||||
if (dataSource != null) {
|
||||
dataSourceStr = dataSource.getName();
|
||||
} else {
|
||||
dataSourceStr = getRootAncestorName();
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, MessageFormat.format("Error getting source data source name (artifact objID={0})", artifact.getId()), ex); //NON-NLS
|
||||
|
||||
}
|
||||
|
||||
if (dataSourceStr.isEmpty() == false) {
|
||||
@@ -563,24 +636,27 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID()) {
|
||||
long size = 0;
|
||||
String path = ""; //NON-NLS
|
||||
if (srcContent != null && srcContent instanceof AbstractFile) {
|
||||
if (srcContent instanceof AbstractFile) {
|
||||
AbstractFile af = (AbstractFile) srcContent;
|
||||
size = af.getSize();
|
||||
try {
|
||||
path = af.getUniquePath();
|
||||
} catch (TskCoreException ex) {
|
||||
path = af.getParentPath();
|
||||
|
||||
}
|
||||
}
|
||||
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.fileSize.name"),
|
||||
sheetSet.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.fileSize.name"),
|
||||
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.fileSize.displayName"),
|
||||
NO_DESCR,
|
||||
size));
|
||||
sheetSet.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.path.name"),
|
||||
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.path.displayName"),
|
||||
NO_DESCR,
|
||||
path));
|
||||
sheetSet
|
||||
.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.path.name"),
|
||||
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.path.displayName"),
|
||||
NO_DESCR,
|
||||
path));
|
||||
}
|
||||
|
||||
return sheet;
|
||||
@@ -597,9 +673,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
List<Tag> tags = new ArrayList<>();
|
||||
try {
|
||||
tags.addAll(Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact));
|
||||
if (srcContent != null) {
|
||||
tags.addAll(Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByContent(srcContent));
|
||||
}
|
||||
tags.addAll(Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByContent(srcContent));
|
||||
} catch (TskCoreException | NoCurrentCaseException ex) {
|
||||
logger.log(Level.SEVERE, MessageFormat.format("Error getting tags for artifact and its source content (artifact objID={0})", artifact.getId()), ex);
|
||||
}
|
||||
@@ -617,7 +691,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
@Override
|
||||
protected final CorrelationAttributeInstance getCorrelationAttributeInstance() {
|
||||
CorrelationAttributeInstance correlationAttribute = null;
|
||||
if (srcContent != null && CentralRepository.isEnabled() && srcContent instanceof AbstractFile) {
|
||||
if (CentralRepository.isEnabled() && srcContent instanceof AbstractFile) {
|
||||
correlationAttribute = CorrelationAttributeUtil.getCorrAttrForFile((AbstractFile) srcContent);
|
||||
}
|
||||
return correlationAttribute;
|
||||
@@ -695,7 +769,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
*/
|
||||
Score score = Score.NO_SCORE;
|
||||
String description = Bundle.BlackboardArtifactNode_createSheet_noScore_description();
|
||||
if (srcContent != null && srcContent instanceof AbstractFile) {
|
||||
if (srcContent instanceof AbstractFile) {
|
||||
if (((AbstractFile) srcContent).getKnown() == TskData.FileKnown.BAD) {
|
||||
score = Score.NOTABLE_SCORE;
|
||||
description = Bundle.BlackboardArtifactNode_createSheet_notableFile_description();
|
||||
@@ -725,7 +799,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
/*
|
||||
* Is the artifact's source content notable?
|
||||
*/
|
||||
if (score == Score.NO_SCORE && srcContent != null) {
|
||||
if (score == Score.NO_SCORE) {
|
||||
try {
|
||||
if (!srcContent.getArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT).isEmpty()) {
|
||||
score = Score.INTERESTING_SCORE;
|
||||
@@ -814,7 +888,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
parentName = parent.getName();
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, MessageFormat.format("Error getting root ancestor name for source content (artifact objID={0})", artifact.getId())); //NON-NLS
|
||||
logger.log(Level.SEVERE, MessageFormat.format("Error getting root ancestor name for source content (artifact objID={0})", artifact.getId()), ex); //NON-NLS
|
||||
return "";
|
||||
}
|
||||
return parentName;
|
||||
@@ -1036,8 +1110,8 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
* @param attribute The correlation attribute instance to use for the
|
||||
* central repository lookup.
|
||||
*
|
||||
* @deprecated Do not use. The other occurrences property is now computed in a
|
||||
* background thread and added to the property sheet via property change
|
||||
* @deprecated Do not use. The other occurrences property is now computed in
|
||||
* a background thread and added to the property sheet via property change
|
||||
* event.
|
||||
*/
|
||||
@NbBundle.Messages({"BlackboardArtifactNode.createSheet.comment.name=C",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013-2018 Basis Technology Corp.
|
||||
* Copyright 2013-2020 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -24,13 +24,11 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.Action;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.timeline.actions.ViewArtifactInTimelineAction;
|
||||
import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
@@ -46,14 +44,14 @@ import static org.sleuthkit.autopsy.datamodel.Bundle.*;
|
||||
* tag name nodes have tag type child nodes; tag type nodes are the parents of
|
||||
* either content or blackboard artifact tag nodes.
|
||||
*/
|
||||
public class BlackboardArtifactTagNode extends DisplayableItemNode {
|
||||
public class BlackboardArtifactTagNode extends TagNode {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(BlackboardArtifactTagNode.class.getName());
|
||||
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/green-tag-icon-16.png"; //NON-NLS
|
||||
private final BlackboardArtifactTag tag;
|
||||
|
||||
public BlackboardArtifactTagNode(BlackboardArtifactTag tag) {
|
||||
super(Children.LEAF, Lookups.fixed(tag, tag.getArtifact(), tag.getContent()));
|
||||
super(Lookups.fixed(tag, tag.getArtifact(), tag.getContent()), tag.getContent());
|
||||
super.setName(tag.getContent().getName());
|
||||
super.setDisplayName(tag.getContent().getName());
|
||||
this.setIconBaseWithExtension(ICON_PATH);
|
||||
@@ -75,6 +73,7 @@ public class BlackboardArtifactTagNode extends DisplayableItemNode {
|
||||
NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagNode.createSheet.srcFile.text"),
|
||||
"",
|
||||
tag.getContent().getName()));
|
||||
addOriginalNameProp(properties);
|
||||
String contentPath;
|
||||
try {
|
||||
contentPath = tag.getContent().getUniquePath();
|
||||
@@ -82,7 +81,6 @@ public class BlackboardArtifactTagNode extends DisplayableItemNode {
|
||||
Logger.getLogger(ContentTagNode.class.getName()).log(Level.SEVERE, "Failed to get path for content (id = " + tag.getContent().getId() + ")", ex); //NON-NLS
|
||||
contentPath = NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagNode.createSheet.unavail.text");
|
||||
}
|
||||
|
||||
properties.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagNode.createSheet.srcFilePath.text"),
|
||||
NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagNode.createSheet.srcFilePath.text"),
|
||||
@@ -146,11 +144,6 @@ public class BlackboardArtifactTagNode extends DisplayableItemNode {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
|
||||
@@ -11,8 +11,6 @@ ArtifactTypeNode.createSheet.childCnt.name=Child Count
|
||||
ArtifactTypeNode.createSheet.childCnt.displayName=Child Count
|
||||
ArtifactTypeNode.createSheet.childCnt.desc=no description
|
||||
BlackboardArtifactNode.noDesc.text=no description
|
||||
BlackboardArtifactNode.createSheet.srcFile.name=Source File
|
||||
BlackboardArtifactNode.createSheet.srcFile.displayName=Source File
|
||||
BlackboardArtifactNode.createSheet.ext.name=Extension
|
||||
BlackboardArtifactNode.createSheet.ext.displayName=Extension
|
||||
BlackboardArtifactNode.createSheet.mimeType.name=MIME Type
|
||||
|
||||
@@ -74,10 +74,12 @@ BlackboardArtifactNode.createSheet.path.displayName=Path
|
||||
BlackboardArtifactNode.createSheet.path.name=Path
|
||||
BlackboardArtifactNode.createSheet.score.displayName=S
|
||||
BlackboardArtifactNode.createSheet.score.name=S
|
||||
BlackboardArtifactNode.createSheet.srcFile.displayName=Source File
|
||||
BlackboardArtifactNode.createSheet.srcFile.name=Source File
|
||||
BlackboardArtifactNode.createSheet.srcFile.origDisplayName=Original Name
|
||||
BlackboardArtifactNode.createSheet.srcFile.origName=Original Name
|
||||
BlackboardArtifactNode.createSheet.taggedItem.description=Result or associated file has been tagged.
|
||||
BlackboardArtifactNode.createSheet.tags.displayName=Tags
|
||||
# {0} - artifactDisplayName
|
||||
BlackboardArtifactNode.displayName.artifact={0} Artifact
|
||||
BlackboardArtifactTagNode.createSheet.userName.text=User Name
|
||||
BlackboardArtifactTagNode.viewSourceArtifact.text=View Source Result
|
||||
Category.five=CAT-5: Non-pertinent
|
||||
@@ -88,6 +90,7 @@ Category.two=CAT-2: Child Exploitation (Non-Illegal/Age Difficult)
|
||||
Category.zero=CAT-0: Uncategorized
|
||||
ContentTagNode.createSheet.artifactMD5.displayName=MD5 Hash
|
||||
ContentTagNode.createSheet.artifactMD5.name=MD5 Hash
|
||||
ContentTagNode.createSheet.origFileName=Original Name
|
||||
ContentTagNode.createSheet.userName.text=User Name
|
||||
DeletedContent.allDelFilter.text=All
|
||||
DeletedContent.createSheet.filterType.desc=no description
|
||||
@@ -175,8 +178,6 @@ ArtifactTypeNode.createSheet.childCnt.name=Child Count
|
||||
ArtifactTypeNode.createSheet.childCnt.displayName=Child Count
|
||||
ArtifactTypeNode.createSheet.childCnt.desc=no description
|
||||
BlackboardArtifactNode.noDesc.text=no description
|
||||
BlackboardArtifactNode.createSheet.srcFile.name=Source File
|
||||
BlackboardArtifactNode.createSheet.srcFile.displayName=Source File
|
||||
BlackboardArtifactNode.createSheet.ext.name=Extension
|
||||
BlackboardArtifactNode.createSheet.ext.displayName=Extension
|
||||
BlackboardArtifactNode.createSheet.mimeType.name=MIME Type
|
||||
@@ -345,6 +346,8 @@ TagNameNode.bbArtTagTypeNodeKey.text=Result Tags
|
||||
TagNameNode.bookmark.text=Bookmark
|
||||
TagNameNode.createSheet.name.name=Name
|
||||
TagNameNode.createSheet.name.displayName=Name
|
||||
TagNode.propertySheet.origName=Original Name
|
||||
TagNode.propertySheet.origNameDisplayName=Original Name
|
||||
TagsNode.displayName.text=Tags
|
||||
TagsNode.createSheet.name.name=Name
|
||||
TagsNode.createSheet.name.displayName=Name
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013-2016 Basis Technology Corp.
|
||||
* Copyright 2013-2020 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -24,7 +24,6 @@ import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.Action;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
@@ -39,18 +38,16 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
/**
|
||||
* Instances of this class wrap ContentTag objects. In the Autopsy presentation
|
||||
* of the SleuthKit data model, they are leaf nodes of a tree consisting of
|
||||
* content and blackboard artifact tags, grouped first by tag type, then by tag
|
||||
* name.
|
||||
* content and artifact tags, grouped first by tag type, then by tag name.
|
||||
*/
|
||||
class ContentTagNode extends DisplayableItemNode {
|
||||
class ContentTagNode extends TagNode {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(ContentTagNode.class.getName());
|
||||
|
||||
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/blue-tag-icon-16.png"; //NON-NLS
|
||||
private final ContentTag tag;
|
||||
|
||||
public ContentTagNode(ContentTag tag) {
|
||||
super(Children.LEAF, Lookups.fixed(tag, tag.getContent()));
|
||||
ContentTagNode(ContentTag tag) {
|
||||
super(Lookups.fixed(tag, tag.getContent()), tag.getContent());
|
||||
super.setName(tag.getContent().getName());
|
||||
super.setDisplayName(tag.getContent().getName());
|
||||
this.setIconBaseWithExtension(ICON_PATH);
|
||||
@@ -58,6 +55,7 @@ class ContentTagNode extends DisplayableItemNode {
|
||||
}
|
||||
|
||||
@Messages({
|
||||
"ContentTagNode.createSheet.origFileName=Original Name",
|
||||
"ContentTagNode.createSheet.artifactMD5.displayName=MD5 Hash",
|
||||
"ContentTagNode.createSheet.artifactMD5.name=MD5 Hash",
|
||||
"ContentTagNode.createSheet.userName.text=User Name"})
|
||||
@@ -79,15 +77,19 @@ class ContentTagNode extends DisplayableItemNode {
|
||||
properties = Sheet.createPropertiesSet();
|
||||
propertySheet.put(properties);
|
||||
}
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.file.name"),
|
||||
properties.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.file.name"),
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.file.displayName"),
|
||||
"",
|
||||
content.getName()));
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.filePath.name"),
|
||||
addOriginalNameProp(properties);
|
||||
properties.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.filePath.name"),
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.filePath.displayName"),
|
||||
"",
|
||||
contentPath));
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.comment.name"),
|
||||
properties.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.comment.name"),
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.comment.displayName"),
|
||||
"",
|
||||
tag.getComment()));
|
||||
@@ -95,23 +97,28 @@ class ContentTagNode extends DisplayableItemNode {
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileModifiedTime.displayName"),
|
||||
"",
|
||||
file != null ? ContentUtils.getStringTime(file.getMtime(), file) : ""));
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileChangedTime.name"),
|
||||
properties.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileChangedTime.name"),
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileChangedTime.displayName"),
|
||||
"",
|
||||
file != null ? ContentUtils.getStringTime(file.getCtime(), file) : ""));
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileAccessedTime.name"),
|
||||
properties.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileAccessedTime.name"),
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileAccessedTime.displayName"),
|
||||
"",
|
||||
file != null ? ContentUtils.getStringTime(file.getAtime(), file) : ""));
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileCreatedTime.name"),
|
||||
properties.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileCreatedTime.name"),
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileCreatedTime.displayName"),
|
||||
"",
|
||||
file != null ? ContentUtils.getStringTime(file.getCrtime(), file) : ""));
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileSize.name"),
|
||||
properties.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileSize.name"),
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileSize.displayName"),
|
||||
"",
|
||||
content.getSize()));
|
||||
properties.put(new NodeProperty<>(Bundle.ContentTagNode_createSheet_artifactMD5_name(),
|
||||
properties.put(new NodeProperty<>(
|
||||
Bundle.ContentTagNode_createSheet_artifactMD5_name(),
|
||||
Bundle.ContentTagNode_createSheet_artifactMD5_displayName(),
|
||||
"",
|
||||
file != null ? StringUtils.defaultString(file.getMd5Hash()) : ""));
|
||||
@@ -128,8 +135,7 @@ class ContentTagNode extends DisplayableItemNode {
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.addAll(Arrays.asList(super.getActions(context)));
|
||||
|
||||
AbstractFile file = getLookup().lookup(AbstractFile.class
|
||||
);
|
||||
AbstractFile file = getLookup().lookup(AbstractFile.class);
|
||||
if (file != null) {
|
||||
actions.add(ViewFileInTimelineAction.createViewFileAction(file));
|
||||
}
|
||||
@@ -144,13 +150,9 @@ class ContentTagNode extends DisplayableItemNode {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2017 Basis Technology Corp.
|
||||
* Copyright 2012-2020 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.Lookup;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
@@ -142,4 +143,26 @@ public abstract class DisplayableItemNode extends AbstractNode {
|
||||
return selectedChildNodeInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the node property sheet by replacing existing properties with new
|
||||
* properties with the same property name.
|
||||
*
|
||||
* @param newProps The replacement property objects.
|
||||
*/
|
||||
protected synchronized final void updatePropertySheet(NodeProperty<?>... newProps) {
|
||||
Sheet currentSheet = this.getSheet();
|
||||
Sheet.Set currentPropsSet = currentSheet.get(Sheet.PROPERTIES);
|
||||
Property<?>[] currentProps = currentPropsSet.getProperties();
|
||||
for (NodeProperty<?> newProp : newProps) {
|
||||
for (int i = 0; i < currentProps.length; i++) {
|
||||
if (currentProps[i].getName().equals(newProp.getName())) {
|
||||
currentProps[i] = newProp;
|
||||
}
|
||||
}
|
||||
}
|
||||
currentPropsSet.put(currentProps);
|
||||
currentSheet.put(currentPropsSet);
|
||||
this.setSheet(currentSheet);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020-2020 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.datamodel;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.datamodel.utils.FileNameTransTask;
|
||||
import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
|
||||
/**
|
||||
* An abstract superclass for a node that represents a tag, uses the name of a
|
||||
* given Content object as its display name, and has a property sheet with an
|
||||
* original name property when machine translation is enabled.
|
||||
*
|
||||
* The translation of the Content name is done in a background thread. The
|
||||
* translated name is made the display name of the node and the untranslated
|
||||
* name is put into both the original name property and into the node's tooltip.
|
||||
*
|
||||
* TODO (Jira-6174): Consider modifying this class to be able to use it more broadly
|
||||
* within the Autopsy data model (i.e., AbstractNode suclasses). It's not really
|
||||
* specific to a tag node.
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"TagNode.propertySheet.origName=Original Name",
|
||||
"TagNode.propertySheet.origNameDisplayName=Original Name"
|
||||
})
|
||||
abstract class TagNode extends DisplayableItemNode {
|
||||
|
||||
private final static String ORIG_NAME_PROP_NAME = Bundle.TagNode_propertySheet_origName();
|
||||
private final static String ORIG_NAME_PROP_DISPLAY_NAME = Bundle.TagNode_propertySheet_origNameDisplayName();
|
||||
|
||||
private final String originalName;
|
||||
private volatile String translatedName;
|
||||
|
||||
/**
|
||||
* An abstract superclass for a node that represents a tag, uses the name of
|
||||
* a given Content object as its display name, and has a property sheet with
|
||||
* an untranslated file name property when machine translation is enabled.
|
||||
*
|
||||
* @param lookup The Lookup of the node.
|
||||
* @param content The Content to use for the node display name.
|
||||
*/
|
||||
TagNode(Lookup lookup, Content content) {
|
||||
super(Children.LEAF, lookup);
|
||||
originalName = content.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
abstract public String getItemType();
|
||||
|
||||
@Override
|
||||
abstract public <T> T accept(DisplayableItemNodeVisitor<T> visitor);
|
||||
|
||||
/**
|
||||
* Adds an original name property to the node's property sheet and submits
|
||||
* an original name translation task.
|
||||
*
|
||||
* The translation of the original name is done in a background thread. The
|
||||
* translated name is made the display name of the node and the untranslated
|
||||
* name is put into both the original name property and into the node's
|
||||
* tooltip.
|
||||
*
|
||||
* @param properties The node's property sheet.
|
||||
*/
|
||||
protected void addOriginalNameProp(Sheet.Set properties) {
|
||||
if (TextTranslationService.getInstance().hasProvider() && UserPreferences.displayTranslatedFileNames()) {
|
||||
properties.put(new NodeProperty<>(
|
||||
ORIG_NAME_PROP_NAME,
|
||||
ORIG_NAME_PROP_DISPLAY_NAME,
|
||||
"",
|
||||
translatedName != null ? originalName : ""));
|
||||
if (translatedName == null) {
|
||||
new FileNameTransTask(originalName, this, new NameTranslationListener()).submit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A listener for PropertyChangeEvents from a background task used to
|
||||
* translate the original display name associated with the node.
|
||||
*/
|
||||
private class NameTranslationListener implements PropertyChangeListener {
|
||||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
String eventType = evt.getPropertyName();
|
||||
if (eventType.equals(FileNameTransTask.getPropertyName())) {
|
||||
translatedName = evt.getNewValue().toString();
|
||||
String originalName = evt.getOldValue().toString();
|
||||
setDisplayName(translatedName);
|
||||
setShortDescription(originalName);
|
||||
updatePropertySheet(new NodeProperty<>(
|
||||
ORIG_NAME_PROP_NAME,
|
||||
ORIG_NAME_PROP_DISPLAY_NAME,
|
||||
"",
|
||||
originalName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -64,7 +64,7 @@ public abstract class AbstractNodePropertySheetTask<T extends AbstractNode> impl
|
||||
* @return The Future of the task, may be used for task cancellation by
|
||||
* calling Future.cancel(true).
|
||||
*/
|
||||
public static Future<?> submitTask(AbstractNodePropertySheetTask<?> task) {
|
||||
private static Future<?> submitTask(AbstractNodePropertySheetTask<?> task) {
|
||||
return executor.submit(task);
|
||||
}
|
||||
|
||||
@@ -104,12 +104,22 @@ public abstract class AbstractNodePropertySheetTask<T extends AbstractNode> impl
|
||||
*
|
||||
* @param node The AbstractNode.
|
||||
*
|
||||
* @return The result of the computation as a PropertyChangeEvent.
|
||||
* @return The result of the computation as a PropertyChangeEvent, may be
|
||||
* null.
|
||||
*/
|
||||
protected abstract PropertyChangeEvent computePropertyValue(T node) throws Exception;
|
||||
|
||||
/**
|
||||
* Submits this task to the ExecutorService for the thread pool.
|
||||
*
|
||||
* @return The task's Future from the ExecutorService.
|
||||
*/
|
||||
public final Future<?> submit() {
|
||||
return submitTask(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
final public void run() {
|
||||
public final void run() {
|
||||
try {
|
||||
T node = this.weakNodeRef.get();
|
||||
PropertyChangeListener listener = this.weakListenerRef.get();
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 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.datamodel.utils;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.sleuthkit.autopsy.texttranslation.utils.FileNameTranslationUtil;
|
||||
|
||||
/**
|
||||
* An AbstractNodePropertySheetTask that translates a file name for an
|
||||
* AbstractNode's property sheet.
|
||||
*/
|
||||
public class FileNameTransTask extends AbstractNodePropertySheetTask<AbstractNode> {
|
||||
|
||||
private final static String EVENT_SOURCE = FileNameTransTask.class.getName();
|
||||
private final static String PROPERTY_NAME = EVENT_SOURCE + ".TranslatedFileName";
|
||||
private final String fileName;
|
||||
|
||||
public static String getPropertyName() {
|
||||
return PROPERTY_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an AbstractNodePropertySheetTask that translates a file name
|
||||
* for an AbstractNode's property sheet. When the translation is complete, a
|
||||
* PropertyChangeEvent will be fired to the node's PropertyChangeListener.
|
||||
* Call getPropertyName() to identify the property.
|
||||
*
|
||||
* @param node The node.
|
||||
* @param listener The node's PropertyChangeListener.
|
||||
* @param fileName THe file name.
|
||||
*/
|
||||
public FileNameTransTask(String fileName, AbstractNode node, PropertyChangeListener listener) {
|
||||
super(node, listener);
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PropertyChangeEvent computePropertyValue(AbstractNode node) throws Exception {
|
||||
String translatedFileName = FileNameTranslationUtil.translate(fileName);
|
||||
return translatedFileName.isEmpty() ? null : new PropertyChangeEvent(EVENT_SOURCE, PROPERTY_NAME, fileName, translatedFileName);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2019 Basis Technology Corp.
|
||||
* Copyright 2012-2020 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -187,27 +187,6 @@ public class DataResultFilterNode extends FilterNode {
|
||||
return propertySets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the display name for the wrapped node.
|
||||
*
|
||||
* OutlineView used in the DataResult table uses getDisplayName() to
|
||||
* populate the first column, which is Source File.
|
||||
*
|
||||
* Hence this override to return the 'correct' displayName for the wrapped
|
||||
* node.
|
||||
*
|
||||
* @return The display name for the node.
|
||||
*/
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
final Node orig = getOriginal();
|
||||
String name = orig.getDisplayName();
|
||||
if ((orig instanceof BlackboardArtifactNode)) {
|
||||
name = ((BlackboardArtifactNode) orig).getSourceName();
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds information about which child node of this node, if any, should be
|
||||
* selected. Can be null.
|
||||
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020-2020 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.utils;
|
||||
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.sleuthkit.autopsy.texttranslation.NoServiceProviderException;
|
||||
import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
|
||||
import org.sleuthkit.autopsy.texttranslation.TranslationException;
|
||||
|
||||
/**
|
||||
* A utility to translate file names.
|
||||
*/
|
||||
public final class FileNameTranslationUtil {
|
||||
|
||||
/**
|
||||
* Translates a file name using the configured machine translation service.
|
||||
*
|
||||
* @param fileName The file name.
|
||||
*
|
||||
* @return The translation of the file name.
|
||||
*
|
||||
* @throws NoServiceProviderException If machine translation is not
|
||||
* configured.
|
||||
* @throws TranslationException If there is an error doing the
|
||||
* translation.
|
||||
*/
|
||||
public static String translate(String fileName) throws NoServiceProviderException, TranslationException {
|
||||
/*
|
||||
* Don't attempt translation if the characters of the file name are all
|
||||
* ASCII chars.
|
||||
*
|
||||
* TODO (Jira-6175): This filter prevents translation of many
|
||||
* non-English file names composed entirely of Latin chars.
|
||||
*/
|
||||
if (fileName.matches("^\\p{ASCII}+$")) {
|
||||
return "";
|
||||
}
|
||||
|
||||
TextTranslationService translator = TextTranslationService.getInstance();
|
||||
String baseName = FilenameUtils.getBaseName(fileName);
|
||||
String translation = translator.translate(baseName);
|
||||
if (!translation.isEmpty()) {
|
||||
String extension = FilenameUtils.getExtension(fileName);
|
||||
if (!extension.isEmpty()) {
|
||||
String extensionDelimiter = (extension.isEmpty()) ? "" : ".";
|
||||
translation += extensionDelimiter + extension;
|
||||
}
|
||||
}
|
||||
return translation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent instantiation of this utility class
|
||||
*/
|
||||
private FileNameTranslationUtil() {
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user