mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-15 01:07:42 +00:00
refactoring and cleanup of DataResultViewerTable
This commit is contained in:
parent
6f3f993073
commit
6af4d0a631
@ -27,9 +27,6 @@
|
|||||||
</Layout>
|
</Layout>
|
||||||
<SubComponents>
|
<SubComponents>
|
||||||
<Container class="org.openide.explorer.view.OutlineView" name="outlineView">
|
<Container class="org.openide.explorer.view.OutlineView" name="outlineView">
|
||||||
<Events>
|
|
||||||
<EventHandler event="componentResized" listener="java.awt.event.ComponentListener" parameters="java.awt.event.ComponentEvent" handler="outlineViewComponentResized"/>
|
|
||||||
</Events>
|
|
||||||
<AuxValues>
|
<AuxValues>
|
||||||
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new OutlineView(DataResultViewerTable.FIRST_COLUMN_LABEL);"/>
|
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new OutlineView(DataResultViewerTable.FIRST_COLUMN_LABEL);"/>
|
||||||
</AuxValues>
|
</AuxValues>
|
||||||
|
@ -26,8 +26,6 @@ import java.awt.Graphics;
|
|||||||
import java.awt.dnd.DnDConstants;
|
import java.awt.dnd.DnDConstants;
|
||||||
import java.awt.event.MouseAdapter;
|
import java.awt.event.MouseAdapter;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.beans.FeatureDescriptor;
|
|
||||||
import java.beans.PropertyChangeEvent;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -37,10 +35,9 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.prefs.Preferences;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.prefs.Preferences;
|
import java.util.prefs.Preferences;
|
||||||
|
import java.util.stream.Stream;
|
||||||
import javax.swing.JTable;
|
import javax.swing.JTable;
|
||||||
import javax.swing.ListSelectionModel;
|
import javax.swing.ListSelectionModel;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
@ -49,8 +46,8 @@ import javax.swing.event.ListSelectionEvent;
|
|||||||
import javax.swing.event.TableColumnModelEvent;
|
import javax.swing.event.TableColumnModelEvent;
|
||||||
import javax.swing.event.TableColumnModelListener;
|
import javax.swing.event.TableColumnModelListener;
|
||||||
import javax.swing.table.TableCellRenderer;
|
import javax.swing.table.TableCellRenderer;
|
||||||
|
|
||||||
import javax.swing.table.TableColumnModel;
|
import javax.swing.table.TableColumnModel;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.netbeans.swing.etable.ETableColumn;
|
import org.netbeans.swing.etable.ETableColumn;
|
||||||
import org.netbeans.swing.outline.DefaultOutlineCellRenderer;
|
import org.netbeans.swing.outline.DefaultOutlineCellRenderer;
|
||||||
import org.netbeans.swing.outline.DefaultOutlineModel;
|
import org.netbeans.swing.outline.DefaultOutlineModel;
|
||||||
@ -99,11 +96,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
private final PleasewaitNodeListener pleasewaitNodeListener = new PleasewaitNodeListener();
|
private final PleasewaitNodeListener pleasewaitNodeListener = new PleasewaitNodeListener();
|
||||||
|
|
||||||
private Node currentRoot;
|
private Node currentRoot;
|
||||||
// When a column in the table is moved, these two variables keep track of where
|
|
||||||
// the column started and where it ended up.
|
|
||||||
private int startColumnIndex = -1;
|
|
||||||
private int endColumnIndex = -1;
|
|
||||||
private OutlineView ov;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convience reference to internal Outline.
|
* Convience reference to internal Outline.
|
||||||
@ -141,104 +134,10 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
outline.setDefaultRenderer(Object.class, new ColorTagCustomRenderer());
|
outline.setDefaultRenderer(Object.class, new ColorTagCustomRenderer());
|
||||||
|
|
||||||
// add a listener so that when columns are moved, the new order is stored
|
// add a listener so that when columns are moved, the new order is stored
|
||||||
outline.getColumnModel().addColumnModelListener(new TableColumnModelListener() {
|
TableListener tableListener = new TableListener();
|
||||||
|
outline.getColumnModel().addColumnModelListener(tableListener);
|
||||||
@Override
|
// the listener also moves columns back if user tries to move the first column out of place
|
||||||
public void columnMoved(TableColumnModelEvent e) {
|
outline.getTableHeader().addMouseListener(tableListener);
|
||||||
int fromIndex = e.getFromIndex();
|
|
||||||
int toIndex = e.getToIndex();
|
|
||||||
if (fromIndex == toIndex) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Because a column may be dragged to several different
|
|
||||||
* positions before the mouse is released (thus causing multiple
|
|
||||||
* TableColumnModelEvents to be fired), we want to keep track of
|
|
||||||
* the starting column index in this potential series of
|
|
||||||
* movements. Therefore we only keep track of the original
|
|
||||||
* fromIndex in startColumnIndex, but we always update
|
|
||||||
* endColumnIndex to know the final position of the moved
|
|
||||||
* column. See the MouseListener mouseReleased method.
|
|
||||||
*/
|
|
||||||
if (startColumnIndex == -1) {
|
|
||||||
startColumnIndex = fromIndex;
|
|
||||||
}
|
|
||||||
endColumnIndex = toIndex;
|
|
||||||
|
|
||||||
// This list contains the keys of propertiesMap in order
|
|
||||||
ArrayList<Integer> indicesList = new ArrayList<>(propertiesMap.keySet());
|
|
||||||
int leftIndex = Math.min(fromIndex, toIndex);
|
|
||||||
int rightIndex = Math.max(fromIndex, toIndex);
|
|
||||||
// Now we can copy the range of keys that have been affected by
|
|
||||||
// the column movement
|
|
||||||
List<Integer> range = indicesList.subList(leftIndex, rightIndex + 1);
|
|
||||||
int rangeSize = range.size();
|
|
||||||
|
|
||||||
if (fromIndex < toIndex) {
|
|
||||||
// column moved right, shift all properties left, put in moved
|
|
||||||
// property at the rightmost index
|
|
||||||
Property<?> movedProp = propertiesMap.get(range.get(0));
|
|
||||||
for (int i = 0; i < rangeSize - 1; i++) {
|
|
||||||
propertiesMap.put(range.get(i), propertiesMap.get(range.get(i + 1)));
|
|
||||||
}
|
|
||||||
propertiesMap.put(range.get(rangeSize - 1), movedProp);
|
|
||||||
} else {
|
|
||||||
// column moved left, shift all properties right, put in moved
|
|
||||||
// property at the leftmost index
|
|
||||||
Property<?> movedProp = propertiesMap.get(range.get(rangeSize - 1));
|
|
||||||
for (int i = rangeSize - 1; i > 0; i--) {
|
|
||||||
propertiesMap.put(range.get(i), propertiesMap.get(range.get(i - 1)));
|
|
||||||
}
|
|
||||||
propertiesMap.put(range.get(0), movedProp);
|
|
||||||
}
|
|
||||||
|
|
||||||
storeState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void columnAdded(TableColumnModelEvent e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void columnRemoved(TableColumnModelEvent e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void columnMarginChanged(ChangeEvent e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void columnSelectionChanged(ListSelectionEvent e) {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// add a listener to move columns back if user tries to move the first column out of place
|
|
||||||
outline.getTableHeader().addMouseListener(new MouseAdapter() {
|
|
||||||
@Override
|
|
||||||
public void mouseReleased(MouseEvent e) {
|
|
||||||
/*
|
|
||||||
* If the startColumnIndex is not -1 (which is the reset value),
|
|
||||||
* that means columns have been moved around. We then check to
|
|
||||||
* see if either the starting or end position is 0 (the first
|
|
||||||
* column), and then swap them back if that is the case because
|
|
||||||
* we don't want to allow movement of the first column. We then
|
|
||||||
* reset startColumnIndex to -1, the reset value. We check if
|
|
||||||
* startColumnIndex is at reset or not because it is possible
|
|
||||||
* for the mouse to be released and a MouseEvent to be fired
|
|
||||||
* without having moved any columns.
|
|
||||||
*/
|
|
||||||
if (startColumnIndex != -1 && (startColumnIndex == 0 || endColumnIndex == 0)) {
|
|
||||||
outline.moveColumn(endColumnIndex, startColumnIndex);
|
|
||||||
}
|
|
||||||
startColumnIndex = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseClicked(MouseEvent e) {
|
|
||||||
storeState();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -251,9 +150,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
public void expandNode(Node n) {
|
public void expandNode(Node n) {
|
||||||
super.expandNode(n);
|
super.expandNode(n);
|
||||||
|
|
||||||
if (this.outlineView != null) {
|
outlineView.expandNode(n);
|
||||||
outlineView.expandNode(n);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -267,12 +164,6 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
|
|
||||||
outlineView = new OutlineView(DataResultViewerTable.FIRST_COLUMN_LABEL);
|
outlineView = new OutlineView(DataResultViewerTable.FIRST_COLUMN_LABEL);
|
||||||
|
|
||||||
outlineView.addComponentListener(new java.awt.event.ComponentAdapter() {
|
|
||||||
public void componentResized(java.awt.event.ComponentEvent evt) {
|
|
||||||
outlineViewComponentResized(evt);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||||
this.setLayout(layout);
|
this.setLayout(layout);
|
||||||
layout.setHorizontalGroup(
|
layout.setHorizontalGroup(
|
||||||
@ -285,42 +176,21 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
);
|
);
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
private void outlineViewComponentResized(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_outlineViewComponentResized
|
|
||||||
}//GEN-LAST:event_outlineViewComponentResized
|
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
private org.openide.explorer.view.OutlineView outlineView;
|
private org.openide.explorer.view.OutlineView outlineView;
|
||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets properties from all children and, recursively, subchildren of Node.
|
* Get the properties from all children and, recursively, subchildren of
|
||||||
* Note: won't work out the box for lazy load - you need to set all children
|
* Node. Note: won't work out the box for lazy load - you need to set all
|
||||||
* props for the parent by hand
|
* children props for the parent by hand
|
||||||
*
|
|
||||||
* JMTODO: This is 'search' goes depth first. Is that really what we want
|
|
||||||
* when getting child headers?
|
|
||||||
*
|
|
||||||
* @param node the Node to get properties for.
|
|
||||||
*
|
|
||||||
* @return A List of properties.
|
|
||||||
*/
|
|
||||||
static private List<Property<?>> getAllChildProperties(Node node) {
|
|
||||||
// This is a set because we add properties of up to 100 child nodes, and we want unique properties
|
|
||||||
Set<Property<?>> propertiesAcc = new LinkedHashSet<>();
|
|
||||||
getAllChildPropertiesHelper(node, 100, propertiesAcc);
|
|
||||||
return new ArrayList<>(propertiesAcc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper to get the properties from all children and, recursively,
|
|
||||||
* subchildren of Node. Note: won't work out the box for lazy load - you
|
|
||||||
* need to set all children props for the parent by hand
|
|
||||||
*
|
*
|
||||||
* @param parent Node with at least one child to get properties from
|
* @param parent Node with at least one child to get properties from
|
||||||
* @param maxRows max number of rows to retrieve properties for (can
|
* @param maxRows max number of rows to retrieve properties for (can
|
||||||
* be used for memory optimization)
|
* be used for memory optimization)
|
||||||
* @param propertiesAcc Accumulator for properties.
|
* @param propertiesAcc Accumulator for properties.
|
||||||
*/
|
*/
|
||||||
static private void getAllChildPropertiesHelper(Node parent, int maxRows, Set<Property<?>> propertiesAcc) {
|
static private void getAllChildProperties(Node parent, int maxRows, Set<Property<?>> propertiesAcc) {
|
||||||
Children children = parent.getChildren();
|
Children children = parent.getChildren();
|
||||||
int childCount = 0;
|
int childCount = 0;
|
||||||
for (Node child : children.getNodes()) {
|
for (Node child : children.getNodes()) {
|
||||||
@ -330,7 +200,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
for (PropertySet ps : child.getPropertySets()) {
|
for (PropertySet ps : child.getPropertySets()) {
|
||||||
propertiesAcc.addAll(Arrays.asList(ps.getProperties()));
|
propertiesAcc.addAll(Arrays.asList(ps.getProperties()));
|
||||||
}
|
}
|
||||||
getAllChildPropertiesHelper(child, maxRows, propertiesAcc);
|
getAllChildProperties(child, maxRows, propertiesAcc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,29 +279,22 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
Node.Property<?> prop = props.remove(0);
|
Node.Property<?> prop = props.remove(0);
|
||||||
((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(prop.getDisplayName());
|
((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(prop.getDisplayName());
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
// Get the columns setup with respect to names and sortability
|
* show the horizontal scroll panel and show all the content & header If
|
||||||
String[] propStrings = new String[props.size() * 2];
|
* there is only one column (which was removed from props above) Just
|
||||||
for (int i = 0; i < props.size(); i++) {
|
* let the table resize itself.
|
||||||
final Property<?> prop = props.get(i);
|
*/
|
||||||
prop.setValue("ComparableColumnTTV", Boolean.TRUE); //NON-NLS
|
|
||||||
//First property column is sorted initially
|
|
||||||
if (i == 0) {
|
|
||||||
prop.setValue("TreeColumnTTV", Boolean.TRUE); // Identifies special property representing first (tree) column. NON-NLS
|
|
||||||
prop.setValue("SortingColumnTTV", Boolean.TRUE); // TreeTableView should be initially sorted by this property column. NON-NLS
|
|
||||||
}
|
|
||||||
propStrings[2 * i] = prop.getName();
|
|
||||||
propStrings[2 * i + 1] = prop.getDisplayName();
|
|
||||||
}
|
|
||||||
|
|
||||||
outlineView.setPropertyColumns(propStrings);
|
|
||||||
|
|
||||||
// show the horizontal scroll panel and show all the content & header
|
|
||||||
// If there is only one column (which was removed from props above)
|
|
||||||
// Just let the table resize itself.
|
|
||||||
outline.setAutoResizeMode((props.isEmpty()) ? JTable.AUTO_RESIZE_ALL_COLUMNS : JTable.AUTO_RESIZE_OFF);
|
outline.setAutoResizeMode((props.isEmpty()) ? JTable.AUTO_RESIZE_ALL_COLUMNS : JTable.AUTO_RESIZE_OFF);
|
||||||
|
|
||||||
if (root.getChildren().getNodesCount() != 0) {
|
assignColumns(props);
|
||||||
|
|
||||||
|
setColumnWidths();
|
||||||
|
|
||||||
|
loadColumnSorting();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setColumnWidths() {
|
||||||
|
if (currentRoot.getChildren().getNodesCount() != 0) {
|
||||||
final Graphics graphics = outlineView.getGraphics();
|
final Graphics graphics = outlineView.getGraphics();
|
||||||
if (graphics != null) {
|
if (graphics != null) {
|
||||||
final FontMetrics metrics = graphics.getFontMetrics();
|
final FontMetrics metrics = graphics.getFontMetrics();
|
||||||
@ -465,15 +328,31 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
// if there's no content just auto resize all columns
|
// if there's no content just auto resize all columns
|
||||||
outline.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
|
outline.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
loadSort();
|
private void assignColumns(List<Property<?>> props) {
|
||||||
|
// Get the columns setup with respect to names and sortability
|
||||||
|
String[] propStrings = new String[props.size() * 2];
|
||||||
|
for (int i = 0; i < props.size(); i++) {
|
||||||
|
final Property<?> prop = props.get(i);
|
||||||
|
prop.setValue("ComparableColumnTTV", Boolean.TRUE); //NON-NLS
|
||||||
|
//First property column is sorted initially
|
||||||
|
if (i == 0) {
|
||||||
|
prop.setValue("TreeColumnTTV", Boolean.TRUE); // Identifies special property representing first (tree) column. NON-NLS
|
||||||
|
prop.setValue("SortingColumnTTV", Boolean.TRUE); // TreeTableView should be initially sorted by this property column. NON-NLS
|
||||||
|
}
|
||||||
|
propStrings[2 * i] = prop.getName();
|
||||||
|
propStrings[2 * i + 1] = prop.getDisplayName();
|
||||||
|
}
|
||||||
|
|
||||||
|
outlineView.setPropertyColumns(propStrings);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store the current column order into a preference file.
|
* Store the current column order and sort information into a preference
|
||||||
|
* file.
|
||||||
*/
|
*/
|
||||||
private synchronized void storeState() {
|
private synchronized void storeColumnState() {
|
||||||
if (currentRoot == null || propertiesMap.isEmpty()) {
|
if (currentRoot == null || propertiesMap.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -485,13 +364,13 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
|
|
||||||
preferences.put(getColumnPositionKey(tfn.getColumnOrderKey(), entry.getValue().getName()), String.valueOf(entry.getKey()));
|
preferences.put(getColumnPositionKey(tfn.getColumnOrderKey(), entry.getValue().getName()), String.valueOf(entry.getKey()));
|
||||||
}
|
}
|
||||||
final TableColumnModel columnModel = ov.getOutline().getColumnModel();
|
final TableColumnModel columnModel = outline.getColumnModel();
|
||||||
|
|
||||||
//store the sorting information
|
//store the sorting information
|
||||||
int numCols = columnModel.getColumnCount();
|
int numCols = columnModel.getColumnCount();
|
||||||
for (int i = 0; i < numCols; i++) {
|
for (int i = 0; i < numCols; i++) {
|
||||||
ETableColumn etc = (ETableColumn) columnModel.getColumn(i);
|
ETableColumn etc = (ETableColumn) columnModel.getColumn(i);
|
||||||
String columnName = ov.getOutline().getColumnName(i);
|
String columnName = outline.getColumnName(i);
|
||||||
if (etc.isSorted()) {
|
if (etc.isSorted()) {
|
||||||
preferences.put(getColumnSortOrderKey(tfn.getColumnOrderKey(), columnName), String.valueOf(etc.isAscending()));
|
preferences.put(getColumnSortOrderKey(tfn.getColumnOrderKey(), columnName), String.valueOf(etc.isAscending()));
|
||||||
preferences.put(getColumnSortRankKey(tfn.getColumnOrderKey(), columnName), String.valueOf(etc.getSortRank()));
|
preferences.put(getColumnSortRankKey(tfn.getColumnOrderKey(), columnName), String.valueOf(etc.getSortRank()));
|
||||||
@ -503,73 +382,60 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static private final class ColumnSortInfo {
|
/**
|
||||||
|
* Reads and applies the column sorting information persisted to the
|
||||||
private final int modelIndex;
|
* preferences file. Must be called after loadColumnOrder() since it depends
|
||||||
private final int rank;
|
* on propertiesMap being initialized, and before assignColumns since it
|
||||||
private final boolean order;
|
* cannot set the sort on columns that have not been added to the table.
|
||||||
|
*/
|
||||||
private ColumnSortInfo(int modelIndex, int rank, boolean order) {
|
private synchronized void loadColumnSorting() {
|
||||||
this.modelIndex = modelIndex;
|
|
||||||
this.rank = rank;
|
|
||||||
this.order = order;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getRank() {
|
|
||||||
return rank;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized void loadSort() {
|
|
||||||
if (currentRoot == null || propertiesMap.isEmpty()) {
|
if (currentRoot == null || propertiesMap.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentRoot instanceof TableFilterNode) {
|
if (currentRoot instanceof TableFilterNode) {
|
||||||
|
final String columnKey = ((TableFilterNode) currentRoot).getColumnOrderKey();
|
||||||
final Preferences preferences = NbPreferences.forModule(DataResultViewerTable.class);
|
final Preferences preferences = NbPreferences.forModule(DataResultViewerTable.class);
|
||||||
TableFilterNode tfn = (TableFilterNode) currentRoot;
|
//organize property sorting information, sorted by rank
|
||||||
|
TreeSet<ColumnSortInfo> treeSet = new TreeSet<>(Comparator.comparing(ColumnSortInfo::getRank));
|
||||||
|
|
||||||
if (currentRoot instanceof TableFilterNode) {
|
propertiesMap.entrySet().stream().forEach(entry -> {
|
||||||
final String columnOrderKey = ((TableFilterNode) currentRoot).getColumnOrderKey();
|
final String propName = entry.getValue().getName();
|
||||||
|
//if the sort rank is undefined, it will be defaulted to 0 => unsorted.
|
||||||
|
Integer sortRank = Integer.valueOf(preferences.get(getColumnSortRankKey(columnKey, propName), "0"));
|
||||||
|
//default to true => ascending
|
||||||
|
Boolean sortOrder = Boolean.valueOf(preferences.get(getColumnSortOrderKey(columnKey, propName), "true"));
|
||||||
|
|
||||||
final Preferences preferences = NbPreferences.forModule(DataResultViewerTable.class);
|
treeSet.add(new ColumnSortInfo(entry.getKey(), sortRank, sortOrder));
|
||||||
|
});
|
||||||
//organize property sorting information, sorted by rank
|
|
||||||
TreeSet<ColumnSortInfo> treeSet = new TreeSet<>(Comparator.comparing(ColumnSortInfo::getRank));
|
|
||||||
propertiesMap.entrySet().stream()
|
|
||||||
.forEach(entry -> {
|
|
||||||
final String propName = entry.getValue().getName();
|
|
||||||
//if the sort rank is undefined, it will be defaulted to 0 => unsorted.
|
|
||||||
Integer sortRank = Integer.valueOf(preferences.get(getColumnSortRankKey(columnOrderKey, propName), "0"));
|
|
||||||
//default to true => ascending
|
|
||||||
Boolean sortOrder = Boolean.valueOf(preferences.get(getColumnSortOrderKey(columnOrderKey, propName), "true"));
|
|
||||||
|
|
||||||
treeSet.add(new ColumnSortInfo(entry.getKey(), sortRank, sortOrder));
|
|
||||||
});
|
|
||||||
|
|
||||||
//apply sort information in rank order.
|
|
||||||
treeSet.forEach(sortInfo -> ov.getOutline().setColumnSorted(sortInfo.modelIndex, sortInfo.order, sortInfo.rank));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
//apply sort information in rank order.
|
||||||
|
treeSet.forEach(sortInfo -> outline.setColumnSorted(sortInfo.modelIndex, sortInfo.order, sortInfo.rank));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the stored column order from the preference file.
|
* Gets a list of child properties (columns) in the order persisted in the
|
||||||
|
* preference file. Also initialized the propertiesMap with the column
|
||||||
|
* order.
|
||||||
*
|
*
|
||||||
* @return a List<Node.Property<?>> of the preferences in order
|
* @return a List<Node.Property<?>> of the properties in the persisted
|
||||||
|
* order.
|
||||||
*/
|
*/
|
||||||
private synchronized List<Node.Property<?>> loadColumnOrder() {
|
private synchronized List<Node.Property<?>> loadColumnOrder() {
|
||||||
List<Property<?>> props = getAllChildProperties(currentRoot);
|
// This is a set because we only want unique properties
|
||||||
|
Set<Property<?>> propertiesAcc = new LinkedHashSet<>();
|
||||||
|
getAllChildProperties(currentRoot, 100, propertiesAcc);
|
||||||
|
List<Property<?>> props = new ArrayList<>(propertiesAcc);
|
||||||
|
|
||||||
// If node is not table filter node, use default order for columns
|
// If node is not table filter node, use default order for columns
|
||||||
if (!(currentRoot instanceof TableFilterNode)) {
|
if (!(currentRoot instanceof TableFilterNode)) {
|
||||||
// The node is not a TableFilterNode, columns are going to be in default order
|
|
||||||
return props;
|
return props;
|
||||||
}
|
}
|
||||||
TableFilterNode tfn = (TableFilterNode) currentRoot;
|
|
||||||
|
|
||||||
|
final String columnKey = ((TableFilterNode) currentRoot).getColumnOrderKey();
|
||||||
propertiesMap.clear();
|
propertiesMap.clear();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We load column index values into the properties map. If a property's
|
* We load column index values into the properties map. If a property's
|
||||||
* index is outside the range of the number of properties or the index
|
* index is outside the range of the number of properties or the index
|
||||||
@ -582,7 +448,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
final Preferences preferences = NbPreferences.forModule(DataResultViewerTable.class);
|
final Preferences preferences = NbPreferences.forModule(DataResultViewerTable.class);
|
||||||
|
|
||||||
for (Property<?> prop : props) {
|
for (Property<?> prop : props) {
|
||||||
Integer value = Integer.valueOf(preferences.get(getColumnPositionKey(tfn.getColumnOrderKey(), prop.getName()), "-1"));
|
Integer value = Integer.valueOf(preferences.get(getColumnPositionKey(columnKey, prop.getName()), "-1"));
|
||||||
if (value >= 0 && value < offset && !propertiesMap.containsKey(value)) {
|
if (value >= 0 && value < offset && !propertiesMap.containsKey(value)) {
|
||||||
propertiesMap.put(value, prop);
|
propertiesMap.put(value, prop);
|
||||||
noPreviousSettings = false;
|
noPreviousSettings = false;
|
||||||
@ -608,25 +474,46 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
* Gets a key for the current node and a property of its child nodes to
|
* Gets a key for the current node and a property of its child nodes to
|
||||||
* store the column position into a preference file.
|
* store the column position into a preference file.
|
||||||
*
|
*
|
||||||
* @param prop Property of the column
|
* @param keyBase The base of the key. Typically a fully quallified class
|
||||||
* @param type The type of the current node
|
* name.
|
||||||
|
* @param propName The name of the specific property to make a key for.
|
||||||
*
|
*
|
||||||
* @return A generated key for the preference file
|
* @return A generated key for the preference file
|
||||||
*/
|
*/
|
||||||
private String getColumnPositionKey(String type, String propName) {
|
private String getColumnPositionKey(String keyBase, String propName) {
|
||||||
return getColumnKeyBase(type, propName) + ".column";
|
return getColumnKeyBase(keyBase, propName) + ".column";
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getColumnSortOrderKey(String type, String propName) {
|
/**
|
||||||
return getColumnKeyBase(type, propName) + ".sortOrder";
|
* Gets a key for the current node and a property of its child nodes to
|
||||||
|
* store the column sort ordering into a preference file.
|
||||||
|
*
|
||||||
|
* @param keyBase The base of the key. Typically a fully quallified class
|
||||||
|
* name.
|
||||||
|
* @param propName The name of the specific property to make a key for.
|
||||||
|
*
|
||||||
|
* @return A generated key for the preference file
|
||||||
|
*/
|
||||||
|
private String getColumnSortOrderKey(String keyBase, String propName) {
|
||||||
|
return getColumnKeyBase(keyBase, propName) + ".sortOrder";
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getColumnSortRankKey(String type, String propName) {
|
/**
|
||||||
return getColumnKeyBase(type, propName) + ".sortRank";
|
* Gets a key for the current node and a property of its child nodes to
|
||||||
|
* store the column sort rank into a preference file.
|
||||||
|
*
|
||||||
|
* @param keyBase The base of the key. Typically a fully quallified class
|
||||||
|
* name.
|
||||||
|
* @param propName The name of the specific property to make a key for.
|
||||||
|
*
|
||||||
|
* @return A generated key for the preference file
|
||||||
|
*/
|
||||||
|
private String getColumnSortRankKey(String keyBase, String propName) {
|
||||||
|
return getColumnKeyBase(keyBase, propName) + ".sortRank";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getColumnKeyBase(String type, String propName) {
|
private static String getColumnKeyBase(String keyBase, String propName) {
|
||||||
return stripNonAlphanumeric(type) + "." + stripNonAlphanumeric(propName);
|
return stripNonAlphanumeric(keyBase) + "." + stripNonAlphanumeric(propName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String stripNonAlphanumeric(String str) {
|
private static String stripNonAlphanumeric(String str) {
|
||||||
@ -653,6 +540,131 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates sorting information for a column to make loadSort simpler.
|
||||||
|
*/
|
||||||
|
static private final class ColumnSortInfo {
|
||||||
|
|
||||||
|
private final int modelIndex;
|
||||||
|
private final int rank;
|
||||||
|
private final boolean order;
|
||||||
|
|
||||||
|
private ColumnSortInfo(int modelIndex, int rank, boolean order) {
|
||||||
|
this.modelIndex = modelIndex;
|
||||||
|
this.rank = rank;
|
||||||
|
this.order = order;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getRank() {
|
||||||
|
return rank;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listens to mouse events and table column events and persists column order
|
||||||
|
* and sorting changes
|
||||||
|
*/
|
||||||
|
private class TableListener extends MouseAdapter implements TableColumnModelListener {
|
||||||
|
|
||||||
|
// When a column in the table is moved, these two variables keep track of where
|
||||||
|
// the column started and where it ended up.
|
||||||
|
private int startColumnIndex = -1;
|
||||||
|
private int endColumnIndex = -1;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void columnMoved(TableColumnModelEvent e) {
|
||||||
|
int fromIndex = e.getFromIndex();
|
||||||
|
int toIndex = e.getToIndex();
|
||||||
|
if (fromIndex == toIndex) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Because a column may be dragged to several different positions
|
||||||
|
* before the mouse is released (thus causing multiple
|
||||||
|
* TableColumnModelEvents to be fired), we want to keep track of the
|
||||||
|
* starting column index in this potential series of movements.
|
||||||
|
* Therefore we only keep track of the original fromIndex in
|
||||||
|
* startColumnIndex, but we always update endColumnIndex to know the
|
||||||
|
* final position of the moved column. See the MouseListener
|
||||||
|
* mouseReleased method.
|
||||||
|
*/
|
||||||
|
if (startColumnIndex == -1) {
|
||||||
|
startColumnIndex = fromIndex;
|
||||||
|
}
|
||||||
|
endColumnIndex = toIndex;
|
||||||
|
|
||||||
|
// This list contains the keys of propertiesMap in order
|
||||||
|
ArrayList<Integer> indicesList = new ArrayList<>(propertiesMap.keySet());
|
||||||
|
int leftIndex = Math.min(fromIndex, toIndex);
|
||||||
|
int rightIndex = Math.max(fromIndex, toIndex);
|
||||||
|
// Now we can copy the range of keys that have been affected by
|
||||||
|
// the column movement
|
||||||
|
List<Integer> range = indicesList.subList(leftIndex, rightIndex + 1);
|
||||||
|
int rangeSize = range.size();
|
||||||
|
|
||||||
|
if (fromIndex < toIndex) {
|
||||||
|
// column moved right, shift all properties left, put in moved
|
||||||
|
// property at the rightmost index
|
||||||
|
Property<?> movedProp = propertiesMap.get(range.get(0));
|
||||||
|
for (int i = 0; i < rangeSize - 1; i++) {
|
||||||
|
propertiesMap.put(range.get(i), propertiesMap.get(range.get(i + 1)));
|
||||||
|
}
|
||||||
|
propertiesMap.put(range.get(rangeSize - 1), movedProp);
|
||||||
|
} else {
|
||||||
|
// column moved left, shift all properties right, put in moved
|
||||||
|
// property at the leftmost index
|
||||||
|
Property<?> movedProp = propertiesMap.get(range.get(rangeSize - 1));
|
||||||
|
for (int i = rangeSize - 1; i > 0; i--) {
|
||||||
|
propertiesMap.put(range.get(i), propertiesMap.get(range.get(i - 1)));
|
||||||
|
}
|
||||||
|
propertiesMap.put(range.get(0), movedProp);
|
||||||
|
}
|
||||||
|
|
||||||
|
storeColumnState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseReleased(MouseEvent e) {
|
||||||
|
/*
|
||||||
|
* If the startColumnIndex is not -1 (which is the reset value),
|
||||||
|
* that means columns have been moved around. We then check to see
|
||||||
|
* if either the starting or end position is 0 (the first column),
|
||||||
|
* and then swap them back if that is the case because we don't want
|
||||||
|
* to allow movement of the first column. We then reset
|
||||||
|
* startColumnIndex to -1, the reset value. We check if
|
||||||
|
* startColumnIndex is at reset or not because it is possible for
|
||||||
|
* the mouse to be released and a MouseEvent to be fired without
|
||||||
|
* having moved any columns.
|
||||||
|
*/
|
||||||
|
if (startColumnIndex != -1 && (startColumnIndex == 0 || endColumnIndex == 0)) {
|
||||||
|
outline.moveColumn(endColumnIndex, startColumnIndex);
|
||||||
|
}
|
||||||
|
startColumnIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseClicked(MouseEvent e) {
|
||||||
|
storeColumnState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void columnAdded(TableColumnModelEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void columnRemoved(TableColumnModelEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void columnMarginChanged(ChangeEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void columnSelectionChanged(ListSelectionEvent e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class PleasewaitNodeListener extends NodeAdapter {
|
private class PleasewaitNodeListener extends NodeAdapter {
|
||||||
|
|
||||||
private volatile boolean load = true;
|
private volatile boolean load = true;
|
||||||
@ -687,7 +699,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
* the outline table. This renderer colors a row if the tags property of the
|
* the outline table. This renderer colors a row if the tags property of the
|
||||||
* node is not empty.
|
* node is not empty.
|
||||||
*/
|
*/
|
||||||
class ColorTagCustomRenderer extends DefaultOutlineCellRenderer {
|
private class ColorTagCustomRenderer extends DefaultOutlineCellRenderer {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user