mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-08 14:19:32 +00:00
TSK-270 Provide Hit Navigation in keyword search results
- initial version, index/scrolling needs to be more precise
This commit is contained in:
parent
681c136f12
commit
54a5abff8e
@ -7,3 +7,10 @@ KeywordSearchTopComponent.filesIndexedNameLabel.text=Files indexed:
|
|||||||
KeywordSearchTopComponent.filesIndexedValLabel.text=-
|
KeywordSearchTopComponent.filesIndexedValLabel.text=-
|
||||||
KeywordSearchTopComponent.filesIndexedNameLabel.AccessibleContext.accessibleName=Files indexed:
|
KeywordSearchTopComponent.filesIndexedNameLabel.AccessibleContext.accessibleName=Files indexed:
|
||||||
KeywordSearchTopComponent.filesIndexedValLabel.AccessibleContext.accessibleName=-
|
KeywordSearchTopComponent.filesIndexedValLabel.AccessibleContext.accessibleName=-
|
||||||
|
ExtractedContentPanel.hitLabel.text=Hit:
|
||||||
|
ExtractedContentPanel.hitCountLabel.text=-
|
||||||
|
ExtractedContentPanel.hitOfLabel.text=of
|
||||||
|
ExtractedContentPanel.hitTotalLabel.text=-
|
||||||
|
ExtractedContentPanel.hitButtonsLabel.text=Hit
|
||||||
|
ExtractedContentPanel.hitPreviousButton.text=
|
||||||
|
ExtractedContentPanel.hitNextButton.text=
|
||||||
|
@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2011 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.keywordsearch;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import org.apache.commons.lang.StringEscapeUtils;
|
||||||
|
|
||||||
|
|
||||||
|
public class ExtractedContentFind {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(ExtractedContentFind.class.getName());
|
||||||
|
|
||||||
|
ExtractedContentFind(ExtractedContentViewer viewer) {
|
||||||
|
this.viewer = viewer;
|
||||||
|
findIndex = new HashMap<MarkupSource, ArrayList<Long>>();
|
||||||
|
curIndex = new HashMap<MarkupSource, Integer>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private HashMap<MarkupSource, ArrayList<Long>>findIndex;
|
||||||
|
private HashMap<MarkupSource, Integer>curIndex;
|
||||||
|
private ExtractedContentViewer viewer;
|
||||||
|
|
||||||
|
public static int INDEX_INITIALIZED = -1;
|
||||||
|
public static int INDEX_NOT_FOUND = -2;
|
||||||
|
|
||||||
|
public int getCurrentIndexTotal(MarkupSource source) {
|
||||||
|
ArrayList<Long> index = indexSource(source);
|
||||||
|
return index.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCurrentIndexI(MarkupSource source) {
|
||||||
|
indexSource(source);
|
||||||
|
Integer curI = curIndex.get(source);
|
||||||
|
if (curI != null)
|
||||||
|
return curI;
|
||||||
|
else return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get next line number corresponding to indexed match, no wrapping
|
||||||
|
* requires call to hasNext() first
|
||||||
|
* or INDEX_NOT_FOUND if no next hit
|
||||||
|
* @param source
|
||||||
|
* @return line number where match occurs
|
||||||
|
*/
|
||||||
|
public long getNext(MarkupSource source) {
|
||||||
|
ArrayList<Long> index = indexSource(source);
|
||||||
|
int total = index.size();
|
||||||
|
int cur = curIndex.get(source);
|
||||||
|
if (total == 0 || cur == total -1) return INDEX_NOT_FOUND;
|
||||||
|
++cur;
|
||||||
|
//update curIndex location
|
||||||
|
curIndex.put(source, cur);
|
||||||
|
return index.get(cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param source
|
||||||
|
* @return true if the source has next hit
|
||||||
|
*/
|
||||||
|
public boolean hasNext(MarkupSource source) {
|
||||||
|
ArrayList<Long> index = indexSource(source);
|
||||||
|
int total = index.size();
|
||||||
|
int cur = curIndex.get(source);
|
||||||
|
if (total == 0) return false;
|
||||||
|
else if (cur == INDEX_INITIALIZED) return true;
|
||||||
|
else if (cur == total - 1)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param source
|
||||||
|
* @return true if the source has previous hit
|
||||||
|
*/
|
||||||
|
public boolean hasPrevious(MarkupSource source) {
|
||||||
|
ArrayList<Long> index = indexSource(source);
|
||||||
|
int total = index.size();
|
||||||
|
int cur = curIndex.get(source);
|
||||||
|
if (total == 0) return false;
|
||||||
|
else if (cur == INDEX_INITIALIZED) return false;
|
||||||
|
else if (cur == 0) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get previous line number corresponding to indexed match, no wrapping
|
||||||
|
* requires call to hasPrevious() first
|
||||||
|
* or INDEX_NOT_FOUND if no previous hit
|
||||||
|
* @param source
|
||||||
|
* @return line number where match occurs
|
||||||
|
*/
|
||||||
|
public long getPrevious(MarkupSource source) {
|
||||||
|
ArrayList<Long> index = indexSource(source);
|
||||||
|
int total = index.size();
|
||||||
|
int cur = curIndex.get(source);
|
||||||
|
if (total == 0 || cur == 0) return INDEX_NOT_FOUND;
|
||||||
|
--cur;
|
||||||
|
//update curIndex location
|
||||||
|
curIndex.put(source, cur);
|
||||||
|
return index.get(cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add MarkupSource to find functionality, or return if already exists for that source.
|
||||||
|
* @param source MarkupSource to add to find
|
||||||
|
*/
|
||||||
|
private ArrayList<Long> indexSource(MarkupSource source) {
|
||||||
|
//return if already indexed
|
||||||
|
ArrayList<Long> indexed = findIndex.get(source);
|
||||||
|
if (indexed != null || source.isSearchable() == false)
|
||||||
|
return indexed;
|
||||||
|
|
||||||
|
indexed = new ArrayList<Long>();
|
||||||
|
String markup = source.getMarkup();
|
||||||
|
|
||||||
|
//logger.log(Level.INFO,markup);
|
||||||
|
final String indexSearchTok = source.getSearchToken();
|
||||||
|
if (indexSearchTok == null || indexSearchTok.equals("")) {
|
||||||
|
return indexed;
|
||||||
|
}
|
||||||
|
final int indexSearchTokLen = indexSearchTok.length();
|
||||||
|
long docOffset = 0;
|
||||||
|
long index = -1;
|
||||||
|
|
||||||
|
while ((index = markup.indexOf(indexSearchTok, (int)docOffset)) >= 0) {
|
||||||
|
//TODO check if (int) cast above presents limitation for large files
|
||||||
|
|
||||||
|
//calculate and store index stripping all markup for scrolling to work properly
|
||||||
|
//need to map index to content with no html
|
||||||
|
//try cheat: compensata fot highlight tags (might be other things, such as escape chars)
|
||||||
|
//perfectly we'd scan both documents at same time and map index from one to another
|
||||||
|
indexed.add(index);
|
||||||
|
docOffset = index + indexSearchTokLen; //next offset past the keyword
|
||||||
|
}
|
||||||
|
//add indices to index collection
|
||||||
|
findIndex.put(source, indexed);
|
||||||
|
//add current for tracking
|
||||||
|
curIndex.put(source, INDEX_INITIALIZED);
|
||||||
|
|
||||||
|
return indexed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -17,7 +17,21 @@
|
|||||||
<DimensionLayout dim="0">
|
<DimensionLayout dim="0">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" alignment="1" attributes="0">
|
<Group type="102" alignment="1" attributes="0">
|
||||||
<EmptySpace pref="334" max="32767" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="hitLabel" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||||
|
<Component id="hitCountLabel" min="-2" pref="12" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="hitOfLabel" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||||
|
<Component id="hitTotalLabel" min="-2" pref="18" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace min="-2" pref="41" max="-2" attributes="0"/>
|
||||||
|
<Component id="hitButtonsLabel" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||||
|
<Component id="hitPreviousButton" min="-2" pref="23" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="hitNextButton" min="-2" pref="23" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace pref="125" max="32767" attributes="0"/>
|
||||||
<Component id="sourceComboBox" min="-2" max="-2" attributes="0"/>
|
<Component id="sourceComboBox" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
@ -27,9 +41,20 @@
|
|||||||
<DimensionLayout dim="1">
|
<DimensionLayout dim="1">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" alignment="0" attributes="0">
|
<Group type="102" alignment="0" attributes="0">
|
||||||
<Component id="sourceComboBox" min="-2" max="-2" attributes="0"/>
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Group type="103" groupAlignment="3" attributes="0">
|
||||||
|
<Component id="sourceComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="hitLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="hitButtonsLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="hitOfLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="hitTotalLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="hitCountLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
<Component id="hitPreviousButton" min="-2" pref="23" max="-2" attributes="0"/>
|
||||||
|
<Component id="hitNextButton" min="-2" pref="23" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Component id="jScrollPane1" pref="274" max="32767" attributes="0"/>
|
<Component id="jScrollPane1" pref="271" max="32767" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
@ -62,5 +87,60 @@
|
|||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
|
<Component class="javax.swing.JLabel" name="hitLabel">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/keywordsearch/Bundle.properties" key="ExtractedContentPanel.hitLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JLabel" name="hitCountLabel">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/keywordsearch/Bundle.properties" key="ExtractedContentPanel.hitCountLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JLabel" name="hitOfLabel">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/keywordsearch/Bundle.properties" key="ExtractedContentPanel.hitOfLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JLabel" name="hitTotalLabel">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/keywordsearch/Bundle.properties" key="ExtractedContentPanel.hitTotalLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JLabel" name="hitButtonsLabel">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/keywordsearch/Bundle.properties" key="ExtractedContentPanel.hitButtonsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JButton" name="hitPreviousButton">
|
||||||
|
<Properties>
|
||||||
|
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||||
|
<Image iconType="3" name="/org/sleuthkit/autopsy/keywordsearch/arrow_left.gif"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/keywordsearch/Bundle.properties" key="ExtractedContentPanel.hitPreviousButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JButton" name="hitNextButton">
|
||||||
|
<Properties>
|
||||||
|
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||||
|
<Image iconType="3" name="/org/sleuthkit/autopsy/keywordsearch/arrow_right.gif"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/keywordsearch/Bundle.properties" key="ExtractedContentPanel.hitNextButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -18,10 +18,19 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.keywordsearch;
|
package org.sleuthkit.autopsy.keywordsearch;
|
||||||
|
|
||||||
|
import java.awt.Point;
|
||||||
|
import java.awt.Rectangle;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.awt.event.ItemEvent;
|
import java.awt.event.ItemEvent;
|
||||||
import java.awt.event.ItemListener;
|
import java.awt.event.ItemListener;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import javax.swing.JViewport;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Panel displays HTML content sent to ExtractedContentViewer, and provides
|
* Panel displays HTML content sent to ExtractedContentViewer, and provides
|
||||||
@ -29,9 +38,12 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
class ExtractedContentPanel extends javax.swing.JPanel {
|
class ExtractedContentPanel extends javax.swing.JPanel {
|
||||||
|
|
||||||
|
private static Logger logger = Logger.getLogger(ExtractedContentPanel.class.getName());
|
||||||
|
|
||||||
ExtractedContentPanel() {
|
ExtractedContentPanel() {
|
||||||
initComponents();
|
initComponents();
|
||||||
|
|
||||||
|
initControls();
|
||||||
extractedTextPane.setContentType("text/html");
|
extractedTextPane.setContentType("text/html");
|
||||||
|
|
||||||
sourceComboBox.addItemListener(new ItemListener() {
|
sourceComboBox.addItemListener(new ItemListener() {
|
||||||
@ -59,6 +71,13 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
|||||||
jScrollPane1 = new javax.swing.JScrollPane();
|
jScrollPane1 = new javax.swing.JScrollPane();
|
||||||
extractedTextPane = new javax.swing.JTextPane();
|
extractedTextPane = new javax.swing.JTextPane();
|
||||||
sourceComboBox = new javax.swing.JComboBox();
|
sourceComboBox = new javax.swing.JComboBox();
|
||||||
|
hitLabel = new javax.swing.JLabel();
|
||||||
|
hitCountLabel = new javax.swing.JLabel();
|
||||||
|
hitOfLabel = new javax.swing.JLabel();
|
||||||
|
hitTotalLabel = new javax.swing.JLabel();
|
||||||
|
hitButtonsLabel = new javax.swing.JLabel();
|
||||||
|
hitPreviousButton = new javax.swing.JButton();
|
||||||
|
hitNextButton = new javax.swing.JButton();
|
||||||
|
|
||||||
extractedTextPane.setEditable(false);
|
extractedTextPane.setEditable(false);
|
||||||
extractedTextPane.setAutoscrolls(false);
|
extractedTextPane.setAutoscrolls(false);
|
||||||
@ -66,12 +85,42 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
|||||||
|
|
||||||
sourceComboBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
|
sourceComboBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
|
||||||
|
|
||||||
|
hitLabel.setText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.hitLabel.text")); // NOI18N
|
||||||
|
|
||||||
|
hitCountLabel.setText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.hitCountLabel.text")); // NOI18N
|
||||||
|
|
||||||
|
hitOfLabel.setText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.hitOfLabel.text")); // NOI18N
|
||||||
|
|
||||||
|
hitTotalLabel.setText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.hitTotalLabel.text")); // NOI18N
|
||||||
|
|
||||||
|
hitButtonsLabel.setText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.hitButtonsLabel.text")); // NOI18N
|
||||||
|
|
||||||
|
hitPreviousButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/keywordsearch/arrow_left.gif"))); // NOI18N
|
||||||
|
hitPreviousButton.setText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.hitPreviousButton.text")); // NOI18N
|
||||||
|
|
||||||
|
hitNextButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/keywordsearch/arrow_right.gif"))); // NOI18N
|
||||||
|
hitNextButton.setText(org.openide.util.NbBundle.getMessage(ExtractedContentPanel.class, "ExtractedContentPanel.hitNextButton.text")); // NOI18N
|
||||||
|
|
||||||
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)
|
||||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||||
.addContainerGap(334, Short.MAX_VALUE)
|
.addContainerGap()
|
||||||
|
.addComponent(hitLabel)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||||
|
.addComponent(hitCountLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 12, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(hitOfLabel)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||||
|
.addComponent(hitTotalLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addGap(41, 41, 41)
|
||||||
|
.addComponent(hitButtonsLabel)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||||
|
.addComponent(hitPreviousButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(hitNextButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 125, Short.MAX_VALUE)
|
||||||
.addComponent(sourceComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(sourceComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addContainerGap())
|
.addContainerGap())
|
||||||
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
|
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
|
||||||
@ -79,18 +128,33 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
|||||||
layout.setVerticalGroup(
|
layout.setVerticalGroup(
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addGroup(layout.createSequentialGroup()
|
.addGroup(layout.createSequentialGroup()
|
||||||
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||||
.addComponent(sourceComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(sourceComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addComponent(hitLabel)
|
||||||
|
.addComponent(hitButtonsLabel)
|
||||||
|
.addComponent(hitOfLabel)
|
||||||
|
.addComponent(hitTotalLabel)
|
||||||
|
.addComponent(hitCountLabel))
|
||||||
|
.addComponent(hitPreviousButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addComponent(hitNextButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 274, Short.MAX_VALUE))
|
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 271, Short.MAX_VALUE))
|
||||||
);
|
);
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
private javax.swing.JTextPane extractedTextPane;
|
private javax.swing.JTextPane extractedTextPane;
|
||||||
|
private javax.swing.JLabel hitButtonsLabel;
|
||||||
|
private javax.swing.JLabel hitCountLabel;
|
||||||
|
private javax.swing.JLabel hitLabel;
|
||||||
|
private javax.swing.JButton hitNextButton;
|
||||||
|
private javax.swing.JLabel hitOfLabel;
|
||||||
|
private javax.swing.JButton hitPreviousButton;
|
||||||
|
private javax.swing.JLabel hitTotalLabel;
|
||||||
private javax.swing.JScrollPane jScrollPane1;
|
private javax.swing.JScrollPane jScrollPane1;
|
||||||
private javax.swing.JComboBox sourceComboBox;
|
private javax.swing.JComboBox sourceComboBox;
|
||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the available sources (selects the first source in the list by
|
* Set the available sources (selects the first source in the list by
|
||||||
* default)
|
* default)
|
||||||
@ -109,8 +173,105 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return currently available sources on the panel
|
||||||
|
*/
|
||||||
|
public List<MarkupSource> getSources() {
|
||||||
|
ArrayList<MarkupSource> sources = new ArrayList<MarkupSource>();
|
||||||
|
for (int i = 0; i < sourceComboBox.getItemCount(); ++i) {
|
||||||
|
sources.add((MarkupSource) sourceComboBox.getItemAt(i));
|
||||||
|
}
|
||||||
|
return sources;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return currently selected Source
|
||||||
|
*/
|
||||||
|
public MarkupSource getSelectedSource() {
|
||||||
|
return (MarkupSource) sourceComboBox.getSelectedItem();
|
||||||
|
}
|
||||||
|
|
||||||
private void setPanelText(String text) {
|
private void setPanelText(String text) {
|
||||||
extractedTextPane.setText(text);
|
extractedTextPane.setText(text);
|
||||||
extractedTextPane.setCaretPosition(0);
|
extractedTextPane.setCaretPosition(0);
|
||||||
|
logger.log(Level.INFO, extractedTextPane.getText());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initControls() {
|
||||||
|
hitPreviousButton.setEnabled(false);
|
||||||
|
hitNextButton.setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param offset to scroll to
|
||||||
|
*/
|
||||||
|
public void scrollTo(int offset) {
|
||||||
|
//extractedTextPane.setCaretPosition(offset);
|
||||||
|
//
|
||||||
|
JViewport viewport = (JViewport) SwingUtilities.getAncestorOfClass(JViewport.class, extractedTextPane);
|
||||||
|
if (viewport == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int height = viewport.getExtentSize().height;
|
||||||
|
try {
|
||||||
|
Rectangle viewRectangle = extractedTextPane.modelToView(offset);
|
||||||
|
if (viewRectangle == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int y = viewRectangle.y - height / 2;
|
||||||
|
y = Math.max(0, y);
|
||||||
|
y = Math.min(y, extractedTextPane.getHeight() - height);
|
||||||
|
viewport.setViewPosition(new Point(0, y));
|
||||||
|
} catch (javax.swing.text.BadLocationException ex) {
|
||||||
|
logger.log(Level.WARNING, "Failed scrolling to index " + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param current, current hit to update the display with
|
||||||
|
*/
|
||||||
|
public void updateCurrentDisplay(int current) {
|
||||||
|
hitCountLabel.setText(Integer.toString(current));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param total total number of hits to update the display with
|
||||||
|
*/
|
||||||
|
public void updateTotalDisplay(int total) {
|
||||||
|
hitTotalLabel.setText(Integer.toString(total));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enable previous hit control
|
||||||
|
* @param enable whether to enable or disable
|
||||||
|
*/
|
||||||
|
public void enablePrevControl(boolean enable) {
|
||||||
|
hitPreviousButton.setEnabled(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enable previous hit control
|
||||||
|
* @param enable whether to enable or disable
|
||||||
|
*/
|
||||||
|
public void enableNextControl(boolean enable) {
|
||||||
|
hitNextButton.setEnabled(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addPrevControlListener(ActionListener l) {
|
||||||
|
hitPreviousButton.addActionListener(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addNextControlListener(ActionListener l) {
|
||||||
|
hitNextButton.addActionListener(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSourceComboControlListener(ActionListener l) {
|
||||||
|
sourceComboBox.addActionListener(l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
package org.sleuthkit.autopsy.keywordsearch;
|
package org.sleuthkit.autopsy.keywordsearch;
|
||||||
|
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -43,8 +45,10 @@ public class ExtractedContentViewer implements DataContentViewer {
|
|||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(ExtractedContentViewer.class.getName());
|
private static final Logger logger = Logger.getLogger(ExtractedContentViewer.class.getName());
|
||||||
private ExtractedContentPanel panel;
|
private ExtractedContentPanel panel;
|
||||||
|
private ExtractedContentFind find;
|
||||||
|
|
||||||
public ExtractedContentViewer() {
|
public ExtractedContentViewer() {
|
||||||
|
find = new ExtractedContentFind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -82,6 +86,16 @@ public class ExtractedContentViewer implements DataContentViewer {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return "Extracted Content";
|
return "Extracted Content";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSearchable() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSearchToken() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -104,6 +118,9 @@ public class ExtractedContentViewer implements DataContentViewer {
|
|||||||
public Component getComponent() {
|
public Component getComponent() {
|
||||||
if (panel == null) {
|
if (panel == null) {
|
||||||
panel = new ExtractedContentPanel();
|
panel = new ExtractedContentPanel();
|
||||||
|
panel.addPrevControlListener(new PrevFindActionListener());
|
||||||
|
panel.addNextControlListener(new NextFindActionListener());
|
||||||
|
panel.addSourceComboControlListener(new SourceChangeActionListener());
|
||||||
}
|
}
|
||||||
return panel;
|
return panel;
|
||||||
}
|
}
|
||||||
@ -177,4 +194,89 @@ public class ExtractedContentViewer implements DataContentViewer {
|
|||||||
String content = (String) solrCore.query(q).getResults().get(0).getFieldValue("content");
|
String content = (String) solrCore.query(q).getResults().get(0).getFieldValue("content");
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class NextFindActionListener implements ActionListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
MarkupSource source = panel.getSelectedSource();
|
||||||
|
if (find.hasNext(source)) {
|
||||||
|
long indexVal = find.getNext(source);
|
||||||
|
logger.log(Level.INFO, "INDEX NEXT: " + indexVal);
|
||||||
|
|
||||||
|
//scroll
|
||||||
|
panel.scrollTo((int)indexVal);
|
||||||
|
|
||||||
|
//update display
|
||||||
|
panel.updateCurrentDisplay(find.getCurrentIndexI(source) + 1);
|
||||||
|
panel.updateTotalDisplay(find.getCurrentIndexTotal(source));
|
||||||
|
|
||||||
|
//update controls if needed
|
||||||
|
if (!find.hasNext(source)) {
|
||||||
|
panel.enableNextControl(false);
|
||||||
|
}
|
||||||
|
if (find.hasPrevious(source)) {
|
||||||
|
panel.enablePrevControl(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PrevFindActionListener implements ActionListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
MarkupSource source = panel.getSelectedSource();
|
||||||
|
if (find.hasPrevious(source)) {
|
||||||
|
long indexVal = find.getPrevious(source);
|
||||||
|
logger.log(Level.INFO, "INDEX PREVIOUS: " + indexVal);
|
||||||
|
//scroll
|
||||||
|
panel.scrollTo((int)indexVal);
|
||||||
|
|
||||||
|
//update display
|
||||||
|
panel.updateCurrentDisplay(find.getCurrentIndexI(source) + 1);
|
||||||
|
panel.updateTotalDisplay(find.getCurrentIndexTotal(source));
|
||||||
|
|
||||||
|
//update controls if needed
|
||||||
|
if (!find.hasPrevious(source)) {
|
||||||
|
panel.enablePrevControl(false);
|
||||||
|
}
|
||||||
|
if (find.hasNext(source)) {
|
||||||
|
panel.enableNextControl(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SourceChangeActionListener implements ActionListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
MarkupSource source = panel.getSelectedSource();
|
||||||
|
|
||||||
|
//setup find buttons
|
||||||
|
|
||||||
|
if (source != null && source.isSearchable()) {
|
||||||
|
panel.updateCurrentDisplay(find.getCurrentIndexI(source) + 1);
|
||||||
|
panel.updateTotalDisplay(find.getCurrentIndexTotal(source));
|
||||||
|
|
||||||
|
if (find.hasNext(source)) {
|
||||||
|
panel.enableNextControl(true);
|
||||||
|
} else {
|
||||||
|
panel.enableNextControl(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (find.hasPrevious(source)) {
|
||||||
|
panel.enablePrevControl(true);
|
||||||
|
} else {
|
||||||
|
panel.enablePrevControl(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panel.enableNextControl(false);
|
||||||
|
panel.enablePrevControl(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,9 @@ import org.sleuthkit.datamodel.Content;
|
|||||||
class HighlightedMatchesSource implements MarkupSource {
|
class HighlightedMatchesSource implements MarkupSource {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(HighlightedMatchesSource.class.getName());
|
private static final Logger logger = Logger.getLogger(HighlightedMatchesSource.class.getName());
|
||||||
|
private static final String HIGHLIGHT_PRE = "<span style=\"background:yellow\">";
|
||||||
|
private static final String HIGHLIGHT_POST = "</span>";
|
||||||
|
|
||||||
Content content;
|
Content content;
|
||||||
String solrQuery;
|
String solrQuery;
|
||||||
Core solrCore;
|
Core solrCore;
|
||||||
@ -54,8 +57,8 @@ class HighlightedMatchesSource implements MarkupSource {
|
|||||||
q.setQuery(solrQuery);
|
q.setQuery(solrQuery);
|
||||||
q.addFilterQuery("id:" + content.getId());
|
q.addFilterQuery("id:" + content.getId());
|
||||||
q.addHighlightField("content");
|
q.addHighlightField("content");
|
||||||
q.setHighlightSimplePre("<span style=\"background:yellow\">");
|
q.setHighlightSimplePre(HIGHLIGHT_PRE);
|
||||||
q.setHighlightSimplePost("</span>");
|
q.setHighlightSimplePost(HIGHLIGHT_POST);
|
||||||
q.setHighlightFragsize(0); // don't fragment the highlight
|
q.setHighlightFragsize(0); // don't fragment the highlight
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -76,4 +79,14 @@ class HighlightedMatchesSource implements MarkupSource {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return "Search Matches";
|
return "Search Matches";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSearchable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSearchToken() {
|
||||||
|
return HIGHLIGHT_PRE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,19 @@ public interface MarkupSource {
|
|||||||
*/
|
*/
|
||||||
String getMarkup();
|
String getMarkup();
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return true if markup is marked to be searchable
|
||||||
|
*/
|
||||||
|
boolean isSearchable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If searchable markup, returns search token, otherwise return empty string
|
||||||
|
* TODO pull up into SearchableMarkupSource abstract class
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String getSearchToken();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return title of markup source
|
* @return title of markup source
|
||||||
*/
|
*/
|
||||||
|
Binary file not shown.
After Width: | Height: | Size: 874 B |
Binary file not shown.
After Width: | Height: | Size: 870 B |
Loading…
x
Reference in New Issue
Block a user