19 package org.sleuthkit.autopsy.keywordsearch;
 
   21 import java.awt.EventQueue;
 
   22 import java.beans.PropertyChangeEvent;
 
   23 import java.beans.PropertyChangeListener;
 
   24 import java.util.Arrays;
 
   25 import java.util.List;
 
   26 import java.util.logging.Level;
 
   27 import java.util.regex.Pattern;
 
   28 import java.util.regex.PatternSyntaxException;
 
   29 import javax.swing.JTable;
 
   30 import javax.swing.ListSelectionModel;
 
   31 import javax.swing.event.ListSelectionEvent;
 
   32 import javax.swing.event.ListSelectionListener;
 
   33 import javax.swing.table.AbstractTableModel;
 
   34 import javax.swing.table.TableColumn;
 
   35 import org.netbeans.spi.options.OptionsPanelController;
 
   36 import org.openide.util.NbBundle;
 
   44 @SuppressWarnings(
"PMD.SingularField") 
 
   45 class GlobalEditListPanel extends javax.swing.JPanel implements ListSelectionListener, OptionsPanel {
 
   47     private static final Logger logger = Logger.getLogger(GlobalEditListPanel.class.getName());
 
   48     private static final long serialVersionUID = 1L;
 
   49     private final KeywordTableModel tableModel;
 
   50     private KeywordList currentKeywordList;
 
   55     GlobalEditListPanel() {
 
   56         tableModel = 
new KeywordTableModel();
 
   58         customizeComponents();
 
   61     private void customizeComponents() {
 
   62         newKeywordsButton.setToolTipText((NbBundle.getMessage(
this.getClass(), 
"KeywordSearchEditListPanel.customizeComponents.addWordToolTip")));
 
   63         deleteWordButton.setToolTipText(NbBundle.getMessage(
this.getClass(), 
"KeywordSearchEditListPanel.customizeComponents.removeSelectedMsg"));
 
   65         keywordTable.getParent().setBackground(keywordTable.getBackground());
 
   66         final int width = jScrollPane1.getPreferredSize().width;
 
   67         keywordTable.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN);
 
   69         for (
int i = 0; i < keywordTable.getColumnCount(); i++) {
 
   70             column = keywordTable.getColumnModel().getColumn(i);
 
   72                 column.setPreferredWidth(((
int) (width * 0.90)));
 
   74                 column.setPreferredWidth(((
int) (width * 0.10)));
 
   77         keywordTable.setCellSelectionEnabled(
false);
 
   78         keywordTable.setRowSelectionAllowed(
true);
 
   80         final ListSelectionModel lsm = keywordTable.getSelectionModel();
 
   81         lsm.addListSelectionListener(
new ListSelectionListener() {
 
   83             public void valueChanged(ListSelectionEvent e) {
 
   84                 boolean canDelete = !(lsm.isSelectionEmpty() || currentKeywordList.isEditable() || IngestManager.getInstance().isIngestRunning());
 
   85                 boolean canEdit = canDelete && (lsm.getMaxSelectionIndex() == lsm.getMinSelectionIndex()); 
 
   86                 deleteWordButton.setEnabled(canDelete);
 
   87                 editWordButton.setEnabled(canEdit);
 
   93         IngestManager.getInstance().addIngestJobEventListener(
new PropertyChangeListener() {
 
   95             public void propertyChange(PropertyChangeEvent evt) {
 
   96                 Object source = evt.getSource();
 
   97                 if (source instanceof String && ((String) source).equals(
"LOCAL")) { 
 
   98                     EventQueue.invokeLater(() -> {
 
  109     void setButtonStates() {
 
  110         boolean isIngestRunning = IngestManager.getInstance().isIngestRunning();
 
  111         boolean isListSelected = currentKeywordList != null;
 
  113         ingestWarningLabel.setVisible(isIngestRunning);
 
  115         boolean canEditList = isListSelected && !isIngestRunning;
 
  116         ingestMessagesCheckbox.setEnabled(canEditList);
 
  117         ingestMessagesCheckbox.setSelected(currentKeywordList != null && currentKeywordList.getIngestMessages());
 
  120         boolean canAddWord = canEditList && !currentKeywordList.isEditable();
 
  121         newKeywordsButton.setEnabled(canAddWord);
 
  124         if ((currentKeywordList == null) || (currentKeywordList.getKeywords().isEmpty())) {
 
  125             deleteWordButton.setEnabled(
false);
 
  126             editWordButton.setEnabled(
false);
 
  130     @NbBundle.Messages({
"GlobalEditListPanel.editKeyword.title=Edit Keyword",
 
  131         "GlobalEditListPanel.warning.title=Warning",
 
  132         "GlobalEditListPanel.warning.text=Boundary characters ^ and $ do not match word boundaries. Consider\nreplacing with an explicit list of boundary characters, such as [ \\.,]"})
 
  140     private boolean addKeywordsAction(String existingKeywords, 
boolean isLiteral, 
boolean isWholeWord) {
 
  141         String keywordsToRedisplay = existingKeywords;
 
  142         AddKeywordsDialog dialog = 
new AddKeywordsDialog();
 
  148         if (!existingKeywords.isEmpty()) {  
 
  149             dialog.setTitle(NbBundle.getMessage(GlobalEditListPanel.class, 
"GlobalEditListPanel.editKeyword.title"));
 
  151         while (badCount > 0) {
 
  152             dialog.setInitialKeywordList(keywordsToRedisplay, isLiteral, isWholeWord);
 
  158             keywordsToRedisplay = 
"";
 
  159             boolean displayedBoundaryWarning = 
false;
 
  161             if (!dialog.getKeywords().isEmpty()) {
 
  163                 for (String newWord : dialog.getKeywords()) {
 
  164                     if (newWord.isEmpty()) {
 
  168                     final Keyword keyword = 
new Keyword(newWord, !dialog.isKeywordRegex(), dialog.isKeywordExact(), currentKeywordList.getName(), newWord);
 
  169                     if (currentKeywordList.hasKeyword(keyword)) {
 
  175                     if (( ! displayedBoundaryWarning) && dialog.isKeywordRegex()) {
 
  176                         if(newWord.startsWith(
"^") || 
 
  177                                 (newWord.endsWith(
"$") && ! newWord.endsWith(
"\\$"))) {
 
  179                             KeywordSearchUtil.displayDialog(NbBundle.getMessage(
this.getClass(), 
"GlobalEditListPanel.warning.title"),
 
  180                                     NbBundle.getMessage(
this.getClass(), 
"GlobalEditListPanel.warning.text"),
 
  181                                     KeywordSearchUtil.DIALOG_MESSAGE_TYPE.WARN);
 
  183                             displayedBoundaryWarning = 
true;
 
  188                     boolean valid = 
true;
 
  190                         Pattern.compile(newWord);
 
  191                     } 
catch (PatternSyntaxException ex1) {
 
  193                     } 
catch (IllegalArgumentException ex2) {
 
  199                         keywordsToRedisplay += newWord + 
"\n";
 
  205                     tableModel.addKeyword(keyword);
 
  208                 XmlKeywordSearchList.getCurrent().addList(currentKeywordList);
 
  209                 firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
 
  211                 if ((badCount > 0) || (dupeCount > 0)) {
 
  217                     KeywordSearchUtil.DIALOG_MESSAGE_TYPE level = KeywordSearchUtil.DIALOG_MESSAGE_TYPE.INFO;
 
  220                             summary += NbBundle.getMessage(GlobalEditListPanel.class, 
"GlobalEditListPanel.keywordsAddedPlural.text", goodCount) + 
"\n";
 
  222                             summary += NbBundle.getMessage(GlobalEditListPanel.class, 
"GlobalEditListPanel.keywordsAdded.text", goodCount) + 
"\n";
 
  227                             summary += NbBundle.getMessage(GlobalEditListPanel.class, 
"GlobalEditListPanel.keywordDupesSkippedPlural.text", dupeCount) + 
"\n";
 
  229                             summary += NbBundle.getMessage(GlobalEditListPanel.class, 
"GlobalEditListPanel.keywordDupesSkipped.text", dupeCount) + 
"\n";
 
  231                         level = KeywordSearchUtil.DIALOG_MESSAGE_TYPE.WARN;
 
  235                             summary += NbBundle.getMessage(GlobalEditListPanel.class, 
"GlobalEditListPanel.keywordErrorsPlural.text", badCount) + 
"\n";
 
  237                             summary += NbBundle.getMessage(GlobalEditListPanel.class, 
"GlobalEditListPanel.keywordErrors.text", badCount) + 
"\n";
 
  239                         level = KeywordSearchUtil.DIALOG_MESSAGE_TYPE.ERROR;
 
  241                     KeywordSearchUtil.displayDialog(NbBundle.getMessage(
this.getClass(), 
"GlobalEditListPanel.addKeywordResults.text"),
 
  246         setFocusOnKeywordTextBox();
 
  248         return (goodCount >= 1 && dupeCount == 0);
 
  257     private void deleteKeywordAction(
int[] selectedKeywords) {
 
  258         tableModel.deleteSelected(selectedKeywords);
 
  259         XmlKeywordSearchList.getCurrent().addList(currentKeywordList);
 
  268     @SuppressWarnings(
"unchecked")
 
  270     private 
void initComponents() {
 
  272         listEditorPanel = 
new javax.swing.JPanel();
 
  273         jScrollPane1 = 
new javax.swing.JScrollPane();
 
  274         keywordTable = 
new javax.swing.JTable();
 
  275         ingestMessagesCheckbox = 
new javax.swing.JCheckBox();
 
  276         keywordsLabel = 
new javax.swing.JLabel();
 
  277         newKeywordsButton = 
new javax.swing.JButton();
 
  278         deleteWordButton = 
new javax.swing.JButton();
 
  279         editWordButton = 
new javax.swing.JButton();
 
  280         ingestWarningLabel = 
new javax.swing.JLabel();
 
  282         setMinimumSize(
new java.awt.Dimension(0, 0));
 
  284         listEditorPanel.setMinimumSize(
new java.awt.Dimension(0, 0));
 
  286         jScrollPane1.setPreferredSize(
new java.awt.Dimension(340, 300));
 
  288         keywordTable.setModel(tableModel);
 
  289         keywordTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_OFF);
 
  290         keywordTable.setGridColor(
new java.awt.Color(153, 153, 153));
 
  291         keywordTable.setMaximumSize(
new java.awt.Dimension(30000, 30000));
 
  292         keywordTable.getTableHeader().setReorderingAllowed(
false);
 
  293         jScrollPane1.setViewportView(keywordTable);
 
  295         ingestMessagesCheckbox.setSelected(
true);
 
  296         ingestMessagesCheckbox.setText(
org.openide.util.NbBundle.getMessage(GlobalEditListPanel.class, 
"KeywordSearchEditListPanel.ingestMessagesCheckbox.text")); 
 
  297         ingestMessagesCheckbox.setToolTipText(
org.openide.util.NbBundle.getMessage(GlobalEditListPanel.class, 
"KeywordSearchEditListPanel.ingestMessagesCheckbox.toolTipText")); 
 
  298         ingestMessagesCheckbox.addActionListener(
new java.awt.event.ActionListener() {
 
  299             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
  300                 ingestMessagesCheckboxActionPerformed(evt);
 
  304         keywordsLabel.setText(
org.openide.util.NbBundle.getMessage(GlobalEditListPanel.class, 
"KeywordSearchEditListPanel.keywordsLabel.text")); 
 
  306         newKeywordsButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/keywordsearch/add16.png"))); 
 
  307         newKeywordsButton.setText(
org.openide.util.NbBundle.getMessage(GlobalEditListPanel.class, 
"GlobalEditListPanel.newKeywordsButton.text")); 
 
  308         newKeywordsButton.addActionListener(
new java.awt.event.ActionListener() {
 
  309             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
  310                 newKeywordsButtonActionPerformed(evt);
 
  314         deleteWordButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/keywordsearch/delete16.png"))); 
 
  315         deleteWordButton.setText(
org.openide.util.NbBundle.getMessage(GlobalEditListPanel.class, 
"KeywordSearchEditListPanel.deleteWordButton.text")); 
 
  316         deleteWordButton.addActionListener(
new java.awt.event.ActionListener() {
 
  317             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
  318                 deleteWordButtonActionPerformed(evt);
 
  322         editWordButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/keywordsearch/edit16.png"))); 
 
  323         editWordButton.setText(
org.openide.util.NbBundle.getMessage(GlobalEditListPanel.class, 
"GlobalEditListPanel.editWordButton.text")); 
 
  324         editWordButton.addActionListener(
new java.awt.event.ActionListener() {
 
  325             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
  326                 editWordButtonActionPerformed(evt);
 
  330         ingestWarningLabel.setFont(ingestWarningLabel.getFont().deriveFont(ingestWarningLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11));
 
  331         ingestWarningLabel.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/modules/hashdatabase/warning16.png"))); 
 
  332         ingestWarningLabel.setText(
org.openide.util.NbBundle.getMessage(GlobalEditListPanel.class, 
"GlobalEditListPanel.ingestWarningLabel.text")); 
 
  334         javax.swing.GroupLayout listEditorPanelLayout = 
new javax.swing.GroupLayout(listEditorPanel);
 
  335         listEditorPanel.setLayout(listEditorPanelLayout);
 
  336         listEditorPanelLayout.setHorizontalGroup(
 
  337             listEditorPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  338             .addGroup(listEditorPanelLayout.createSequentialGroup()
 
  340                 .addGroup(listEditorPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  341                     .addGroup(listEditorPanelLayout.createSequentialGroup()
 
  342                         .addComponent(keywordsLabel)
 
  343                         .addGap(0, 0, Short.MAX_VALUE))
 
  344                     .addGroup(listEditorPanelLayout.createSequentialGroup()
 
  346                         .addGroup(listEditorPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  347                             .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 566, Short.MAX_VALUE)
 
  348                             .addGroup(listEditorPanelLayout.createSequentialGroup()
 
  349                                 .addComponent(newKeywordsButton)
 
  351                                 .addComponent(editWordButton)
 
  353                                 .addComponent(deleteWordButton)
 
  354                                 .addGap(0, 0, Short.MAX_VALUE))
 
  355                             .addGroup(listEditorPanelLayout.createSequentialGroup()
 
  356                                 .addComponent(ingestMessagesCheckbox)
 
  357                                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  358                                 .addComponent(ingestWarningLabel)))))
 
  362         listEditorPanelLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, 
new java.awt.Component[] {deleteWordButton, editWordButton, newKeywordsButton});
 
  364         listEditorPanelLayout.setVerticalGroup(
 
  365             listEditorPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  366             .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, listEditorPanelLayout.createSequentialGroup()
 
  368                 .addComponent(keywordsLabel)
 
  369                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  370                 .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 256, Short.MAX_VALUE)
 
  371                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  372                 .addGroup(listEditorPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
 
  373                     .addComponent(deleteWordButton)
 
  374                     .addComponent(newKeywordsButton)
 
  375                     .addComponent(editWordButton))
 
  376                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  377                 .addGroup(listEditorPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
 
  378                     .addComponent(ingestMessagesCheckbox)
 
  379                     .addComponent(ingestWarningLabel))
 
  383         javax.swing.GroupLayout layout = 
new javax.swing.GroupLayout(
this);
 
  384         this.setLayout(layout);
 
  385         layout.setHorizontalGroup(
 
  386             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  387             .addComponent(listEditorPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  389         layout.setVerticalGroup(
 
  390             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  391             .addGroup(layout.createSequentialGroup()
 
  392                 .addComponent(listEditorPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  397     private void deleteWordButtonActionPerformed(java.awt.event.ActionEvent evt) {
 
  398         if (KeywordSearchUtil.displayConfirmDialog(NbBundle.getMessage(
this.getClass(), 
"KeywordSearchEditListPanel.removeKwMsg"),
 
  399                 NbBundle.getMessage(
this.getClass(), 
"KeywordSearchEditListPanel.deleteWordButtonActionPerformed.delConfirmMsg"),
 
  400                 KeywordSearchUtil.DIALOG_MESSAGE_TYPE.WARN)) {
 
  401             deleteKeywordAction(keywordTable.getSelectedRows());
 
  402             firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
 
  406     private void ingestMessagesCheckboxActionPerformed(java.awt.event.ActionEvent evt) {
 
  407         currentKeywordList.setIngestMessages(ingestMessagesCheckbox.isSelected());
 
  408         XmlKeywordSearchList updater = XmlKeywordSearchList.getCurrent();
 
  409         updater.addList(currentKeywordList);
 
  410         firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
 
  413     private void newKeywordsButtonActionPerformed(java.awt.event.ActionEvent evt) {
 
  414         addKeywordsAction(
"", 
true, 
true);
 
  417     private void editWordButtonActionPerformed(java.awt.event.ActionEvent evt) {
 
  418         int[] selectedKeywords = keywordTable.getSelectedRows();
 
  419         if (selectedKeywords.length == 1) {
 
  420             Keyword currentKeyword = currentKeywordList.getKeywords().get(selectedKeywords[0]);
 
  421             if (addKeywordsAction(currentKeyword.getSearchTerm(), currentKeyword.searchTermIsLiteral(), currentKeyword.searchTermIsWholeWord())) {
 
  422                 deleteKeywordAction(selectedKeywords);
 
  428     private javax.swing.JButton deleteWordButton;
 
  429     private javax.swing.JButton editWordButton;
 
  430     private javax.swing.JCheckBox ingestMessagesCheckbox;
 
  431     private javax.swing.JLabel ingestWarningLabel;
 
  432     private javax.swing.JScrollPane jScrollPane1;
 
  433     private javax.swing.JTable keywordTable;
 
  434     private javax.swing.JLabel keywordsLabel;
 
  435     private javax.swing.JPanel listEditorPanel;
 
  436     private javax.swing.JButton newKeywordsButton;
 
  440     public void valueChanged(ListSelectionEvent e) {
 
  442         ListSelectionModel listSelectionModel = (ListSelectionModel) e.getSource();
 
  443         currentKeywordList = null;
 
  444         if (!listSelectionModel.isSelectionEmpty()) {
 
  445             XmlKeywordSearchList loader = XmlKeywordSearchList.getCurrent();
 
  446             if (listSelectionModel.getMinSelectionIndex() == listSelectionModel.getMaxSelectionIndex()) {
 
  447                 currentKeywordList = loader.getListsL(
false).get(listSelectionModel.getMinSelectionIndex());
 
  455     public void store() {
 
  464     KeywordList getCurrentKeywordList() {
 
  465         return currentKeywordList;
 
  468     void setCurrentKeywordList(KeywordList list) {
 
  469         currentKeywordList = list;
 
  481             return currentKeywordList == null ? 0 : currentKeywordList.getKeywords().size();
 
  486             String colName = null;
 
  490                     colName = NbBundle.getMessage(this.getClass(), 
"KeywordSearchEditListPanel.kwColName");
 
  493                     colName = NbBundle.getMessage(this.getClass(), 
"KeywordSearch.typeColLbl");
 
  504             if (currentKeywordList == null) {
 
  507             Keyword word = currentKeywordList.getKeywords().get(rowIndex);
 
  508             switch (columnIndex) {
 
  510                     ret = word.getSearchTerm();
 
  513                     ret = word.getSearchTermType();
 
  516                     logger.log(Level.SEVERE, 
"Invalid table column index: {0}", columnIndex); 
 
  528         public void setValueAt(Object aValue, 
int rowIndex, 
int columnIndex) {
 
  533             return getValueAt(0, c).getClass();
 
  536         void addKeyword(Keyword keyword) {
 
  537             if (!currentKeywordList.hasKeyword(keyword)) {
 
  538                 currentKeywordList.getKeywords().add(keyword);
 
  540             fireTableDataChanged();
 
  544             fireTableDataChanged();
 
  548         void deleteSelected(
int[] selected) {
 
  549             List<Keyword> words = currentKeywordList.getKeywords();
 
  550             Arrays.sort(selected);
 
  551             for (
int arrayi = selected.length - 1; arrayi >= 0; arrayi--) {
 
  552                 words.remove(selected[arrayi]);
 
  561     void setFocusOnKeywordTextBox() {
 
  562         newKeywordsButton.requestFocus();
 
boolean isCellEditable(int rowIndex, int columnIndex)
void setValueAt(Object aValue, int rowIndex, int columnIndex)
String getColumnName(int column)
Class<?> getColumnClass(int c)
Object getValueAt(int rowIndex, int columnIndex)