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         for (FilterArea fa : this.filterAreas) {
 
   99             fa.setMaximumSize(
new Dimension(Integer.MAX_VALUE, fa.getMinimumSize().height));
 
  100             fa.setAlignmentX(Component.LEFT_ALIGNMENT);
 
  104         for (FileSearchFilter filter : this.getFilters()) {
 
  105             filter.addPropertyChangeListener(
new PropertyChangeListener() {
 
  107                 public void propertyChange(PropertyChangeEvent evt) {
 
  108                     searchButton.setEnabled(isValidSearch());
 
  113         addListenerToAll(
new ActionListener() {
 
  115             public void actionPerformed(ActionEvent e) {
 
  119         searchButton.setEnabled(isValidSearch());
 
  125     private boolean isValidSearch() {
 
  126         boolean enabled = 
false;
 
  127         for (FileSearchFilter filter : this.getFilters()) {
 
  128             if (filter.isEnabled()) {
 
  130                 if (!filter.isValid()) {
 
  143     private void search() {
 
  145         this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
 
  147             if (this.isValidSearch()) {
 
  148                 String title = NbBundle.getMessage(this.getClass(), 
"FileSearchPanel.search.results.title", ++resultWindowCount);
 
  149                 String pathText = NbBundle.getMessage(this.getClass(), 
"FileSearchPanel.search.results.pathText");
 
  152                 Case currentCase = Case.getCurrentCase(); 
 
  153                 long totalMatches = 0;
 
  154                 List<AbstractFile> contentList = null;
 
  156                     SleuthkitCase tskDb = currentCase.getSleuthkitCase();
 
  157                     contentList = tskDb.findAllFilesWhere(this.getQuery());
 
  159                 } 
catch (TskCoreException ex) {
 
  160                     Logger logger = Logger.getLogger(this.getClass().getName());
 
  161                     logger.log(Level.WARNING, 
"Error while trying to get the number of matches.", ex); 
 
  164                 if (contentList == null) {
 
  165                     contentList = Collections.<AbstractFile>emptyList();
 
  168                 SearchNode sn = 
new SearchNode(contentList);
 
  169                 final TopComponent searchResultWin = DataResultTopComponent.createInstance(title, pathText,
 
  170                         new TableFilterNode(sn, 
true, sn.getName()), contentList.size());
 
  172                 searchResultWin.requestActive(); 
 
  179                 if (totalMatches > 10000) {
 
  181                     String msg = NbBundle.getMessage(this.getClass(), 
"FileSearchPanel.search.results.msg", totalMatches);
 
  182                     String details = NbBundle.getMessage(this.getClass(), 
"FileSearchPanel.search.results.details");
 
  183                     MessageNotifyUtil.Notify.info(msg, details);
 
  186                 throw new FilterValidationException(
 
  187                         NbBundle.getMessage(
this.getClass(), 
"FileSearchPanel.search.exception.noFilterSelected.msg"));
 
  189         } 
catch (FilterValidationException ex) {
 
  190             NotifyDescriptor d = 
new NotifyDescriptor.Message(
 
  191                     NbBundle.getMessage(
this.getClass(), 
"FileSearchPanel.search.validationErr.msg", ex.getMessage()));
 
  192             DialogDisplayer.getDefault().notify(d);
 
  194             this.setCursor(null);
 
  216     private String getQuery() throws FilterValidationException {
 
  221         for (FileSearchFilter f : this.getEnabledFilters()) {
 
  222             String result = f.getPredicate();
 
  223             if (!result.isEmpty()) {
 
  225                     query += 
" AND (" + result + 
")"; 
 
  227                     query += 
" (" + result + 
")"; 
 
  233         if (query.isEmpty()) {
 
  234             throw new FilterValidationException(EMPTY_WHERE_CLAUSE);
 
  239     private Collection<FileSearchFilter> getFilters() {
 
  240         Collection<FileSearchFilter> filters = 
new ArrayList<>();
 
  242         for (FilterArea fa : this.filterAreas) {
 
  243             filters.addAll(fa.getFilters());
 
  249     private Collection<FileSearchFilter> getEnabledFilters() {
 
  250         Collection<FileSearchFilter> enabledFilters = 
new ArrayList<>();
 
  252         for (FileSearchFilter f : this.getFilters()) {
 
  254                 enabledFilters.add(f);
 
  258         return enabledFilters;
 
  261     void addListenerToAll(ActionListener l) {
 
  262         searchButton.addActionListener(l);
 
  263         for (FilterArea fa : this.filterAreas) {
 
  264             for (FileSearchFilter fsf : fa.getFilters()) {
 
  265                 fsf.addActionListener(l);
 
  275     @SuppressWarnings(
"unchecked")
 
  277     private 
void initComponents() {
 
  279         filterPanel = 
new javax.swing.JPanel();
 
  280         searchButton = 
new javax.swing.JButton();
 
  282         setPreferredSize(
new java.awt.Dimension(300, 300));
 
  284         filterPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10));
 
  285         filterPanel.setPreferredSize(
new java.awt.Dimension(300, 400));
 
  286         filterPanel.setLayout(
new javax.swing.BoxLayout(filterPanel, javax.swing.BoxLayout.Y_AXIS));
 
  288         searchButton.setText(
org.openide.util.NbBundle.getMessage(FileSearchPanel.class, 
"FileSearchPanel.searchButton.text")); 
 
  290         javax.swing.GroupLayout layout = 
new javax.swing.GroupLayout(
this);
 
  291         this.setLayout(layout);
 
  292         layout.setHorizontalGroup(
 
  293             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  294             .addComponent(filterPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  295             .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
 
  296                 .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  297                 .addComponent(searchButton)
 
  300         layout.setVerticalGroup(
 
  301             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  302             .addGroup(layout.createSequentialGroup()
 
  303                 .addComponent(filterPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  305                 .addComponent(searchButton)
 
  311     private javax.swing.JPanel filterPanel;
 
  312     private javax.swing.JButton searchButton;