📄 jxtreetable.java
字号:
* think the table is being edited, as <code>getEditingRow</code> returns * -1, and therefore doesn't automaticly resize the editor for us. */ public void sizeColumnsToFit(int resizingColumn) { /** @todo Review wrt doLayout() */ super.sizeColumnsToFit(resizingColumn); // rg:changed if (getEditingColumn() != -1 && isHierarchical(editingColumn)) { Rectangle cellRect = getCellRect(realEditingRow(), getEditingColumn(), false); Component component = getEditorComponent(); component.setBounds(cellRect); component.validate(); } } /** * Overridden to message super and forward the method to the tree. * Since the tree is not actually in the component hieachy it will * never receive this unless we forward it in this manner. */ public void updateUI() { super.updateUI(); if (renderer != null) { // final int savedHeight = renderer.getRowHeight(); renderer.updateUI(); // renderer.setRowHeight(savedHeight); // Do this so that the editor is referencing the current renderer // from the tree. The renderer can potentially change each time // laf changes. setDefaultEditor(AbstractTreeTableModel.hierarchicalColumnClass, new TreeTableCellEditor(renderer)); if (getBackground() == null || getBackground()instanceof UIResource) { setBackground(renderer.getBackground()); } } } /** * Determines if the specified column contains hierarchical nodes. * * @param column zero-based index of the column * @return true if the class of objects in the specified column implement * the {@link javax.swing.tree.TreeNode} interface; false otherwise. */ public boolean isHierarchical(int column) { return AbstractTreeTableModel.hierarchicalColumnClass.isAssignableFrom( getColumnClass(column)); } /** * Initializes this JXTreeTable and permanently binds the specified renderer * to it. * * @param renderer private tree/renderer permanently and exclusively bound * to this JXTreeTable. */ private final void init(TreeTableCellRenderer renderer) { this.renderer = renderer; // Force the JTable and JTree to share their row selection models. ListToTreeSelectionModelWrapper selectionWrapper = new ListToTreeSelectionModelWrapper(); // JW: when would that happen? if (renderer != null) { renderer.bind(this); // IMPORTANT: link back! renderer.setSelectionModel(selectionWrapper); } setSelectionModel(selectionWrapper.getListSelectionModel()); setDefaultRenderer(AbstractTreeTableModel.hierarchicalColumnClass, renderer); // propagate the lineStyle property to the renderer PropertyChangeListener l = new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { JXTreeTable.this.renderer.putClientProperty(evt.getPropertyName(), evt.getNewValue()); } }; addPropertyChangeListener("JTree.lineStyle", l); } /** * ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel * to listen for changes in the ListSelectionModel it maintains. Once * a change in the ListSelectionModel happens, the paths are updated * in the DefaultTreeSelectionModel. */ class ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel { /** Set to true when we are updating the ListSelectionModel. */ protected boolean updatingListSelectionModel; public ListToTreeSelectionModelWrapper() { super(); getListSelectionModel().addListSelectionListener (createListSelectionListener()); } /** * Returns the list selection model. ListToTreeSelectionModelWrapper * listens for changes to this model and updates the selected paths * accordingly. */ ListSelectionModel getListSelectionModel() { return listSelectionModel; } /** * This is overridden to set <code>updatingListSelectionModel</code> * and message super. This is the only place DefaultTreeSelectionModel * alters the ListSelectionModel. */ public void resetRowSelection() { if (!updatingListSelectionModel) { updatingListSelectionModel = true; try { super.resetRowSelection(); } finally { updatingListSelectionModel = false; } } // Notice how we don't message super if // updatingListSelectionModel is true. If // updatingListSelectionModel is true, it implies the // ListSelectionModel has already been updated and the // paths are the only thing that needs to be updated. } /** * Creates and returns an instance of ListSelectionHandler. */ protected ListSelectionListener createListSelectionListener() { return new ListSelectionHandler(); } /** * If <code>updatingListSelectionModel</code> is false, this will * reset the selected paths from the selected rows in the list * selection model. */ protected void updateSelectedPathsFromSelectedRows() { if (!updatingListSelectionModel) { updatingListSelectionModel = true; try { // This is way expensive, ListSelectionModel needs an // enumerator for iterating. int min = listSelectionModel.getMinSelectionIndex(); int max = listSelectionModel.getMaxSelectionIndex(); clearSelection(); if (min != -1 && max != -1) { for (int counter = min; counter <= max; counter++) { if (listSelectionModel.isSelectedIndex(counter)) { TreePath selPath = renderer.getPathForRow( counter); if (selPath != null) { addSelectionPath(selPath); } } } } } finally { updatingListSelectionModel = false; } } } /** * Class responsible for calling updateSelectedPathsFromSelectedRows * when the selection of the list changse. */ class ListSelectionHandler implements ListSelectionListener { public void valueChanged(ListSelectionEvent e) { updateSelectedPathsFromSelectedRows(); } } } private static class TreeTableModelAdapter extends AbstractTableModel { private TreeModelListener treeModelListener; /** * Maintains a TreeTableModel and a JTree as purely implementation details. * Developers can plug in any type of custom TreeTableModel through a * JXTreeTable constructor or through setTreeTableModel(). * * @param model Underlying data model for the JXTreeTable that will ultimately * be bound to this TreeTableModelAdapter * @param tree TreeTableCellRenderer instantiated with the same model as * specified by the model parameter of this constructor * @throws IllegalArgumentException if a null model argument is passed * @throws IllegalArgumentException if a null tree argument is passed */ TreeTableModelAdapter(TreeTableModel model, JTree tree) { assert model != null; assert tree != null; this.tree = tree; // need tree to implement getRowCount() setTreeTableModel(model); tree.addTreeExpansionListener(new TreeExpansionListener() { // Don't use fireTableRowsInserted() here; the selection model // would get updated twice. public void treeExpanded(TreeExpansionEvent event) { fireTableDataChanged(); } public void treeCollapsed(TreeExpansionEvent event) { fireTableDataChanged(); } }); } /** * * @param model must not be null! */ public void setTreeTableModel(TreeTableModel model) { TreeTableModel old = getTreeTableModel(); if (old != null) { old.removeTreeModelListener(getTreeModelListener()); } this.model = model; // Install a TreeModelListener that can update the table when // tree changes. model.addTreeModelListener(getTreeModelListener()); fireTableStructureChanged(); } /** * @return */ private TreeModelListener getTreeModelListener() { if (treeModelListener == null) { treeModelListener = new TreeModelListener() { // We use delayedFireTableDataChanged as we can // not be guaranteed the tree will have finished processing // the event before us. public void treeNodesChanged(TreeModelEvent e) { delayedFireTableDataChanged(e, 0); } public void treeNodesInserted(TreeModelEvent e) { delayedFireTableDataChanged(e, 1); } public void treeNodesRemoved(TreeModelEvent e) { delayedFireTableDataChanged(e, 2); } public void treeStructureChanged(TreeModelEvent e) { delayedFireTableDataChanged(); } }; } return treeModelListener; } /** * Returns the real TreeTableModel that is wrapped by this TreeTableModelAdapter. * * @return the real TreeTableModel that is wrapped by this TreeTableModelAdapter */ public TreeTableModel getTreeTableModel() { return model; } /** * Returns the JXTreeTable instance to which this TreeTableModelAdapter is * permanently and exclusively bound. For use by * {@link org.jdesktop.swingx.JXTreeTable#setModel(javax.swing.table.TableModel)}. * * @return JXTreeTable to which this TreeTableModelAdapter is permanently bound */ protected JXTreeTable getTreeTable() { return treeTable; } /** * Immutably binds this TreeTableModelAdapter to the specified JXTreeTable. * * @param treeTable the JXTreeTable instance that this adapter is bound to. */ protected final void bind(JXTreeTable treeTable) { // Suppress potentially subversive invocation! // Prevent clearing out the deck for possible hijack attempt later! if (treeTable == null) { throw new IllegalArgumentException("null treeTable"); } if (this.treeTable == null) { this.treeTable = treeTable; } else { throw new IllegalArgumentException("adapter already bound"); } } // Wrappers, implementing TableModel interface. // TableModelListener management provided by AbstractTableModel superclass. public Class getColumnClass(int column) { return model.getColumnClass(column); } public int getColumnCount() { return model.getColumnCount(); } public String getColumnName(int column) { return model.getColumnName(column); } public int getRowCount() { return tree.getRowCount(); } public Object getValueAt(int row, int column) { return model.getValueAt(nodeForRow(row), column); } public boolean isCellEditable(int row, int column) { return model.isCellEditable(nodeForRow(row), column); } public void setValueAt(Object value, int row, int column) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -