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;