3415: Show SQLite table contents

- First cut.
This commit is contained in:
Raman 2018-01-19 13:01:08 -05:00
parent 1f44f08783
commit c4bb6dba61
6 changed files with 619 additions and 143 deletions

View File

@ -35,5 +35,11 @@ MessageContentViewer.attachmentsPanel.TabConstraints.tabTitle=Attachments
MessageContentViewer.viewInNewWindowButton.text=View in New Window
JPEGViewerDummy.jLabel1.text=You are looking at a JPEG file:
JPEGViewerDummy.jTextField1.text=jTextField1
SQLiteViewer.jLabel1.text=Table
SQLiteViewer.nextPageButton.text=
SQLiteViewer.prevPageButton.text=
SQLiteViewer.numPagesLabel.text=N
SQLiteViewer.jLabel3.text=of
SQLiteViewer.currPageLabel.text=x
SQLiteViewer.jLabel2.text=Page
SQLiteViewer.numEntriesField.text=num Entries
SQLiteViewer.jLabel1.text=Table

View File

@ -0,0 +1,89 @@
/*
* Autopsy Forensic Browser
*
* 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;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.sleuthkit.autopsy.datamodel.NodeProperty;
public class SQLiteTableRowFactory extends ChildFactory<Integer> {
private final ArrayList<Map<String, Object>> rows;
public SQLiteTableRowFactory(ArrayList<Map<String, Object>> rows) {
this.rows = rows;
}
@Override
protected boolean createKeys(List<Integer> keys) {
if (rows != null) {
for (int i = 0; i < rows.size(); i++) {
keys.add(i);
}
}
return true;
}
@Override
protected Node createNodeForKey(Integer key) {
if (Objects.isNull(rows) || rows.isEmpty() || key >= rows.size()) {
return null;
}
return new SQLiteTableRowNode(rows.get(key));
}
}
class SQLiteTableRowNode extends AbstractNode {
private final Map<String, Object> row;
public SQLiteTableRowNode(Map<String, Object> row) {
super(Children.LEAF);
this.row = row;
}
@Override
protected Sheet createSheet() {
Sheet s = super.createSheet();
Sheet.Set properties = s.get(Sheet.PROPERTIES);
if (properties == null) {
properties = Sheet.createPropertiesSet();
s.put(properties);
}
for (Map.Entry<String, Object> col : row.entrySet()) {
String colName = col.getKey();
String colVal = col.getValue().toString();
properties.put(new NodeProperty<>(colName, colName, colName, colVal)); // NON-NLS
}
return s;
}
}

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.4" maxVersion="1.9" 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="tableScrollPane" alignment="0" pref="400" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="tableScrollPane" alignment="0" pref="300" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="tableScrollPane">
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
</Container>
</SubComponents>
</Form>

View File

@ -0,0 +1,143 @@
/*
* Autopsy Forensic Browser
*
* 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;
import java.util.ArrayList;
import java.util.Map;
import java.util.Objects;
import javax.swing.ListSelectionModel;
import javax.swing.table.TableColumnModel;
import org.netbeans.swing.etable.ETableColumn;
import org.netbeans.swing.etable.ETableColumnModel;
import org.netbeans.swing.outline.Outline;
import org.openide.explorer.ExplorerManager;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
public class SQLiteTableView extends javax.swing.JPanel implements ExplorerManager.Provider {
private final Outline outline;
private final org.openide.explorer.view.OutlineView outlineView;
private ExplorerManager explorerManager;
private final ArrayList<Map<String, Object>> tableRows;
/**
* Creates new form SQLiteTableView
* @param rows
*/
public SQLiteTableView(ArrayList<Map<String, Object>> rows) {
this.tableRows = rows;
outlineView = new org.openide.explorer.view.OutlineView();
initComponents();
outline = outlineView.getOutline();
outlineView.setPropertyColumns(); // column headers will be set later
outline.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
customize();
}
private void customize() {
tableScrollPane.setViewportView(outlineView);
this.setVisible(true);
outline.setRowSelectionAllowed(false);
outline.setRootVisible(false);
explorerManager = new ExplorerManager();
explorerManager.setRootContext(new AbstractNode(Children.create(new SQLiteTableRowFactory(tableRows), true)));
setupColumns();
}
/**
* Sets up the columns in the display table
*/
private void setupColumns() {
if (Objects.isNull(tableRows) || tableRows.isEmpty())
return;
Map<String, Object> row = tableRows.get(0);
// Get the columns setup with respect to names and sortability
String[] propStrings = new String[row.size() * 2];
int i = 0;
for (Map.Entry<String, Object > col: row.entrySet()) {
String colName = col.getKey();
propStrings[2 * i] = colName;
propStrings[2 * i + 1] = colName;
i++;
}
outlineView.setPropertyColumns(propStrings);
// RAMAN TBD: Set width based on actual data in the top N rows??
// TBD: Cant seem to geta horizontal scroll bar
for (int col = 0; col< outline.getModel().getColumnCount(); col++) {
outline.getColumnModel().getColumn(col).setMinWidth(50);
}
// Hide the 'Nodes' column
TableColumnModel columnModel = outline.getColumnModel();
ETableColumn column = (ETableColumn) columnModel.getColumn(0);
((ETableColumnModel) columnModel).setColumnHidden(column, true);
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
tableScrollPane = new javax.swing.JScrollPane();
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
);
}// </editor-fold>//GEN-END:initComponents
@Override
public ExplorerManager getExplorerManager() {
return explorerManager;
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JScrollPane tableScrollPane;
// End of variables declaration//GEN-END:variables
}

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Form version="1.9" maxVersion="1.9" 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"/>
@ -16,22 +16,27 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jHdrPanel" alignment="0" max="32767" attributes="0"/>
<Component id="jTableDataPanel" alignment="0" max="32767" attributes="0"/>
<Component id="jHdrPanel" max="32767" attributes="0"/>
<Component id="jTableDataPanel" 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="jHdrPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Component id="jTableDataPanel" max="32767" attributes="0"/>
<Component id="jHdrPanel" min="-2" pref="53" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
<Component id="jTableDataPanel" pref="317" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JPanel" name="jHdrPanel">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[536, 40]"/>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
@ -39,11 +44,23 @@
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="tablesDropdownList" min="-2" pref="130" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="23" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="numEntriesField" min="-2" pref="71" max="-2" attributes="0"/>
<EmptySpace pref="130" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="15" max="-2" attributes="0"/>
<Component id="jLabel2" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="currPageLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jLabel3" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="numPagesLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="prevPageButton" min="-2" pref="23" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="nextPageButton" min="-2" pref="23" max="-2" attributes="0"/>
<EmptySpace pref="133" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -55,8 +72,14 @@
<Component id="tablesDropdownList" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="numEntriesField" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jLabel2" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="currPageLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jLabel3" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="numPagesLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="nextPageButton" alignment="0" min="-2" pref="23" max="-2" attributes="0"/>
<Component id="prevPageButton" alignment="0" min="-2" pref="23" max="-2" attributes="0"/>
</Group>
<EmptySpace pref="16" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -97,57 +120,113 @@
<Border info="null"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="jLabel2">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="SQLiteViewer.jLabel2.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="currPageLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="SQLiteViewer.currPageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="jLabel3">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="SQLiteViewer.jLabel3.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="numPagesLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="SQLiteViewer.numPagesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="prevPageButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/corecomponents/btn_step_back.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="SQLiteViewer.prevPageButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="borderPainted" type="boolean" value="false"/>
<Property name="contentAreaFilled" type="boolean" value="false"/>
<Property name="disabledSelectedIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png"/>
</Property>
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
<Insets value="[2, 0, 2, 0]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[23, 23]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="numEntriesFieldActionPerformed"/>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="prevPageButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="nextPageButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="SQLiteViewer.nextPageButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="borderPainted" type="boolean" value="false"/>
<Property name="contentAreaFilled" type="boolean" value="false"/>
<Property name="disabledSelectedIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png"/>
</Property>
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
<Insets value="[2, 0, 2, 0]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[23, 23]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="nextPageButtonActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="jTableDataPanel">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="jScrollPane1" pref="0" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="15" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="jScrollPane1" pref="275" max="32767" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTable" name="jTable1">
<Properties>
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.editors2.TableModelEditor">
<Table columnCount="4" rowCount="4">
<Column editable="true" title="Title 1" type="java.lang.Object"/>
<Column editable="true" title="Title 2" type="java.lang.Object"/>
<Column editable="true" title="Title 3" type="java.lang.Object"/>
<Column editable="true" title="Title 4" type="java.lang.Object"/>
</Table>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents>
<LayoutCode>
<CodeStatement>
<CodeExpression id="1_jTableDataPanel">
<CodeVariable name="jTableDataPanel" type="8194" declaredType="javax.swing.JPanel"/>
<ExpressionOrigin>
<ExpressionProvider type="ComponentRef">
<ComponentRef name="jTableDataPanel"/>
</ExpressionProvider>
</ExpressionOrigin>
</CodeExpression>
<StatementProvider type="CodeMethod">
<CodeMethod name="setLayout" class="java.awt.Container" parameterTypes="java.awt.LayoutManager"/>
</StatementProvider>
<Parameters>
<CodeExpression id="2">
<ExpressionOrigin>
<ExpressionProvider type="CodeConstructor">
<CodeConstructor class="javax.swing.OverlayLayout" parameterTypes="java.awt.Container"/>
</ExpressionProvider>
<Parameters>
<CodeExpression id="1_jTableDataPanel"/>
</Parameters>
</ExpressionOrigin>
</CodeExpression>
</Parameters>
</CodeStatement>
</LayoutCode>
</Container>
</SubComponents>
</Form>

View File

@ -1,21 +1,4 @@
/*
* Autopsy Forensic Browser
*
* 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;
import java.awt.Component;
@ -27,12 +10,17 @@ import java.util.logging.Level;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
import java.util.concurrent.ExecutionException;
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
@ -44,20 +32,21 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
public static final String[] SUPPORTED_MIMETYPES = new String[]{"application/x-sqlite3"};
private static final Logger LOGGER = Logger.getLogger(FileViewer.class.getName());
private Connection connection = null;
private String tmpDBPathName = null;
private File tmpDBFile = null;
// TBD: Change the value to be a Array of ColDefs
Map<String, String> dbTablesMap = new TreeMap<>();
private static final int ROWS_PER_PAGE = 100;
private int numRows; // num of rows in the selected table
private int currPage = 0; // curr page of rows being displayed
/**
* Creates new form SQLiteViewer
*/
public SQLiteViewer() {
initComponents();
customizeComponents();
}
/**
@ -73,9 +62,15 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
tablesDropdownList = new javax.swing.JComboBox<>();
jLabel1 = new javax.swing.JLabel();
numEntriesField = new javax.swing.JTextField();
jLabel2 = new javax.swing.JLabel();
currPageLabel = new javax.swing.JLabel();
jLabel3 = new javax.swing.JLabel();
numPagesLabel = new javax.swing.JLabel();
prevPageButton = new javax.swing.JButton();
nextPageButton = new javax.swing.JButton();
jTableDataPanel = new javax.swing.JPanel();
jScrollPane1 = new javax.swing.JScrollPane();
jTable1 = new javax.swing.JTable();
jHdrPanel.setPreferredSize(new java.awt.Dimension(536, 40));
tablesDropdownList.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
tablesDropdownList.addActionListener(new java.awt.event.ActionListener() {
@ -89,9 +84,38 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
numEntriesField.setEditable(false);
numEntriesField.setText(org.openide.util.NbBundle.getMessage(SQLiteViewer.class, "SQLiteViewer.numEntriesField.text")); // NOI18N
numEntriesField.setBorder(null);
numEntriesField.addActionListener(new java.awt.event.ActionListener() {
org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(SQLiteViewer.class, "SQLiteViewer.jLabel2.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(currPageLabel, org.openide.util.NbBundle.getMessage(SQLiteViewer.class, "SQLiteViewer.currPageLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(jLabel3, org.openide.util.NbBundle.getMessage(SQLiteViewer.class, "SQLiteViewer.jLabel3.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(numPagesLabel, org.openide.util.NbBundle.getMessage(SQLiteViewer.class, "SQLiteViewer.numPagesLabel.text")); // NOI18N
prevPageButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(prevPageButton, org.openide.util.NbBundle.getMessage(SQLiteViewer.class, "SQLiteViewer.prevPageButton.text")); // NOI18N
prevPageButton.setBorderPainted(false);
prevPageButton.setContentAreaFilled(false);
prevPageButton.setDisabledSelectedIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png"))); // NOI18N
prevPageButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
prevPageButton.setPreferredSize(new java.awt.Dimension(23, 23));
prevPageButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
numEntriesFieldActionPerformed(evt);
prevPageButtonActionPerformed(evt);
}
});
nextPageButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(nextPageButton, org.openide.util.NbBundle.getMessage(SQLiteViewer.class, "SQLiteViewer.nextPageButton.text")); // NOI18N
nextPageButton.setBorderPainted(false);
nextPageButton.setContentAreaFilled(false);
nextPageButton.setDisabledSelectedIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png"))); // NOI18N
nextPageButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
nextPageButton.setPreferredSize(new java.awt.Dimension(23, 23));
nextPageButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
nextPageButtonActionPerformed(evt);
}
});
@ -102,11 +126,23 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
.addGroup(jHdrPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(jLabel1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(tablesDropdownList, javax.swing.GroupLayout.PREFERRED_SIZE, 130, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(23, 23, 23)
.addGap(18, 18, 18)
.addComponent(numEntriesField, javax.swing.GroupLayout.PREFERRED_SIZE, 71, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(130, Short.MAX_VALUE))
.addGap(15, 15, 15)
.addComponent(jLabel2)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(currPageLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jLabel3)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(numPagesLabel)
.addGap(18, 18, 18)
.addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, 0)
.addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(133, Short.MAX_VALUE))
);
jHdrPanelLayout.setVerticalGroup(
jHdrPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -115,40 +151,18 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
.addGroup(jHdrPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(tablesDropdownList, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel1)
.addComponent(numEntriesField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addContainerGap(16, Short.MAX_VALUE))
);
jTable1.setModel(new javax.swing.table.DefaultTableModel(
new Object [][] {
{null, null, null, null},
{null, null, null, null},
{null, null, null, null},
{null, null, null, null}
},
new String [] {
"Title 1", "Title 2", "Title 3", "Title 4"
}
));
jScrollPane1.setViewportView(jTable1);
javax.swing.GroupLayout jTableDataPanelLayout = new javax.swing.GroupLayout(jTableDataPanel);
jTableDataPanel.setLayout(jTableDataPanelLayout);
jTableDataPanelLayout.setHorizontalGroup(
jTableDataPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jTableDataPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
.addGap(15, 15, 15))
);
jTableDataPanelLayout.setVerticalGroup(
jTableDataPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jTableDataPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 275, Short.MAX_VALUE)
.addComponent(numEntriesField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel2)
.addComponent(currPageLabel)
.addComponent(jLabel3)
.addComponent(numPagesLabel)
.addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE))
.addContainerGap())
);
jTableDataPanel.setLayout(new javax.swing.OverlayLayout(jTableDataPanel));
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
@ -159,15 +173,39 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jHdrPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jTableDataPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addComponent(jHdrPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 53, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, 0)
.addComponent(jTableDataPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 317, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
private void numEntriesFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_numEntriesFieldActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_numEntriesFieldActionPerformed
private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed
currPage++;
if (currPage * ROWS_PER_PAGE > numRows) {
nextPageButton.setEnabled(false);
}
currPageLabel.setText(Integer.toString(currPage));
prevPageButton.setEnabled(true);
// read and display a page of rows
String tableName = (String) this.tablesDropdownList.getSelectedItem();
readTable(tableName, (currPage - 1) * ROWS_PER_PAGE + 1, ROWS_PER_PAGE);
}//GEN-LAST:event_nextPageButtonActionPerformed
private void prevPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prevPageButtonActionPerformed
currPage--;
if (currPage == 1) {
prevPageButton.setEnabled(false);
}
currPageLabel.setText(Integer.toString(currPage));
nextPageButton.setEnabled(true);
// read and display a page of rows
String tableName = (String) this.tablesDropdownList.getSelectedItem();
readTable(tableName, (currPage - 1) * ROWS_PER_PAGE + 1, ROWS_PER_PAGE);
}//GEN-LAST:event_prevPageButtonActionPerformed
private void tablesDropdownListActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tablesDropdownListActionPerformed
JComboBox<String> cb = (JComboBox<String>) evt.getSource();
@ -176,17 +214,21 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
return;
}
readTable(tableName);
selectTable(tableName);
}//GEN-LAST:event_tablesDropdownListActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel currPageLabel;
private javax.swing.JPanel jHdrPanel;
private javax.swing.JLabel jLabel1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTable jTable1;
private javax.swing.JLabel jLabel2;
private javax.swing.JLabel jLabel3;
private javax.swing.JPanel jTableDataPanel;
private javax.swing.JButton nextPageButton;
private javax.swing.JTextField numEntriesField;
private javax.swing.JLabel numPagesLabel;
private javax.swing.JButton prevPageButton;
private javax.swing.JComboBox<String> tablesDropdownList;
// End of variables declaration//GEN-END:variables
@ -209,11 +251,11 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
public void resetComponent() {
dbTablesMap.clear();
tablesDropdownList.setEnabled(true);
tablesDropdownList.removeAllItems();
numEntriesField.setText("");
// close DB connection to file
if (null != connection) {
try {
@ -231,11 +273,6 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
}
}
private void customizeComponents() {
// add a actionListener to jTablesComboBox
}
/**
* Process the given SQLite DB file
*
@ -327,30 +364,26 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
// RAMAN TBD: parse and save the table schema
}
} catch (Exception ex) {
} catch (SQLException ex) {
LOGGER.log(Level.WARNING, "Error while trying to get columns from sqlite db." + connection, ex); //NON-NLS
}
}
} catch (Exception e) {
} catch (SQLException e) {
LOGGER.log(Level.SEVERE, "Error getting table names from the DB", e); //NON-NLS
}
return true;
}
private void readTable(String tableName) {
// TBD: need to handle cancelling if one is already in progress
new SwingWorker<Integer, Void>() {
private void selectTable(String tableName) {
new SwingWorker<Integer, Void>() {
@Override
protected Integer doInBackground() throws Exception {
try {
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(
"SELECT COUNT(*) as count FROM " + tableName); //NON-NLS
"SELECT count (*) as count FROM " + tableName); //NON-NLS
// TBD: read the rows here and popluate the ExplorerManager.
return resultSet.getInt("count");
} catch (SQLException ex) {
LOGGER.log(Level.SEVERE, "Failed to get data for table.", ex); //NON-NLS
@ -363,8 +396,70 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
protected void done() {
super.done();
try {
int numRows = get();
numRows = get();
numEntriesField.setText(numRows + " entries");
currPage = 1;
currPageLabel.setText(Integer.toString(currPage));
numPagesLabel.setText(Integer.toString((numRows/ROWS_PER_PAGE)+1));
prevPageButton.setEnabled(false);
jTableDataPanel.removeAll();
jTableDataPanel.repaint();
if (numRows > 0) {
nextPageButton.setEnabled(((numRows > ROWS_PER_PAGE)));
readTable(tableName, (currPage-1)*ROWS_PER_PAGE + 1, ROWS_PER_PAGE);
}
else {
nextPageButton.setEnabled(false);
}
} catch (InterruptedException | ExecutionException ex) {
LOGGER.log(Level.SEVERE, "Unexpected exception while reading table.", ex); //NON-NLS
}
}
}.execute();
}
private void readTable(String tableName, int startRow, int numRowsToRead) {
// TBD: need to handle cancelling if one is already in progress
new SwingWorker<ArrayList<Map<String, Object>>, Void>() {
@Override
protected ArrayList<Map<String, Object>> doInBackground() throws Exception {
try {
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(
"SELECT * FROM " + tableName
+ " LIMIT " + Integer.toString(numRowsToRead)
+ " OFFSET " + Integer.toString(startRow - 1)
); //NON-NLS
return resultSetToArrayList(resultSet);
} catch (SQLException ex) {
LOGGER.log(Level.SEVERE, "Failed to get data for table.", ex); //NON-NLS
}
//NON-NLS
return null;
}
@Override
protected void done() {
super.done();
try {
ArrayList<Map<String, Object>> rows = get();
if (Objects.nonNull(rows)) {
JPanel selectedTableView = new SQLiteTableView(rows);
jTableDataPanel.removeAll();
jTableDataPanel.setLayout(new javax.swing.OverlayLayout(jTableDataPanel));
jTableDataPanel.add(selectedTableView);
jTableDataPanel.repaint();
}
} catch (InterruptedException | ExecutionException ex) {
LOGGER.log(Level.SEVERE, "Unexpected exception while reading table.", ex); //NON-NLS
}
@ -373,6 +468,29 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
}
private ArrayList<Map<String, Object>> resultSetToArrayList(ResultSet rs) throws SQLException {
ResultSetMetaData md = rs.getMetaData();
int columns = md.getColumnCount();
ArrayList<Map<String, Object>> arraylist = new ArrayList<>();
while (rs.next()) {
Map<String, Object> row = new LinkedHashMap<>(columns);
for (int i = 1; i <= columns; ++i) {
if (rs.getObject(i) == null) {
row.put(md.getColumnName(i), "");
} else {
if (md.getColumnTypeName(i).compareToIgnoreCase("blob") == 0) {
row.put(md.getColumnName(i), "BLOB Data not shown...");
} else {
row.put(md.getColumnName(i), rs.getObject(i));
}
}
}
arraylist.add(row);
}
return arraylist;
}
enum SQLStorageClass {
NULL,
INTEGER,
@ -390,6 +508,13 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
this.colName = colName;
this.storageClass = sc;
}
public String getColName() {
return colName;
}
public SQLStorageClass getColStorageClass() {
return storageClass;
}
}
}