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;
59 class FileSearchPanel
extends javax.swing.JPanel {
61 private final List<FilterArea> filterAreas =
new ArrayList<>();
62 private static int resultWindowCount = 0;
63 private static final String EMPTY_WHERE_CLAUSE = NbBundle.getMessage(DateSearchFilter.class,
"FileSearchPanel.emptyWhereClause.text");
72 public FileSearchPanel() {
74 customizeComponents();
81 private void customizeComponents() {
83 JLabel label =
new JLabel(NbBundle.getMessage(
this.getClass(),
"FileSearchPanel.custComp.label.text"));
84 label.setAlignmentX(Component.LEFT_ALIGNMENT);
85 label.setBorder(
new EmptyBorder(0, 0, 10, 0));
86 filterPanel.add(label);
89 this.filterAreas.add(
new FilterArea(NbBundle.getMessage(
this.getClass(),
"FileSearchPanel.filterTitle.name"),
new NameSearchFilter()));
91 List<FileSearchFilter> metadataFilters =
new ArrayList<>();
92 metadataFilters.add(
new SizeSearchFilter());
93 metadataFilters.add(
new MimeTypeFilter());
94 metadataFilters.add(
new DateSearchFilter());
95 this.filterAreas.add(
new FilterArea(NbBundle.getMessage(
this.getClass(),
"FileSearchPanel.filterTitle.metadata"), metadataFilters));
97 this.filterAreas.add(
new FilterArea(NbBundle.getMessage(
this.getClass(),
"FileSearchPanel.filterTitle.knownStatus"),
new KnownStatusSearchFilter()));
99 this.filterAreas.add(
new FilterArea(NbBundle.getMessage(
this.getClass(),
"HashSearchPanel.md5CheckBox.text"),
new HashSearchFilter()));
101 for (FilterArea fa : this.filterAreas) {
102 fa.setMaximumSize(
new Dimension(Integer.MAX_VALUE, fa.getMinimumSize().height));
103 fa.setAlignmentX(Component.LEFT_ALIGNMENT);
107 for (FileSearchFilter filter : this.getFilters()) {
108 filter.addPropertyChangeListener(
new PropertyChangeListener() {
110 public void propertyChange(PropertyChangeEvent evt) {
111 searchButton.setEnabled(isValidSearch());
115 addListenerToAll(
new ActionListener() {
117 public void actionPerformed(ActionEvent e) {
121 searchButton.setEnabled(isValidSearch());
127 private boolean isValidSearch() {
128 boolean enabled =
false;
129 for (FileSearchFilter filter : this.getFilters()) {
130 if (filter.isEnabled()) {
132 if (!filter.isValid()) {
133 errorLabel.setText(filter.getLastError());
139 errorLabel.setText(
"");
147 private void search() {
149 this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
151 if (this.isValidSearch()) {
152 String title = NbBundle.getMessage(this.getClass(),
"FileSearchPanel.search.results.title", ++resultWindowCount);
153 String pathText = NbBundle.getMessage(this.getClass(),
"FileSearchPanel.search.results.pathText");
156 Case currentCase = Case.getOpenCase();
157 long totalMatches = 0;
158 List<AbstractFile> contentList = null;
160 SleuthkitCase tskDb = currentCase.getSleuthkitCase();
161 contentList = tskDb.findAllFilesWhere(this.getQuery());
163 }
catch (TskCoreException ex) {
164 Logger logger = Logger.getLogger(this.getClass().getName());
165 logger.log(Level.WARNING,
"Error while trying to get the number of matches.", ex);
168 if (contentList == null) {
169 contentList = Collections.<AbstractFile>emptyList();
172 SearchNode sn =
new SearchNode(contentList);
173 final TopComponent searchResultWin = DataResultTopComponent.createInstance(title, pathText,
174 new TableFilterNode(sn,
true, sn.getName()), contentList.size());
176 searchResultWin.requestActive();
183 if (totalMatches > 10000) {
185 String msg = NbBundle.getMessage(this.getClass(),
"FileSearchPanel.search.results.msg", totalMatches);
186 String details = NbBundle.getMessage(this.getClass(),
"FileSearchPanel.search.results.details");
187 MessageNotifyUtil.Notify.info(msg, details);
190 throw new FilterValidationException(
191 NbBundle.getMessage(
this.getClass(),
"FileSearchPanel.search.exception.noFilterSelected.msg"));
193 }
catch (FilterValidationException | NoCurrentCaseException ex) {
194 NotifyDescriptor d =
new NotifyDescriptor.Message(
195 NbBundle.getMessage(
this.getClass(),
"FileSearchPanel.search.validationErr.msg", ex.getMessage()));
196 DialogDisplayer.getDefault().notify(d);
198 this.setCursor(null);
220 private String getQuery() throws FilterValidationException {
225 for (FileSearchFilter f : this.getEnabledFilters()) {
226 String result = f.getPredicate();
227 if (!result.isEmpty()) {
229 query +=
" AND (" + result +
")";
231 query +=
" (" + result +
")";
237 if (query.isEmpty()) {
238 throw new FilterValidationException(EMPTY_WHERE_CLAUSE);
243 private Collection<FileSearchFilter> getFilters() {
244 Collection<FileSearchFilter> filters =
new ArrayList<>();
246 for (FilterArea fa : this.filterAreas) {
247 filters.addAll(fa.getFilters());
253 private Collection<FileSearchFilter> getEnabledFilters() {
254 Collection<FileSearchFilter> enabledFilters =
new ArrayList<>();
256 for (FileSearchFilter f : this.getFilters()) {
258 enabledFilters.add(f);
262 return enabledFilters;
265 void addListenerToAll(ActionListener l) {
266 searchButton.addActionListener(l);
267 for (FilterArea fa : this.filterAreas) {
268 for (FileSearchFilter fsf : fa.getFilters()) {
269 fsf.addActionListener(l);
279 @SuppressWarnings(
"unchecked")
281 private
void initComponents() {
283 filterPanel =
new javax.swing.JPanel();
284 searchButton =
new javax.swing.JButton();
285 errorLabel =
new javax.swing.JLabel();
287 setPreferredSize(
new java.awt.Dimension(300, 300));
289 filterPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10));
290 filterPanel.setPreferredSize(
new java.awt.Dimension(300, 400));
291 filterPanel.setLayout(
new javax.swing.BoxLayout(filterPanel, javax.swing.BoxLayout.Y_AXIS));
293 searchButton.setText(
org.openide.util.NbBundle.getMessage(FileSearchPanel.class,
"FileSearchPanel.searchButton.text"));
295 errorLabel.setText(
org.openide.util.NbBundle.getMessage(FileSearchPanel.class,
"FileSearchPanel.errorLabel.text"));
296 errorLabel.setForeground(
new java.awt.Color(255, 51, 51));
298 javax.swing.GroupLayout layout =
new javax.swing.GroupLayout(
this);
299 this.setLayout(layout);
300 layout.setHorizontalGroup(
301 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
302 .addComponent(filterPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
303 .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
305 .addComponent(errorLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
306 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
307 .addComponent(searchButton)
310 layout.setVerticalGroup(
311 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
312 .addGroup(layout.createSequentialGroup()
313 .addComponent(filterPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 266, Short.MAX_VALUE)
314 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
315 .addComponent(searchButton)
316 .addComponent(errorLabel))
322 private javax.swing.JLabel errorLabel;
323 private javax.swing.JPanel filterPanel;
324 private javax.swing.JButton searchButton;