diff --git a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties index 6603682cfb..4b08fd2d45 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties @@ -44,4 +44,7 @@ VisualizationPanel.backButton.toolTipText=Click to go back VisualizationPanel.forwardButton.toolTipText=Click to go forward VisualizationPanel.fastOrganicLayoutButton.toolTipText=Click to redraw the chart VisualizationPanel.clearVizButton.toolTipText=Click to clear the chart +FiltersPanel.limitHeaderLabel.text=Communications Limit: +FiltersPanel.mostRecentLabel.text=Most Recent: +FiltersPanel.limitErrorMsgLabel.text=Invalid integer value. VisualizationPanel.forwardButton.text= diff --git a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED index a0e989ee6a..7a3ef27eec 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties-MERGED @@ -87,6 +87,9 @@ VisualizationPanel.backButton.toolTipText=Click to go back VisualizationPanel.forwardButton.toolTipText=Click to go forward VisualizationPanel.fastOrganicLayoutButton.toolTipText=Click to redraw the chart VisualizationPanel.clearVizButton.toolTipText=Click to clear the chart +FiltersPanel.limitHeaderLabel.text=Communications Limit: +FiltersPanel.mostRecentLabel.text=Most Recent: +FiltersPanel.limitErrorMsgLabel.text=Invalid integer value. VisualizationPanel.forwardButton.text= VisualizationPanel_action_dialogs_title=Communications VisualizationPanel_action_name_text=Snapshot Report diff --git a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form index 38a3e7adbf..8bd260ea4b 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form +++ b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form @@ -16,8 +16,8 @@ - - + + @@ -25,11 +25,12 @@ - + + @@ -44,12 +45,14 @@ - - - - - - + + + + + + + + @@ -78,7 +81,7 @@ - + @@ -91,16 +94,14 @@ + + - - - - - - - - - + + + + + @@ -114,9 +115,9 @@ - - - + + + @@ -156,11 +157,16 @@ - + + + + + + - + @@ -184,7 +190,7 @@ - + @@ -195,16 +201,14 @@ + + - - - - - - - - - + + + + + @@ -216,7 +220,7 @@ - + @@ -258,7 +262,7 @@ - + @@ -268,7 +272,7 @@ - + @@ -297,7 +301,7 @@ - + @@ -406,5 +410,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java index c33f5d67d1..f8a883794e 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java @@ -37,7 +37,12 @@ import java.util.Map.Entry; import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.stream.Collectors; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.Icon; +import javax.swing.ImageIcon; import javax.swing.JCheckBox; +import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.SwingWorker; import org.openide.util.NbBundle; @@ -57,6 +62,7 @@ import org.sleuthkit.datamodel.CommunicationsFilter; import org.sleuthkit.datamodel.CommunicationsFilter.AccountTypeFilter; import org.sleuthkit.datamodel.CommunicationsFilter.DateRangeFilter; import org.sleuthkit.datamodel.CommunicationsFilter.DeviceFilter; +import org.sleuthkit.datamodel.CommunicationsFilter.MostRecentFilter; import org.sleuthkit.datamodel.DataSource; import static org.sleuthkit.datamodel.Relationship.Type.CALL_LOG; import static org.sleuthkit.datamodel.Relationship.Type.CONTACT; @@ -172,14 +178,30 @@ final public class FiltersPanel extends JPanel { private void validateFilters() { boolean someDevice = devicesMap.values().stream().anyMatch(JCheckBox::isSelected); boolean someAccountType = accountTypeMap.values().stream().anyMatch(JCheckBox::isSelected); + boolean validLimit = validateLimitValue(); deviceRequiredLabel.setVisible(someDevice == false); accountTypeRequiredLabel.setVisible(someAccountType == false); + limitErrorMsgLabel.setVisible(!validLimit); - applyFiltersButton.setEnabled(someDevice && someAccountType); - refreshButton.setEnabled(someDevice && someAccountType && needsRefresh); + applyFiltersButton.setEnabled(someDevice && someAccountType && validLimit); + refreshButton.setEnabled(someDevice && someAccountType && needsRefresh && validLimit); needsRefreshLabel.setVisible(needsRefresh); } + + private boolean validateLimitValue() { + String selectedValue = (String)limitComboBox.getSelectedItem(); + if(selectedValue.trim().equalsIgnoreCase("all")) { + return true; + } else { + try{ + int value = Integer.parseInt(selectedValue); + return value > 0; + } catch( NumberFormatException ex) { + return false; + } + } + } /** * Update the filter widgets, and apply them. @@ -209,7 +231,7 @@ final public class FiltersPanel extends JPanel { Case.addEventTypeSubscriber(EnumSet.of(CURRENT_CASE), evt -> { //clear the device filter widget when the case changes. devicesMap.clear(); - devicesPane.removeAll(); + devicesListPane.removeAll(); }); } @@ -234,19 +256,18 @@ final public class FiltersPanel extends JPanel { //don't show a check box for credit cards } else { accountTypeMap.computeIfAbsent(type, t -> { - final JCheckBox jCheckBox = new JCheckBox( - "
" + type.getDisplayName() + "
", - true - ); - jCheckBox.addItemListener(validationListener); - accountTypePane.add(jCheckBox); + + CheckBoxIconPanel panel = new CheckBoxIconPanel( + type.getDisplayName(), + new ImageIcon(FiltersPanel.class.getResource(Utils.getIconFilePath(type)))); + panel.setSelected(true); + panel.addItemListener(validationListener); + accountTypeListPane.add(panel); if (t.equals(Account.Type.DEVICE)) { //Deveice type filter is enabled based on whether we are in table or graph view. - jCheckBox.setEnabled(deviceAccountTypeEnabled); + panel.setEnabled(deviceAccountTypeEnabled); } - return jCheckBox; + return panel.getCheckBox(); }); } }); @@ -265,7 +286,7 @@ final public class FiltersPanel extends JPanel { devicesMap.computeIfAbsent(dataSource.getDeviceId(), ds -> { final JCheckBox jCheckBox = new JCheckBox(dsName, initialState); jCheckBox.addItemListener(validationListener); - devicesPane.add(jCheckBox); + devicesListPane.add(jCheckBox); return jCheckBox; }); } @@ -289,6 +310,8 @@ final public class FiltersPanel extends JPanel { setDeviceFilter((DeviceFilter)subFilter); } else if( subFilter instanceof AccountTypeFilter) { setAccountTypeFilter((AccountTypeFilter) subFilter); + } else if (subFilter instanceof MostRecentFilter ) { + setMostRecentFilter((MostRecentFilter)subFilter); } }); } @@ -341,6 +364,15 @@ final public class FiltersPanel extends JPanel { endDatePicker.setEnabled(state.isEnabled()); } + private void setMostRecentFilter(MostRecentFilter filter) { + int limit = filter.getLimit(); + if(limit > 0) { + limitComboBox.setSelectedItem(filter.getLimit()); + } else { + limitComboBox.setSelectedItem("All"); + } + } + @Subscribe void filtersBack(CVTEvents.StateChangeEvent event) { if(event.getCommunicationsState().getCommunicationsFilter() != null){ @@ -385,45 +417,46 @@ final public class FiltersPanel extends JPanel { } }); - accountTypePane.setLayout(new javax.swing.BoxLayout(accountTypePane, javax.swing.BoxLayout.Y_AXIS)); - jScrollPane3.setViewportView(accountTypePane); + accountTypesScrollPane.setPreferredSize(new java.awt.Dimension(2, 200)); + + accountTypeListPane.setLayout(new javax.swing.BoxLayout(accountTypeListPane, javax.swing.BoxLayout.Y_AXIS)); + accountTypesScrollPane.setViewportView(accountTypeListPane); accountTypeRequiredLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/error-icon-16.png"))); // NOI18N accountTypeRequiredLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.accountTypeRequiredLabel.text")); // NOI18N accountTypeRequiredLabel.setForeground(new java.awt.Color(255, 0, 0)); accountTypeRequiredLabel.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT); - javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); - jPanel2.setLayout(jPanel2Layout); - jPanel2Layout.setHorizontalGroup( - jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel2Layout.createSequentialGroup() - .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(jPanel2Layout.createSequentialGroup() + javax.swing.GroupLayout accountTypesPaneLayout = new javax.swing.GroupLayout(accountTypesPane); + accountTypesPane.setLayout(accountTypesPaneLayout); + accountTypesPaneLayout.setHorizontalGroup( + accountTypesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, accountTypesPaneLayout.createSequentialGroup() + .addGroup(accountTypesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(accountTypesPaneLayout.createSequentialGroup() .addComponent(accountTypesLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(accountTypeRequiredLabel)) - .addGroup(jPanel2Layout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(jScrollPane3) - .addGroup(jPanel2Layout.createSequentialGroup() - .addGap(0, 0, Short.MAX_VALUE) - .addComponent(unCheckAllAccountTypesButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(checkAllAccountTypesButton))))) + .addGroup(accountTypesPaneLayout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(unCheckAllAccountTypesButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(checkAllAccountTypesButton)) + .addGroup(accountTypesPaneLayout.createSequentialGroup() + .addGap(10, 10, 10) + .addComponent(accountTypesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) .addGap(0, 0, 0)) ); - jPanel2Layout.setVerticalGroup( - jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel2Layout.createSequentialGroup() - .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + accountTypesPaneLayout.setVerticalGroup( + accountTypesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(accountTypesPaneLayout.createSequentialGroup() + .addGroup(accountTypesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(accountTypesLabel) .addComponent(accountTypeRequiredLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 243, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(accountTypesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(accountTypesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(checkAllAccountTypesButton) .addComponent(unCheckAllAccountTypesButton))) ); @@ -445,46 +478,45 @@ final public class FiltersPanel extends JPanel { } }); - jScrollPane2.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); - jScrollPane2.setMinimumSize(new java.awt.Dimension(27, 75)); + devicesScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + devicesScrollPane.setMinimumSize(new java.awt.Dimension(27, 75)); - devicesPane.setMinimumSize(new java.awt.Dimension(4, 100)); - devicesPane.setLayout(new javax.swing.BoxLayout(devicesPane, javax.swing.BoxLayout.Y_AXIS)); - jScrollPane2.setViewportView(devicesPane); + devicesListPane.setMinimumSize(new java.awt.Dimension(4, 100)); + devicesListPane.setLayout(new javax.swing.BoxLayout(devicesListPane, javax.swing.BoxLayout.Y_AXIS)); + devicesScrollPane.setViewportView(devicesListPane); deviceRequiredLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/error-icon-16.png"))); // NOI18N deviceRequiredLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.deviceRequiredLabel.text")); // NOI18N deviceRequiredLabel.setForeground(new java.awt.Color(255, 0, 0)); deviceRequiredLabel.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT); - javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3); - jPanel3.setLayout(jPanel3Layout); - jPanel3Layout.setHorizontalGroup( - jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel3Layout.createSequentialGroup() + javax.swing.GroupLayout devicesPaneLayout = new javax.swing.GroupLayout(devicesPane); + devicesPane.setLayout(devicesPaneLayout); + devicesPaneLayout.setHorizontalGroup( + devicesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(devicesPaneLayout.createSequentialGroup() .addComponent(devicesLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(deviceRequiredLabel)) - .addGroup(jPanel3Layout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel3Layout.createSequentialGroup() - .addGap(0, 0, Short.MAX_VALUE) - .addComponent(unCheckAllDevicesButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(checkAllDevicesButton)) - .addComponent(jScrollPane2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addGroup(devicesPaneLayout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(unCheckAllDevicesButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(checkAllDevicesButton)) + .addGroup(devicesPaneLayout.createSequentialGroup() + .addGap(10, 10, 10) + .addComponent(devicesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); - jPanel3Layout.setVerticalGroup( - jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel3Layout.createSequentialGroup() - .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + devicesPaneLayout.setVerticalGroup( + devicesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(devicesPaneLayout.createSequentialGroup() + .addGroup(devicesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(devicesLabel) .addComponent(deviceRequiredLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 94, Short.MAX_VALUE) + .addComponent(devicesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 94, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addGroup(devicesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(checkAllDevicesButton) .addComponent(unCheckAllDevicesButton)) .addGap(5, 5, 5)) @@ -511,38 +543,39 @@ final public class FiltersPanel extends JPanel { endDatePicker.setEnabled(false); - javax.swing.GroupLayout jPanel4Layout = new javax.swing.GroupLayout(jPanel4); - jPanel4.setLayout(jPanel4Layout); - jPanel4Layout.setHorizontalGroup( - jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel4Layout.createSequentialGroup() - .addComponent(dateRangeLabel) + javax.swing.GroupLayout dateRangePaneLayout = new javax.swing.GroupLayout(dateRangePane); + dateRangePane.setLayout(dateRangePaneLayout); + dateRangePaneLayout.setHorizontalGroup( + dateRangePaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(dateRangePaneLayout.createSequentialGroup() + .addGroup(dateRangePaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(dateRangeLabel) + .addGroup(dateRangePaneLayout.createSequentialGroup() + .addContainerGap() + .addGroup(dateRangePaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, dateRangePaneLayout.createSequentialGroup() + .addComponent(endCheckBox) + .addGap(12, 12, 12) + .addComponent(endDatePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(dateRangePaneLayout.createSequentialGroup() + .addComponent(startCheckBox) + .addGap(12, 12, 12) + .addComponent(startDatePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))) .addGap(0, 0, Short.MAX_VALUE)) - .addGroup(jPanel4Layout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel4Layout.createSequentialGroup() - .addComponent(endCheckBox) - .addGap(12, 12, 12) - .addComponent(endDatePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(jPanel4Layout.createSequentialGroup() - .addComponent(startCheckBox) - .addGap(12, 12, 12) - .addComponent(startDatePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))) ); - jPanel4Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {endCheckBox, startCheckBox}); + dateRangePaneLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {endCheckBox, startCheckBox}); - jPanel4Layout.setVerticalGroup( - jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel4Layout.createSequentialGroup() + dateRangePaneLayout.setVerticalGroup( + dateRangePaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(dateRangePaneLayout.createSequentialGroup() .addComponent(dateRangeLabel) .addGap(6, 6, 6) - .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addGroup(dateRangePaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(startDatePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(startCheckBox)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addGroup(dateRangePaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(endDatePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(endCheckBox))) ); @@ -553,22 +586,70 @@ final public class FiltersPanel extends JPanel { needsRefreshLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.needsRefreshLabel.text")); // NOI18N needsRefreshLabel.setForeground(new java.awt.Color(255, 0, 0)); + limitHeaderLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.limitHeaderLabel.text")); // NOI18N + + mostRecentLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.mostRecentLabel.text")); // NOI18N + + limitComboBox.setEditable(true); + limitComboBox.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "All", "10000", "5000", "1000", "500", "100" })); + limitComboBox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + limitComboBoxActionPerformed(evt); + } + }); + + limitErrorMsgLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/error-icon-16.png"))); // NOI18N + limitErrorMsgLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.limitErrorMsgLabel.text")); // NOI18N + limitErrorMsgLabel.setForeground(new java.awt.Color(255, 0, 0)); + limitErrorMsgLabel.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING); + + javax.swing.GroupLayout limitPaneLayout = new javax.swing.GroupLayout(limitPane); + limitPane.setLayout(limitPaneLayout); + limitPaneLayout.setHorizontalGroup( + limitPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(limitPaneLayout.createSequentialGroup() + .addComponent(limitHeaderLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(limitErrorMsgLabel) + .addContainerGap()) + .addGroup(limitPaneLayout.createSequentialGroup() + .addContainerGap() + .addComponent(mostRecentLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(limitComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + limitPaneLayout.setVerticalGroup( + limitPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(limitPaneLayout.createSequentialGroup() + .addContainerGap() + .addGroup(limitPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(limitHeaderLabel) + .addComponent(limitErrorMsgLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(limitPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(mostRecentLabel) + .addComponent(limitComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(0, 32, Short.MAX_VALUE)) + ); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jPanel2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(devicesPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(accountTypesPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() .addComponent(filtersTitleLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(applyFiltersButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(refreshButton)) - .addComponent(jPanel4, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(dateRangePane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() .addContainerGap() .addComponent(needsRefreshLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(limitPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -581,12 +662,14 @@ final public class FiltersPanel extends JPanel { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(needsRefreshLabel) .addGap(4, 4, 4) - .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGap(18, 18, 18) - .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGap(18, 18, 18) - .addComponent(jPanel4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(19, Short.MAX_VALUE)) + .addComponent(devicesPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(accountTypesPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(dateRangePane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(limitPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -611,6 +694,7 @@ final public class FiltersPanel extends JPanel { commsFilter.addAndFilter(getDateRangeFilter()); commsFilter.addAndFilter(new CommunicationsFilter.RelationshipTypeFilter( ImmutableSet.of(CALL_LOG, MESSAGE, CONTACT))); + commsFilter.addAndFilter(getMostRecentFilter()); return commsFilter; } @@ -654,6 +738,20 @@ final public class FiltersPanel extends JPanel { endCheckBox.isSelected() ? endDatePicker.getDate().atStartOfDay(zone).toEpochSecond() : 0); } + private MostRecentFilter getMostRecentFilter() { + String value = (String)limitComboBox.getSelectedItem(); + if(value.trim().equalsIgnoreCase("all")){ + return new MostRecentFilter(-1); + } else{ + try { + int count = Integer.parseInt(value); + return new MostRecentFilter(count); + } catch(NumberFormatException ex) { + return null; + } + } + } + private DateControlState getStartControlState() { return new DateControlState (startDatePicker.getDate(), startCheckBox.isSelected()); } @@ -811,12 +909,18 @@ final public class FiltersPanel extends JPanel { private void startCheckBoxStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_startCheckBoxStateChanged startDatePicker.setEnabled(startCheckBox.isSelected()); + validateFilters(); }//GEN-LAST:event_startCheckBoxStateChanged private void endCheckBoxStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_endCheckBoxStateChanged endDatePicker.setEnabled(endCheckBox.isSelected()); + validateFilters(); }//GEN-LAST:event_endCheckBoxStateChanged + private void limitComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_limitComboBoxActionPerformed + validateFilters(); + }//GEN-LAST:event_limitComboBoxActionPerformed + /** * A class to wrap the state of the date controls that consist of a date picker * and a checkbox. @@ -859,24 +963,29 @@ final public class FiltersPanel extends JPanel { } // Variables declaration - do not modify//GEN-BEGIN:variables - private final javax.swing.JPanel accountTypePane = new javax.swing.JPanel(); + private final javax.swing.JPanel accountTypeListPane = new javax.swing.JPanel(); private final javax.swing.JLabel accountTypeRequiredLabel = new javax.swing.JLabel(); private final javax.swing.JLabel accountTypesLabel = new javax.swing.JLabel(); + private final javax.swing.JPanel accountTypesPane = new javax.swing.JPanel(); + private final javax.swing.JScrollPane accountTypesScrollPane = new javax.swing.JScrollPane(); private final javax.swing.JButton applyFiltersButton = new javax.swing.JButton(); private final javax.swing.JButton checkAllAccountTypesButton = new javax.swing.JButton(); private final javax.swing.JButton checkAllDevicesButton = new javax.swing.JButton(); private final javax.swing.JLabel dateRangeLabel = new javax.swing.JLabel(); + private final javax.swing.JPanel dateRangePane = new javax.swing.JPanel(); private final javax.swing.JLabel deviceRequiredLabel = new javax.swing.JLabel(); private final javax.swing.JLabel devicesLabel = new javax.swing.JLabel(); + private final javax.swing.JPanel devicesListPane = new javax.swing.JPanel(); private final javax.swing.JPanel devicesPane = new javax.swing.JPanel(); + private final javax.swing.JScrollPane devicesScrollPane = new javax.swing.JScrollPane(); private final javax.swing.JCheckBox endCheckBox = new javax.swing.JCheckBox(); private final com.github.lgooddatepicker.components.DatePicker endDatePicker = new com.github.lgooddatepicker.components.DatePicker(); private final javax.swing.JLabel filtersTitleLabel = new javax.swing.JLabel(); - private final javax.swing.JPanel jPanel2 = new javax.swing.JPanel(); - private final javax.swing.JPanel jPanel3 = new javax.swing.JPanel(); - private final javax.swing.JPanel jPanel4 = new javax.swing.JPanel(); - private final javax.swing.JScrollPane jScrollPane2 = new javax.swing.JScrollPane(); - private final javax.swing.JScrollPane jScrollPane3 = new javax.swing.JScrollPane(); + private final javax.swing.JComboBox limitComboBox = new javax.swing.JComboBox<>(); + private final javax.swing.JLabel limitErrorMsgLabel = new javax.swing.JLabel(); + private final javax.swing.JLabel limitHeaderLabel = new javax.swing.JLabel(); + private final javax.swing.JPanel limitPane = new javax.swing.JPanel(); + private final javax.swing.JLabel mostRecentLabel = new javax.swing.JLabel(); private final javax.swing.JLabel needsRefreshLabel = new javax.swing.JLabel(); private final javax.swing.JButton refreshButton = new javax.swing.JButton(); private final javax.swing.JCheckBox startCheckBox = new javax.swing.JCheckBox(); @@ -885,6 +994,66 @@ final public class FiltersPanel extends JPanel { private final javax.swing.JButton unCheckAllDevicesButton = new javax.swing.JButton(); // End of variables declaration//GEN-END:variables + + /** + * This class is a small panel that appears to just be a checkbox but + * adds the functionality of being able to show an icon between the checkbox + * and label. + */ + final class CheckBoxIconPanel extends JPanel{ + private final JCheckBox checkbox; + private final JLabel label; + + /** + * Creates a JPanel instance with the specified label and image. + * + * @param labelText The text to be displayed by the checkbox label. + * @param image The image to be dispayed by the label. + */ + private CheckBoxIconPanel(String labelText, Icon image) { + checkbox = new JCheckBox(); + label = new JLabel(labelText); + label.setIcon(image); + setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); + + add(checkbox); + add(label); + add(Box.createHorizontalGlue()); + } + + /** + * Sets the state of the checkbox. + * + * @param selected true if the button is selected, otherwise false + */ + void setSelected(boolean selected) { + checkbox.setSelected(selected); + } + + @Override + public void setEnabled(boolean enabled) { + checkbox.setEnabled(enabled); + } + + /** + * Returns the instance of the JCheckBox. + * + * @return JCheckbox instance + */ + JCheckBox getCheckBox() { + return checkbox; + } + + /** + * Adds an ItemListener to the checkbox. + * + * @param l the ItemListener to be added. + */ + void addItemListener(ItemListener l) { + checkbox.addItemListener(l); + } + } + /** * A simple class that implements CaseDbAccessQueryCallback. Can be used * as an anonymous innerclass with the CaseDbAccessManager select function. @@ -897,4 +1066,4 @@ final public class FiltersPanel extends JPanel { } } -} +} \ No newline at end of file