This commit is contained in:
Jeff Wallace 2013-09-10 14:46:57 -04:00
commit c754648924
16 changed files with 1556 additions and 250 deletions

View File

@ -18,11 +18,11 @@
*/ */
package org.sleuthkit.autopsy.core; package org.sleuthkit.autopsy.core;
import com.sun.javafx.application.PlatformImpl;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.openide.modules.ModuleInstall; import org.openide.modules.ModuleInstall;
import org.openide.windows.WindowManager; import org.openide.windows.WindowManager;
@ -37,10 +37,11 @@ public class Installer extends ModuleInstall {
private List<ModuleInstall> packageInstallers; private List<ModuleInstall> packageInstallers;
private static final Logger logger = Logger.getLogger(Installer.class.getName()); private static final Logger logger = Logger.getLogger(Installer.class.getName());
private volatile boolean javaFxInit = true; private static volatile boolean javaFxInit = false;
public Installer() { public Installer() {
javaFxInit = true; logger.log(Level.INFO, "core installer created");
javaFxInit = false;
packageInstallers = new ArrayList<ModuleInstall>(); packageInstallers = new ArrayList<ModuleInstall>();
packageInstallers.add(org.sleuthkit.autopsy.coreutils.Installer.getDefault()); packageInstallers.add(org.sleuthkit.autopsy.coreutils.Installer.getDefault());
@ -54,23 +55,20 @@ public class Installer extends ModuleInstall {
* Check if JavaFx initialized * Check if JavaFx initialized
* @return false if java fx not initialized (classes coult not load), true if initialized * @return false if java fx not initialized (classes coult not load), true if initialized
*/ */
public boolean isJavaFxInited() { public static boolean isJavaFxInited() {
return this.javaFxInit; return javaFxInit;
} }
private void initJavaFx() { private static void initJavaFx() {
//initialize java fx if exists //initialize java fx if exists
System.setProperty("javafx.macosx.embedded", "true");
try { try {
// Creating a JFXPanel initializes JavaFX
new JFXPanel();
Platform.setImplicitExit(false); Platform.setImplicitExit(false);
PlatformImpl.startup(new Runnable() { javaFxInit = true;
@Override
public void run() {
logger.log(Level.INFO, "Initializing JavaFX for image viewing");
}
});
} catch (UnsatisfiedLinkError | NoClassDefFoundError | Exception e) { } catch (UnsatisfiedLinkError | NoClassDefFoundError | Exception e) {
//in case javafx not present //in case javafx not present
javaFxInit = false;
final String msg = "Error initializing JavaFX. "; final String msg = "Error initializing JavaFX. ";
final String details = " Some features will not be available. " final String details = " Some features will not be available. "
+ " Check that you have the right JRE installed (Oracle JRE > 1.7.10). "; + " Check that you have the right JRE installed (Oracle JRE > 1.7.10). ";

View File

@ -361,6 +361,7 @@
<attr name="originalFile" stringvalue="Actions/Tools/org-sleuthkit-autopsy-ingest-IngestMessagesAction.instance"/> <attr name="originalFile" stringvalue="Actions/Tools/org-sleuthkit-autopsy-ingest-IngestMessagesAction.instance"/>
</file> </file>
</folder> </folder>
<folder name="QuickSearch_hidden" />
</folder> </folder>

View File

@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.corecomponentinterfaces;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.openide.util.Lookup; import org.openide.util.Lookup;
@ -71,17 +72,47 @@ public class CoreComponentControl {
/** /**
* Closes all TopComponent windows that needed ({@link DataExplorer}, {@link DataResult}, and * Closes all TopComponent windows that needed ({@link DataExplorer}, {@link DataResult}, and
* {@link DataContent}) * {@link DataContent}).
*
* Note: The DataContent Top Component must be closed before the Directory Tree
* and Favorites Top Components. Otherwise a NullPointerException will be thrown
* from JFXPanel.
*/ */
public static void closeCoreWindows() { public static void closeCoreWindows() {
WindowManager wm = WindowManager.getDefault(); WindowManager wm = WindowManager.getDefault();
Set<? extends Mode> modes = wm.getModes();
Iterator<? extends Mode> iter = wm.getModes().iterator(); Iterator<? extends Mode> iter = wm.getModes().iterator();
TopComponent directoryTree = null;
TopComponent favorites = null;
String tcName = "";
while (iter.hasNext()) { while (iter.hasNext()) {
Mode mode = iter.next(); Mode mode = iter.next();
for (TopComponent tc : mode.getTopComponents()) { for (TopComponent tc : mode.getTopComponents()) {
tcName = tc.getName();
if (tcName == null) {
logger.log(Level.INFO, "tcName was null");
tcName = "";
}
switch (tcName) {
case "Directory Tree":
directoryTree = tc;
break;
case "Favorites":
favorites = tc;
break;
default:
tc.close(); tc.close();
break;
} }
} }
} }
if (directoryTree != null) {
directoryTree.close();
}
if (favorites != null) {
favorites.close();
}
}
} }

View File

@ -189,8 +189,7 @@ public class DataContentPanel extends javax.swing.JPanel implements DataContent,
// let the user decide if we should stay with the current viewer // let the user decide if we should stay with the current viewer
int tabIndex = keepCurrentViewer ? currTabIndex : preferredViewerIndex; int tabIndex = keepCurrentViewer ? currTabIndex : preferredViewerIndex;
// set the tab to the one the user wants, then set that viewer's node.
jTabbedPane1.setSelectedIndex(tabIndex);
UpdateWrapper dcv = viewers.get(tabIndex); UpdateWrapper dcv = viewers.get(tabIndex);
// this is really only needed if no tabs were enabled // this is really only needed if no tabs were enabled
if (jTabbedPane1.isEnabledAt(tabIndex) == false) { if (jTabbedPane1.isEnabledAt(tabIndex) == false) {
@ -199,6 +198,9 @@ public class DataContentPanel extends javax.swing.JPanel implements DataContent,
else { else {
dcv.setNode(selectedNode); dcv.setNode(selectedNode);
} }
// set the tab to the one the user wants, then set that viewer's node.
jTabbedPane1.setSelectedIndex(tabIndex);
} }
@Override @Override

View File

@ -128,7 +128,7 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
return; //prevent from loading twice if setNode() called mult. times return; //prevent from loading twice if setNode() called mult. times
} }
resetComponent(); lastFile = file;
final Dimension dims = DataContentViewerMedia.this.getSize(); final Dimension dims = DataContentViewerMedia.this.getSize();
@ -140,7 +140,7 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
videoPanel.setupVideo(file, dims); videoPanel.setupVideo(file, dims);
switchPanels(true); switchPanels(true);
} }
lastFile = file;
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.SEVERE, "Exception while setting node", e); logger.log(Level.SEVERE, "Exception while setting node", e);
} }
@ -182,8 +182,8 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
@Override @Override
public void resetComponent() { public void resetComponent() {
videoPanel.reset(); // No need to reset the video panel. It resets itself when a node is
// @@@ Seems like we should also reset the image viewer... // set.
lastFile = null; lastFile = null;
} }

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.4" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Properties>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" red="0" type="rgb"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout"/>
</Form>

View File

@ -18,14 +18,13 @@
*/ */
package org.sleuthkit.autopsy.corecomponents; package org.sleuthkit.autopsy.corecomponents;
import com.sun.javafx.application.PlatformImpl;
import java.awt.Component;
import java.awt.Dimension; import java.awt.Dimension;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.List; import java.util.List;
import java.util.concurrent.CancellationException; import java.util.concurrent.CancellationException;
import java.util.logging.Level; import java.util.logging.Level;
import javafx.application.Platform;
import javafx.beans.InvalidationListener; import javafx.beans.InvalidationListener;
import javafx.beans.Observable; import javafx.beans.Observable;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
@ -45,19 +44,23 @@ import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority; import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.scene.media.Media; import javafx.scene.media.Media;
import javafx.scene.media.MediaBuilder;
import javafx.scene.media.MediaException; import javafx.scene.media.MediaException;
import javafx.scene.media.MediaPlayer; import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaPlayer.Status; import javafx.scene.media.MediaPlayer.Status;
import static javafx.scene.media.MediaPlayer.Status.PAUSED;
import static javafx.scene.media.MediaPlayer.Status.PLAYING;
import static javafx.scene.media.MediaPlayer.Status.READY; import static javafx.scene.media.MediaPlayer.Status.READY;
import static javafx.scene.media.MediaPlayer.Status.STOPPED;
import javafx.scene.media.MediaPlayerBuilder;
import javafx.scene.media.MediaView; import javafx.scene.media.MediaView;
import javafx.scene.text.Font;
import javafx.util.Duration; import javafx.util.Duration;
import javax.swing.BoxLayout;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.SwingWorker; import javax.swing.SwingWorker;
import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory; import org.netbeans.api.progress.ProgressHandleFactory;
import org.openide.modules.ModuleInstall;
import org.openide.util.Cancellable; import org.openide.util.Cancellable;
import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProvider;
import org.openide.util.lookup.ServiceProviders; import org.openide.util.lookup.ServiceProviders;
@ -67,6 +70,7 @@ import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.autopsy.core.Installer;
/** /**
* Video viewer part of the Media View layered pane. * Video viewer part of the Media View layered pane.
@ -79,7 +83,6 @@ public class FXVideoPanel extends MediaViewVideoPanel {
private static final Logger logger = Logger.getLogger(MediaViewVideoPanel.class.getName()); private static final Logger logger = Logger.getLogger(MediaViewVideoPanel.class.getName());
private boolean fxInited = false; private boolean fxInited = false;
// FX Components // FX Components
private MediaPlayer fxMediaPlayer;
private MediaPane mediaPane; private MediaPane mediaPane;
// Current media content representations // Current media content representations
private AbstractFile currentFile; private AbstractFile currentFile;
@ -90,35 +93,53 @@ public class FXVideoPanel extends MediaViewVideoPanel {
* Creates new form MediaViewVideoPanel * Creates new form MediaViewVideoPanel
*/ */
public FXVideoPanel() { public FXVideoPanel() {
org.sleuthkit.autopsy.core.Installer coreInstaller = fxInited = Installer.isJavaFxInited();
ModuleInstall.findObject(org.sleuthkit.autopsy.core.Installer.class, false);
if (coreInstaller != null) {
fxInited = coreInstaller.isJavaFxInited();
}
initComponents(); initComponents();
customizeComponents(); if (fxInited) {
setupFx();
}
} }
public JPanel getVideoPanel() { public JPanel getVideoPanel() {
return videoPanel; return this;
} }
public Component getVideoComponent() { private void setupFx() {
return videoComponent; Platform.runLater(new Runnable() {
} @Override
public void run() {
videoComponent = new JFXPanel();
mediaPane = new MediaPane();
Scene fxScene = new Scene(mediaPane);
videoComponent.setScene(fxScene);
private void customizeComponents() { SwingUtilities.invokeLater(new Runnable() {
setupFx(); @Override
public void run() {
add(videoComponent);
}
});
}
});
} }
@Override @Override
synchronized void setupVideo(final AbstractFile file, final Dimension dims) { void setupVideo(final AbstractFile file, final Dimension dims) {
if(file.equals(currentFile)) {
return;
}
if (!Case.isCaseOpen()) {
//handle in-between condition when case is being closed
//and an image was previously selected
return;
}
reset();
currentFile = file; currentFile = file;
final boolean deleted = file.isDirNameFlagSet(TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC); final boolean deleted = file.isDirNameFlagSet(TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC);
if (deleted) { if (deleted) {
mediaPane.setInfoLabelText("Playback of deleted videos is not supported, use an external player."); mediaPane.setInfoLabelText("Playback of deleted videos is not supported, use an external player.");
videoPanel.removeAll(); removeAll();
return; return;
} }
@ -133,56 +154,22 @@ public class FXVideoPanel extends MediaViewVideoPanel {
ExtractMedia em = new ExtractMedia(currentFile, getJFile(currentFile)); ExtractMedia em = new ExtractMedia(currentFile, getJFile(currentFile));
em.execute(); em.execute();
mediaPane.setFit(dims);
} }
synchronized void setupFx() {
if(!fxInited) {
return;
}
logger.log(Level.INFO, "In Setup FX");
PlatformImpl.runLater(new Runnable() {
@Override
public void run() {
mediaPane = new MediaPane();
logger.log(Level.INFO, "Created MediaPane");
Scene fxScene = new Scene(mediaPane);
videoComponent = new JFXPanel();
videoComponent.setScene(fxScene);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
// Configure VideoPanel
videoPanel.removeAll();
videoPanel.setLayout(new BoxLayout(videoPanel, BoxLayout.Y_AXIS));
videoPanel.add(videoComponent);
videoPanel.setVisible(true);
}
});
}
});
}
@Override @Override
void reset() { void reset() {
Platform.runLater(new Runnable() {
PlatformImpl.runLater(new Runnable() {
@Override @Override
public void run() { public void run() {
if (fxMediaPlayer != null) { if (mediaPane != null) {
if (fxMediaPlayer.getStatus() == MediaPlayer.Status.PLAYING ) { mediaPane.reset();
fxMediaPlayer.stop();
}
fxMediaPlayer = null;
}
if (videoComponent != null) {
videoComponent = null;
} }
} }
}); });
currentFile = null; currentFile = null;
} }
@ -207,37 +194,14 @@ public class FXVideoPanel extends MediaViewVideoPanel {
* regenerated by the Form Editor. * regenerated by the Form Editor.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code"> // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() { private void initComponents() {
videoPanel = new javax.swing.JPanel(); setBackground(new java.awt.Color(0, 0, 0));
setLayout(new javax.swing.BoxLayout(this, javax.swing.BoxLayout.LINE_AXIS));
javax.swing.GroupLayout videoPanelLayout = new javax.swing.GroupLayout(videoPanel); }// </editor-fold>//GEN-END:initComponents
videoPanel.setLayout(videoPanelLayout); // Variables declaration - do not modify//GEN-BEGIN:variables
videoPanelLayout.setHorizontalGroup( // End of variables declaration//GEN-END:variables
videoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 448, Short.MAX_VALUE)
);
videoPanelLayout.setVerticalGroup(
videoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 248, Short.MAX_VALUE)
);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(videoPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(videoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
}// </editor-fold>
// Variables declaration - do not modify
private javax.swing.JPanel videoPanel;
// End of variables declaration
@Override @Override
public boolean isInited() { public boolean isInited() {
@ -265,8 +229,13 @@ public class FXVideoPanel extends MediaViewVideoPanel {
return extractedBytes; return extractedBytes;
} }
public Media getMedia() { /**
return new Media(Paths.get(jFile.getAbsolutePath()).toUri().toString()); * Get the URI of the media file.
*
* @return the URI of the media file.
*/
public String getMediaUri() {
return Paths.get(jFile.getAbsolutePath()).toUri().toString();
} }
@Override @Override
@ -307,13 +276,10 @@ public class FXVideoPanel extends MediaViewVideoPanel {
if (!this.isCancelled()) { if (!this.isCancelled()) {
logger.log(Level.INFO, "ExtractMedia in done: " + jFile.getName()); logger.log(Level.INFO, "ExtractMedia in done: " + jFile.getName());
try { try {
PlatformImpl.runLater(new Runnable() { Platform.runLater(new Runnable() {
@Override @Override
public void run() { public void run() {
fxMediaPlayer = new MediaPlayer(getMedia()); mediaPane.prepareMedia(getMediaUri());
logger.log(Level.INFO, "Fx Media Player null? " + (fxMediaPlayer == null));
logger.log(Level.INFO, "Media Tools null? " + (mediaPane == null));
mediaPane.setMediaPlayer(fxMediaPlayer);
} }
}); });
} catch(MediaException e) { } catch(MediaException e) {
@ -327,14 +293,27 @@ public class FXVideoPanel extends MediaViewVideoPanel {
} }
} }
/**
* The JavaFX Component that contains the Media and it's Controls.
*
*/
private class MediaPane extends BorderPane { private class MediaPane extends BorderPane {
private MediaPlayer mediaPlayer; private MediaPlayer mediaPlayer;
private MediaView mediaView; private MediaView mediaView;
/** The Duration of the media. **/
private Duration duration; private Duration duration;
/** The container for the media controls. **/
private HBox mediaTools; private HBox mediaTools;
/** The container for the media video output. **/
private HBox mediaViewPane; private HBox mediaViewPane;
private VBox controlPanel;
private Slider progressSlider; private Slider progressSlider;
private Button pauseButton; private Button pauseButton;
private Button stopButton;
private Label progressLabel; private Label progressLabel;
private Label infoLabel; private Label infoLabel;
private int totalHours; private int totalHours;
@ -342,6 +321,36 @@ public class FXVideoPanel extends MediaViewVideoPanel {
private int totalSeconds; private int totalSeconds;
private String durationFormat = "%02d:%02d:%02d/%02d:%02d:%02d "; private String durationFormat = "%02d:%02d:%02d/%02d:%02d:%02d ";
/** The EventHandler for MediaPlayer.onReady(). **/
private final ReadyListener READY_LISTENER = new ReadyListener();
/** The EventHandler for MediaPlayer.onEndOfMedia(). **/
private final EndOfMediaListener END_LISTENER = new EndOfMediaListener();
/** The EventHandler for the CurrentTime property of the MediaPlayer. **/
private final TimeListener TIME_LISTENER = new TimeListener();
/** The EventHandler for MediaPlayer.onPause and MediaPlayer.onStop. **/
private final NotPlayListener NOT_PLAY_LISTENER = new NotPlayListener();
/** The EventHandler for MediaPlayer.onPlay. **/
private final PlayListener PLAY_LISTENER = new PlayListener();
private static final String PLAY_TEXT = "";
private static final String PAUSE_TEXT = "||";
private static final String STOP_TEXT = "X";
/** CSS-formatted skin for pauseButton when showing PLAY_TEXT. **/
private static final String PLAY_STYLE = "-fx-text-fill: green;";
/** CSS-formatted skin for pauseButton when showing PAUSE_TEXT. **/
private static final String PAUSE_STYLE = "-fx-font-weight: bolder;";
/** CSS-formatted skin for stopButton. **/
private static final String STOP_STYLE = "-fx-text-fill: red; -fx-font-weight: bold;";
public MediaPane() { public MediaPane() {
// Video Display // Video Display
mediaViewPane = new HBox(); mediaViewPane = new HBox();
@ -349,26 +358,30 @@ public class FXVideoPanel extends MediaViewVideoPanel {
mediaViewPane.setAlignment(Pos.CENTER); mediaViewPane.setAlignment(Pos.CENTER);
mediaView = new MediaView(); mediaView = new MediaView();
mediaViewPane.getChildren().add(mediaView); mediaViewPane.getChildren().add(mediaView);
setAlignment(mediaViewPane, Pos.CENTER);
setCenter(mediaViewPane); setCenter(mediaViewPane);
// Media Controls // Media Controls
VBox controlPanel = new VBox(); controlPanel = new VBox();
mediaTools = new HBox(); mediaTools = new HBox();
mediaTools.setAlignment(Pos.CENTER); mediaTools.setAlignment(Pos.CENTER);
mediaTools.setPadding(new Insets(5, 10, 5, 10)); mediaTools.setPadding(new Insets(5, 10, 5, 10));
pauseButton = new Button(""); pauseButton = new Button(PLAY_TEXT);
pauseButton.setStyle(PLAY_STYLE);
stopButton = new Button(STOP_TEXT);
stopButton.setStyle(STOP_STYLE);
mediaTools.getChildren().add(pauseButton); mediaTools.getChildren().add(pauseButton);
mediaTools.getChildren().add(new Label(" ")); mediaTools.getChildren().add(new Label(" "));
mediaTools.getChildren().add(stopButton);
mediaTools.getChildren().add(new Label(" "));
progressSlider = new Slider(); progressSlider = new Slider();
HBox.setHgrow(progressSlider,Priority.ALWAYS); HBox.setHgrow(progressSlider,Priority.ALWAYS);
progressSlider.setMinWidth(50); progressSlider.setMinWidth(50);
progressSlider.setMaxWidth(Double.MAX_VALUE); progressSlider.setMaxWidth(Double.MAX_VALUE);
mediaTools.getChildren().add(progressSlider); mediaTools.getChildren().add(progressSlider);
progressLabel = new Label(); progressLabel = new Label();
progressLabel.setPrefWidth(130); progressLabel.setPrefWidth(135);
progressLabel.setMinWidth(50); progressLabel.setMinWidth(135);
mediaTools.getChildren().add(progressLabel); mediaTools.getChildren().add(progressLabel);
controlPanel.getChildren().add(mediaTools); controlPanel.getChildren().add(mediaTools);
@ -379,8 +392,39 @@ public class FXVideoPanel extends MediaViewVideoPanel {
setProgressActionListeners(); setProgressActionListeners();
} }
/**
* Setup the MediaPane for media playback. Run on the JavaFx Thread.
*
*
* @param mediaUri the URI of the media
*/
public void prepareMedia(String mediaUri) {
mediaPlayer = createMediaPlayer(mediaUri);
mediaView.setMediaPlayer(mediaPlayer);
}
/**
* Reset this MediaPane.
*
*/
public void reset() {
if (mediaPlayer != null) {
if (mediaPlayer.getStatus() == Status.PLAYING) {
mediaPlayer.stop();
}
mediaPlayer = null;
}
resetProgress();
}
/**
* Set the Information Label of this MediaPane.
*
* @param text
*/
public void setInfoLabelText(final String text) { public void setInfoLabelText(final String text) {
PlatformImpl.runLater(new Runnable() { logger.log(Level.INFO, "Setting Info Label Text: " + text);
Platform.runLater(new Runnable() {
@Override @Override
public void run() { public void run() {
infoLabel.setText(text); infoLabel.setText(text);
@ -388,54 +432,26 @@ public class FXVideoPanel extends MediaViewVideoPanel {
}); });
} }
public void setMediaPlayer(MediaPlayer mp) { /**
pauseButton.setDisable(true); * Set the size of the MediaPane and it's components.
mediaPlayer = mp; *
mediaView.setMediaPlayer(mp); * @param dims the current dimensions of the DataContentViewer
pauseButton.setDisable(false); */
public void setFit(final Dimension dims) {
setMediaActionListeners(); Platform.runLater(new Runnable() {
}
private void setMediaActionListeners() {
mediaPlayer.setOnReady(new Runnable() {
@Override @Override
public void run() { public void run() {
duration = mediaPlayer.getMedia().getDuration(); setPrefSize(dims.getWidth(), dims.getHeight());
long durationInMillis = (long) fxMediaPlayer.getMedia().getDuration().toMillis(); // Set the Video output to fit the size allocated for it. give an
// extra few px to ensure the info label will be shown
// pick out the total hours, minutes, seconds mediaView.setFitHeight(dims.getHeight() - controlPanel.getHeight());
long durationSeconds = (int) durationInMillis / 1000;
totalHours = (int) durationSeconds / 3600;
durationSeconds -= totalHours * 3600;
totalMinutes = (int) durationSeconds / 60;
durationSeconds -= totalMinutes * 60;
totalSeconds = (int) durationSeconds;
updateProgress();
}
});
mediaPlayer.setOnEndOfMedia(new Runnable() {
@Override
public void run() {
Duration beginning = mediaPlayer.getStartTime();
mediaPlayer.stop();
mediaPlayer.pause();
pauseButton.setText("");
updateSlider(beginning);
updateTime(beginning);
}
});
mediaPlayer.currentTimeProperty().addListener(new ChangeListener<Duration>() {
@Override
public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration newValue) {
updateSlider(newValue);
updateTime(newValue);
} }
}); });
} }
/**
* Set the action listeners for the pause button and progress slider.
*/
private void setProgressActionListeners() { private void setProgressActionListeners() {
pauseButton.setOnAction(new EventHandler<ActionEvent>() { pauseButton.setOnAction(new EventHandler<ActionEvent>() {
@Override @Override
@ -445,22 +461,31 @@ public class FXVideoPanel extends MediaViewVideoPanel {
switch (status) { switch (status) {
// If playing, pause // If playing, pause
case PLAYING: case PLAYING:
pauseButton.setText("");
mediaPlayer.pause(); mediaPlayer.pause();
break; break;
// If ready, paused or stopped, continue playing // If ready, paused or stopped, continue playing
case READY: case READY:
case PAUSED: case PAUSED:
case STOPPED: case STOPPED:
pauseButton.setText("||");
mediaPlayer.play(); mediaPlayer.play();
break; break;
default: default:
logger.log(Level.INFO, "MediaPlayer in unexpected state: " + status.toString());
// If the MediaPlayer is in an unexpected state, stop playback.
mediaPlayer.stop();
setInfoLabelText("Playback error.");
break; break;
} }
} }
}); });
stopButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent e) {
mediaPlayer.stop();
}
});
progressSlider.valueProperty().addListener(new InvalidationListener() { progressSlider.valueProperty().addListener(new InvalidationListener() {
@Override @Override
public void invalidated(Observable o) { public void invalidated(Observable o) {
@ -471,15 +496,61 @@ public class FXVideoPanel extends MediaViewVideoPanel {
}); });
} }
/**
* Reset the progress label and slider to zero.
*/
private void resetProgress() {
totalHours = 0;
totalMinutes = 0;
totalSeconds = 0;
progressSlider.setValue(0.0);
updateTime(Duration.ZERO);
}
/**
* Construct a MediaPlayer from the given Media URI.
*
* Also adds the necessary listeners to MediaPlayer events.
*
* @param mediaUri the location of the media.
* @return a MediaPlayer
*/
private MediaPlayer createMediaPlayer(String mediaUri) {
MediaBuilder mediaBuilder = MediaBuilder.create();
mediaBuilder.source(mediaUri);
Media media = mediaBuilder.build();
MediaPlayerBuilder mediaPlayerBuilder = MediaPlayerBuilder.create();
mediaPlayerBuilder.media(media);
mediaPlayerBuilder.onReady(READY_LISTENER);
mediaPlayerBuilder.onPaused(NOT_PLAY_LISTENER);
mediaPlayerBuilder.onStopped(NOT_PLAY_LISTENER);
mediaPlayerBuilder.onPlaying(PLAY_LISTENER);
mediaPlayerBuilder.onEndOfMedia(END_LISTENER);
MediaPlayer player = mediaPlayerBuilder.build();
player.currentTimeProperty().addListener(TIME_LISTENER);
return player;
}
/**
* Update the progress slider and label with the current time of the media.
*/
private void updateProgress() { private void updateProgress() {
Duration currentTime = mediaPlayer.getCurrentTime(); Duration currentTime = mediaPlayer.getCurrentTime();
updateSlider(currentTime); updateSlider(currentTime);
updateTime(currentTime); updateTime(currentTime);
} }
/**
* Update the slider with the current time.
*
* @param currentTime
*/
private void updateSlider(Duration currentTime) { private void updateSlider(Duration currentTime) {
if (progressSlider != null) { if (progressSlider != null) {
progressSlider.setDisable(duration.isUnknown()); progressSlider.setDisable(currentTime.isUnknown());
if (!progressSlider.isDisabled() && duration.greaterThan(Duration.ZERO) if (!progressSlider.isDisabled() && duration.greaterThan(Duration.ZERO)
&& !progressSlider.isValueChanging()) { && !progressSlider.isValueChanging()) {
progressSlider.setValue(currentTime.divide(duration.toMillis()).toMillis() * 100.0); progressSlider.setValue(currentTime.divide(duration.toMillis()).toMillis() * 100.0);
@ -487,6 +558,11 @@ public class FXVideoPanel extends MediaViewVideoPanel {
} }
} }
/**
* Update the progress label with the current time.
*
* @param currentTime
*/
private void updateTime(Duration currentTime) { private void updateTime(Duration currentTime) {
long millisElapsed = (long) currentTime.toMillis(); long millisElapsed = (long) currentTime.toMillis();
@ -502,11 +578,16 @@ public class FXVideoPanel extends MediaViewVideoPanel {
String durationStr = String.format(durationFormat, String durationStr = String.format(durationFormat,
elapsedHours, elapsedMinutes, elapsedSeconds, elapsedHours, elapsedMinutes, elapsedSeconds,
totalHours, totalMinutes, totalSeconds); totalHours, totalMinutes, totalSeconds);
progressLabel.setText(durationStr); setProgressLabelText(durationStr);
} }
/**
* Update the progress label to show the text.
*
* @param text
*/
private void setProgressLabelText(final String text) { private void setProgressLabelText(final String text) {
PlatformImpl.runLater(new Runnable() { Platform.runLater(new Runnable() {
@Override @Override
public void run() { public void run() {
progressLabel.setText(text); progressLabel.setText(text);
@ -515,13 +596,87 @@ public class FXVideoPanel extends MediaViewVideoPanel {
} }
private void setInfoLabelToolTipText(final String text) { private void setInfoLabelToolTipText(final String text) {
PlatformImpl.runLater(new Runnable() { Platform.runLater(new Runnable() {
@Override @Override
public void run() { public void run() {
infoLabel.setTooltip(new Tooltip(text)); infoLabel.setTooltip(new Tooltip(text));
} }
}); });
} }
/**
* Responds to MediaPlayer onReady events.
*
* Updates the progress label with the duration of the media.
*/
private class ReadyListener implements Runnable {
@Override
public void run() {
duration = mediaPlayer.getMedia().getDuration();
long durationInMillis = (long) mediaPlayer.getMedia().getDuration().toMillis();
// pick out the total hours, minutes, seconds
long durationSeconds = (int) durationInMillis / 1000;
totalHours = (int) durationSeconds / 3600;
durationSeconds -= totalHours * 3600;
totalMinutes = (int) durationSeconds / 60;
durationSeconds -= totalMinutes * 60;
totalSeconds = (int) durationSeconds;
updateProgress();
}
}
/**
* Responds to MediaPlayer onEndOfMediaEvents.
*
* Prepares the media to be replayed.
*/
private class EndOfMediaListener implements Runnable {
@Override
public void run() {
Duration beginning = mediaPlayer.getStartTime();
mediaPlayer.stop();
mediaPlayer.pause();
pauseButton.setText(PLAY_TEXT);
updateSlider(beginning);
updateTime(beginning);
}
}
/**
* Responds to changes in the MediaPlayer currentTime property.
*
* Updates the progress slider and label with the current Time.
*/
private class TimeListener implements ChangeListener<Duration> {
@Override
public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration newValue) {
updateSlider(newValue);
updateTime(newValue);
}
}
/**
* Triggered when MediaPlayer State changes to PAUSED or Stopped.
*/
private class NotPlayListener implements Runnable {
@Override
public void run() {
pauseButton.setText(PLAY_TEXT);
pauseButton.setStyle(PLAY_STYLE);
}
}
/**
* Triggered when MediaPlayer State changes to PLAYING.
*/
private class PlayListener implements Runnable {
@Override
public void run() {
pauseButton.setText(PAUSE_TEXT);
pauseButton.setStyle(PAUSE_STYLE);
}
}
} }
/** /**
@ -566,7 +721,7 @@ public class FXVideoPanel extends MediaViewVideoPanel {
// } // }
// //
// private void initFx(final java.io.File file) { // private void initFx(final java.io.File file) {
// PlatformImpl.runAndWait(new Runnable() { // Platform.runAndWait(new Runnable() {
// @Override // @Override
// public void run() { // public void run() {
// logger.log(Level.INFO, "In initFX."); // logger.log(Level.INFO, "In initFX.");
@ -620,7 +775,7 @@ public class FXVideoPanel extends MediaViewVideoPanel {
// logger.log(Level.INFO, "Grabbing a frame..."); // logger.log(Level.INFO, "Grabbing a frame...");
// final long timeStamp = i * frameInterval + INTER_FRAME_PERIOD_MS; // final long timeStamp = i * frameInterval + INTER_FRAME_PERIOD_MS;
// //
// // PlatformImpl.runLater(new Runnable() { // // Platform.runLater(new Runnable() {
// // @Override // // @Override
// // public void run() { // // public void run() {
// // synchronized (frameLock) { // // synchronized (frameLock) {

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="controlPanel" max="32767" attributes="0"/>
<Component id="videoPanel" alignment="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="videoPanel" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="controlPanel" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JPanel" name="videoPanel">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="231" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
</Container>
<Container class="javax.swing.JPanel" name="controlPanel">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="6" pref="6" max="-2" attributes="0"/>
<Component id="infoLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="pauseButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="progressSlider" pref="265" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="progressLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="progressSlider" min="-2" max="-2" attributes="0"/>
<Component id="pauseButton" min="-2" max="-2" attributes="0"/>
<Component id="progressLabel" alignment="0" min="-2" pref="29" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
<Component id="infoLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JButton" name="pauseButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MediaViewVideoPanel.pauseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="pauseButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JSlider" name="progressSlider">
</Component>
<Component class="javax.swing.JLabel" name="progressLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MediaViewVideoPanel.progressLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="infoLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MediaViewVideoPanel.infoLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@ -437,7 +437,7 @@ public class GstVideoPanel extends MediaViewVideoPanel {
* regenerated by the Form Editor. * regenerated by the Form Editor.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code"> // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() { private void initComponents() {
videoPanel = new javax.swing.JPanel(); videoPanel = new javax.swing.JPanel();
@ -455,69 +455,70 @@ public class GstVideoPanel extends MediaViewVideoPanel {
); );
videoPanelLayout.setVerticalGroup( videoPanelLayout.setVerticalGroup(
videoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) videoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 188, Short.MAX_VALUE) .addGap(0, 231, Short.MAX_VALUE)
); );
org.openide.awt.Mnemonics.setLocalizedText(pauseButton, org.openide.util.NbBundle.getMessage(MediaViewVideoPanel.class, "MediaViewVideoPanel.pauseButton.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(pauseButton, org.openide.util.NbBundle.getMessage(GstVideoPanel.class, "MediaViewVideoPanel.pauseButton.text")); // NOI18N
pauseButton.addActionListener(new java.awt.event.ActionListener() { pauseButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) { public void actionPerformed(java.awt.event.ActionEvent evt) {
pauseButtonActionPerformed(evt); pauseButtonActionPerformed(evt);
} }
}); });
org.openide.awt.Mnemonics.setLocalizedText(progressLabel, org.openide.util.NbBundle.getMessage(MediaViewVideoPanel.class, "MediaViewVideoPanel.progressLabel.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(progressLabel, org.openide.util.NbBundle.getMessage(GstVideoPanel.class, "MediaViewVideoPanel.progressLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(infoLabel, org.openide.util.NbBundle.getMessage(MediaViewVideoPanel.class, "MediaViewVideoPanel.infoLabel.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(infoLabel, org.openide.util.NbBundle.getMessage(GstVideoPanel.class, "MediaViewVideoPanel.infoLabel.text")); // NOI18N
javax.swing.GroupLayout controlPanelLayout = new javax.swing.GroupLayout(controlPanel); javax.swing.GroupLayout controlPanelLayout = new javax.swing.GroupLayout(controlPanel);
controlPanel.setLayout(controlPanelLayout); controlPanel.setLayout(controlPanelLayout);
controlPanelLayout.setHorizontalGroup( controlPanelLayout.setHorizontalGroup(
controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(controlPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(controlPanelLayout.createSequentialGroup()
.addGap(6, 6, 6)
.addComponent(infoLabel)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(controlPanelLayout.createSequentialGroup() .addGroup(controlPanelLayout.createSequentialGroup()
.addComponent(pauseButton) .addComponent(pauseButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(progressSlider, javax.swing.GroupLayout.DEFAULT_SIZE, 357, Short.MAX_VALUE) .addComponent(progressSlider, javax.swing.GroupLayout.DEFAULT_SIZE, 265, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(progressLabel) .addComponent(progressLabel)
.addContainerGap()) .addContainerGap())))
.addGroup(controlPanelLayout.createSequentialGroup()
.addComponent(infoLabel)
.addGap(0, 0, Short.MAX_VALUE))
); );
controlPanelLayout.setVerticalGroup( controlPanelLayout.setVerticalGroup(
controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(controlPanelLayout.createSequentialGroup() .addGroup(controlPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(pauseButton)
.addComponent(progressSlider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(progressSlider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(progressLabel, javax.swing.GroupLayout.Alignment.TRAILING)) .addComponent(pauseButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(progressLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 29, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(infoLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(infoLabel)
.addContainerGap())
); );
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout); this.setLayout(layout);
layout.setHorizontalGroup( layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(videoPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(controlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(controlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(videoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
); );
layout.setVerticalGroup( layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addComponent(videoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(videoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(controlPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(controlPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addContainerGap())
); );
}// </editor-fold> }// </editor-fold>
private void pauseButtonActionPerformed(java.awt.event.ActionEvent evt) { private void pauseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pauseButtonActionPerformed
synchronized (playbinLock) { synchronized (playbinLock) {
if (gstPlaybin2 == null) {
infoLabel.setText("Error: Playbin is null");
return;
}
State state = gstPlaybin2.getState(); State state = gstPlaybin2.getState();
if (state.equals(State.PLAYING)) { if (state.equals(State.PLAYING)) {
if (gstPlaybin2.pause() == StateChangeReturn.FAILURE) { if (gstPlaybin2.pause() == StateChangeReturn.FAILURE) {
@ -551,15 +552,16 @@ public class GstVideoPanel extends MediaViewVideoPanel {
em.getExtractedBytes(); em.getExtractedBytes();
} }
} }
} }//GEN-LAST:event_pauseButtonActionPerformed
// Variables declaration - do not modify
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JPanel controlPanel; private javax.swing.JPanel controlPanel;
private javax.swing.JLabel infoLabel; private javax.swing.JLabel infoLabel;
private javax.swing.JButton pauseButton; private javax.swing.JButton pauseButton;
private javax.swing.JLabel progressLabel; private javax.swing.JLabel progressLabel;
private javax.swing.JSlider progressSlider; private javax.swing.JSlider progressSlider;
private javax.swing.JPanel videoPanel; private javax.swing.JPanel videoPanel;
// End of variables declaration // End of variables declaration//GEN-END:variables
private class VideoProgressWorker extends SwingWorker<Object, Object> { private class VideoProgressWorker extends SwingWorker<Object, Object> {

View File

@ -18,10 +18,10 @@
*/ */
package org.sleuthkit.autopsy.corecomponents; package org.sleuthkit.autopsy.corecomponents;
import com.sun.javafx.application.PlatformImpl;
import java.awt.Insets; import java.awt.Insets;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level; import java.util.logging.Level;
import javafx.application.Platform;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import javax.swing.UIManager; import javax.swing.UIManager;
@ -29,9 +29,9 @@ import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.UnsupportedLookAndFeelException; import javax.swing.UnsupportedLookAndFeelException;
import org.netbeans.swing.tabcontrol.plaf.DefaultTabbedContainerUI; import org.netbeans.swing.tabcontrol.plaf.DefaultTabbedContainerUI;
import org.openide.modules.ModuleInstall; import org.openide.modules.ModuleInstall;
import org.openide.util.Exceptions;
import org.openide.windows.WindowManager; import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
/** /**
* Manages this module's lifecycle. Opens the startup dialog during startup. * Manages this module's lifecycle. Opens the startup dialog during startup.
@ -57,7 +57,7 @@ public class Installer extends ModuleInstall {
public void restored() { public void restored() {
super.restored(); super.restored();
//setupLAF(); setupLAF();
UIManager.put("ViewTabDisplayerUI", "org.sleuthkit.autopsy.corecomponents.NoTabsTabDisplayerUI"); UIManager.put("ViewTabDisplayerUI", "org.sleuthkit.autopsy.corecomponents.NoTabsTabDisplayerUI");
UIManager.put(DefaultTabbedContainerUI.KEY_VIEW_CONTENT_BORDER, BorderFactory.createEmptyBorder()); UIManager.put(DefaultTabbedContainerUI.KEY_VIEW_CONTENT_BORDER, BorderFactory.createEmptyBorder());
UIManager.put("TabbedPane.contentBorderInsets", new Insets(0, 0, 0, 0)); UIManager.put("TabbedPane.contentBorderInsets", new Insets(0, 0, 0, 0));
@ -85,24 +85,57 @@ public class Installer extends ModuleInstall {
//UIManager.put("nimbusBlueGrey", new Color()); //UIManager.put("nimbusBlueGrey", new Color());
//UIManager.put("control", new Color()); //UIManager.put("control", new Color());
if (System.getProperty("os.name").toLowerCase().contains("mac")) {
setupMacOsXLAF();
}
Logger logger = Logger.getLogger(Installer.class.getName()); }
//use Nimbus if available
/**
* Set the look and feel to be the Cross Platform 'Metal', but keep Aqua
* dependent elements that set the Menu Bar to be in the correct place on
* Mac OS X.
*/
private void setupMacOsXLAF() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException | UnsupportedLookAndFeelException ex) {
logger.log(Level.WARNING, "Unable to set theme. ", ex);
}
final String[] UI_MENU_ITEM_KEYS = new String[]{"MenuBarUI",
"MenuUI",
"MenuItemUI",
"CheckBoxMenuItemUI",
"RadioButtonMenuItemUI",
"PopupMenuUI"};
Map<Object, Object> uiEntries = new TreeMap<Object, Object>();
// Store the keys that deal with menu items
for(String key : UI_MENU_ITEM_KEYS) {
uiEntries.put(key, UIManager.get(key));
}
//use Metal if available
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) { if ("Nimbus".equals(info.getName())) {
try { try {
UIManager.setLookAndFeel(info.getClassName()); UIManager.setLookAndFeel(info.getClassName());
} catch (ClassNotFoundException ex) { } catch (ClassNotFoundException | InstantiationException |
logger.log(Level.WARNING, "Unable to set theme. ", ex); IllegalAccessException | UnsupportedLookAndFeelException ex) {
} catch (InstantiationException ex) {
logger.log(Level.WARNING, "Unable to set theme. ", ex);
} catch (IllegalAccessException ex) {
logger.log(Level.WARNING, "Unable to set theme. ", ex);
} catch (UnsupportedLookAndFeelException ex) {
logger.log(Level.WARNING, "Unable to set theme. ", ex); logger.log(Level.WARNING, "Unable to set theme. ", ex);
} }
break; break;
} }
} }
// Overwrite the Metal menu item keys to use the Aqua versions
for(Map.Entry entry : uiEntries.entrySet()) {
UIManager.put(entry.getKey(), entry.getValue());
}
} }
} }

View File

@ -18,14 +18,13 @@
*/ */
package org.sleuthkit.autopsy.corecomponents; package org.sleuthkit.autopsy.corecomponents;
import com.sun.javafx.application.PlatformImpl;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.EventQueue; import java.awt.EventQueue;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Collection;
import java.util.logging.Level; import java.util.logging.Level;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel; import javafx.embed.swing.JFXPanel;
import javafx.embed.swing.SwingFXUtils; import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene; import javafx.scene.Scene;
@ -33,8 +32,7 @@ import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane; import javafx.scene.layout.BorderPane;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import org.openide.modules.ModuleInstall; import javax.swing.SwingUtilities;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.corelibs.ScalrWrapper; import org.sleuthkit.autopsy.corelibs.ScalrWrapper;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
@ -61,11 +59,7 @@ public class MediaViewImagePanel extends javax.swing.JPanel {
org.sleuthkit.autopsy.core.Installer coreInstaller = fxInited = org.sleuthkit.autopsy.core.Installer.isJavaFxInited();
ModuleInstall.findObject(org.sleuthkit.autopsy.core.Installer.class, false);
if (coreInstaller != null) {
fxInited = coreInstaller.isJavaFxInited();
}
if (fxInited) { if (fxInited) {
@ -82,7 +76,7 @@ public class MediaViewImagePanel extends javax.swing.JPanel {
*/ */
private void setupFx() { private void setupFx() {
// load the image // load the image
PlatformImpl.runLater(new Runnable() { Platform.runLater(new Runnable() {
@Override @Override
public void run() { public void run() {
fxPanel = new JFXPanel(); fxPanel = new JFXPanel();
@ -129,7 +123,7 @@ public class MediaViewImagePanel extends javax.swing.JPanel {
fxPanel.setVisible(false); fxPanel.setVisible(false);
// load the image // load the image
PlatformImpl.runLater(new Runnable() { Platform.runLater(new Runnable() {
@Override @Override
public void run() { public void run() {
if (!Case.isCaseOpen()) { if (!Case.isCaseOpen()) {
@ -188,8 +182,13 @@ public class MediaViewImagePanel extends javax.swing.JPanel {
fxPanel.setScene(fxScene); fxPanel.setScene(fxScene);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
//show the panel after fully loaded //show the panel after fully loaded
fxPanel.setVisible(true); fxPanel.setVisible(true);
}
});
} }
}); });

View File

@ -18,7 +18,7 @@
*/ */
package org.sleuthkit.autopsy.corelibs; package org.sleuthkit.autopsy.corelibs;
import java.io.File; import com.sun.javafx.PlatformUtil;
import org.hyperic.sigar.Sigar; import org.hyperic.sigar.Sigar;
/** /**
@ -42,7 +42,11 @@ public class SigarLoader {
if (sigar == null) { if (sigar == null) {
try { try {
//rely on netbeans / jna to locate the lib variation for architecture/OS //rely on netbeans / jna to locate the lib variation for architecture/OS
if (PlatformUtil.isWindows()) {
System.loadLibrary("libsigar"); System.loadLibrary("libsigar");
} else {
System.loadLibrary("sigar");
}
sigar = new Sigar(); sigar = new Sigar();
sigar.enableLogging(false); //forces a test sigar.enableLogging(false); //forces a test

View File

@ -0,0 +1,938 @@
#!/usr/bin/perl -w
my $VER="4.1.0";
#
# This program is based on the 'mactime' program by Dan Farmer and
# and the 'mac_daddy' program by Rob Lee.
#
# It takes as input data from either 'ils -m' or 'fls -m' (from The Sleuth
# Kit) or 'mac-robber'.
# Based on the dates as arguments given, the data is sorted by and
# printed.
#
# The Sleuth Kit
# Brian Carrier [carrier <at> sleuthkit [dot] org]
# Copyright (c) 2003-2012 Brian Carrier. All rights reserved
#
# TASK
# Copyright (c) 2002 Brian Carrier, @stake Inc. All rights reserved
#
#
# The modifications to the original mactime are distributed under
# the Common Public License 1.0
#
#
# Copyright 1999 by Dan Farmer. All rights reserved. Some individual
# files may be covered by other copyrights (this will be noted in the
# file itself.)
#
# Redistribution and use in source and binary forms are permitted
# provided that this entire copyright notice is duplicated in all such
# copies.
#
# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
#
# IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA, OR PROFITS OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
use POSIX;
use strict;
my $debug = 0;
# %month_to_digit = ("Jan", 1, "Feb", 2, "Mar", 3, "Apr", 4, "May", 5, "Jun", 6,
# "Jul", 7, "Aug", 8, "Sep", 9, "Oct", 10, "Nov", 11, "Dec", 12);
my %digit_to_month = (
"01", "Jan", "02", "Feb", "03", "Mar", "04", "Apr",
"05", "May", "06", "Jun", "07", "Jul", "08", "Aug",
"09", "Sep", "10", "Oct", "11", "Nov", "12", "Dec"
);
my %digit_to_day = (
"0", "Sun", "1", "Mon", "2", "Tue", "3", "Wed",
"4", "Thu", "5", "Fri", "6", "Sat"
);
sub usage {
print <<EOF;
mactime [-b body_file] [-p password_file] [-g group_file] [-i day|hour idx_file] [-d] [-h] [-V] [-y] [-z TIME_ZONE] [DATE]
-b: Specifies the body file location, else STDIN is used
-d: Output in comma delimited format
-h: Display a header with session information
-i [day | hour] file: Specifies the index file with a summary of results
-y: Dates are displayed in ISO 8601 format
-m: Dates have month as number instead of word (does not work with -y)
-z: Specify the timezone the data came from (in the local system format) (does not work with -y)
-g: Specifies the group file location, else GIDs are used
-p: Specifies the password file location, else UIDs are used
-V: Prints the version to STDOUT
[DATE]: starting date (yyyy-mm-dd) or range (yyyy-mm-dd..yyyy-mm-dd)
EOF
exit(1);
}
sub version {
print "The Sleuth Kit ver $VER\n";
}
my $BODY = "";
my $GROUP = "";
my $PASSWD = "";
my $TIME = "";
my $INDEX = ""; # File name of index
my $INDEX_DAY = 1; # Daily index (for $INDEX_TYPE)
my $INDEX_HOUR = 2;
my $INDEX_TYPE = $INDEX_DAY; # Saved to type of index
my $COMMA = 0; # Comma delimited output
my $iso8601 = 0;
my $month_num = 0;
my $header = 0;
my $in_seconds = 0;
my $out_seconds = 0;
my %timestr2macstr;
my %file2other;
my %gid2names = ();
my %uid2names = ();
my $_HAS_DATETIME_TIMEZONE = 0;
eval "use DateTime::TimeZone";
if ($@) {
$_HAS_DATETIME_TIMEZONE = 0;
} else {
$_HAS_DATETIME_TIMEZONE = 1;
}
sub get_timezone_list() {
my @t_list;
if ( ! $_HAS_DATETIME_TIMEZONE ) {
return @t_list;
}
foreach ( DateTime::TimeZone->all_names() ) {
push( @t_list, $_ );
}
foreach( keys( %{DateTime::TimeZone->links()}) ) {
push( @t_list, $_ );
}
return sort { $a cmp $b } @t_list;
}
usage() if (scalar(@ARGV) == 0);
while ((scalar(@ARGV) > 0) && (($_ = $ARGV[0]) =~ /^-(.)(.*)/)) {
# Body File
if (/^-b$/) {
shift(@ARGV);
if (defined $ARGV[0]) {
$BODY = $ARGV[0];
}
else {
print "-b requires body file argument\n";
}
}
elsif (/^-d$/) {
$COMMA = 1;
}
# Group File
elsif (/^-g$/) {
shift(@ARGV);
if (defined $ARGV[0]) {
&'load_group_info($ARGV[0]);
$GROUP = $ARGV[0];
}
else {
print "-g requires group file argument\n";
usage();
}
}
# Password File
elsif (/^-p$/) {
shift(@ARGV);
if (defined $ARGV[0]) {
&'load_passwd_info($ARGV[0]);
$PASSWD = $ARGV[0];
}
else {
print "-p requires password file argument\n";
usage();
}
}
elsif (/^-h$/) {
$header = 1;
}
# Index File
elsif (/^-i$/) {
shift(@ARGV);
if (defined $ARGV[0]) {
# Find out what type
if ($ARGV[0] eq "day") {
$INDEX_TYPE = $INDEX_DAY;
}
elsif ($ARGV[0] eq "hour") {
$INDEX_TYPE = $INDEX_HOUR;
}
shift(@ARGV);
unless (defined $ARGV[0]) {
print "-i requires index file argument\n";
usage();
}
$INDEX = $ARGV[0];
}
else {
print "-i requires index file argument and type\n";
usage();
}
open(INDEX, ">$INDEX") or die "Can not open $INDEX";
}
elsif (/^-V$/) {
version();
exit(0);
}
elsif (/^-m$/) {
$month_num = 1;
}
elsif (/^-y$/) {
$iso8601 = 1;
}
elsif (/^-z$/) {
shift(@ARGV);
if (defined $ARGV[0]) {
my $tz = "$ARGV[0]";
if ($tz =~ m/^list$/i) {
if ($_HAS_DATETIME_TIMEZONE) {
my $txt = "
-----------------------------------
TIMEZONE LIST
-----------------------------------\n";
foreach ( get_timezone_list() ) {
$txt .= $_ . "\n";
}
print( $txt );
}
else {
print "DateTime module not loaded -- cannot list timezones\n";
}
exit(0);
}
# validate the string if we have DateTime module
elsif ($_HAS_DATETIME_TIMEZONE) {
my $realtz = 0;
foreach ( get_timezone_list() ) {
if ($tz =~ m/^$_$/i) {
$realtz = $_;
last;
}
}
if ($realtz) {
$ENV{TZ} = $realtz;
}
else {
print "invalid timezone provided. Use -z to list valid timezones.\n";
usage();
}
}
# blindly take it otherwise
else {
$ENV{TZ} = $tz;
}
}
else {
print "-z requires the time zone argument\n";
usage();
}
}
else {
print "Unknown option: $_\n";
usage();
}
shift(@ARGV);
}
# Was the time given
if (defined $ARGV[0]) {
my $t_in;
my $t_out;
$TIME = $ARGV[0];
if ($ARGV[0] =~ /\.\./) {
($t_in, $t_out) = split(/\.\./, $ARGV[0]);
}
else {
$t_in = $ARGV[0];
$t_out = 0;
}
$in_seconds = parse_isodate($t_in);
die "Invalid Date: $t_in\n" if ($in_seconds < 0);
if ($t_out) {
$out_seconds = parse_isodate($t_out);
die "Invalid Date: $t_out\n" if ($out_seconds < 0);
}
else {
$out_seconds = 0;
}
}
else {
$in_seconds = 0;
$out_seconds = 0;
}
# Print header info
print_header() if ($header == 1);
# Print the index header
if ($INDEX ne "") {
my $time_str = "";
if ($INDEX_TYPE == $INDEX_DAY) {
$time_str = "Daily";
}
else {
$time_str = "Hourly";
}
if ($BODY ne "") {
print INDEX "$time_str Summary for Timeline of $BODY\n\n";
}
else {
print INDEX "$time_str Summary for Timeline of STDIN\n\n";
}
}
read_body();
print_tl();
################ SUBROUTINES ##################
#convert yyyy-mm-dd string to Unix date
sub parse_isodate {
my $iso_date = shift;
my $sec = 0;
my $min = 0;
my $hour = 0;
my $wday = 0;
my $yday = 0;
if ($iso_date =~ /^(\d\d\d\d)\-(\d\d)\-(\d\d)$/) {
return mktime($sec, $min, $hour, $3, $2 - 1, $1 - 1900, $wday, $yday);
}
else {
return -1;
}
}
# Read the body file from the BODY variable
sub read_body {
# Read the body file from STDIN or the -b specified body file
if ($BODY ne "") {
open(BODY, "<$BODY") or die "Can't open $BODY";
}
else {
open(BODY, "<&STDIN") or die "Can't dup STDIN";
}
while (<BODY>) {
next if ((/^\#/) || (/^\s+$/));
chomp;
my (
$tmp1, $file, $st_ino, $st_ls,
$st_uid, $st_gid, $st_size, $st_atime,
$st_mtime, $st_ctime, $st_crtime, $tmp2
)
= &tm_split($_);
# Sanity check so that we ignore the header entries
next unless ((defined $st_ino) && ($st_ino =~ /[\d-]+/));
next unless ((defined $st_uid) && ($st_uid =~ /\d+/));
next unless ((defined $st_gid) && ($st_gid =~ /\d+/));
next unless ((defined $st_size) && ($st_size =~ /\d+/));
next unless ((defined $st_mtime) && ($st_mtime =~ /\d+/));
next unless ((defined $st_atime) && ($st_atime =~ /\d+/));
next unless ((defined $st_ctime) && ($st_ctime =~ /\d+/));
next unless ((defined $st_crtime) && ($st_crtime =~ /\d+/));
# we need *some* value in mactimes!
next if (!$st_atime && !$st_mtime && !$st_ctime && !$st_crtime);
# Skip if these are all too early
next
if ( ($st_mtime < $in_seconds)
&& ($st_atime < $in_seconds)
&& ($st_ctime < $in_seconds)
&& ($st_crtime < $in_seconds));
# add leading zeros to timestamps because we will later sort
# these using a string-based comparison
$st_mtime = sprintf("%.10d", $st_mtime);
$st_atime = sprintf("%.10d", $st_atime);
$st_ctime = sprintf("%.10d", $st_ctime);
$st_crtime = sprintf("%.10d", $st_crtime);
# Put all the times in one big array along with the inode and
# name (they are used in the final sorting)
# If the date on the file is too old, don't put it in the array
my $post = ",$st_ino,$file";
if ($out_seconds) {
$timestr2macstr{"$st_mtime$post"} .= "m"
if (
($st_mtime >= $in_seconds)
&& ($st_mtime < $out_seconds)
&& ( (!(exists $timestr2macstr{"$st_mtime$post"}))
|| ($timestr2macstr{"$st_mtime$post"} !~ /m/))
);
$timestr2macstr{"$st_atime$post"} .= "a"
if (
($st_atime >= $in_seconds)
&& ($st_atime < $out_seconds)
&& ( (!(exists $timestr2macstr{"$st_atime$post"}))
|| ($timestr2macstr{"$st_atime$post"} !~ /a/))
);
$timestr2macstr{"$st_ctime$post"} .= "c"
if (
($st_ctime >= $in_seconds)
&& ($st_ctime < $out_seconds)
&& ( (!(exists $timestr2macstr{"$st_ctime$post"}))
|| ($timestr2macstr{"$st_ctime$post"} !~ /c/))
);
$timestr2macstr{"$st_crtime$post"} .= "b"
if (
($st_crtime >= $in_seconds)
&& ($st_crtime < $out_seconds)
&& ( (!(exists $timestr2macstr{"$st_crtime$post"}))
|| ($timestr2macstr{"$st_crtime$post"} !~ /b/))
);
}
else {
$timestr2macstr{"$st_mtime$post"} .= "m"
if (
($st_mtime >= $in_seconds)
&& ( (!(exists $timestr2macstr{"$st_mtime$post"}))
|| ($timestr2macstr{"$st_mtime$post"} !~ /m/))
);
$timestr2macstr{"$st_atime$post"} .= "a"
if (
($st_atime >= $in_seconds)
&& ( (!(exists $timestr2macstr{"$st_atime$post"}))
|| ($timestr2macstr{"$st_atime$post"} !~ /a/))
);
$timestr2macstr{"$st_ctime$post"} .= "c"
if (
($st_ctime >= $in_seconds)
&& ( (!(exists $timestr2macstr{"$st_ctime$post"}))
|| ($timestr2macstr{"$st_ctime$post"} !~ /c/))
);
$timestr2macstr{"$st_crtime$post"} .= "b"
if (
($st_crtime >= $in_seconds)
&& ( (!(exists $timestr2macstr{"$st_crtime$post"}))
|| ($timestr2macstr{"$st_crtime$post"} !~ /b/))
);
}
# if the UID or GID is not in the array then add it.
# these are filled if the -p or -g options are given
$uid2names{$st_uid} = $st_uid
unless (defined $uid2names{$st_uid});
$gid2names{$st_gid} = $st_gid
unless (defined $gid2names{$st_gid});
#
# put /'s between multiple UID/GIDs
#
$uid2names{$st_uid} =~ s@\s@/@g;
$gid2names{$st_gid} =~ s@\s@/@g;
$file2other{$file} =
"$st_ls:$uid2names{$st_uid}:$gid2names{$st_gid}:$st_size";
}
close BODY;
} # end of read_body
sub print_header {
return if ($header == 0);
print "The Sleuth Kit mactime Timeline\n";
print "Input Source: ";
if ($BODY eq "") {
print "STDIN\n";
}
else {
print "$BODY\n";
}
print "Time: $TIME\t\t" if ($TIME ne "");
if ($ENV{TZ} eq "") {
print "\n";
}
else {
print "Timezone: $ENV{TZ}\n";
}
print "passwd File: $PASSWD" if ($PASSWD ne "");
if ($GROUP ne "") {
print "\t" if ($PASSWD ne "");
print "group File: $GROUP";
}
print "\n" if (($PASSWD ne "") || ($GROUP ne ""));
print "\n";
}
#
# Print the time line
#
sub print_tl {
my $prev_day = ""; # has the format of 'day day_week mon year'
my $prev_hour = ""; # has just the hour and is used for hourly index
my $prev_cnt = 0;
my $old_date_string = "";
my $delim = ":";
if ($COMMA != 0) {
print "Date,Size,Type,Mode,UID,GID,Meta,File Name\n";
$delim = ",";
}
# Cycle through the files and print them in sorted order.
# Note that we sort using a string comparison because the keys
# also contain the inode and file name
for my $key (sort { $a cmp $b } keys %timestr2macstr) {
my $time;
my $inode;
my $file;
if ($key =~ /^(\d+),([\d-]+),(.*)$/) {
$time = $1;
$inode = $2;
$file = $3;
}
else {
next;
}
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst);
if ($iso8601) {
($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
gmtime($time);
}
else {
($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
localtime($time);
}
# the month here is 0-11, not 1-12, like what we want
$mon++;
print
"\t($sec,$min,$hour,MDay: $mday,M: $mon,$year,$wday,$yday,$isdst) = ($time)\n"
if $debug;
#
# cosmetic change to make it look like unix dates
#
$mon = "0$mon" if $mon < 10;
$mday = "0$mday" if $mday < 10;
$hour = "0$hour" if $hour < 10;
$min = "0$min" if $min < 10;
$sec = "0$sec" if $sec < 10;
my $yeart = $year + 1900;
# How do we print the date?
#
my $date_string;
if ($iso8601) {
if ($time == 0) {
$date_string = "0000-00-00T00:00:00Z";
}
else {
$date_string =
"$yeart-$mon-${mday}T$hour:$min:${sec}Z";
}
}
else {
if ($time == 0) {
$date_string = "Xxx Xxx 00 0000 00:00:00";
}
elsif ($month_num) {
$date_string =
"$digit_to_day{$wday} $mon $mday $yeart $hour:$min:$sec";
}
else {
$date_string =
"$digit_to_day{$wday} $digit_to_month{$mon} $mday $yeart $hour:$min:$sec";
}
}
#
# However, we only print the date if it's different from the one
# above. We need to fill the empty space with blanks, though.
#
if ($old_date_string eq $date_string) {
if ($iso8601) {
$date_string = " ";
}
else {
$date_string = " ";
}
$prev_cnt++
if ($INDEX ne "");
}
else {
$old_date_string = $date_string;
# Indexing code
if ($INDEX ne "") {
# First time it is run
if ($prev_day eq "") {
$prev_day = "$mday $wday $mon $yeart";
$prev_hour = $hour;
$prev_cnt = 0;
}
# A new day, so print the results
elsif ($prev_day ne "$mday $wday $mon $yeart") {
my @prev_vals = split(/ /, $prev_day);
my $date_str;
if ($month_num) {
$date_str =
"$digit_to_day{$prev_vals[1]} "
. "$prev_vals[2] "
. "$prev_vals[0] ${prev_vals[3]}";
}
else {
$date_str =
"$digit_to_day{$prev_vals[1]} "
. "$digit_to_month{$prev_vals[2]} "
. "$prev_vals[0] ${prev_vals[3]}";
}
$date_str .= " $prev_hour:00:00"
if ($INDEX_TYPE == $INDEX_HOUR);
print INDEX "${date_str}${delim} $prev_cnt\n";
# Reset
$prev_cnt = 0;
$prev_day = "$mday $wday $mon $yeart";
$prev_hour = $hour;
}
# Same day, but new hour
elsif (($INDEX_TYPE == $INDEX_HOUR) && ($prev_hour != $hour)) {
my @prev_vals = split(/ /, $prev_day);
if ($month_num) {
print INDEX "$digit_to_day{$prev_vals[1]} "
. "$prev_vals[2] "
. "$prev_vals[0] ${prev_vals[3]} "
. "$prev_hour:00:00${delim} $prev_cnt\n";
}
else {
print INDEX "$digit_to_day{$prev_vals[1]} "
. "$digit_to_month{$prev_vals[2]} "
. "$prev_vals[0] ${prev_vals[3]} "
. "$prev_hour:00:00${delim} $prev_cnt\n";
}
# Reset
$prev_cnt = 0;
$prev_hour = $hour;
}
$prev_cnt++;
}
}
#
# Muck around with the [mac]times string to make it pretty.
#
my $mactime_tmp = $timestr2macstr{$key};
my $mactime = "";
if ($mactime_tmp =~ /m/) {
$mactime = "m";
}
else {
$mactime = ".";
}
if ($mactime_tmp =~ /a/) {
$mactime .= "a";
}
else {
$mactime .= ".";
}
if ($mactime_tmp =~ /c/) {
$mactime .= "c";
}
else {
$mactime .= ".";
}
if ($mactime_tmp =~ /b/) {
$mactime .= "b";
}
else {
$mactime .= ".";
}
my ($ls, $uids, $groups, $size) = split(/:/, $file2other{$file});
print "FILE: $file MODES: $ls U: $uids G: $groups S: $size\n"
if $debug;
if ($COMMA == 0) {
printf("%s %8s %3s %s %-8s %-8s %-8s %s\n",
$date_string, $size, $mactime, $ls, $uids, $groups, $inode,
$file);
}
else {
# escape any quotes in filename
my $file_tmp = $file;
$file_tmp =~ s/\"/\"\"/g;
printf("%s,%s,%s,%s,%s,%s,%s,\"%s\"\n",
$old_date_string, $size, $mactime, $ls, $uids, $groups, $inode,
$file_tmp);
}
}
# Finish the index page for the last entry
if (($INDEX ne "") && ($prev_cnt > 0)) {
my @prev_vals = split(/ /, $prev_day);
my $date_str;
if ($month_num) {
$date_str =
"$digit_to_day{$prev_vals[1]} "
. "$prev_vals[2] "
. "$prev_vals[0] ${prev_vals[3]}";
}
else {
$date_str =
"$digit_to_day{$prev_vals[1]} "
. "$digit_to_month{$prev_vals[2]} "
. "$prev_vals[0] ${prev_vals[3]}";
}
$date_str .= " $prev_hour:00:00"
if ($INDEX_TYPE == $INDEX_HOUR);
print INDEX "${date_str}${delim} $prev_cnt\n";
close INDEX;
}
}
#
# Routines for reading and caching user and group information. These
# are used in multiple programs... it caches the info once, then hopefully
# won't be used again.
#
# Steve Romig, May 1991.
#
# Provides a bunch of routines and a bunch of arrays. Routines
# (and their usage):
#
# load_passwd_info($use_getent, $file_name)
#
# loads user information into the %uname* and %uid* arrays
# (see below).
#
# If $use_getent is non-zero:
# get the info via repeated 'getpwent' calls. This can be
# *slow* on some hosts, especially if they are running as a
# YP (NIS) client.
# If $use_getent is 0:
# if $file_name is "", then get the info from reading the
# results of "ypcat passwd" and from /etc/passwd. Otherwise,
# read the named file. The file should be in passwd(5)
# format.
#
# load_group_info($use_gentent, $file_name)
#
# is similar to load_passwd_info.
#
# Information is stored in several convenient associative arrays:
#
# %uid2names Assoc array, indexed by uid, value is list of
# user names with that uid, in form "name name
# name...".
#
# %gid2members Assoc array, indexed by gid, value is list of
# group members in form "name name name..."
#
# %gname2gid Assoc array, indexed by group name, value is
# matching gid.
#
# %gid2names Assoc array, indexed by gid, value is the
# list of group names with that gid in form
# "name name name...".
#
# You can also use routines named the same as the arrays - pass the index
# as the arg, get back the value. If you use this, get{gr|pw}{uid|gid|nam}
# will be used to lookup entries that aren't found in the cache.
#
# To be done:
# probably ought to add routines to deal with full names.
# maybe there ought to be some anal-retentive checking of password
# and group entries.
# probably ought to cache get{pw|gr}{nam|uid|gid} lookups also.
# probably ought to avoid overwriting existing entries (eg, duplicate
# names in password file would collide in the tables that are
# indexed by name).
#
# Disclaimer:
# If you use YP and you use netgroup entries such as
# +@servers::::::
# +:*:::::/usr/local/utils/messages
# then loading the password file in with &load_passwd_info(0) will get
# you mostly correct YP stuff *except* that it won't do the password and
# shell substitutions as you'd expect. You might want to use
# &load_passwd_info(1) instead to use getpwent calls to do the lookups,
# which would be more correct.
#
#
# minor changes to make it fit with the TCT program, 9/25/99, - dan
# A whole lot removed to clean it up for TSK - July 2008 - Brian
#
package main;
my $passwd_loaded = 0; # flags to use to avoid reloading everything
my $group_loaded = 0; # unnecessarily...
#
# Update user information for the user named $name. We cache the password,
# uid, login group, home directory and shell.
#
sub add_pw_info {
my ($name, $tmp, $uid) = @_;
if ((defined $name) && ($name ne "")) {
if ((defined $uid) && ($uid ne "")) {
if (defined($uid2names{$uid})) {
$uid2names{$uid} .= " $name";
}
else {
$uid2names{$uid} = $name;
}
}
}
}
#
# Update group information for the group named $name. We cache the gid
# and the list of group members.
#
sub add_gr_info {
my ($name, $tmp, $gid) = @_;
if ((defined $name) && ($name ne "")) {
if ((defined $gid) && ($gid ne "")) {
if (defined($gid2names{$gid})) {
$gid2names{$gid} .= " $name";
}
else {
$gid2names{$gid} = $name;
}
}
}
}
sub load_passwd_info {
my ($file_name) = @_;
my (@pw_info);
if ($passwd_loaded) {
return;
}
$passwd_loaded = 1;
open(FILE, $file_name)
|| die "can't open $file_name";
while (<FILE>) {
chop;
if ($_ !~ /^\+/) {
&add_pw_info(split(/:/));
}
}
close(FILE);
}
sub load_group_info {
my ($file_name) = @_;
my (@gr_info);
if ($group_loaded) {
return;
}
$group_loaded = 1;
open(FILE, $file_name)
|| die "can't open $file_name";
while (<FILE>) {
chop;
if ($_ !~ /^\+/) {
&add_gr_info(split(/:/));
}
}
close(FILE);
}
#
# Split a time machine record.
#
sub tm_split {
my ($line) = @_;
my (@fields);
for (@fields = split(/\|/, $line)) {
s/%([A-F0-9][A-F0-9])/pack("C", hex($1))/egis;
}
return @fields;
}
1;

View File

@ -18,7 +18,6 @@
*/ */
package org.sleuthkit.autopsy.timeline; package org.sleuthkit.autopsy.timeline;
import com.sun.javafx.application.PlatformImpl;
import java.awt.Component; import java.awt.Component;
import java.awt.Cursor; import java.awt.Cursor;
import java.awt.Dimension; import java.awt.Dimension;
@ -86,6 +85,7 @@ import org.openide.util.actions.Presenter;
import org.openide.util.lookup.Lookups; import org.openide.util.lookup.Lookups;
import org.openide.windows.WindowManager; import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.core.Installer;
import org.sleuthkit.autopsy.corecomponents.DataContentPanel; import org.sleuthkit.autopsy.corecomponents.DataContentPanel;
import org.sleuthkit.autopsy.corecomponents.DataResultPanel; import org.sleuthkit.autopsy.corecomponents.DataResultPanel;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
@ -98,7 +98,6 @@ import org.sleuthkit.autopsy.datamodel.FileNode;
import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.coreutils.ExecUtil; import org.sleuthkit.autopsy.coreutils.ExecUtil;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
@ -147,11 +146,7 @@ public class Timeline extends CallableSystemAction implements Presenter.Toolbar,
public Timeline() { public Timeline() {
super(); super();
org.sleuthkit.autopsy.core.Installer coreInstaller = fxInited = Installer.isJavaFxInited();
ModuleInstall.findObject(org.sleuthkit.autopsy.core.Installer.class, false);
if (coreInstaller != null) {
fxInited = coreInstaller.isJavaFxInited();
}
} }
@ -211,7 +206,7 @@ public class Timeline extends CallableSystemAction implements Presenter.Toolbar,
//JavaFX thread //JavaFX thread
//JavaFX components MUST be run in the JavaFX thread, otherwise massive amounts of exceptions will be thrown and caught. Liable to freeze up and crash. //JavaFX components MUST be run in the JavaFX thread, otherwise massive amounts of exceptions will be thrown and caught. Liable to freeze up and crash.
//Components can be declared whenever, but initialization and manipulation must take place here. //Components can be declared whenever, but initialization and manipulation must take place here.
PlatformImpl.runLater(new Runnable() { Platform.runLater(new Runnable() {
@Override @Override
public void run() { public void run() {
try { try {
@ -1044,18 +1039,23 @@ public class Timeline extends CallableSystemAction implements Presenter.Toolbar,
} }
private String makeMacTime(String pathToBodyFile) { private String makeMacTime(String pathToBodyFile) {
String cmdpath = "";
String macpath = ""; String macpath = "";
String[] mactimeArgs;
final String machome = macRoot.getAbsolutePath(); final String machome = macRoot.getAbsolutePath();
pathToBodyFile = PlatformUtil.getOSFilePath(pathToBodyFile); pathToBodyFile = PlatformUtil.getOSFilePath(pathToBodyFile);
if (PlatformUtil.isWindowsOS()) { if (PlatformUtil.isWindowsOS()) {
macpath = machome + java.io.File.separator + "mactime.exe"; macpath = machome + java.io.File.separator + "mactime.exe";
macpath = PlatformUtil.getOSFilePath(macpath); cmdpath = PlatformUtil.getOSFilePath(cmdpath);
mactimeArgs = new String[]{"-b", pathToBodyFile, "-d", "-y"};
} else { } else {
macpath = "perl " + machome + java.io.File.separator + "mactime.pl"; cmdpath = "perl";
macpath = machome + java.io.File.separator + "mactime.pl";
mactimeArgs = new String[]{macpath, "-b", pathToBodyFile, "-d", "-y"};
} }
String macfile = moduleDir.getAbsolutePath() + java.io.File.separator + mactimeFileName; String macfile = moduleDir.getAbsolutePath() + java.io.File.separator + mactimeFileName;
String[] mactimeArgs = new String[]{"-b", pathToBodyFile, "-d", "-y"};
String output = ""; String output = "";
ExecUtil execUtil = new ExecUtil(); ExecUtil execUtil = new ExecUtil();
@ -1063,7 +1063,7 @@ public class Timeline extends CallableSystemAction implements Presenter.Toolbar,
try { try {
//JavaSystemCaller.Exec.execute("\"" + command + "\""); //JavaSystemCaller.Exec.execute("\"" + command + "\"");
writer = new FileWriter(macfile); writer = new FileWriter(macfile);
execUtil.execute(writer, macpath, mactimeArgs); execUtil.execute(writer, cmdpath, mactimeArgs);
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
logger.log(Level.WARNING, "Mactime process was interrupted by user", ie); logger.log(Level.WARNING, "Mactime process was interrupted by user", ie);
return null; return null;

BIN
branding_autopsy/icon.icns Normal file

Binary file not shown.

View File

@ -86,7 +86,7 @@
<copy file="${basedir}/branding_${app.name}/icon.ico" tofile="${zip-tmp}/${app.name}/icon.ico" overwrite="true"/> <copy file="${basedir}/branding_${app.name}/icon.ico" tofile="${zip-tmp}/${app.name}/icon.ico" overwrite="true"/>
<property name="app.property.file" value="${zip-tmp}/${app.name}/etc/${app.name}.conf" /> <property name="app.property.file" value="${zip-tmp}/${app.name}/etc/${app.name}.conf" />
<property name="jvm.options" value="&quot;--branding ${app.name} -J-Xms24m -J-Xmx512m -J-XX:MaxPermSize=128M -J-Xverify:none&quot;" /> <property name="jvm.options" value="&quot;--branding ${app.name} -J-Xms24m -J-Xmx512m -J-XX:MaxPermSize=128M -J-Xverify:none -J-Xdock:name=${app.title}&quot;" />
<propertyfile file="${app.property.file}"> <propertyfile file="${app.property.file}">
<!-- Note: can be higher on 64 bit systems, should be in sync with project.properties --> <!-- Note: can be higher on 64 bit systems, should be in sync with project.properties -->
<entry key="default_options" value="@JVM_OPTIONS" /> <entry key="default_options" value="@JVM_OPTIONS" />