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"})
 
  895             int originalPage = currentPage;
 
  898                 currentPage = Integer.decode(gotoPageTextField.getText());
 
  899             } 
catch (NumberFormatException e) {
 
  904             if (currentPage > totalPages || currentPage < 1) {
 
  905                 currentPage = originalPage;
 
  906                 JOptionPane.showMessageDialog(DataResultViewerTable.this,
 
  907                         Bundle.DataResultViewerTable_goToPageTextField_msgDlg(totalPages),
 
  908                         Bundle.DataResultViewerTable_goToPageTextField_err(),
 
  909                         JOptionPane.WARNING_MESSAGE);
 
  912             postPageChangeEvent();
 
  919         void postPageChangeEvent() {
 
  921                 BaseChildFactory.post(nodeName, 
new PageChangeEvent(currentPage));
 
  922             } 
catch (BaseChildFactory.NoSuchEventBusException ex) {
 
  923                 LOGGER.log(Level.WARNING, 
"Failed to post page change event.", ex); 
 
  925             DataResultViewerTable.this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
 
  933         void postPageSizeChangeEvent() {
 
  937             if (
this == pagingSupport) {
 
  941                 BaseChildFactory.post(nodeName, 
new PageSizeChangeEvent(UserPreferences.getResultsTablePageSize()));
 
  942             } 
catch (BaseChildFactory.NoSuchEventBusException ex) {
 
  943                 LOGGER.log(Level.WARNING, 
"Failed to post page size change event.", ex); 
 
  955                 totalPages = 
event.getPageCount();
 
  956                 if (totalPages > 1) {
 
  958                     togglePageControls(
true);
 
  962                 if (nodeName.equals(rootNode.getName())) {
 
  974             pageLabel.setVisible(onOff);
 
  975             pagesLabel.setVisible(onOff);
 
  976             pagePrevButton.setVisible(onOff);
 
  977             pageNextButton.setVisible(onOff);
 
  978             pageNumLabel.setVisible(onOff);
 
  979             gotoPageLabel.setVisible(onOff);
 
  980             gotoPageTextField.setVisible(onOff);
 
  981             gotoPageTextField.setVisible(onOff);
 
  986         @NbBundle.Messages({
"# {0} - currentPage", 
"# {1} - totalPages",
 
  987             "DataResultViewerTable.pageNumbers.curOfTotal={0} of {1}"})
 
  989             if (totalPages == 0) {
 
  990                 pagePrevButton.setEnabled(
false);
 
  991                 pageNextButton.setEnabled(
false);
 
  992                 pageNumLabel.setText(
"");
 
  993                 gotoPageTextField.setText(
"");
 
  994                 gotoPageTextField.setEnabled(
false);
 
  996                 pageNumLabel.setText(Bundle.DataResultViewerTable_pageNumbers_curOfTotal(Integer.toString(currentPage), Integer.toString(totalPages)));
 
  998                 pageNextButton.setEnabled(currentPage != totalPages);
 
  999                 pagePrevButton.setEnabled(currentPage != 1);
 
 1000                 gotoPageTextField.setEnabled(totalPages > 1);
 
 1001                 gotoPageTextField.setText(
"");
 
 1012         @NbBundle.Messages({
"DataResultViewerTable.commentRender.name=C",
 
 1013             "DataResultViewerTable.commentRender.toolTip=C(omments) indicates whether the item has a comment",
 
 1014             "DataResultViewerTable.scoreRender.name=S",
 
 1015             "DataResultViewerTable.scoreRender.toolTip=S(core) indicates whether the item is interesting or notable",
 
 1016             "DataResultViewerTable.countRender.name=O",
 
 1017             "DataResultViewerTable.countRender.toolTip=O(ccurrences) indicates the number of data sources containing the item in the Central Repository"})
 
 1020             if (e.getSource() instanceof ETableColumnModel) {
 
 1021                 TableColumn column = ((TableColumnModel) e.getSource()).getColumn(e.getToIndex());
 
 1022                 if (column.getHeaderValue().toString().equals(Bundle.DataResultViewerTable_commentRender_name())) {
 
 1024                     outlineView.setPropertyColumnDescription(column.getHeaderValue().toString(), Bundle.DataResultViewerTable_commentRender_toolTip());
 
 1026                 } 
else if (column.getHeaderValue().toString().equals(Bundle.DataResultViewerTable_scoreRender_name())) {
 
 1028                     outlineView.setPropertyColumnDescription(column.getHeaderValue().toString(), Bundle.DataResultViewerTable_scoreRender_toolTip());
 
 1030                 } 
else if (column.getHeaderValue().toString().equals(Bundle.DataResultViewerTable_countRender_name())) {
 
 1031                     outlineView.setPropertyColumnDescription(column.getHeaderValue().toString(), Bundle.DataResultViewerTable_countRender_toolTip());
 
 1067     private class TableListener extends MouseAdapter implements TableColumnModelListener {
 
 1071         private int startColumnIndex = -1;
 
 1072         private int endColumnIndex = -1;
 
 1077             int fromIndex = e.getFromIndex();
 
 1078             int toIndex = e.getToIndex();
 
 1079             if (fromIndex == toIndex) {
 
 1093             if (startColumnIndex == -1) {
 
 1094                 startColumnIndex = fromIndex;
 
 1096             endColumnIndex = toIndex;
 
 1099             ArrayList<Integer> indicesList = 
new ArrayList<>(propertiesMap.keySet());
 
 1100             int leftIndex = Math.min(fromIndex, toIndex);
 
 1101             int rightIndex = Math.max(fromIndex, toIndex);
 
 1104             List<Integer> range = indicesList.subList(leftIndex, rightIndex + 1);
 
 1105             int rangeSize = range.size();
 
 1107             if (fromIndex < toIndex) {
 
 1110                 Property<?> movedProp = propertiesMap.get(range.get(0));
 
 1111                 for (
int i = 0; i < rangeSize - 1; i++) {
 
 1112                     propertiesMap.put(range.get(i), propertiesMap.get(range.get(i + 1)));
 
 1114                 propertiesMap.put(range.get(rangeSize - 1), movedProp);
 
 1118                 Property<?> movedProp = propertiesMap.get(range.get(rangeSize - 1));
 
 1119                 for (
int i = rangeSize - 1; i > 0; i--) {
 
 1120                     propertiesMap.put(range.get(i), propertiesMap.get(range.get(i - 1)));
 
 1122                 propertiesMap.put(range.get(0), movedProp);
 
 1141             if (startColumnIndex != -1 && (startColumnIndex == 0 || endColumnIndex == 0)) {
 
 1142                 outline.moveColumn(endColumnIndex, startColumnIndex);
 
 1144             startColumnIndex = -1;
 
 1150             storeColumnSorting();
 
 1155             columnAddedOrRemoved();
 
 1160             columnAddedOrRemoved();
 
 1169             if (listenToVisibilitEvents) {
 
 1193             this.listenToVisibilitEvents = b;
 
 1203         private static final long serialVersionUID = 1L;
 
 1205         @NbBundle.Messages({
"DataResultViewerTable.commentRenderer.crComment.toolTip=Comment exists in Central Repository",
 
 1206             "DataResultViewerTable.commentRenderer.tagComment.toolTip=Comment exists on associated tag(s)",
 
 1207             "DataResultViewerTable.commentRenderer.crAndTagComment.toolTip=Comments exist both in Central Repository and on associated tag(s)",
 
 1208             "DataResultViewerTable.commentRenderer.noComment.toolTip=No comments found"})
 
 1211             Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
 
 1212             setBackground(component.getBackground());  
 
 1213             setHorizontalAlignment(CENTER);
 
 1214             Object switchValue = null;
 
 1218                     switchValue = ((Node.Property) value).getValue();
 
 1219                 } 
catch (IllegalAccessException | InvocationTargetException ex) {
 
 1224                 switchValue = value;
 
 1229                 switch ((HasCommentStatus) switchValue) {
 
 1231                         setIcon(COMMENT_ICON);
 
 1232                         setToolTipText(Bundle.DataResultViewerTable_commentRenderer_crComment_toolTip());
 
 1235                         setIcon(COMMENT_ICON);
 
 1236                         setToolTipText(Bundle.DataResultViewerTable_commentRenderer_tagComment_toolTip());
 
 1238                     case CR_AND_TAG_COMMENTS:
 
 1239                         setIcon(COMMENT_ICON);
 
 1240                         setToolTipText(Bundle.DataResultViewerTable_commentRenderer_crAndTagComment_toolTip());
 
 1242                     case TAG_NO_COMMENT:
 
 1246                         setToolTipText(Bundle.DataResultViewerTable_commentRenderer_noComment_toolTip());
 
 1263         private static final long serialVersionUID = 1L;
 
 1267             Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
 
 1268             setBackground(component.getBackground());  
 
 1269             setHorizontalAlignment(CENTER);
 
 1270             Object switchValue = null;
 
 1274                     switchValue = ((Node.Property) value).getValue();
 
 1275                     setToolTipText(((FeatureDescriptor) value).getShortDescription());
 
 1276                 } 
catch (IllegalAccessException | InvocationTargetException ex) {
 
 1282                 switchValue = value;
 
 1285             if ((switchValue instanceof 
Score)) {
 
 1287                 switch ((Score) switchValue) {
 
 1288                     case INTERESTING_SCORE:
 
 1289                         setIcon(INTERESTING_SCORE_ICON);
 
 1292                         setIcon(NOTABLE_ICON_SCORE);
 
 1312         private static final long serialVersionUID = 1L;
 
 1316             Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
 
 1317             setBackground(component.getBackground());  
 
 1318             setHorizontalAlignment(LEFT);
 
 1319             Object countValue = null;
 
 1323                     countValue = ((Node.Property) value).getValue();
 
 1324                     setToolTipText(((FeatureDescriptor) value).getShortDescription());
 
 1325                 } 
catch (IllegalAccessException | InvocationTargetException ex) {
 
 1333             if ((countValue instanceof Long)) {
 
 1335                 if ((Long) countValue >= 0) {
 
 1336                     setText(countValue.toString());
 
 1370     @SuppressWarnings(
"unchecked")
 
 1372     private 
void initComponents() {
 
 1374         pageLabel = 
new javax.swing.JLabel();
 
 1375         pageNumLabel = 
new javax.swing.JLabel();
 
 1376         pagesLabel = 
new javax.swing.JLabel();
 
 1377         pagePrevButton = 
new javax.swing.JButton();
 
 1378         pageNextButton = 
new javax.swing.JButton();
 
 1380         gotoPageLabel = 
new javax.swing.JLabel();
 
 1381         gotoPageTextField = 
new javax.swing.JTextField();
 
 1382         exportCSVButton = 
new javax.swing.JButton();
 
 1384         pageLabel.setText(
org.openide.util.NbBundle.getMessage(
DataResultViewerTable.class, 
"DataResultViewerTable.pageLabel.text")); 
 
 1386         pageNumLabel.setText(
org.openide.util.NbBundle.getMessage(
DataResultViewerTable.class, 
"DataResultViewerTable.pageNumLabel.text")); 
 
 1388         pagesLabel.setText(
org.openide.util.NbBundle.getMessage(
DataResultViewerTable.class, 
"DataResultViewerTable.pagesLabel.text")); 
 
 1390         pagePrevButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back.png"))); 
 
 1391         pagePrevButton.setText(
org.openide.util.NbBundle.getMessage(
DataResultViewerTable.class, 
"DataResultViewerTable.pagePrevButton.text")); 
 
 1392         pagePrevButton.setDisabledIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png"))); 
 
 1393         pagePrevButton.setFocusable(
false);
 
 1394         pagePrevButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
 
 1395         pagePrevButton.setMargin(
new java.awt.Insets(2, 0, 2, 0));
 
 1396         pagePrevButton.setPreferredSize(
new java.awt.Dimension(55, 23));
 
 1397         pagePrevButton.setRolloverIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png"))); 
 
 1398         pagePrevButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
 
 1399         pagePrevButton.addActionListener(
new java.awt.event.ActionListener() {
 
 1400             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
 1401                 pagePrevButtonActionPerformed(evt);
 
 1405         pageNextButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png"))); 
 
 1406         pageNextButton.setText(
org.openide.util.NbBundle.getMessage(
DataResultViewerTable.class, 
"DataResultViewerTable.pageNextButton.text")); 
 
 1407         pageNextButton.setDisabledIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png"))); 
 
 1408         pageNextButton.setFocusable(
false);
 
 1409         pageNextButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
 
 1410         pageNextButton.setMargin(
new java.awt.Insets(2, 0, 2, 0));
 
 1411         pageNextButton.setMaximumSize(
new java.awt.Dimension(27, 23));
 
 1412         pageNextButton.setMinimumSize(
new java.awt.Dimension(27, 23));
 
 1413         pageNextButton.setRolloverIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png"))); 
 
 1414         pageNextButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
 
 1415         pageNextButton.addActionListener(
new java.awt.event.ActionListener() {
 
 1416             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
 1417                 pageNextButtonActionPerformed(evt);
 
 1421         gotoPageLabel.setText(
org.openide.util.NbBundle.getMessage(
DataResultViewerTable.class, 
"DataResultViewerTable.gotoPageLabel.text")); 
 
 1423         gotoPageTextField.setText(
org.openide.util.NbBundle.getMessage(
DataResultViewerTable.class, 
"DataResultViewerTable.gotoPageTextField.text")); 
 
 1424         gotoPageTextField.addActionListener(
new java.awt.event.ActionListener() {
 
 1425             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
 1426                 gotoPageTextFieldActionPerformed(evt);
 
 1430         exportCSVButton.setText(
org.openide.util.NbBundle.getMessage(
DataResultViewerTable.class, 
"DataResultViewerTable.exportCSVButton.text")); 
 
 1431         exportCSVButton.addActionListener(
new java.awt.event.ActionListener() {
 
 1432             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
 1433                 exportCSVButtonActionPerformed(evt);
 
 1437         javax.swing.GroupLayout layout = 
new javax.swing.GroupLayout(
this);
 
 1438         this.setLayout(layout);
 
 1439         layout.setHorizontalGroup(
 
 1440             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
 1441             .addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 904, Short.MAX_VALUE)
 
 1442             .addGroup(layout.createSequentialGroup()
 
 1444                 .addComponent(pageLabel)
 
 1445                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
 1446                 .addComponent(pageNumLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 53, javax.swing.GroupLayout.PREFERRED_SIZE)
 
 1448                 .addComponent(pagesLabel)
 
 1449                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
 
 1450                 .addComponent(pagePrevButton, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE)
 
 1451                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
 1452                 .addComponent(pageNextButton, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE)
 
 1453                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
 
 1454                 .addComponent(gotoPageLabel)
 
 1455                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
 1456                 .addComponent(gotoPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 33, javax.swing.GroupLayout.PREFERRED_SIZE)
 
 1457                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
 1458                 .addComponent(exportCSVButton))
 
 1461         layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, 
new java.awt.Component[] {pageNextButton, pagePrevButton});
 
 1463         layout.setVerticalGroup(
 
 1464             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
 1465             .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
 
 1467                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
 
 1468                     .addComponent(pageLabel)
 
 1469                     .addComponent(pageNumLabel)
 
 1470                     .addComponent(pagesLabel)
 
 1471                     .addComponent(pagePrevButton, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)
 
 1472                     .addComponent(pageNextButton, javax.swing.GroupLayout.PREFERRED_SIZE, 15, javax.swing.GroupLayout.PREFERRED_SIZE)
 
 1473                     .addComponent(gotoPageLabel)
 
 1474                     .addComponent(gotoPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
 
 1475                     .addComponent(exportCSVButton))
 
 1477                 .addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 321, Short.MAX_VALUE)
 
 1481         layout.linkSize(javax.swing.SwingConstants.VERTICAL, 
new java.awt.Component[] {pageNextButton, pagePrevButton});
 
 1483         gotoPageLabel.getAccessibleContext().setAccessibleName(
"");
 
 1487         pagingSupport.previousPage();
 
 1491         pagingSupport.nextPage();
 
 1495         pagingSupport.gotoPage();
 
 1498     @NbBundle.Messages({
"DataResultViewerTable.exportCSVButtonActionPerformed.empty=No data to export" 
 1501         Node currentRoot = this.getExplorerManager().getRootContext();
 
 1502         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)