19 package org.sleuthkit.autopsy.corecomponents;
 
   21 import com.google.common.eventbus.Subscribe;
 
   22 import java.awt.Component;
 
   23 import java.awt.Cursor;
 
   24 import java.awt.FontMetrics;
 
   25 import java.awt.Graphics;
 
   26 import java.awt.dnd.DnDConstants;
 
   27 import java.awt.event.MouseAdapter;
 
   28 import java.awt.event.MouseEvent;
 
   29 import java.beans.FeatureDescriptor;
 
   30 import java.beans.PropertyChangeEvent;
 
   31 import java.beans.PropertyVetoException;
 
   32 import java.lang.reflect.InvocationTargetException;
 
   33 import java.util.ArrayList;
 
   34 import java.util.Comparator;
 
   35 import java.util.HashMap;
 
   36 import java.util.LinkedList;
 
   37 import java.util.List;
 
   39 import java.util.Queue;
 
   40 import java.util.TreeMap;
 
   41 import java.util.TreeSet;
 
   42 import java.util.concurrent.ConcurrentHashMap;
 
   43 import java.util.logging.Level;
 
   44 import java.util.prefs.PreferenceChangeEvent;
 
   45 import java.util.prefs.Preferences;
 
   46 import javax.swing.ImageIcon;
 
   47 import javax.swing.JOptionPane;
 
   48 import javax.swing.JTable;
 
   49 import javax.swing.ListSelectionModel;
 
   50 import static javax.swing.SwingConstants.CENTER;
 
   51 import javax.swing.SwingUtilities;
 
   52 import javax.swing.event.ChangeEvent;
 
   53 import javax.swing.event.ListSelectionEvent;
 
   54 import javax.swing.event.TableColumnModelEvent;
 
   55 import javax.swing.event.TableColumnModelListener;
 
   56 import javax.swing.event.TreeExpansionListener;
 
   57 import javax.swing.table.TableCellRenderer;
 
   58 import javax.swing.table.TableColumn;
 
   59 import javax.swing.table.TableColumnModel;
 
   60 import org.netbeans.swing.etable.ETableColumn;
 
   61 import org.netbeans.swing.etable.ETableColumnModel;
 
   62 import org.netbeans.swing.outline.DefaultOutlineCellRenderer;
 
   63 import org.netbeans.swing.outline.DefaultOutlineModel;
 
   64 import org.netbeans.swing.outline.Outline;
 
   65 import org.openide.explorer.ExplorerManager;
 
   66 import org.openide.explorer.view.OutlineView;
 
   67 import org.openide.nodes.AbstractNode;
 
   68 import org.openide.nodes.Children;
 
   69 import org.openide.nodes.Node;
 
   70 import org.openide.nodes.Node.Property;
 
   71 import org.openide.nodes.NodeEvent;
 
   72 import org.openide.nodes.NodeListener;
 
   73 import org.openide.nodes.NodeMemberEvent;
 
   74 import org.openide.nodes.NodeReorderEvent;
 
   75 import org.openide.util.ImageUtilities;
 
   76 import org.openide.util.NbBundle;
 
   77 import org.openide.util.NbPreferences;
 
   78 import org.openide.util.lookup.ServiceProvider;
 
  101 @ServiceProvider(service = DataResultViewer.class)
 
  102 @SuppressWarnings(
"PMD.SingularField") 
 
  105     private static final long serialVersionUID = 1L;
 
  108     private static final String NOTEPAD_ICON_PATH = 
"org/sleuthkit/autopsy/images/notepad16.png";
 
  109     private static final String RED_CIRCLE_ICON_PATH = 
"org/sleuthkit/autopsy/images/red-circle-exclamation.png";
 
  110     private static final String YELLOW_CIRCLE_ICON_PATH = 
"org/sleuthkit/autopsy/images/yellow-circle-yield.png";
 
  111     private static final ImageIcon COMMENT_ICON = 
new ImageIcon(ImageUtilities.loadImage(NOTEPAD_ICON_PATH, 
false));
 
  112     private static final ImageIcon INTERESTING_SCORE_ICON = 
new ImageIcon(ImageUtilities.loadImage(YELLOW_CIRCLE_ICON_PATH, 
false));
 
  113     private static final ImageIcon NOTABLE_ICON_SCORE = 
new ImageIcon(ImageUtilities.loadImage(RED_CIRCLE_ICON_PATH, 
false));
 
  114     @NbBundle.Messages(
"DataResultViewerTable.firstColLbl=Name")
 
  115     static private final String FIRST_COLUMN_LABEL = Bundle.DataResultViewerTable_firstColLbl();
 
  129     private final Map<String, PagingSupport> nodeNameToPagingSupportMap = 
new ConcurrentHashMap<>();
 
  144         this(null, Bundle.DataResultViewerTable_title());
 
  157         this(explorerManager, Bundle.DataResultViewerTable_title());
 
  171         super(explorerManager);
 
  173         this.columnMap = 
new HashMap<>();
 
  174         this.propertiesMap = 
new TreeMap<>();
 
  181         initializePagingSupport();
 
  187             exportCSVButton.setEnabled(
false);
 
  193         outlineView.setAllowedDragActions(DnDConstants.ACTION_NONE);
 
  195         outline = outlineView.getOutline();
 
  196         outline.setRowSelectionAllowed(
true);
 
  197         outline.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
 
  198         outline.setRootVisible(
false);
 
  199         outline.setDragEnabled(
false);
 
  206         outline.getColumnModel().addColumnModelListener(outlineViewListener);
 
  209         outline.getColumnModel().addColumnModelListener(iconRendererListener);
 
  215         outline.getTableHeader().addMouseListener(outlineViewListener);
 
  219         if (pagingSupport == null) {
 
  232                 setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
 
  237                 nodeNameToPagingSupportMap.values().forEach((ps) -> {
 
  238                     ps.postPageSizeChangeEvent();
 
  264     @NbBundle.Messages(
"DataResultViewerTable.title=Table")
 
  289     public 
void setNode(Node rootNode) {
 
  290         if (!SwingUtilities.isEventDispatchThread()) {
 
  291             LOGGER.log(Level.SEVERE, 
"Attempting to run setNode() from non-EDT thread");
 
  302         outline.unsetQuickFilter();
 
  304         this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
 
  306             if (rootNode != null) {
 
  307                 this.rootNode = rootNode;
 
  313                 String nodeName = rootNode.getName();
 
  314                 pagingSupport = nodeNameToPagingSupportMap.get(nodeName);
 
  315                 if (pagingSupport == null) {
 
  317                     nodeNameToPagingSupportMap.put(nodeName, pagingSupport);
 
  321                 rootNode.addNodeListener(
new NodeListener() {
 
  323                     public void childrenAdded(NodeMemberEvent nme) {
 
  330                         SwingUtilities.invokeLater(() -> {
 
  336                     public void childrenRemoved(NodeMemberEvent nme) {
 
  337                         SwingUtilities.invokeLater(() -> {
 
  343                     public void childrenReordered(NodeReorderEvent nre) {
 
  348                     public void nodeDestroyed(NodeEvent ne) {
 
  353                     public void propertyChange(PropertyChangeEvent evt) {
 
  370             if (rootNode != null && rootNode.getChildren().getNodesCount() > 0) {
 
  371                 this.getExplorerManager().setRootContext(this.rootNode);
 
  374                 Node emptyNode = 
new AbstractNode(Children.LEAF);
 
  375                 this.getExplorerManager().setRootContext(emptyNode);
 
  376                 outline.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
 
  378                 outlineView.setPropertyColumns();
 
  381             this.setCursor(null);
 
  392         outlineView.addTreeExpansionListener(listener);
 
  417         List<Node.Property<?>> props = loadColumnOrder();
 
  418         boolean propsExist = props.isEmpty() == 
false;
 
  419         Node.Property<?> firstProp = null;
 
  421             firstProp = props.remove(0);
 
  429         outline.setAutoResizeMode((props.isEmpty()) ? JTable.AUTO_RESIZE_ALL_COLUMNS : JTable.AUTO_RESIZE_OFF);
 
  431         assignColumns(props); 
 
  432         if (firstProp != null) {
 
  433             ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(firstProp.getDisplayName());
 
  457         loadColumnVisibility();
 
  463         SwingUtilities.invokeLater(() -> {
 
  465                 NodeSelectionInfo selectedChildInfo = ((TableFilterNode) rootNode).getChildNodeSelectionInfo();
 
  466                 if (null != selectedChildInfo) {
 
  467                     Node[] childNodes = rootNode.getChildren().getNodes(
true);
 
  468                     for (
int i = 0; i < childNodes.length; ++i) {
 
  469                         Node childNode = childNodes[i];
 
  470                         if (selectedChildInfo.
matches(childNode)) {
 
  472                                 this.getExplorerManager().setSelectedNodes(
new Node[]{childNode});
 
  473                             } 
catch (PropertyVetoException ex) {
 
  474                                 LOGGER.log(Level.SEVERE, 
"Failed to select node specified by selected child info", ex);
 
  479                     ((TableFilterNode) rootNode).setChildNodeSelectionInfo(null);
 
  499         TableColumnModel columnModel = outline.getColumnModel();
 
  500         int columnCount = columnModel.getColumnCount();
 
  502         for (Map.Entry<Integer, Property<?>> entry : propertiesMap.entrySet()) {
 
  503             final String propName = entry.getValue().getName();
 
  504             if (entry.getKey() < columnCount) {
 
  505                 final ETableColumn column = (ETableColumn) columnModel.getColumn(entry.getKey());
 
  506                 columnMap.put(propName, column);
 
  517         if (rootNode.getChildren().getNodesCount() != 0) {
 
  518             final Graphics graphics = outlineView.getGraphics();
 
  520             if (graphics != null) {
 
  522                 double outlineViewWidth = outlineView.getSize().getWidth();
 
  524                 List<Integer> columnWidths = 
new ArrayList<>();
 
  525                 final FontMetrics metrics = graphics.getFontMetrics();
 
  530                 int totalColumnWidth = 0;
 
  531                 int cntMaxSizeColumns =0;
 
  535                 for (
int column = 0; column < outline.getModel().getColumnCount(); column++) {
 
  536                     int firstColumnPadding = (column == 0) ? 32 : 0;
 
  537                     int columnWidthLimit = (column == 0) ? 350 : 300;
 
  541                     for (
int row = 0; row < Math.min(100, outline.getRowCount()); row++) {
 
  542                         TableCellRenderer renderer = outline.getCellRenderer(row, column);
 
  543                         Component comp = outline.prepareRenderer(renderer, row, column);
 
  544                         valuesWidth = Math.max(comp.getPreferredSize().width, valuesWidth);
 
  547                     int headerWidth = metrics.stringWidth(outline.getColumnName(column));
 
  548                     valuesWidth += firstColumnPadding; 
 
  550                     int columnWidth = Math.max(valuesWidth, headerWidth);
 
  551                     columnWidth += 2 * margin + padding; 
 
  553                     columnWidth = Math.min(columnWidth, columnWidthLimit);
 
  554                     columnWidths.add(columnWidth);
 
  556                     totalColumnWidth += columnWidth;
 
  558                     if( columnWidth == columnWidthLimit) {
 
  570                 if (totalColumnWidth < outlineViewWidth) {
 
  571                     if  (cntMaxSizeColumns > 0) {
 
  572                         extraWidth = (int) ((outlineViewWidth - totalColumnWidth)/cntMaxSizeColumns);
 
  574                         extraWidth = (int) ((outlineViewWidth - totalColumnWidth)/columnWidths.size());
 
  578                 for(
int column = 0; column < columnWidths.size(); column++) {
 
  579                     int columnWidth = columnWidths.get(column);
 
  581                     if(cntMaxSizeColumns > 0) {
 
  582                         if(columnWidth >= ((column == 0) ? 350 : 300)) {
 
  583                             columnWidth += extraWidth;
 
  586                         columnWidth += extraWidth;
 
  589                     outline.getColumnModel().getColumn(column).setPreferredWidth(columnWidth);
 
  594             outline.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
 
  599         return outline.getColumnModel();
 
  607         String[] propStrings = 
new String[props.size() * 2];
 
  608         for (
int i = 0; i < props.size(); i++) {
 
  609             final Property<?> prop = props.get(i);
 
  610             prop.setValue(
"ComparableColumnTTV", Boolean.TRUE); 
 
  613                 prop.setValue(
"TreeColumnTTV", Boolean.TRUE); 
 
  614                 prop.setValue(
"SortingColumnTTV", Boolean.TRUE); 
 
  616             propStrings[2 * i] = prop.getName();
 
  617             propStrings[2 * i + 1] = prop.getDisplayName();
 
  619         outlineView.setPropertyColumns(propStrings);
 
  627         if (rootNode == null || propertiesMap.isEmpty()) {
 
  631             TableFilterNode tfn = (TableFilterNode) rootNode;
 
  633             final ETableColumnModel columnModel = (ETableColumnModel) outline.getColumnModel();
 
  634             for (Map.Entry<String, ETableColumn> entry : columnMap.entrySet()) {
 
  635                 String columnName = entry.getKey();
 
  636                 final String columnHiddenKey = ResultViewerPersistence.getColumnHiddenKey(tfn, columnName);
 
  637                 final TableColumn column = entry.getValue();
 
  638                 boolean columnHidden = columnModel.isColumnHidden(column);
 
  640                     preferences.putBoolean(columnHiddenKey, 
true);
 
  642                     preferences.remove(columnHiddenKey);
 
  653         if (rootNode == null || propertiesMap.isEmpty()) {
 
  657             TableFilterNode tfn = (TableFilterNode) rootNode;
 
  660             for (Map.Entry<Integer, Property<?>> entry : propertiesMap.entrySet()) {
 
  661                 preferences.putInt(ResultViewerPersistence.getColumnPositionKey(tfn, entry.getValue().getName()), entry.getKey());
 
  670         if (rootNode == null || propertiesMap.isEmpty()) {
 
  674             final TableFilterNode tfn = ((TableFilterNode) rootNode);
 
  676             ETableColumnModel columnModel = (ETableColumnModel) outline.getColumnModel();
 
  677             for (Map.Entry<String, ETableColumn> entry : columnMap.entrySet()) {
 
  678                 ETableColumn etc = entry.getValue();
 
  679                 String columnName = entry.getKey();
 
  681                 final String columnSortOrderKey = ResultViewerPersistence.getColumnSortOrderKey(tfn, columnName);
 
  682                 final String columnSortRankKey = ResultViewerPersistence.getColumnSortRankKey(tfn, columnName);
 
  683                 if (etc.isSorted() && (columnModel.isColumnHidden(etc) == 
false)) {
 
  684                     preferences.putBoolean(columnSortOrderKey, etc.isAscending());
 
  685                     preferences.putInt(columnSortRankKey, etc.getSortRank());
 
  687                     columnModel.setColumnSorted(etc, 
true, 0);
 
  688                     preferences.remove(columnSortOrderKey);
 
  689                     preferences.remove(columnSortRankKey);
 
  702         if (rootNode == null || propertiesMap.isEmpty()) {
 
  706             final TableFilterNode tfn = (TableFilterNode) rootNode;
 
  709             TreeSet<ColumnSortInfo> sortInfos = 
new TreeSet<>(Comparator.comparing(ColumnSortInfo::getRank));
 
  710             propertiesMap.entrySet().stream().forEach(entry -> {
 
  711                 final String propName = entry.getValue().getName();
 
  713                 Integer sortRank = preferences.getInt(ResultViewerPersistence.getColumnSortRankKey(tfn, propName), 0);
 
  715                 Boolean sortOrder = preferences.getBoolean(ResultViewerPersistence.getColumnSortOrderKey(tfn, propName), 
true);
 
  716                 sortInfos.add(
new ColumnSortInfo(entry.getKey(), sortRank, sortOrder));
 
  719             sortInfos.forEach(sortInfo -> outline.setColumnSorted(sortInfo.modelIndex, sortInfo.order, sortInfo.rank));
 
  728         if (rootNode == null || propertiesMap.isEmpty()) {
 
  733             final TableFilterNode tfn = ((TableFilterNode) rootNode);
 
  734             ETableColumnModel columnModel = (ETableColumnModel) outline.getColumnModel();
 
  735             for (Map.Entry<Integer, Property<?>> entry : propertiesMap.entrySet()) {
 
  736                 final String propName = entry.getValue().getName();
 
  737                 boolean hidden = preferences.getBoolean(ResultViewerPersistence.getColumnHiddenKey(tfn, propName), 
false);
 
  738                 final TableColumn column = columnMap.get(propName);
 
  739                 columnModel.setColumnHidden(column, hidden);
 
  754         List<Property<?>> props = ResultViewerPersistence.getAllChildProperties(rootNode, 100);
 
  761         final TableFilterNode tfn = ((TableFilterNode) rootNode);
 
  762         propertiesMap.clear();
 
  770         int offset = props.size();
 
  774         for (Property<?> prop : props) {
 
  775             Integer value = preferences.getInt(ResultViewerPersistence.getColumnPositionKey(tfn, prop.getName()), -1);
 
  776             if (value >= 0 && value < offset && !propertiesMap.containsKey(value)) {
 
  777                 propertiesMap.put(value, prop);
 
  779                 propertiesMap.put(offset, prop);
 
  789         compactPropertiesMap();
 
  791         return new ArrayList<>(propertiesMap.values());
 
  801         int size = propertiesMap.size();
 
  802         Queue<Integer> availablePositions = 
new LinkedList<>();
 
  803         for (
int i = 0; i < size; i++) {
 
  804             if (!propertiesMap.containsKey(i)) {
 
  805                 availablePositions.add(i);
 
  810         if (availablePositions.isEmpty()) {
 
  817         ArrayList<Integer> keys = 
new ArrayList<>(propertiesMap.keySet());
 
  818         for (
int key : keys) {
 
  820                 propertiesMap.put(availablePositions.remove(), propertiesMap.remove(key));
 
  831         this.outlineView.removeAll();
 
  832         this.outlineView = null;
 
  833         super.clearComponent();
 
  846             this.modelIndex = modelIndex;
 
  870             this.nodeName = nodeName;
 
  875             if (!nodeName.isEmpty()) {
 
  883             postPageChangeEvent();
 
  886         void previousPage() {
 
  888             postPageChangeEvent();
 
  891         @NbBundle.Messages({
"# {0} - totalPages",
 
  892             "DataResultViewerTable.goToPageTextField.msgDlg=Please enter a valid page number between 1 and {0}",
 
  893             "DataResultViewerTable.goToPageTextField.err=Invalid page number"})
 
  896                 currentPage = Integer.decode(gotoPageTextField.getText());
 
  897             } 
catch (NumberFormatException e) {
 
  902             if (currentPage > totalPages || currentPage < 1) {
 
  904                 JOptionPane.showMessageDialog(DataResultViewerTable.this,
 
  905                         Bundle.DataResultViewerTable_goToPageTextField_msgDlg(totalPages),
 
  906                         Bundle.DataResultViewerTable_goToPageTextField_err(),
 
  907                         JOptionPane.WARNING_MESSAGE);
 
  910             postPageChangeEvent();
 
  917         void postPageChangeEvent() {
 
  919                 BaseChildFactory.post(nodeName, 
new PageChangeEvent(currentPage));
 
  920             } 
catch (BaseChildFactory.NoSuchEventBusException ex) {
 
  921                 LOGGER.log(Level.WARNING, 
"Failed to post page change event.", ex); 
 
  923             DataResultViewerTable.this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
 
  931         void postPageSizeChangeEvent() {
 
  935             if (
this == pagingSupport) {
 
  939                 BaseChildFactory.post(nodeName, 
new PageSizeChangeEvent(UserPreferences.getResultsTablePageSize()));
 
  940             } 
catch (BaseChildFactory.NoSuchEventBusException ex) {
 
  941                 LOGGER.log(Level.WARNING, 
"Failed to post page size change event.", ex); 
 
  953                 totalPages = 
event.getPageCount();
 
  954                 if (totalPages > 1) {
 
  956                     togglePageControls(
true);
 
  960                 if (nodeName.equals(rootNode.getName())) {
 
  972             pageLabel.setVisible(onOff);
 
  973             pagesLabel.setVisible(onOff);
 
  974             pagePrevButton.setVisible(onOff);
 
  975             pageNextButton.setVisible(onOff);
 
  976             pageNumLabel.setVisible(onOff);
 
  977             gotoPageLabel.setVisible(onOff);
 
  978             gotoPageTextField.setVisible(onOff);
 
  979             gotoPageTextField.setVisible(onOff);
 
  984         @NbBundle.Messages({
"# {0} - currentPage", 
"# {1} - totalPages",
 
  985             "DataResultViewerTable.pageNumbers.curOfTotal={0} of {1}"})
 
  987             if (totalPages == 0) {
 
  988                 pagePrevButton.setEnabled(
false);
 
  989                 pageNextButton.setEnabled(
false);
 
  990                 pageNumLabel.setText(
"");
 
  991                 gotoPageTextField.setText(
"");
 
  992                 gotoPageTextField.setEnabled(
false);
 
  994                 pageNumLabel.setText(Bundle.DataResultViewerTable_pageNumbers_curOfTotal(Integer.toString(currentPage), Integer.toString(totalPages)));
 
  996                 pageNextButton.setEnabled(currentPage != totalPages);
 
  997                 pagePrevButton.setEnabled(currentPage != 1);
 
  998                 gotoPageTextField.setEnabled(totalPages > 1);
 
  999                 gotoPageTextField.setText(
"");
 
 1010         @NbBundle.Messages({
"DataResultViewerTable.commentRender.name=C",
 
 1011             "DataResultViewerTable.commentRender.toolTip=C(omments) indicates whether the item has a comment",
 
 1012             "DataResultViewerTable.scoreRender.name=S",
 
 1013             "DataResultViewerTable.scoreRender.toolTip=S(core) indicates whether the item is interesting or notable",
 
 1014             "DataResultViewerTable.countRender.name=O",
 
 1015             "DataResultViewerTable.countRender.toolTip=O(ccurrences) indicates the number of data sources containing the item in the Central Repository"})
 
 1018             if (e.getSource() instanceof ETableColumnModel) {
 
 1019                 TableColumn column = ((TableColumnModel) e.getSource()).getColumn(e.getToIndex());
 
 1020                 if (column.getHeaderValue().toString().equals(Bundle.DataResultViewerTable_commentRender_name())) {
 
 1022                     outlineView.setPropertyColumnDescription(column.getHeaderValue().toString(), Bundle.DataResultViewerTable_commentRender_toolTip());
 
 1024                 } 
else if (column.getHeaderValue().toString().equals(Bundle.DataResultViewerTable_scoreRender_name())) {
 
 1026                     outlineView.setPropertyColumnDescription(column.getHeaderValue().toString(), Bundle.DataResultViewerTable_scoreRender_toolTip());
 
 1028                 } 
else if (column.getHeaderValue().toString().equals(Bundle.DataResultViewerTable_countRender_name())) {
 
 1029                     outlineView.setPropertyColumnDescription(column.getHeaderValue().toString(), Bundle.DataResultViewerTable_countRender_toolTip());
 
 1065     private class TableListener extends MouseAdapter implements TableColumnModelListener {
 
 1069         private int startColumnIndex = -1;
 
 1070         private int endColumnIndex = -1;
 
 1075             int fromIndex = e.getFromIndex();
 
 1076             int toIndex = e.getToIndex();
 
 1077             if (fromIndex == toIndex) {
 
 1091             if (startColumnIndex == -1) {
 
 1092                 startColumnIndex = fromIndex;
 
 1094             endColumnIndex = toIndex;
 
 1097             ArrayList<Integer> indicesList = 
new ArrayList<>(propertiesMap.keySet());
 
 1098             int leftIndex = Math.min(fromIndex, toIndex);
 
 1099             int rightIndex = Math.max(fromIndex, toIndex);
 
 1102             List<Integer> range = indicesList.subList(leftIndex, rightIndex + 1);
 
 1103             int rangeSize = range.size();
 
 1105             if (fromIndex < toIndex) {
 
 1108                 Property<?> movedProp = propertiesMap.get(range.get(0));
 
 1109                 for (
int i = 0; i < rangeSize - 1; i++) {
 
 1110                     propertiesMap.put(range.get(i), propertiesMap.get(range.get(i + 1)));
 
 1112                 propertiesMap.put(range.get(rangeSize - 1), movedProp);
 
 1116                 Property<?> movedProp = propertiesMap.get(range.get(rangeSize - 1));
 
 1117                 for (
int i = rangeSize - 1; i > 0; i--) {
 
 1118                     propertiesMap.put(range.get(i), propertiesMap.get(range.get(i - 1)));
 
 1120                 propertiesMap.put(range.get(0), movedProp);
 
 1139             if (startColumnIndex != -1 && (startColumnIndex == 0 || endColumnIndex == 0)) {
 
 1140                 outline.moveColumn(endColumnIndex, startColumnIndex);
 
 1142             startColumnIndex = -1;
 
 1148             storeColumnSorting();
 
 1153             columnAddedOrRemoved();
 
 1158             columnAddedOrRemoved();
 
 1167             if (listenToVisibilitEvents) {
 
 1191             this.listenToVisibilitEvents = b;
 
 1201         private static final long serialVersionUID = 1L;
 
 1203         @NbBundle.Messages({
"DataResultViewerTable.commentRenderer.crComment.toolTip=Comment exists in Central Repository",
 
 1204             "DataResultViewerTable.commentRenderer.tagComment.toolTip=Comment exists on associated tag(s)",
 
 1205             "DataResultViewerTable.commentRenderer.crAndTagComment.toolTip=Comments exist both in Central Repository and on associated tag(s)",
 
 1206             "DataResultViewerTable.commentRenderer.noComment.toolTip=No comments found"})
 
 1209             Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
 
 1210             setBackground(component.getBackground());  
 
 1211             setHorizontalAlignment(CENTER);
 
 1212             Object switchValue = null;
 
 1216                     switchValue = ((Node.Property) value).getValue();
 
 1217                 } 
catch (IllegalAccessException | InvocationTargetException ex) {
 
 1222                 switchValue = value;
 
 1227                 switch ((HasCommentStatus) switchValue) {
 
 1229                         setIcon(COMMENT_ICON);
 
 1230                         setToolTipText(Bundle.DataResultViewerTable_commentRenderer_crComment_toolTip());
 
 1233                         setIcon(COMMENT_ICON);
 
 1234                         setToolTipText(Bundle.DataResultViewerTable_commentRenderer_tagComment_toolTip());
 
 1236                     case CR_AND_TAG_COMMENTS:
 
 1237                         setIcon(COMMENT_ICON);
 
 1238                         setToolTipText(Bundle.DataResultViewerTable_commentRenderer_crAndTagComment_toolTip());
 
 1240                     case TAG_NO_COMMENT:
 
 1244                         setToolTipText(Bundle.DataResultViewerTable_commentRenderer_noComment_toolTip());
 
 1261         private static final long serialVersionUID = 1L;
 
 1265             Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
 
 1266             setBackground(component.getBackground());  
 
 1267             setHorizontalAlignment(CENTER);
 
 1268             Object switchValue = null;
 
 1272                     switchValue = ((Node.Property) value).getValue();
 
 1273                     setToolTipText(((FeatureDescriptor) value).getShortDescription());
 
 1274                 } 
catch (IllegalAccessException | InvocationTargetException ex) {
 
 1280                 switchValue = value;
 
 1283             if ((switchValue instanceof 
Score)) {
 
 1285                 switch ((Score) switchValue) {
 
 1286                     case INTERESTING_SCORE:
 
 1287                         setIcon(INTERESTING_SCORE_ICON);
 
 1290                         setIcon(NOTABLE_ICON_SCORE);
 
 1310         private static final long serialVersionUID = 1L;
 
 1314             Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
 
 1315             setBackground(component.getBackground());  
 
 1316             setHorizontalAlignment(LEFT);
 
 1317             Object countValue = null;
 
 1321                     countValue = ((Node.Property) value).getValue();
 
 1322                     setToolTipText(((FeatureDescriptor) value).getShortDescription());
 
 1323                 } 
catch (IllegalAccessException | InvocationTargetException ex) {
 
 1331             if ((countValue instanceof Long)) {
 
 1333                 if ((Long) countValue >= 0) {
 
 1334                     setText(countValue.toString());
 
 1368     @SuppressWarnings(
"unchecked")
 
 1370     private 
void initComponents() {
 
 1372         pageLabel = 
new javax.swing.JLabel();
 
 1373         pageNumLabel = 
new javax.swing.JLabel();
 
 1374         pagesLabel = 
new javax.swing.JLabel();
 
 1375         pagePrevButton = 
new javax.swing.JButton();
 
 1376         pageNextButton = 
new javax.swing.JButton();
 
 1378         gotoPageLabel = 
new javax.swing.JLabel();
 
 1379         gotoPageTextField = 
new javax.swing.JTextField();
 
 1380         exportCSVButton = 
new javax.swing.JButton();
 
 1382         pageLabel.setText(
org.openide.util.NbBundle.getMessage(
DataResultViewerTable.class, 
"DataResultViewerTable.pageLabel.text")); 
 
 1384         pageNumLabel.setText(
org.openide.util.NbBundle.getMessage(
DataResultViewerTable.class, 
"DataResultViewerTable.pageNumLabel.text")); 
 
 1386         pagesLabel.setText(
org.openide.util.NbBundle.getMessage(
DataResultViewerTable.class, 
"DataResultViewerTable.pagesLabel.text")); 
 
 1388         pagePrevButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back.png"))); 
 
 1389         pagePrevButton.setText(
org.openide.util.NbBundle.getMessage(
DataResultViewerTable.class, 
"DataResultViewerTable.pagePrevButton.text")); 
 
 1390         pagePrevButton.setDisabledIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png"))); 
 
 1391         pagePrevButton.setFocusable(
false);
 
 1392         pagePrevButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
 
 1393         pagePrevButton.setMargin(
new java.awt.Insets(2, 0, 2, 0));
 
 1394         pagePrevButton.setPreferredSize(
new java.awt.Dimension(55, 23));
 
 1395         pagePrevButton.setRolloverIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png"))); 
 
 1396         pagePrevButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
 
 1397         pagePrevButton.addActionListener(
new java.awt.event.ActionListener() {
 
 1398             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
 1399                 pagePrevButtonActionPerformed(evt);
 
 1403         pageNextButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png"))); 
 
 1404         pageNextButton.setText(
org.openide.util.NbBundle.getMessage(
DataResultViewerTable.class, 
"DataResultViewerTable.pageNextButton.text")); 
 
 1405         pageNextButton.setDisabledIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png"))); 
 
 1406         pageNextButton.setFocusable(
false);
 
 1407         pageNextButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
 
 1408         pageNextButton.setMargin(
new java.awt.Insets(2, 0, 2, 0));
 
 1409         pageNextButton.setMaximumSize(
new java.awt.Dimension(27, 23));
 
 1410         pageNextButton.setMinimumSize(
new java.awt.Dimension(27, 23));
 
 1411         pageNextButton.setRolloverIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png"))); 
 
 1412         pageNextButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
 
 1413         pageNextButton.addActionListener(
new java.awt.event.ActionListener() {
 
 1414             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
 1415                 pageNextButtonActionPerformed(evt);
 
 1419         gotoPageLabel.setText(
org.openide.util.NbBundle.getMessage(
DataResultViewerTable.class, 
"DataResultViewerTable.gotoPageLabel.text")); 
 
 1421         gotoPageTextField.setText(
org.openide.util.NbBundle.getMessage(
DataResultViewerTable.class, 
"DataResultViewerTable.gotoPageTextField.text")); 
 
 1422         gotoPageTextField.addActionListener(
new java.awt.event.ActionListener() {
 
 1423             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
 1424                 gotoPageTextFieldActionPerformed(evt);
 
 1428         exportCSVButton.setText(
org.openide.util.NbBundle.getMessage(
DataResultViewerTable.class, 
"DataResultViewerTable.exportCSVButton.text")); 
 
 1429         exportCSVButton.addActionListener(
new java.awt.event.ActionListener() {
 
 1430             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
 1431                 exportCSVButtonActionPerformed(evt);
 
 1435         javax.swing.GroupLayout layout = 
new javax.swing.GroupLayout(
this);
 
 1436         this.setLayout(layout);
 
 1437         layout.setHorizontalGroup(
 
 1438             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
 1439             .addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 904, Short.MAX_VALUE)
 
 1440             .addGroup(layout.createSequentialGroup()
 
 1442                 .addComponent(pageLabel)
 
 1443                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
 1444                 .addComponent(pageNumLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 53, javax.swing.GroupLayout.PREFERRED_SIZE)
 
 1446                 .addComponent(pagesLabel)
 
 1447                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
 
 1448                 .addComponent(pagePrevButton, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE)
 
 1449                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
 1450                 .addComponent(pageNextButton, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE)
 
 1451                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
 
 1452                 .addComponent(gotoPageLabel)
 
 1453                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
 1454                 .addComponent(gotoPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 33, javax.swing.GroupLayout.PREFERRED_SIZE)
 
 1455                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
 1456                 .addComponent(exportCSVButton))
 
 1459         layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, 
new java.awt.Component[] {pageNextButton, pagePrevButton});
 
 1461         layout.setVerticalGroup(
 
 1462             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
 1463             .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
 
 1465                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
 
 1466                     .addComponent(pageLabel)
 
 1467                     .addComponent(pageNumLabel)
 
 1468                     .addComponent(pagesLabel)
 
 1469                     .addComponent(pagePrevButton, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)
 
 1470                     .addComponent(pageNextButton, javax.swing.GroupLayout.PREFERRED_SIZE, 15, javax.swing.GroupLayout.PREFERRED_SIZE)
 
 1471                     .addComponent(gotoPageLabel)
 
 1472                     .addComponent(gotoPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
 
 1473                     .addComponent(exportCSVButton))
 
 1475                 .addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 321, Short.MAX_VALUE)
 
 1479         layout.linkSize(javax.swing.SwingConstants.VERTICAL, 
new java.awt.Component[] {pageNextButton, pagePrevButton});
 
 1481         gotoPageLabel.getAccessibleContext().setAccessibleName(
"");
 
 1485         pagingSupport.previousPage();
 
 1489         pagingSupport.nextPage();
 
 1493         pagingSupport.gotoPage();
 
 1496     @NbBundle.Messages({
"DataResultViewerTable.exportCSVButtonActionPerformed.empty=No data to export" 
 1499         Node currentRoot = this.getExplorerManager().getRootContext();
 
 1500         if (currentRoot != null && currentRoot.getChildren().getNodesCount() > 0) {
 
javax.swing.JLabel pageLabel
 
void mouseReleased(MouseEvent e)
 
boolean matches(Node candidateNode)
 
javax.swing.JLabel pageNumLabel
 
Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
 
TableColumnModel getColumnModel()
 
final Map< String, ETableColumn > columnMap
 
Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
 
org.openide.explorer.view.OutlineView outlineView
 
void compactPropertiesMap()
 
void columnRemoved(TableColumnModelEvent e)
 
void columnAdded(TableColumnModelEvent e)
 
synchronized List< Node.Property<?> > loadColumnOrder()
 
synchronized void storeColumnVisibility()
 
void pageNextButtonActionPerformed(java.awt.event.ActionEvent evt)
 
void subscribeToPageCountChange(PageCountChangeEvent event)
 
static void register(String nodeName, Object subscriber)
 
synchronized void storeColumnSorting()
 
javax.swing.JButton pageNextButton
 
synchronized void assignColumns(List< Property<?>> props)
 
final IconRendererTableListener iconRendererListener
 
void columnMarginChanged(ChangeEvent e)
 
static final String FIRST_COLUMN_LABEL
 
void mouseClicked(MouseEvent e)
 
void columnSelectionChanged(ListSelectionEvent e)
 
void columnRemoved(TableColumnModelEvent e)
 
javax.swing.JTextField gotoPageTextField
 
final TableListener outlineViewListener
 
void columnAddedOrRemoved()
 
void exportCSVButtonActionPerformed(java.awt.event.ActionEvent evt)
 
boolean listenToVisibilitEvents
 
void columnMoved(TableColumnModelEvent e)
 
DataResultViewer createInstance()
 
javax.swing.JLabel gotoPageLabel
 
static final String RESULTS_TABLE_PAGE_SIZE
 
final Map< Integer, Property<?> > propertiesMap
 
void gotoPageTextFieldActionPerformed(java.awt.event.ActionEvent evt)
 
void columnSelectionChanged(ListSelectionEvent e)
 
javax.swing.JButton pagePrevButton
 
javax.swing.JLabel pagesLabel
 
synchronized void loadColumnVisibility()
 
ColumnSortInfo(int modelIndex, int rank, boolean order)
 
void addTreeExpansionListener(TreeExpansionListener listener)
 
void listenToVisibilityChanges(boolean b)
 
synchronized static Logger getLogger(String name)
 
synchronized void loadColumnSorting()
 
static void addChangeListener(PreferenceChangeListener listener)
 
void pagePrevButtonActionPerformed(java.awt.event.ActionEvent evt)
 
void initializePagingSupport()
 
static void info(String message)
 
void columnMoved(TableColumnModelEvent e)
 
javax.swing.JButton exportCSVButton
 
DataResultViewerTable(ExplorerManager explorerManager)
 
void columnMarginChanged(ChangeEvent e)
 
boolean isSupported(Node candidateRootNode)
 
static void saveNodesToCSV(Collection<?extends Node > nodesToExport, Component component)
 
void columnAdded(TableColumnModelEvent e)
 
synchronized void storeColumnOrder()
 
DataResultViewerTable(ExplorerManager explorerManager, String title)
 
void togglePageControls(boolean onOff)