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

Copyright © 2012-2015 Basis Technology. Generated on: Mon Oct 19 2015
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.