25 package org.sleuthkit.autopsy.filesearch;
27 import java.awt.Component;
28 import java.awt.Cursor;
29 import java.awt.Dimension;
30 import java.awt.event.ActionEvent;
31 import java.awt.event.ActionListener;
32 import java.beans.PropertyChangeEvent;
33 import java.beans.PropertyChangeListener;
34 import java.util.ArrayList;
35 import java.util.Collection;
36 import java.util.Collections;
37 import java.util.List;
38 import java.util.logging.Level;
39 import javax.swing.JLabel;
40 import javax.swing.border.EmptyBorder;
41 import org.openide.DialogDisplayer;
42 import org.openide.NotifyDescriptor;
43 import org.openide.util.NbBundle;
44 import org.openide.windows.TopComponent;
58 class FileSearchPanel
extends javax.swing.JPanel {
60 private final List<FilterArea> filterAreas =
new ArrayList<>();
61 private static int resultWindowCount = 0;
62 private static final String EMPTY_WHERE_CLAUSE = NbBundle.getMessage(DateSearchFilter.class,
"FileSearchPanel.emptyWhereClause.text");
71 public FileSearchPanel() {
73 customizeComponents();
80 private void customizeComponents() {
82 JLabel label =
new JLabel(NbBundle.getMessage(
this.getClass(),
"FileSearchPanel.custComp.label.text"));
83 label.setAlignmentX(Component.LEFT_ALIGNMENT);
84 label.setBorder(
new EmptyBorder(0, 0, 10, 0));
85 filterPanel.add(label);
88 this.filterAreas.add(
new FilterArea(NbBundle.getMessage(
this.getClass(),
"FileSearchPanel.filterTitle.name"),
new NameSearchFilter()));
90 List<FileSearchFilter> metadataFilters =
new ArrayList<>();
91 metadataFilters.add(
new SizeSearchFilter());
92 metadataFilters.add(
new MimeTypeFilter());
93 metadataFilters.add(
new DateSearchFilter());
94 this.filterAreas.add(
new FilterArea(NbBundle.getMessage(
this.getClass(),
"FileSearchPanel.filterTitle.metadata"), metadataFilters));
96 this.filterAreas.add(
new FilterArea(NbBundle.getMessage(
this.getClass(),
"FileSearchPanel.filterTitle.knownStatus"),
new KnownStatusSearchFilter()));
98 this.filterAreas.add(
new FilterArea(NbBundle.getMessage(
this.getClass(),
"HashSearchPanel.md5CheckBox.text"),
new HashSearchFilter()));
100 for (FilterArea fa : this.filterAreas) {
101 fa.setMaximumSize(
new Dimension(Integer.MAX_VALUE, fa.getMinimumSize().height));
102 fa.setAlignmentX(Component.LEFT_ALIGNMENT);
106 for (FileSearchFilter filter : this.getFilters()) {
107 filter.addPropertyChangeListener(
new PropertyChangeListener() {
109 public void propertyChange(PropertyChangeEvent evt) {
110 searchButton.setEnabled(isValidSearch());
114 addListenerToAll(
new ActionListener() {
116 public void actionPerformed(ActionEvent e) {
120 searchButton.setEnabled(isValidSearch());
126 private boolean isValidSearch() {
127 boolean enabled =
false;
128 for (FileSearchFilter filter : this.getFilters()) {
129 if (filter.isEnabled()) {
131 if (!filter.isValid()) {
132 errorLabel.setText(filter.getLastError());
138 errorLabel.setText(
"");
146 private void search() {
148 this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
150 if (this.isValidSearch()) {
151 String title = NbBundle.getMessage(this.getClass(),
"FileSearchPanel.search.results.title", ++resultWindowCount);
152 String pathText = NbBundle.getMessage(this.getClass(),
"FileSearchPanel.search.results.pathText");
155 Case currentCase = Case.getCurrentCase();
156 long totalMatches = 0;
157 List<AbstractFile> contentList = null;
159 SleuthkitCase tskDb = currentCase.getSleuthkitCase();
160 contentList = tskDb.findAllFilesWhere(this.getQuery());
162 }
catch (TskCoreException ex) {
163 Logger logger = Logger.getLogger(this.getClass().getName());
164 logger.log(Level.WARNING,
"Error while trying to get the number of matches.", ex);
167 if (contentList == null) {
168 contentList = Collections.<AbstractFile>emptyList();
171 SearchNode sn =
new SearchNode(contentList);
172 final TopComponent searchResultWin = DataResultTopComponent.createInstance(title, pathText,
173 new TableFilterNode(sn,
true, sn.getName()), contentList.size());
175 searchResultWin.requestActive();
182 if (totalMatches > 10000) {
184 String msg = NbBundle.getMessage(this.getClass(),
"FileSearchPanel.search.results.msg", totalMatches);
185 String details = NbBundle.getMessage(this.getClass(),
"FileSearchPanel.search.results.details");
186 MessageNotifyUtil.Notify.info(msg, details);
189 throw new FilterValidationException(
190 NbBundle.getMessage(
this.getClass(),
"FileSearchPanel.search.exception.noFilterSelected.msg"));
192 }
catch (FilterValidationException ex) {
193 NotifyDescriptor d =
new NotifyDescriptor.Message(
194 NbBundle.getMessage(
this.getClass(),
"FileSearchPanel.search.validationErr.msg", ex.getMessage()));
195 DialogDisplayer.getDefault().notify(d);
197 this.setCursor(null);
219 private String getQuery() throws FilterValidationException {
224 for (FileSearchFilter f : this.getEnabledFilters()) {
225 String result = f.getPredicate();
226 if (!result.isEmpty()) {
228 query +=
" AND (" + result +
")";
230 query +=
" (" + result +
")";
236 if (query.isEmpty()) {
237 throw new FilterValidationException(EMPTY_WHERE_CLAUSE);
242 private Collection<FileSearchFilter> getFilters() {
243 Collection<FileSearchFilter> filters =
new ArrayList<>();
245 for (FilterArea fa : this.filterAreas) {
246 filters.addAll(fa.getFilters());
252 private Collection<FileSearchFilter> getEnabledFilters() {
253 Collection<FileSearchFilter> enabledFilters =
new ArrayList<>();
255 for (FileSearchFilter f : this.getFilters()) {
257 enabledFilters.add(f);
261 return enabledFilters;
264 void addListenerToAll(ActionListener l) {
265 searchButton.addActionListener(l);
266 for (FilterArea fa : this.filterAreas) {
267 for (FileSearchFilter fsf : fa.getFilters()) {
268 fsf.addActionListener(l);
278 @SuppressWarnings(
"unchecked")
280 private
void initComponents() {
282 filterPanel =
new javax.swing.JPanel();
283 searchButton =
new javax.swing.JButton();
284 errorLabel =
new javax.swing.JLabel();
286 setPreferredSize(
new java.awt.Dimension(300, 300));
288 filterPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10));
289 filterPanel.setPreferredSize(
new java.awt.Dimension(300, 400));
290 filterPanel.setLayout(
new javax.swing.BoxLayout(filterPanel, javax.swing.BoxLayout.Y_AXIS));
292 searchButton.setText(
org.openide.util.NbBundle.getMessage(FileSearchPanel.class,
"FileSearchPanel.searchButton.text"));
294 errorLabel.setForeground(
new java.awt.Color(255, 51, 51));
295 errorLabel.setText(
org.openide.util.NbBundle.getMessage(FileSearchPanel.class,
"FileSearchPanel.errorLabel.text"));
297 javax.swing.GroupLayout layout =
new javax.swing.GroupLayout(
this);
298 this.setLayout(layout);
299 layout.setHorizontalGroup(
300 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
301 .addComponent(filterPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
302 .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
304 .addComponent(errorLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
305 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
306 .addComponent(searchButton)
309 layout.setVerticalGroup(
310 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
311 .addGroup(layout.createSequentialGroup()
312 .addComponent(filterPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 266, Short.MAX_VALUE)
313 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
314 .addComponent(searchButton)
315 .addComponent(errorLabel))
321 private javax.swing.JLabel errorLabel;
322 private javax.swing.JPanel filterPanel;
323 private javax.swing.JButton searchButton;