mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-15 09:17:42 +00:00
3504: Allow user to format SQLite columns as EPOCH dates
This commit is contained in:
parent
399c7adfb8
commit
707ec08eff
@ -1,7 +1,20 @@
|
|||||||
/*
|
/*
|
||||||
* To change this license header, choose License Headers in Project Properties.
|
* Autopsy Forensic Browser
|
||||||
* To change this template file, choose Tools | Templates
|
*
|
||||||
* and open the template in the editor.
|
* Copyright 2018 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.contentviewers;
|
package org.sleuthkit.autopsy.contentviewers;
|
||||||
|
|
||||||
@ -17,8 +30,8 @@ import org.openide.nodes.Node;
|
|||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Custom Cell renderer to display a SQLite column cell as readable Epoch date/time
|
||||||
*
|
*
|
||||||
* @author raman
|
|
||||||
*/
|
*/
|
||||||
public class EpochTimeCellRenderer extends DefaultTableCellRenderer {
|
public class EpochTimeCellRenderer extends DefaultTableCellRenderer {
|
||||||
|
|
||||||
@ -26,40 +39,52 @@ public class EpochTimeCellRenderer extends DefaultTableCellRenderer {
|
|||||||
private static final Logger LOGGER = Logger.getLogger(FileViewer.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(FileViewer.class.getName());
|
||||||
|
|
||||||
private static final String FORMAT_STRING = "yyyy/MM/dd HH:mm:ss"; //NON-NLS
|
private static final String FORMAT_STRING = "yyyy/MM/dd HH:mm:ss"; //NON-NLS
|
||||||
private static final SimpleDateFormat dateFormat = new SimpleDateFormat(FORMAT_STRING);
|
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat(FORMAT_STRING);
|
||||||
|
|
||||||
private final boolean renderAsEpoch;
|
private final boolean renderAsEpoch;
|
||||||
|
|
||||||
public EpochTimeCellRenderer(boolean renderAsEpoch) {
|
EpochTimeCellRenderer(boolean renderAsEpoch) {
|
||||||
this.renderAsEpoch = renderAsEpoch;
|
this.renderAsEpoch = renderAsEpoch;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
|
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
|
||||||
if (value != null) {
|
|
||||||
|
// Set the forceground/background so its obvious when the cell is selected.
|
||||||
String textStr = "No Value";
|
if (isSelected) {
|
||||||
|
super.setForeground(table.getSelectionForeground());
|
||||||
|
super.setBackground(table.getSelectionBackground());
|
||||||
|
} else {
|
||||||
|
super.setForeground( table.getForeground());
|
||||||
|
super.setBackground( table.getBackground());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value == null) {
|
||||||
|
setText("");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
String textStr = "";
|
||||||
try {
|
try {
|
||||||
|
// get the col property value
|
||||||
if (value instanceof Node.Property<?>) {
|
if (value instanceof Node.Property<?>) {
|
||||||
Node.Property<?> np = (Node.Property)value;
|
Node.Property<?> nodeProp = (Node.Property)value;
|
||||||
textStr = np.getValue().toString();
|
textStr = nodeProp.getValue().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (renderAsEpoch) {
|
if (renderAsEpoch) {
|
||||||
long epochTime = Long.parseUnsignedLong(textStr);
|
long epochTime = Long.parseUnsignedLong(textStr);
|
||||||
if (epochTime > 0 ) {
|
if (epochTime > 0 ) {
|
||||||
|
Font font = getFont();
|
||||||
Font f = getFont();
|
setFont(font.deriveFont(font.getStyle() | Font.ITALIC));
|
||||||
setFont(f.deriveFont(f.getStyle() | Font.ITALIC));
|
setText(DATE_FORMAT.format(new Date(epochTime)));
|
||||||
setText(dateFormat.format(new Date(epochTime)));
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
setText(textStr);
|
setText(textStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else { // Display raw data
|
||||||
setText(textStr);
|
setText(textStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (NumberFormatException e) {
|
catch (NumberFormatException e) {
|
||||||
setText(textStr);
|
setText(textStr);
|
||||||
@ -69,12 +94,12 @@ public class EpochTimeCellRenderer extends DefaultTableCellRenderer {
|
|||||||
LOGGER.log(Level.SEVERE, "Error in getting column value.", ex); //NON-NLS
|
LOGGER.log(Level.SEVERE, "Error in getting column value.", ex); //NON-NLS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
setText("");
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isRenderingAsEpoch() {
|
||||||
|
return this.renderAsEpoch;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -18,17 +18,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.contentviewers;
|
package org.sleuthkit.autopsy.contentviewers;
|
||||||
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import javax.swing.AbstractAction;
|
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import javax.swing.table.TableColumn;
|
|
||||||
import javax.swing.table.TableColumnModel;
|
|
||||||
import org.netbeans.swing.outline.Outline;
|
|
||||||
import org.openide.nodes.AbstractNode;
|
import org.openide.nodes.AbstractNode;
|
||||||
import org.openide.nodes.ChildFactory;
|
import org.openide.nodes.ChildFactory;
|
||||||
import org.openide.nodes.Children;
|
import org.openide.nodes.Children;
|
||||||
@ -36,13 +31,15 @@ import org.openide.nodes.Node;
|
|||||||
import org.openide.nodes.Sheet;
|
import org.openide.nodes.Sheet;
|
||||||
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory class to generate nodes for SQLite table rows
|
||||||
|
*/
|
||||||
public class SQLiteTableRowFactory extends ChildFactory<Integer> {
|
public class SQLiteTableRowFactory extends ChildFactory<Integer> {
|
||||||
|
|
||||||
private final List<Map<String, Object>> rows;
|
private final List<Map<String, Object>> rows;
|
||||||
//private final Outline outline;
|
|
||||||
private final List<Action> colActions;
|
private final List<Action> colActions;
|
||||||
|
|
||||||
public SQLiteTableRowFactory(List<Map<String, Object>> rows, List<Action> actions ) {
|
SQLiteTableRowFactory(List<Map<String, Object>> rows, List<Action> actions ) {
|
||||||
this.rows = rows;
|
this.rows = rows;
|
||||||
this.colActions = actions;
|
this.colActions = actions;
|
||||||
}
|
}
|
||||||
@ -68,13 +65,15 @@ public class SQLiteTableRowFactory extends ChildFactory<Integer> {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Node for SQLite table row
|
||||||
|
*/
|
||||||
class SQLiteTableRowNode extends AbstractNode {
|
class SQLiteTableRowNode extends AbstractNode {
|
||||||
|
|
||||||
private final Map<String, Object> row;
|
private final Map<String, Object> row;
|
||||||
//private final Outline outline;
|
|
||||||
private final List<Action> nodeActions;
|
private final List<Action> nodeActions;
|
||||||
|
|
||||||
|
|
||||||
SQLiteTableRowNode(Map<String, Object> row, List<Action> actions) {
|
SQLiteTableRowNode(Map<String, Object> row, List<Action> actions) {
|
||||||
super(Children.LEAF);
|
super(Children.LEAF);
|
||||||
this.row = row;
|
this.row = row;
|
||||||
@ -84,21 +83,20 @@ class SQLiteTableRowNode extends AbstractNode {
|
|||||||
@Override
|
@Override
|
||||||
protected Sheet createSheet() {
|
protected Sheet createSheet() {
|
||||||
|
|
||||||
Sheet s = super.createSheet();
|
Sheet sheet = super.createSheet();
|
||||||
Sheet.Set properties = s.get(Sheet.PROPERTIES);
|
Sheet.Set properties = sheet.get(Sheet.PROPERTIES);
|
||||||
if (properties == null) {
|
if (properties == null) {
|
||||||
properties = Sheet.createPropertiesSet();
|
properties = Sheet.createPropertiesSet();
|
||||||
s.put(properties);
|
sheet.put(properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<String, Object> col : row.entrySet()) {
|
for (Map.Entry<String, Object> col : row.entrySet()) {
|
||||||
String colName = col.getKey();
|
String colName = col.getKey();
|
||||||
String colVal = col.getValue().toString();
|
String colVal = col.getValue().toString();
|
||||||
|
|
||||||
properties.put(new NodeProperty<>(colName, colName, colName, colVal)); // NON-NLS
|
properties.put(new NodeProperty<>(colName, colName, colName, colVal)); // NON-NLS
|
||||||
}
|
}
|
||||||
|
|
||||||
return s;
|
return sheet;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -106,10 +104,8 @@ class SQLiteTableRowNode extends AbstractNode {
|
|||||||
List<Action> actions = new ArrayList<>();
|
List<Action> actions = new ArrayList<>();
|
||||||
|
|
||||||
actions.addAll(Arrays.asList(super.getActions(context)));
|
actions.addAll(Arrays.asList(super.getActions(context)));
|
||||||
|
|
||||||
actions.addAll(nodeActions);
|
actions.addAll(nodeActions);
|
||||||
//actions.add(parseColAction);
|
|
||||||
|
|
||||||
return actions.toArray(new Action[actions.size()]);
|
return actions.toArray(new Action[actions.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,8 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import javax.swing.AbstractAction;
|
import javax.swing.AbstractAction;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
|
import javax.swing.JMenu;
|
||||||
|
import javax.swing.JMenuItem;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JTable;
|
import javax.swing.JTable;
|
||||||
import javax.swing.ListSelectionModel;
|
import javax.swing.ListSelectionModel;
|
||||||
@ -41,7 +43,12 @@ import org.netbeans.swing.outline.Outline;
|
|||||||
import org.openide.explorer.ExplorerManager;
|
import org.openide.explorer.ExplorerManager;
|
||||||
import org.openide.nodes.AbstractNode;
|
import org.openide.nodes.AbstractNode;
|
||||||
import org.openide.nodes.Children;
|
import org.openide.nodes.Children;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.util.actions.Presenter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Panel to display a SQLite table
|
||||||
|
*/
|
||||||
class SQLiteTableView extends JPanel implements ExplorerManager.Provider {
|
class SQLiteTableView extends JPanel implements ExplorerManager.Provider {
|
||||||
|
|
||||||
private final org.openide.explorer.view.OutlineView outlineView;
|
private final org.openide.explorer.view.OutlineView outlineView;
|
||||||
@ -68,6 +75,7 @@ class SQLiteTableView extends JPanel implements ExplorerManager.Provider {
|
|||||||
outline.setRowSelectionAllowed(false);
|
outline.setRowSelectionAllowed(false);
|
||||||
outline.setRootVisible(false);
|
outline.setRootVisible(false);
|
||||||
|
|
||||||
|
outline.setCellSelectionEnabled(true);
|
||||||
explorerManager = new ExplorerManager();
|
explorerManager = new ExplorerManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,6 +84,10 @@ class SQLiteTableView extends JPanel implements ExplorerManager.Provider {
|
|||||||
*
|
*
|
||||||
* @param tableRows
|
* @param tableRows
|
||||||
*/
|
*/
|
||||||
|
@NbBundle.Messages({"SQLiteTableView.DisplayAs.text=Display as",
|
||||||
|
"SQLiteTableView.DisplayAsMenuItem.Date=Date",
|
||||||
|
"SQLiteTableView.DisplayAsMenuItem.RawData=Raw Data"
|
||||||
|
})
|
||||||
void setupTable(List<Map<String, Object>> tableRows) {
|
void setupTable(List<Map<String, Object>> tableRows) {
|
||||||
|
|
||||||
|
|
||||||
@ -110,10 +122,8 @@ class SQLiteTableView extends JPanel implements ExplorerManager.Provider {
|
|||||||
|
|
||||||
List<Action> nodeActions = new ArrayList<>();
|
List<Action> nodeActions = new ArrayList<>();
|
||||||
|
|
||||||
nodeActions.add(new ParseColAction("Parse column as Epoch time", outline, new EpochTimeCellRenderer(true)) );
|
nodeActions.add(new ParseColAction(Bundle.SQLiteTableView_DisplayAs_text(), outline) );
|
||||||
//nodeActions.add(new ParseColAction("Display column as original type", outline, new DefaultTableCellRenderer()) );
|
|
||||||
nodeActions.add(new ParseColAction("Display column as original type", outline, new EpochTimeCellRenderer(false)) );
|
|
||||||
|
|
||||||
explorerManager.setRootContext(new AbstractNode(Children.create(new SQLiteTableRowFactory(tableRows, nodeActions), true)));
|
explorerManager.setRootContext(new AbstractNode(Children.create(new SQLiteTableRowFactory(tableRows, nodeActions), true)));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -173,26 +183,77 @@ class SQLiteTableView extends JPanel implements ExplorerManager.Provider {
|
|||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
|
|
||||||
private class ParseColAction extends AbstractAction {
|
/**
|
||||||
|
* Action to handle "Display as" menu item.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private class ParseColAction extends AbstractAction implements Presenter.Popup {
|
||||||
private final Outline outline;
|
private final Outline outline;
|
||||||
private TableCellRenderer colCellRenderer;
|
private final String displayName;
|
||||||
|
|
||||||
|
ParseColAction(String displayName, Outline outline ) {
|
||||||
private ParseColAction(String displayName, Outline outline, TableCellRenderer colCellRenderer ) {
|
|
||||||
super(displayName);
|
super(displayName);
|
||||||
this.outline = outline;
|
this.outline = outline;
|
||||||
this.colCellRenderer = colCellRenderer;
|
this.displayName = displayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
int selCol = outline.getSelectedColumn();
|
@Override
|
||||||
|
public JMenuItem getPopupPresenter() {
|
||||||
TableColumnModel columnModel = outline.getColumnModel();
|
return new DisplayColAsMenu();
|
||||||
|
}
|
||||||
TableColumn column = columnModel.getColumn(selCol);
|
|
||||||
column.setCellRenderer(colCellRenderer);
|
/**
|
||||||
|
* Class to SubMenu for "Display As" menu
|
||||||
|
*/
|
||||||
|
private class DisplayColAsMenu extends JMenu {
|
||||||
|
|
||||||
|
DisplayColAsMenu() {
|
||||||
|
super(displayName);
|
||||||
|
initMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
final void initMenu() {
|
||||||
|
|
||||||
|
int selCol = outline.getSelectedColumn();
|
||||||
|
if (selCol < 0 ) {
|
||||||
|
selCol = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableColumnModel columnModel = outline.getColumnModel();
|
||||||
|
TableColumn column = columnModel.getColumn(selCol);
|
||||||
|
|
||||||
|
JMenuItem parseAsEpochItem = new JMenuItem(Bundle.SQLiteTableView_DisplayAsMenuItem_Date());
|
||||||
|
parseAsEpochItem.addActionListener((ActionEvent evt) -> {
|
||||||
|
column.setCellRenderer(new EpochTimeCellRenderer(true));
|
||||||
|
});
|
||||||
|
parseAsEpochItem.setEnabled(false);
|
||||||
|
add(parseAsEpochItem);
|
||||||
|
|
||||||
|
JMenuItem parseAsOriginalItem = new JMenuItem(Bundle.SQLiteTableView_DisplayAsMenuItem_RawData());
|
||||||
|
parseAsOriginalItem.addActionListener((ActionEvent evt) -> {
|
||||||
|
column.setCellRenderer(new EpochTimeCellRenderer(false));
|
||||||
|
});
|
||||||
|
parseAsOriginalItem.setEnabled(false);
|
||||||
|
add(parseAsOriginalItem);
|
||||||
|
|
||||||
|
// Enable the relevant menuitem based on the current display state of the column
|
||||||
|
TableCellRenderer currRenderer = column.getCellRenderer();
|
||||||
|
if (currRenderer instanceof EpochTimeCellRenderer) {
|
||||||
|
if (((EpochTimeCellRenderer) currRenderer).isRenderingAsEpoch()) {
|
||||||
|
parseAsOriginalItem.setEnabled(true);
|
||||||
|
} else {
|
||||||
|
parseAsEpochItem.setEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
parseAsEpochItem.setEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user