Autopsy  4.14.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
IngestMessagePanel.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-2018 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.ingest;
20 
21 import java.awt.Color;
22 import java.awt.Component;
23 import java.awt.Cursor;
24 import java.awt.Dimension;
25 import java.awt.Font;
26 import java.awt.Graphics;
27 import java.beans.PropertyChangeEvent;
28 import java.beans.PropertyChangeListener;
29 import java.beans.PropertyChangeSupport;
30 import java.text.DateFormat;
31 import java.text.SimpleDateFormat;
32 import java.util.ArrayList;
33 import java.util.Collections;
34 import java.util.Date;
35 import java.util.HashMap;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.logging.Level;
39 import javax.swing.DefaultComboBoxModel;
40 import javax.swing.JLabel;
41 import javax.swing.JPanel;
42 import javax.swing.JTable;
43 import javax.swing.ListSelectionModel;
44 import javax.swing.SwingConstants;
45 import javax.swing.event.ListSelectionEvent;
46 import javax.swing.event.ListSelectionListener;
47 import javax.swing.event.TableModelEvent;
48 import javax.swing.event.TableModelListener;
49 import javax.swing.table.AbstractTableModel;
50 import javax.swing.table.DefaultTableCellRenderer;
51 import javax.swing.table.TableCellRenderer;
52 import org.openide.util.NbBundle;
56 import org.sleuthkit.datamodel.BlackboardArtifact;
57 
61 @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
62 class IngestMessagePanel extends JPanel implements TableModelListener {
63 
64  private final MessageTableModel tableModel;
65  private MessageTableRenderer renderer;
66  private final IngestMessageMainPanel mainPanel;
67  private static final Color ERROR_COLOR = new Color(255, 90, 90);
68  private volatile int lastRowSelected = -1;
69  private volatile long totalMessages = 0;
70  private static final Logger logger = Logger.getLogger(IngestMessagePanel.class.getName());
71  private static final PropertyChangeSupport messagePcs = new PropertyChangeSupport(IngestMessagePanel.class);
72  static final String TOTAL_NUM_MESSAGES_CHANGED = "TOTAL_NUM_MESSAGES_CHANGED"; // total number of messages changed NON-NLS
73  static final String MESSAGES_BOX_CLEARED = "MESSAGES_BOX_CLEARED"; // all messaged in inbox were cleared NON-NLS
74  static final String TOTAL_NUM_NEW_MESSAGES_CHANGED = "TOTAL_NUM_NEW_MESSAGES_CHANGED"; // total number of new messages changed NON-NLS
75 
79  public IngestMessagePanel(IngestMessageMainPanel mainPanel) {
80  this.mainPanel = mainPanel;
81  tableModel = new MessageTableModel();
82  initComponents();
83  customizeComponents();
84  }
85 
86  public void markAllSeen() {
87  tableModel.markAllSeen();
88  }
89 
90  int getLastRowSelected() {
91  return this.lastRowSelected;
92  }
93 
94  synchronized IngestMessageGroup getSelectedMessage() {
95  if (lastRowSelected < 0) {
96  return null;
97  }
98 
99  return tableModel.getMessageGroup(lastRowSelected);
100  }
101 
102  synchronized IngestMessageGroup getMessageGroup(int rowNumber) {
103  return tableModel.getMessageGroup(rowNumber);
104  }
105 
106  synchronized static void addPropertyChangeSupportListener(PropertyChangeListener l) {
107  messagePcs.addPropertyChangeListener(l);
108  }
109 
115  @SuppressWarnings("unchecked")
116  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
117  private void initComponents() {
118 
119  jScrollPane1 = new javax.swing.JScrollPane();
120  messageTable = new javax.swing.JTable();
121  controlPanel = new javax.swing.JPanel();
122  sortByLabel = new javax.swing.JLabel();
123  sortByComboBox = new javax.swing.JComboBox<>();
124  totalMessagesNameLabel = new javax.swing.JLabel();
125  totalMessagesNameVal = new javax.swing.JLabel();
126  totalUniqueMessagesNameLabel = new javax.swing.JLabel();
127  totalUniqueMessagesNameVal = new javax.swing.JLabel();
128 
129  setOpaque(false);
130 
131  jScrollPane1.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1));
132  jScrollPane1.setOpaque(false);
133  jScrollPane1.setPreferredSize(new java.awt.Dimension(32767, 32767));
134 
135  messageTable.setBackground(new java.awt.Color(221, 221, 235));
136  messageTable.setFont(messageTable.getFont().deriveFont(messageTable.getFont().getSize()+1f));
137  messageTable.setModel(tableModel);
138  messageTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_OFF);
139  messageTable.setAutoscrolls(false);
140  messageTable.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
141  messageTable.setGridColor(new java.awt.Color(204, 204, 204));
142  messageTable.setOpaque(false);
143  messageTable.setSelectionForeground(new java.awt.Color(0, 0, 0));
144  messageTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
145  messageTable.setShowHorizontalLines(false);
146  messageTable.setShowVerticalLines(false);
147  messageTable.getTableHeader().setReorderingAllowed(false);
148  jScrollPane1.setViewportView(messageTable);
149 
150  sortByLabel.setText(org.openide.util.NbBundle.getMessage(IngestMessagePanel.class, "IngestMessagePanel.sortByLabel.text")); // NOI18N
151 
152  sortByComboBox.setToolTipText(org.openide.util.NbBundle.getMessage(IngestMessagePanel.class, "IngestMessagePanel.sortByComboBox.toolTipText")); // NOI18N
153  sortByComboBox.addActionListener(new java.awt.event.ActionListener() {
154  public void actionPerformed(java.awt.event.ActionEvent evt) {
155  sortByComboBoxActionPerformed(evt);
156  }
157  });
158 
159  totalMessagesNameLabel.setText(org.openide.util.NbBundle.getMessage(IngestMessagePanel.class, "IngestMessagePanel.totalMessagesNameLabel.text")); // NOI18N
160 
161  totalMessagesNameVal.setText(org.openide.util.NbBundle.getMessage(IngestMessagePanel.class, "IngestMessagePanel.totalMessagesNameVal.text")); // NOI18N
162 
163  totalUniqueMessagesNameLabel.setText(org.openide.util.NbBundle.getMessage(IngestMessagePanel.class, "IngestMessagePanel.totalUniqueMessagesNameLabel.text")); // NOI18N
164 
165  totalUniqueMessagesNameVal.setText(org.openide.util.NbBundle.getMessage(IngestMessagePanel.class, "IngestMessagePanel.totalUniqueMessagesNameVal.text")); // NOI18N
166 
167  javax.swing.GroupLayout controlPanelLayout = new javax.swing.GroupLayout(controlPanel);
168  controlPanel.setLayout(controlPanelLayout);
169  controlPanelLayout.setHorizontalGroup(
170  controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
171  .addGroup(controlPanelLayout.createSequentialGroup()
172  .addGap(10, 10, 10)
173  .addComponent(sortByLabel)
174  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
175  .addComponent(sortByComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
176  .addGap(101, 101, 101)
177  .addComponent(totalMessagesNameLabel)
178  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
179  .addComponent(totalMessagesNameVal, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
180  .addGap(22, 22, 22)
181  .addComponent(totalUniqueMessagesNameLabel)
182  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
183  .addComponent(totalUniqueMessagesNameVal, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
184  .addGap(22, 22, 22))
185  );
186  controlPanelLayout.setVerticalGroup(
187  controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
188  .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
189  .addComponent(sortByComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
190  .addComponent(sortByLabel)
191  .addComponent(totalUniqueMessagesNameLabel)
192  .addComponent(totalUniqueMessagesNameVal)
193  .addComponent(totalMessagesNameLabel)
194  .addComponent(totalMessagesNameVal))
195  );
196 
197  javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
198  this.setLayout(layout);
199  layout.setHorizontalGroup(
200  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
201  .addComponent(controlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
202  .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 376, Short.MAX_VALUE)
203  );
204  layout.setVerticalGroup(
205  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
206  .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
207  .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 201, Short.MAX_VALUE)
208  .addGap(0, 0, 0)
209  .addComponent(controlPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
210  );
211  }// </editor-fold>//GEN-END:initComponents
212 
213  private void sortByComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sortByComboBoxActionPerformed
214  synchronized (this) {
215  if (sortByComboBox.getSelectedIndex() == 0) {
216  tableModel.reSort(true);
217  } else {
218  tableModel.reSort(false);
219  }
220  }
221  }//GEN-LAST:event_sortByComboBoxActionPerformed
222  // Variables declaration - do not modify//GEN-BEGIN:variables
223  private javax.swing.JPanel controlPanel;
224  private javax.swing.JScrollPane jScrollPane1;
225  private javax.swing.JTable messageTable;
226  private javax.swing.JComboBox<String> sortByComboBox;
227  private javax.swing.JLabel sortByLabel;
228  private javax.swing.JLabel totalMessagesNameLabel;
229  private javax.swing.JLabel totalMessagesNameVal;
230  private javax.swing.JLabel totalUniqueMessagesNameLabel;
231  private javax.swing.JLabel totalUniqueMessagesNameVal;
232  // End of variables declaration//GEN-END:variables
233 
234  private void customizeComponents() {
235  mainPanel.setOpaque(true);
236  jScrollPane1.setOpaque(true);
237  messageTable.setOpaque(false);
238 
243  sortByComboBox.setModel(new DefaultComboBoxModel<>(new String[] {
244  NbBundle.getMessage(this.getClass(), "IngestMessagePanel.sortByComboBox.model.time"),
245  NbBundle.getMessage(this.getClass(), "IngestMessagePanel.sortByComboBox.model.priority")}));
246 
247  jScrollPane1.setWheelScrollingEnabled(true);
248 
249  messageTable.setAutoscrolls(false);
250  messageTable.setShowHorizontalLines(false);
251  messageTable.setShowVerticalLines(false);
252 
253  messageTable.getParent().setBackground(messageTable.getBackground());
254 
255  renderer = new MessageTableRenderer();
256  int numCols = messageTable.getColumnCount();
257 
258  // add the cell renderer to all columns
259  for (int i = 0; i < numCols; ++i) {
260  messageTable.getColumnModel().getColumn(i).setCellRenderer(renderer);
261  }
262 
263  messageTable.setCellSelectionEnabled(false);
264  messageTable.setColumnSelectionAllowed(false);
265  messageTable.setRowSelectionAllowed(true);
266  messageTable.getSelectionModel().addListSelectionListener(new MessageVisitedSelection());
267 
268  //this should be done at the end to make it easy to initialize before events are handled
269  tableModel.addTableModelListener(this);
270  }
271 
272  @Override
273  public void paint(Graphics g) {
274  super.paint(g);
275 
276  //workaround to force table resize when window resizes. Use better layout instead?
277  setTableSize(messageTable.getParent().getSize());
278  }
279 
280  @Override
281  public void setPreferredSize(Dimension dmnsn) {
282  super.setPreferredSize(dmnsn);
283  setTableSize(messageTable.getParent().getSize());
284  }
285 
286  void setTableSize(Dimension d) {
287  double[] columnWidths = new double[]{0.20, 0.08, 0.08, 0.49, 0.15};
288  int numCols = messageTable.getColumnCount();
289  for (int i = 0; i < numCols; ++i) {
290  messageTable.getColumnModel().getColumn(i).setPreferredWidth((int) (d.width * columnWidths[i]));
291  }
292  }
293 
294  public synchronized void addMessage(IngestMessage m) {
295  tableModel.addMessage(m);
296 
297  //update total individual messages count
298  ++totalMessages;
299  final int newMsgUnreadUnique = tableModel.getNumberUnreadGroups();
300 
301  try {
302  messagePcs.firePropertyChange(TOTAL_NUM_MESSAGES_CHANGED, 0, newMsgUnreadUnique);
303  } catch (Exception e) {
304  logger.log(Level.SEVERE, "IngestMessagePanel listener threw exception", e); //NON-NLS
305  MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "IngestMessagePanel.moduleErr"),
306  NbBundle.getMessage(this.getClass(),
307  "IngestMessagePanel.moduleErr.errListenUpdates.text"),
308  MessageNotifyUtil.MessageType.ERROR);
309  }
310 
311  //update labels
312  this.totalMessagesNameVal.setText(Long.toString(totalMessages));
313  final int totalMessagesUnique = tableModel.getNumberGroups();
314  this.totalUniqueMessagesNameVal.setText(Integer.toString(totalMessagesUnique));
315  }
316 
317  public synchronized void clearMessages() {
318  final int origMsgGroups = tableModel.getNumberUnreadGroups();
319  totalMessages = 0;
320  tableModel.clearMessages();
321  totalMessagesNameVal.setText("-");
322  totalUniqueMessagesNameVal.setText("-");
323 
324  try {
325  messagePcs.firePropertyChange(MESSAGES_BOX_CLEARED, origMsgGroups, 0);
326  } catch (Exception e) {
327  logger.log(Level.SEVERE, "IngestMessagePanel listener threw exception", e); //NON-NLS
328  MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "IngestMessagePanel.moduleErr"),
329  NbBundle.getMessage(this.getClass(),
330  "IngestMessagePanel.moduleErr.errListenUpdates.text"),
331  MessageNotifyUtil.MessageType.ERROR);
332  }
333  }
334 
335  public synchronized int getMessagesCount() {
336  return tableModel.getNumberMessages();
337  }
338 
339  private synchronized void setVisited(int rowNumber) {
340  final int origMsgGroups = tableModel.getNumberUnreadGroups();
341  tableModel.setVisited(rowNumber);
342  lastRowSelected = rowNumber;
343 
344  try {
345  messagePcs.firePropertyChange(TOOL_TIP_TEXT_KEY, origMsgGroups, tableModel.getNumberUnreadGroups());
346  } catch (Exception e) {
347  logger.log(Level.SEVERE, "IngestMessagePanel listener threw exception", e); //NON-NLS
348  MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "IngestMessagePanel.moduleErr"),
349  NbBundle.getMessage(this.getClass(),
350  "IngestMessagePanel.moduleErr.errListenUpdates.text"),
351  MessageNotifyUtil.MessageType.ERROR);
352  }
353  }
354 
355  @Override
356  public void tableChanged(TableModelEvent e) {
357  int newMessages = tableModel.getNumberNewMessages();
358 
359  try {
360  messagePcs.firePropertyChange(new PropertyChangeEvent(tableModel, TOTAL_NUM_NEW_MESSAGES_CHANGED, -1, newMessages));
361  } catch (Exception ee) {
362  logger.log(Level.SEVERE, "IngestMessagePanel listener threw exception", ee); //NON-NLS
363  MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "IngestMessagePanel.moduleErr"),
364  NbBundle.getMessage(this.getClass(),
365  "IngestMessagePanel.moduleErr.errListenUpdates.text"),
366  MessageNotifyUtil.MessageType.ERROR);
367  }
368  }
369 
370  private class MessageTableModel extends AbstractTableModel {
371 
372  private final String[] columnNames = new String[]{
373  NbBundle.getMessage(this.getClass(), "IngestMessagePanel.MsgTableMod.colNames.module"),
374  NbBundle.getMessage(this.getClass(), "IngestMessagePanel.MsgTableMod.colNames.num"),
375  NbBundle.getMessage(this.getClass(), "IngestMessagePanel.MsgTableMod.colNames.new"),
376  NbBundle.getMessage(this.getClass(), "IngestMessagePanel.MsgTableMod.colNames.subject"),
377  NbBundle.getMessage(this.getClass(), "IngestMessagePanel.MsgTableMod.colNames.timestamp")};
378  private final List<TableEntry> messageData = new ArrayList<>();
379  //for keeping track of messages to group, per module, by uniqness
380  private final Map<String, Map<String, List<IngestMessageGroup>>> groupings = new HashMap<>();
381  private boolean chronoSort = true; //chronological sort default
382  private static final int MESSAGE_GROUP_THRESH = 3; //group messages after 3 messages per module with same uniqness
383  private final Logger logger = Logger.getLogger(MessageTableModel.class.getName());
384 
385  @Override
386  public int getColumnCount() {
387  return columnNames.length;
388  }
389 
390  @Override
391  public synchronized int getRowCount() {
392  return getNumberGroups();
393  }
394 
395  public synchronized void markAllSeen() {
396  for (TableEntry entry : messageData) {
397  entry.hasBeenSeen(true);
398  }
399  fireTableChanged(new TableModelEvent(this));
400  }
401 
402  public synchronized int getNumberNewMessages() {
403  int newMessages = 0;
404  for (TableEntry entry : messageData) {
405  if (!entry.hasBeenSeen()) {
406  ++newMessages;
407  }
408  }
409  return newMessages;
410  }
411 
412  public synchronized int getNumberGroups() {
413  return messageData.size();
414  }
415 
416  public synchronized int getNumberMessages() {
417  int total = 0;
418  for (TableEntry e : messageData) {
419  total += e.messageGroup.getCount();
420  }
421  return total;
422  }
423 
424  public synchronized int getNumberUnreadMessages() {
425  int total = 0;
426  for (TableEntry e : messageData) {
427  if (!e.hasBeenVisited) {
428  total += e.messageGroup.getCount();
429  }
430  }
431  return total;
432  }
433 
434  public synchronized int getNumberUnreadGroups() {
435  int total = 0;
436  for (TableEntry e : messageData) {
437  if (!e.hasBeenVisited) {
438  ++total;
439  }
440  }
441  return total;
442  }
443 
444  @Override
445  public String getColumnName(int column) {
446  return columnNames[column];
447  }
448 
449  @Override
450  public synchronized Object getValueAt(int rowIndex, int columnIndex) {
451  Object ret = null;
452 
453  int numMessages = messageData.size();
454  if (rowIndex > messageData.size() - 1
455  || columnIndex > columnNames.length - 1) {
456  //temporary check if the rare case still occurrs
457  //#messages is now lower after last regrouping, and gui event thinks it's not
458  logger.log(Level.WARNING, "Requested inbox message at" + rowIndex, ", only have " + numMessages); //NON-NLS
459  return "";
460  }
461  TableEntry entry = messageData.get(rowIndex);
462 
463  switch (columnIndex) {
464  case 0:
465  ret = entry.messageGroup.getSource();
466  break;
467  case 1:
468  ret = entry.messageGroup.getCount();
469  break;
470  case 2:
471  ret = !entry.hasBeenSeen();
472  break;
473  case 3:
474  ret = entry.messageGroup.getSubject();
475  break;
476  case 4:
477  ret = entry.messageGroup.getDatePosted();
478  break;
479  default:
480  logger.log(Level.SEVERE, "Invalid table column index: {0}", columnIndex); //NON-NLS
481  break;
482  }
483  return ret;
484  }
485 
486  @Override
487  public boolean isCellEditable(int rowIndex, int columnIndex) {
488  return false;
489  }
490 
491  @Override
492  public Class<?> getColumnClass(int c) {
493  return getValueAt(0, c).getClass();
494  }
495 
496  private synchronized int getTableEntryIndex(String uniqueKey) {
497  int ret = -1;
498  int i = 0;
499  for (TableEntry e : messageData) {
500  if (e.messageGroup.getUniqueKey().equals(uniqueKey)) {
501  ret = i;
502  break;
503  }
504  ++i;
505  }
506  return ret;
507  }
508 
509  public synchronized void addMessage(IngestMessage m) {
510  //check how many messages per module with the same uniqness
511  //and add to existing group or create a new group
512  String moduleName = m.getSource();
513  IngestMessageGroup messageGroup = null;
514  if (moduleName != null && m.getMessageType() == IngestMessage.MessageType.DATA) {
515  //not a manager message, a data message, then group
516  if (!groupings.containsKey(moduleName)) {
517  groupings.put(moduleName, new HashMap<>());
518  }
519  final Map<String, List<IngestMessageGroup>> groups = groupings.get(moduleName);
520  //groups for this uniqueness
521  final String uniqueness = m.getUniqueKey();
522  List<IngestMessageGroup> uniqGroups = groups.get(uniqueness);
523  if (uniqGroups == null) {
524  //first one with this uniqueness
525  uniqGroups = new ArrayList<>();
526  messageGroup = new IngestMessageGroup(m);
527  uniqGroups.add(messageGroup);
528  groups.put(uniqueness, uniqGroups);
529  } else {
530  final int uniqueGroupsCount = uniqGroups.size();
531  if (uniqueGroupsCount > MESSAGE_GROUP_THRESH) {
532  //merge them
533  messageGroup = uniqGroups.get(0);
534  for (int i = 1; i < uniqueGroupsCount; ++i) {
535  messageGroup.addAll(uniqGroups.get(i));
536  }
537  //add the new msg
538  messageGroup.add(m);
539  //remove merged groups
540  uniqGroups.clear();
541 
542  //add the group with all messages merged
543  uniqGroups.add(messageGroup);
544 
545  //remove all rows with this uniquness, new merged row will be added to the bottom
546  int toRemove;
547  while ((toRemove = getTableEntryIndex(uniqueness)) != -1) {
548  messageData.remove(toRemove);
549  //remove the row, will be added to the bottom
550  this.fireTableRowsDeleted(toRemove, toRemove);
551  }
552 
553  } else if (uniqueGroupsCount == 1) {
554  IngestMessageGroup first = uniqGroups.get(0);
555  //one group with multiple messages
556  if (first.getCount() > 1) {
557  //had already been merged
558  first.add(m);
559  messageGroup = first;
560  //move to bottom of table
561  //remove from existing position
562  int toRemove;
563  while ((toRemove = getTableEntryIndex(uniqueness)) != -1) {
564  messageData.remove(toRemove);
565  //remove the row, will be added to the bottom
566  this.fireTableRowsDeleted(toRemove, toRemove);
567  }
568 
569  } else {
570  //one group with one message
571  //create another group
572  messageGroup = new IngestMessageGroup(m);
573  uniqGroups.add(messageGroup);
574 
575  }
576  } else {
577  //multiple groups with 1 msg each
578  //create another group, until need to merge
579  messageGroup = new IngestMessageGroup(m);
580  uniqGroups.add(messageGroup);
581  //add to bottom
582  }
583  }
584 
585  } else {
586  //manager or non-data message
587  messageGroup = new IngestMessageGroup(m);
588  }
589 
590  //add new or updated row to the bottom
591  messageData.add(new TableEntry(messageGroup));
592  int newRowIndex = messageData.size() - 1;
593  fireTableRowsInserted(newRowIndex, newRowIndex);
594 
595  //if priority sort, need to re-sort everything
596  if (chronoSort == false) {
597  Collections.sort(messageData);
598  fireTableDataChanged();
599  }
600  }
601 
602  public synchronized void clearMessages() {
603  messageData.clear();
604  groupings.clear();
605  fireTableDataChanged();
606  }
607 
608  public synchronized void setVisited(int rowNumber) {
609  messageData.get(rowNumber).hasBeenVisited(true);
610  //repaint the cell
611  fireTableCellUpdated(rowNumber, 2);
612  }
613 
614  public synchronized void setVisitedAll() {
615  int row = 0;
616  for (TableEntry e : messageData) {
617  if (!e.hasBeenVisited) {
618  e.hasBeenVisited(true);
619  fireTableCellUpdated(row, 2);
620  }
621  ++row;
622  }
623  }
624 
625  public synchronized boolean isVisited(int rowNumber) {
626  if (rowNumber < messageData.size()) {
627  return messageData.get(rowNumber).hasBeenVisited();
628  } else {
629  return false;
630  }
631  }
632 
633  public synchronized MessageType getMessageType(int rowNumber) {
634  if (rowNumber < messageData.size()) {
635  return messageData.get(rowNumber).messageGroup.getMessageType();
636  } else {
637  return null;
638  }
639  }
640 
641  public synchronized IngestMessageGroup getMessageGroup(int rowNumber) {
642  if (rowNumber < messageData.size()) {
643  return messageData.get(rowNumber).messageGroup;
644  } else {
645  return null;
646  }
647  }
648 
649  public synchronized void reSort(boolean chronoLogical) {
650  if (chronoSort == chronoLogical) {
651  return;
652  }
653 
654  chronoSort = chronoLogical;
655  Collections.sort(messageData);
656  fireTableDataChanged();
657  }
658 
659  class TableEntry implements Comparable<TableEntry> {
660 
661  IngestMessageGroup messageGroup;
662  boolean hasBeenVisited = false;
663  boolean hasBeenSeen = false;
664 
665  public boolean hasBeenVisited() {
666  return hasBeenVisited;
667  }
668 
669  public void hasBeenVisited(boolean visited) {
670  hasBeenVisited = visited;
671  }
672 
673  public boolean hasBeenSeen() {
674  return hasBeenSeen;
675  }
676 
677  public void hasBeenSeen(boolean seen) {
678  hasBeenSeen = seen;
679  }
680 
681  TableEntry(IngestMessageGroup messageGroup) {
682  this.messageGroup = messageGroup;
683  }
684 
685  @Override
686  public int compareTo(TableEntry o) {
687  if (chronoSort == true) {
688  return this.messageGroup.getDatePosted().compareTo(o.messageGroup.getDatePosted());
689  } else {
690  return messageGroup.getCount() - o.messageGroup.getCount();
691  }
692  }
693  }
694  }
695 
696  //represents grouping of similar messages
697  //with the same uniqness
698  static class IngestMessageGroup {
699 
700  static final Color VERY_HIGH_PRI_COLOR = new Color(164, 164, 202); //for a single message in a group
701  static final Color HIGH_PRI_COLOR = new Color(180, 180, 211);
702  static final Color MED_PRI_COLOR = new Color(199, 199, 222);
703  static final Color LOW_PRI_COLOR = new Color(221, 221, 235);
704  private final List<IngestMessage> messages;
705 
706  IngestMessageGroup(IngestMessage message) {
707  messages = new ArrayList<>();
708  messages.add(message);
709  }
710 
711  private List<IngestMessage> getMessages() {
712  return messages;
713  }
714 
715  synchronized void add(IngestMessage message) {
716  messages.add(message);
717  }
718 
719  //add all messages from another group
720  synchronized void addAll(IngestMessageGroup group) {
721  for (IngestMessage m : group.getMessages()) {
722  messages.add(m);
723  }
724  }
725 
726  synchronized int getCount() {
727  return messages.size();
728  }
729 
730  synchronized String getDetails() {
731  StringBuilder b = new StringBuilder("");
732  for (IngestMessage m : messages) {
733  String details = m.getDetails();
734  if (details == null || details.equals("")) {
735  continue;
736  }
737  b.append(details);
738  b.append("<br />"); //NON-NLS
739  b.append("<hr />"); //NON-NLS
740  }
741 
742  return b.toString();
743  }
744 
750  synchronized Color getColor() {
751  int count = messages.size();
752  if (count == 1) {
753  return VERY_HIGH_PRI_COLOR;
754  } else if (count < 5) {
755  return HIGH_PRI_COLOR;
756  } else if (count < 15) {
757  return MED_PRI_COLOR;
758  } else {
759  return LOW_PRI_COLOR;
760  }
761  }
762 
768  synchronized Date getDatePosted() {
769  return messages.get(messages.size() - 1).getDatePosted();
770  }
771 
777  synchronized String getSubject() {
778  return messages.get(0).getSubject();
779  }
780 
781  /*
782  * return unique key, should be the same for all msgs
783  */
784  synchronized String getUniqueKey() {
785  return messages.get(0).getUniqueKey();
786  }
787 
788  /*
789  * return source module, should be the same for all msgs
790  */
791  synchronized String getSource() {
792  return messages.get(0).getSource();
793  }
794 
795  /*
796  * return data of the first message
797  */
798  synchronized BlackboardArtifact getData() {
799  return messages.get(0).getData();
800  }
801 
802  /*
803  * return message type, should be the same for all msgs
804  */
805  synchronized IngestMessage.MessageType getMessageType() {
806  return messages.get(0).getMessageType();
807  }
808  }
809 
810  /*
811  * Main TableCellRenderer to be used for ingest message inbox. Delegates to
812  * other TableCellRenderers based different factors such as column data type
813  * or column number.
814  */
815  private class MessageTableRenderer extends DefaultTableCellRenderer {
816 
817  private final TableCellRenderer booleanRenderer = new BooleanRenderer();
818  private final TableCellRenderer defaultRenderer = new DefaultRenderer();
819  private final TableCellRenderer dateRenderer = new DateRenderer();
820  protected int rowSelected;
821 
822  public void setRowSelected(int rowSelected) {
823  this.rowSelected = rowSelected;
824  }
825 
826  @Override
827  public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
828  if (value instanceof Boolean) {
829  return booleanRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
830  } else if (value instanceof Date) {
831  return dateRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
832  } else {
833  return defaultRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
834  }
835  }
836  }
837 
838  /*
839  * TableCellRenderer used to render boolean values with a bullet point.
840  */
841  private class BooleanRenderer extends DefaultTableCellRenderer {
842 
843  private final String bulletChar = new String(Character.toChars(0x2022));
844 
845  @Override
846  public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
847 
848  super.setForeground(table.getSelectionForeground());
849  super.setBackground(table.getSelectionBackground());
850 
851  boolean boolVal;
852  if (value instanceof Boolean) {
853  boolVal = ((Boolean) value);
854  } else {
855  throw new RuntimeException(NbBundle.getMessage(this.getClass(),
856  "IngestMessagePanel.BooleanRenderer.exception.nonBoolVal.msg"));
857  }
858 
859  String aValue = boolVal ? bulletChar : "";
860 
861  JLabel cell = (JLabel) super.getTableCellRendererComponent(table, aValue, isSelected, hasFocus, row, column);
862 
863  // center the bullet in the JLabel
864  cell.setHorizontalAlignment(SwingConstants.CENTER);
865 
866  // increase the font size
867  cell.setFont(cell.getFont().deriveFont(Font.PLAIN, cell.getFont().getSize()+5));
868 
869  final IngestMessageGroup messageGroup = tableModel.getMessageGroup(row);
870  if (messageGroup != null) {
871  MessageType mt = messageGroup.getMessageType();
872  if (mt == MessageType.ERROR) {
873  cell.setBackground(ERROR_COLOR);
874  } else if (mt == MessageType.WARNING) {
875  cell.setBackground(Color.orange);
876  } else {
877  //cell.setBackground(table.getBackground());
878  cell.setBackground(messageGroup.getColor());
879  }
880  }
881  return cell;
882  }
883  }
884 
889  private class DefaultRenderer extends DefaultTableCellRenderer {
890 
891  @Override
893  JTable table, Object value,
894  boolean isSelected, boolean hasFocus,
895  int row, int column) {
896 
897  Component cell = super.getTableCellRendererComponent(
898  table, value, false, false, row, column);
899 
900  Font visitedFont = cell.getFont().deriveFont(Font.PLAIN, cell.getFont().getSize()+1);
901  Font notVisitedFont = cell.getFont().deriveFont(Font.BOLD, cell.getFont().getSize()+1);
902 
903  if (column == 3) {
904  String subject = (String) value;
905  setToolTipText(subject);
906  if (tableModel.isVisited(row)) {
907  cell.setFont(visitedFont);
908  } else {
909  cell.setFont(notVisitedFont);
910  }
911  }
912 
913  final IngestMessageGroup messageGroup = tableModel.getMessageGroup(row);
914  if (messageGroup != null) {
915  MessageType mt = messageGroup.getMessageType();
916  if (mt == MessageType.ERROR) {
917  cell.setBackground(ERROR_COLOR);
918  } else if (mt == MessageType.WARNING) {
919  cell.setBackground(Color.orange);
920  } else {
921  //cell.setBackground(table.getBackground());
922  cell.setBackground(messageGroup.getColor());
923  }
924  }
925  return cell;
926  }
927  }
928 
929  private class DateRenderer extends DefaultTableCellRenderer {
930 
931  @Override
932  public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
933 
934  super.setForeground(table.getSelectionForeground());
935  super.setBackground(table.getSelectionBackground());
936 
937  Object aValue = value;
938  if (value instanceof Date) {
939  Date date = (Date) value;
940  DateFormat df = new SimpleDateFormat("HH:mm:ss");
941  aValue = df.format(date);
942  } else {
943  throw new RuntimeException(NbBundle.getMessage(this.getClass(),
944  "IngestMessagePanel.DateRenderer.exception.nonDateVal.text"));
945  }
946 
947  Component cell = super.getTableCellRendererComponent(table, aValue, isSelected, hasFocus, row, column);
948 
949  final IngestMessageGroup messageGroup = tableModel.getMessageGroup(row);
950  if (messageGroup != null) {
951  MessageType mt = messageGroup.getMessageType();
952  if (mt == MessageType.ERROR) {
953  cell.setBackground(ERROR_COLOR);
954  } else if (mt == MessageType.WARNING) {
955  cell.setBackground(Color.orange);
956  } else {
957  //cell.setBackground(table.getBackground());
958  cell.setBackground(messageGroup.getColor());
959  }
960  }
961 
962  return cell;
963  }
964  }
965 
969  private class MessageVisitedSelection implements ListSelectionListener {
970 
971  @Override
972  public void valueChanged(ListSelectionEvent e) {
973  ListSelectionModel selModel = (ListSelectionModel) e.getSource();
974  if (selModel.isSelectionEmpty() || selModel.getValueIsAdjusting()) {
975  return;
976  }
977 
978  final int minIndex = selModel.getMinSelectionIndex();
979  final int maxIndex = selModel.getMaxSelectionIndex();
980  int selected = -1;
981  for (int i = minIndex; i <= maxIndex; i++) {
982  if (selModel.isSelectedIndex(i)) {
983  selected = i;
984  break;
985  }
986  }
987  selModel.clearSelection();
988  if (selected != -1) {
989  setVisited(selected);
990  messageTable.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
991  //check if has details
992  IngestMessageGroup m = getMessageGroup(selected);
993  if (m != null) {
994  String details = m.getDetails();
995  if (details != null && !details.equals("")) {
996  mainPanel.showDetails(selected);
997  }
998  }
999  messageTable.setCursor(null);
1000  }
1001  }
1002  }
1003 }
synchronized IngestMessageGroup getMessageGroup(int rowNumber)
Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
synchronized Object getValueAt(int rowIndex, int columnIndex)

Copyright © 2012-2020 Basis Technology. Generated on: Wed Apr 8 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.