fix bugs, validate ammount spinner,a dd View in Timeine action to a few more palces

This commit is contained in:
jmillman 2016-06-16 17:12:10 -04:00
parent 9350a0fac7
commit fe7daed3fc
8 changed files with 120 additions and 18 deletions

View File

@ -130,7 +130,7 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
try {
AbstractFile c = findLinked(artifact);
if (c != null) {
actionsList.add(new ViewFileInTimelineAction(c, false));
actionsList.add(ViewFileInTimelineAction.createViewFileAction(c));
}
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, MessageFormat.format("Error getting linked file from blackboard artifact{0}.", artifact.getArtifactID()), ex); //NON-NLS
@ -140,7 +140,7 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
//if this artifact has associated content, add the action to view the content in the timeline
AbstractFile file = getLookup().lookup(AbstractFile.class);
if (null != file) {
actionsList.add(new ViewFileInTimelineAction(file, true));
actionsList.add(ViewFileInTimelineAction.createViewSourceFileAction(file));
}
return actionsList.toArray(new Action[actionsList.size()]);

View File

@ -27,6 +27,7 @@ import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Directory;
import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM;
@ -80,12 +81,13 @@ public class DirectoryNode extends AbstractFsContentNode<AbstractFile> {
actions.add(null); // creates a menu separator
}
actions.add(new NewWindowViewAction(NbBundle.getMessage(this.getClass(), "DirectoryNode.viewInNewWin.text"), this));
actions.add(ViewFileInTimelineAction.createViewFileAction(getContent()));
actions.add(null); // creates a menu separator
actions.add(ExtractAction.getInstance());
actions.add(null); // creates a menu separator
actions.add(AddContentTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions());
return actions.toArray(new Action[0]);
return actions.toArray(new Action[actions.size()]);
}
@Override

View File

@ -89,7 +89,7 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
}
actionsList.add(new NewWindowViewAction(Bundle.FileNode_getActions_viewInNewWin_text(), this));
actionsList.add(new ExternalViewerAction(Bundle.FileNode_getActions_openInExtViewer_text(), this));
actionsList.add(new ViewFileInTimelineAction(getContent(), false));
actionsList.add(ViewFileInTimelineAction.createViewFileAction(getContent()));
actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance());

View File

@ -47,8 +47,11 @@ import javafx.scene.control.TableView;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;
import javafx.stage.Modality;
import javafx.util.StringConverter;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.WordUtils;
import org.controlsfx.validation.ValidationSupport;
import org.controlsfx.validation.Validator;
import org.joda.time.Interval;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
@ -106,6 +109,7 @@ final class ShowInTimelineDialog extends Dialog<ViewInTimelineRequestedEvent> {
ChronoField.HOUR_OF_DAY,
ChronoField.MINUTE_OF_HOUR,
ChronoField.SECOND_OF_MINUTE);
private final ValidationSupport validationSupport;
/**
* Common Private Constructor
@ -114,6 +118,9 @@ final class ShowInTimelineDialog extends Dialog<ViewInTimelineRequestedEvent> {
* @param eventIDS A List of eventIDs to present to the user to choose
* from.
*/
@NbBundle.Messages({
"ShowInTimelineDialog.amountValidator.message=The entered amount must be parsable as a number.",
"ShowInTimelineDialog.eventSelectionValidator.message=You must select an event."})
private ShowInTimelineDialog(TimeLineController controller, List<Long> eventIDS) {
this.controller = controller;
@ -135,6 +142,17 @@ final class ShowInTimelineDialog extends Dialog<ViewInTimelineRequestedEvent> {
assert amountSpinner != null : "fx:id=\"amountsSpinner\" was not injected: check your FXML file 'ShowInTimelineDialog.fxml'.";
assert unitComboBox != null : "fx:id=\"unitChoiceBox\" was not injected: check your FXML file 'ShowInTimelineDialog.fxml'.";
validationSupport = new ValidationSupport();
validationSupport.registerValidator(amountSpinner.getEditor(), false, Validator.createPredicateValidator((String value) -> {
try {
Double.parseDouble(value);
return true;
} catch (NumberFormatException ex) {
return false;
}
}, Bundle.ShowInTimelineDialog_amountValidator_message()));
//configure dialog properties
PromptDialogManager.setDialogIcons(this);
@ -148,6 +166,21 @@ final class ShowInTimelineDialog extends Dialog<ViewInTimelineRequestedEvent> {
///configure dialog controls
amountSpinner.setValueFactory(new SpinnerValueFactory.IntegerSpinnerValueFactory(1, 1000));
amountSpinner.getValueFactory().setConverter(new StringConverter<Integer>() {
@Override
public String toString(Integer object) {
return object.toString();
}
@Override
public Integer fromString(String string) {
try {
return Integer.valueOf(string);
} catch (NumberFormatException ex) {
return amountSpinner.getValue();
}
}
});
unitComboBox.setButtonCell(new ChronoFieldListCell());
unitComboBox.setCellFactory(comboBox -> new ChronoFieldListCell());
@ -182,6 +215,8 @@ final class ShowInTimelineDialog extends Dialog<ViewInTimelineRequestedEvent> {
chooseEventLabel.setManaged(false);
eventTable.getSelectionModel().select(0);
getDialogPane().lookupButton(SHOW).disableProperty().bind(validationSupport.invalidProperty());
//set result converter that does not require selection.
setResultConverter(buttonType -> {
if (buttonType == SHOW) {
@ -205,7 +240,7 @@ final class ShowInTimelineDialog extends Dialog<ViewInTimelineRequestedEvent> {
this(controller, controller.getEventsModel().getEventIDsForFile(file, false));
//require selection to enable show button
getDialogPane().lookupButton(SHOW).disableProperty().bind(eventTable.getSelectionModel().selectedItemProperty().isNull());
getDialogPane().lookupButton(SHOW).disableProperty().bind(validationSupport.invalidProperty().or(eventTable.getSelectionModel().selectedItemProperty().isNull()));
//set result converter that uses selection.
setResultConverter(buttonType -> {

View File

@ -32,17 +32,24 @@ import org.sleuthkit.datamodel.AbstractFile;
public final class ViewFileInTimelineAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private final AbstractFile file;
@NbBundle.Messages({"ViewFileInTimelineAction.fileSource.displayName=View File in Timeline... ",
"ViewFileInTimelineAction.artifactSource.displayName=View Source File in Timeline... "})
public ViewFileInTimelineAction(AbstractFile file, boolean isArtifactSource) {
super(isArtifactSource
? Bundle.ViewFileInTimelineAction_artifactSource_displayName()
: Bundle.ViewFileInTimelineAction_fileSource_displayName());
private ViewFileInTimelineAction(AbstractFile file, String displayName) {
super(displayName);
this.file = file;
}
@NbBundle.Messages({"ViewFileInTimelineAction.viewFile.displayName=View File in Timeline... "})
public static ViewFileInTimelineAction createViewFileAction(AbstractFile file) {
return new ViewFileInTimelineAction(file, Bundle.ViewFileInTimelineAction_viewFile_displayName());
}
@NbBundle.Messages({"ViewFileInTimelineAction.viewSourceFile.displayName=View Source File in Timeline... "})
public static ViewFileInTimelineAction createViewSourceFileAction(AbstractFile file) {
return new ViewFileInTimelineAction(file, Bundle.ViewFileInTimelineAction_viewSourceFile_displayName());
}
@Override
public void actionPerformed(ActionEvent e) {
SystemAction.get(OpenTimelineAction.class).showFileInTimeline(file);

View File

@ -19,6 +19,7 @@
package org.sleuthkit.autopsy.timeline.explorernodes;
import java.lang.reflect.InvocationTargetException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@ -33,16 +34,19 @@ import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.datamodel.DataModelActionsFactory;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
import org.sleuthkit.autopsy.datamodel.NodeProperty;
import org.sleuthkit.autopsy.timeline.TimeLineController;
import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction;
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
import org.sleuthkit.autopsy.timeline.datamodel.SingleEvent;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
@ -107,20 +111,70 @@ public class EventNode extends DisplayableItemNode {
}
@Override
@NbBundle.Messages({
"EventNode.getAction.errorTitle=Error getting actions",
"EventNode.getAction.linkedFileMessage=There was a problem getting actions for the selected result. "
+ " The 'View File in Timeline' action will not be available."})
public Action[] getActions(boolean context) {
Action[] superActions = super.getActions(context);
List<Action> actionsList = new ArrayList<>();
actionsList.addAll(Arrays.asList(superActions));
final Content content = getLookup().lookup(Content.class);
final BlackboardArtifact artifact = getLookup().lookup(BlackboardArtifact.class);
final AbstractFile sourceFile = getLookup().lookup(AbstractFile.class);
final List<Action> factoryActions = DataModelActionsFactory.getActions(content, artifact != null);
/*
* if this event is derived from an artifact, add actions to view the
* source file and a "linked" file, if present.
*/
final BlackboardArtifact artifact = getLookup().lookup(BlackboardArtifact.class);
if (artifact != null) {
try {
AbstractFile linkedfile = findLinked(artifact);
if (linkedfile != null) {
actionsList.add(ViewFileInTimelineAction.createViewFileAction(linkedfile));
}
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, MessageFormat.format("Error getting linked file from blackboard artifact{0}.", artifact.getArtifactID()), ex); //NON-NLS
MessageNotifyUtil.Notify.error(Bundle.EventNode_getAction_errorTitle(), Bundle.EventNode_getAction_linkedFileMessage());
}
//if this event has associated content, add the action to view the content in the timeline
if (null != sourceFile) {
actionsList.add(ViewFileInTimelineAction.createViewSourceFileAction(sourceFile));
}
}
//get default actions for the file
final List<Action> factoryActions = DataModelActionsFactory.getActions(sourceFile, artifact != null);
actionsList.addAll(factoryActions);
return actionsList.toArray(new Action[actionsList.size()]);
}
/**
* this code started as a cut and past of
* DataResultFilterNode.GetPopupActionsDisplayableItemNodeVisitor.findLinked(BlackboardArtifactNode
* ba)
*
*
* @param artifact
*
* @return
*/
static private AbstractFile findLinked(BlackboardArtifact artifact) throws TskCoreException {
BlackboardAttribute pathIDAttribute = artifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PATH_ID));
if (pathIDAttribute != null) {
long contentID = pathIDAttribute.getValueLong();
if (contentID != -1) {
return artifact.getSleuthkitCase().getAbstractFileById(contentID);
}
}
return null;
}
@Override
public boolean isLeafTypeNode() {
return true;

View File

@ -356,7 +356,7 @@ class ListTimeline extends BorderPane {
*/
private void scrollTo(Integer index) {
if (visibleEvents.contains(table.getItems().get(index)) == false) {
table.scrollTo(index);
table.scrollTo(index - visibleEvents.size() / 2);
}
}

View File

@ -111,9 +111,13 @@ public class ListViewPane extends AbstractTimeLineView {
FilteredEventsModel eventsModel = getEventsModel();
Set<Long> selectedEventIDs;
TimeLineController controller = getController();
//grab the currently selected event
Set<Long> selectedEventIDs = ImmutableSet.copyOf(getController().getSelectedEventIDs());
synchronized (controller) {
selectedEventIDs = ImmutableSet.copyOf(controller.getSelectedEventIDs());
}
//clear the chart and set the time range.
resetView(eventsModel.getTimeRange());