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

Copyright © 2012-2016 Basis Technology. Generated on: Fri Sep 29 2017
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.