diff -r 3659afb5fe5b -r f400de1faf47 spi.viewmodel/apichanges.xml --- a/spi.viewmodel/apichanges.xml Mon May 31 22:14:44 2010 +0200 +++ b/spi.viewmodel/apichanges.xml Mon May 31 22:59:21 2010 +0200 @@ -384,6 +384,21 @@ + + + Custom table cell renderers and editors. + + + + + + This API introduce TableRendererModel and TableRendererModelFilter + that can be used to provide custom table cell renderers and cell editors. + + + + + diff -r 3659afb5fe5b -r f400de1faf47 spi.viewmodel/manifest.mf --- a/spi.viewmodel/manifest.mf Mon May 31 22:14:44 2010 +0200 +++ b/spi.viewmodel/manifest.mf Mon May 31 22:59:21 2010 +0200 @@ -1,5 +1,5 @@ Manifest-Version: 1.0 OpenIDE-Module: org.netbeans.spi.viewmodel/2 OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/viewmodel/Bundle.properties -OpenIDE-Module-Specification-Version: 1.27 +OpenIDE-Module-Specification-Version: 1.28 diff -r 3659afb5fe5b -r f400de1faf47 spi.viewmodel/src/org/netbeans/modules/viewmodel/DelegatingCellEditor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/spi.viewmodel/src/org/netbeans/modules/viewmodel/DelegatingCellEditor.java Mon May 31 22:59:21 2010 +0200 @@ -0,0 +1,190 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2010 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +package org.netbeans.modules.viewmodel; + +import java.awt.Component; +import java.awt.Point; +import java.awt.event.MouseEvent; +import java.util.EventObject; +import javax.swing.JTable; +import javax.swing.event.CellEditorListener; +import javax.swing.table.TableCellEditor; +import org.netbeans.spi.viewmodel.TableRendererModel; +import org.netbeans.spi.viewmodel.UnknownTypeException; +import org.netbeans.swing.outline.Outline; +import org.netbeans.swing.outline.OutlineModel; +import org.openide.util.Exceptions; + +/** + * + * @author Martin Entlicher + */ +class DelegatingCellEditor implements TableCellEditor { + + private String columnID; + private TableCellEditor defaultEditor; + private TableCellEditor currentEditor; + + public DelegatingCellEditor(String columnID, TableCellEditor defaultEditor) { + this.columnID = columnID; + this.defaultEditor = defaultEditor; + } + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { + Outline outline = (Outline) table; + OutlineModel om = (OutlineModel) outline.getModel(); + TreeModelNode tmn = (TreeModelNode) DelegatingCellRenderer.getNodeAt(om, row); + TableRendererModel trm = tmn.getModel(); + try { + if (trm.canEditCell(tmn.getObject(), columnID)) { + TableCellEditor editor = trm.getCellEditor(tmn.getObject(), columnID); + if (editor != null) { + currentEditor = editor; + return editor.getTableCellEditorComponent(table, value, isSelected, row, column); + } + } + } catch (UnknownTypeException ex) { + } + // No specific editor + currentEditor = defaultEditor; + return defaultEditor.getTableCellEditorComponent(table, value, isSelected, row, column); + } + + @Override + public Object getCellEditorValue() { + if (currentEditor != null) { + return currentEditor.getCellEditorValue(); + } + Exceptions.printStackTrace(new IllegalStateException("No current editor.")); + return null; + } + + @Override + public boolean isCellEditable(EventObject anEvent) { + if (!(anEvent.getSource() instanceof Outline)) { + return false; + } + Outline outline = (Outline) anEvent.getSource(); + if (!(anEvent instanceof MouseEvent)) { + return false; + } + MouseEvent event = (MouseEvent) anEvent; + Point p = event.getPoint(); + + // Locate the editor under the event location + //int column = outline.columnAtPoint(p); + int row = outline.rowAtPoint(p); + OutlineModel om = (OutlineModel) outline.getModel(); + TreeModelNode tmn = (TreeModelNode) DelegatingCellRenderer.getNodeAt(om, row); + TableRendererModel trm = tmn.getModel(); + try { + return trm.canEditCell(tmn.getObject(), columnID); + } catch (UnknownTypeException ex) { + } + return defaultEditor.isCellEditable(anEvent); + } + + @Override + public boolean shouldSelectCell(EventObject anEvent) { + if (!(anEvent.getSource() instanceof Outline)) { + return false; + } + Outline outline = (Outline) anEvent.getSource(); + if (!(anEvent instanceof MouseEvent)) { + return false; + } + MouseEvent event = (MouseEvent) anEvent; + Point p = event.getPoint(); + + // Locate the editor under the event location + //int column = outline.columnAtPoint(p); + int row = outline.rowAtPoint(p); + OutlineModel om = (OutlineModel) outline.getModel(); + TreeModelNode tmn = (TreeModelNode) DelegatingCellRenderer.getNodeAt(om, row); + TableRendererModel trm = tmn.getModel(); + try { + if (trm.canEditCell(tmn.getObject(), columnID)) { + TableCellEditor editor = trm.getCellEditor(tmn.getObject(), columnID); + if (editor != null) { + return editor.shouldSelectCell(anEvent); + } + } + } catch (UnknownTypeException ex) { + } + return defaultEditor.shouldSelectCell(anEvent); + } + + @Override + public boolean stopCellEditing() { + if (currentEditor != null) { + boolean status = currentEditor.stopCellEditing(); + currentEditor = null; + return status; + } + Exceptions.printStackTrace(new IllegalStateException("No current editor.")); + return true; + } + + @Override + public void cancelCellEditing() { + if (currentEditor != null) { + currentEditor.cancelCellEditing(); + currentEditor = null; + } + Exceptions.printStackTrace(new IllegalStateException("No current editor.")); + } + + @Override + public void addCellEditorListener(CellEditorListener l) { + currentEditor.addCellEditorListener(l); + } + + @Override + public void removeCellEditorListener(CellEditorListener l) { + currentEditor.removeCellEditorListener(l); + } + +} diff -r 3659afb5fe5b -r f400de1faf47 spi.viewmodel/src/org/netbeans/modules/viewmodel/DelegatingCellRenderer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/spi.viewmodel/src/org/netbeans/modules/viewmodel/DelegatingCellRenderer.java Mon May 31 22:59:21 2010 +0200 @@ -0,0 +1,100 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2010 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +package org.netbeans.modules.viewmodel; + +import java.awt.Component; +import javax.swing.JTable; +import javax.swing.table.TableCellRenderer; +import javax.swing.tree.TreePath; +import org.netbeans.spi.viewmodel.TableRendererModel; +import org.netbeans.spi.viewmodel.UnknownTypeException; +import org.netbeans.swing.outline.Outline; +import org.netbeans.swing.outline.OutlineModel; +import org.openide.explorer.view.Visualizer; +import org.openide.nodes.Node; +import org.openide.util.Exceptions; + +/** + * + * @author Martin Entlicher + */ +class DelegatingCellRenderer implements TableCellRenderer { + + private String columnID; + private TableCellRenderer defaultRenderer; + + public DelegatingCellRenderer(String columnID, TableCellRenderer defaultRenderer) { + this.columnID = columnID; + this.defaultRenderer = defaultRenderer; + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + Outline outline = (Outline) table; + OutlineModel om = (OutlineModel) outline.getModel(); + TreeModelNode tmn = (TreeModelNode) getNodeAt(om, row); + TableRendererModel trm = tmn.getModel(); + try { + if (trm.canRenderCell(tmn.getObject(), columnID)) { + TableCellRenderer renderer = trm.getCellRenderer(tmn.getObject(), columnID); + if (renderer != null) { + return renderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + } + } + } catch (UnknownTypeException ex) { + } + // No specific renderer + return defaultRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + } + + static final Node getNodeAt(OutlineModel om, int row) { + Node result = null; + TreePath path = om.getLayout().getPathForRow(row); + if (path != null) { + result = Visualizer.findNode(path.getLastPathComponent()); + } + return result; + } +} diff -r 3659afb5fe5b -r f400de1faf47 spi.viewmodel/src/org/netbeans/modules/viewmodel/OutlineTable.java --- a/spi.viewmodel/src/org/netbeans/modules/viewmodel/OutlineTable.java Mon May 31 22:14:44 2010 +0200 +++ b/spi.viewmodel/src/org/netbeans/modules/viewmodel/OutlineTable.java Mon May 31 22:59:21 2010 +0200 @@ -652,6 +652,14 @@ if (ci < columnsToSet.length && columns[i] == columnsToSet[ci]) { TableColumn tc = tcm.getColumn(tci); tableColumns[i] = tc; + if (columns[i] instanceof Column) { + tableColumns[i].setCellEditor(new DelegatingCellEditor( + ((Column) columns[i]).getName(), + treeTable.getTable().getCellEditor(0, tci))); + tableColumns[i].setCellRenderer(new DelegatingCellRenderer( + ((Column) columns[i]).getName(), + treeTable.getTable().getCellRenderer(0, tci))); + } if (columns[i].isHidden()) { ecm.setColumnHidden(tc, true); } else { @@ -662,6 +670,12 @@ tableColumns[i] = tcm.getColumn(0); if (columns[i] instanceof Column) { tableColumns[i].setCellEditor(((Column)columns[i]).getTableCellEditor()); + tableColumns[i].setCellEditor(new DelegatingCellEditor( + ((Column) columns[i]).getName(), + treeTable.getTable().getCellEditor(0, 0))); + tableColumns[i].setCellRenderer(new DelegatingCellRenderer( + ((Column) columns[i]).getName(), + treeTable.getTable().getCellRenderer(0, 0))); } } } @@ -910,7 +924,7 @@ ((DefaultOutlineModel) m).setNodesColumnLabel(name); } } - + /* public List getExpandedPaths () { List result = new ArrayList (); diff -r 3659afb5fe5b -r f400de1faf47 spi.viewmodel/src/org/netbeans/modules/viewmodel/TreeModelNode.java --- a/spi.viewmodel/src/org/netbeans/modules/viewmodel/TreeModelNode.java Mon May 31 22:14:44 2010 +0200 +++ b/spi.viewmodel/src/org/netbeans/modules/viewmodel/TreeModelNode.java Mon May 31 22:59:21 2010 +0200 @@ -44,6 +44,7 @@ package org.netbeans.modules.viewmodel; +import java.awt.Component; import java.awt.Image; import java.awt.datatransfer.Transferable; import java.awt.event.ActionEvent; @@ -70,11 +71,13 @@ import java.util.logging.Logger; import javax.swing.AbstractAction; import javax.swing.Action; +import javax.swing.JTable; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; +import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import org.netbeans.spi.viewmodel.AsynchronousModelFilter; @@ -504,6 +507,10 @@ public Object getObject () { return object; + } + + Models.CompoundModel getModel() { + return model; } private Task refreshTask; diff -r 3659afb5fe5b -r f400de1faf47 spi.viewmodel/src/org/netbeans/spi/viewmodel/Models.java --- a/spi.viewmodel/src/org/netbeans/spi/viewmodel/Models.java Mon May 31 22:14:44 2010 +0200 +++ b/spi.viewmodel/src/org/netbeans/spi/viewmodel/Models.java Mon May 31 22:59:21 2010 +0200 @@ -69,6 +69,8 @@ import javax.swing.Action; import javax.swing.JComponent; import javax.swing.SwingUtilities; +import javax.swing.table.TableCellEditor; +import javax.swing.table.TableCellRenderer; import org.netbeans.modules.viewmodel.AsynchronousModel; import org.netbeans.modules.viewmodel.DefaultTreeExpansionManager; @@ -241,7 +243,7 @@ // ; or the models directly boolean hasLists = false; int modelsSize = models.size(); - if (11 <= modelsSize && modelsSize <= 14) { + if (11 <= modelsSize && modelsSize <= 15) { Iterator it = models.iterator (); boolean failure = false; while (it.hasNext ()) { @@ -277,26 +279,17 @@ // ml.asynchModels = (List) models.get(12); if (modelsSize > 12) { // AsynchronousModelFilter ml.asynchModelFilters = (List) models.get(12); + if (modelsSize > 13) { + ml.tableRendererModels = (List) models.get(13); + if (modelsSize > 14) { + ml.tableRendererModelFilters = (List) models.get(14); + } + } } //} - } else { - ml.treeExpansionModelFilters = Collections.emptyList(); } //treeExpansionModelFilters = (models.size() > 11) ? (List) models.get(11) : (List) Collections.EMPTY_LIST; } else { // We have the models, need to find out what they implement - ml.treeModels = new LinkedList (); - ml.treeModelFilters = new LinkedList (); - ml.treeExpansionModels = new LinkedList (); - ml.treeExpansionModelFilters = new LinkedList (); - ml.nodeModels = new LinkedList (); - ml.nodeModelFilters = new LinkedList (); - ml.tableModels = new LinkedList (); - ml.tableModelFilters = new LinkedList (); - ml.nodeActionsProviders = new LinkedList (); - ml.nodeActionsProviderFilters = new LinkedList (); - //ml.asynchModels = new LinkedList (); - ml.asynchModelFilters = new LinkedList (); - ml.columnModels = new LinkedList (); otherModels = (List) models; } @@ -381,6 +374,10 @@ new DefaultAsynchronousModel(),//new DelegatingAsynchronousModel (ml.asynchModels), ml.asynchModelFilters ), + createCompoundTableRendererModel ( + new DelegatingTableRendererModel(ml.tableRendererModels), + ml.tableRendererModelFilters + ), propertiesHelpID ); if (defaultExpansionModel != null) { @@ -515,6 +512,29 @@ return tm; } + /** + * Creates {@link org.netbeans.spi.viewmodel.TableModel} for given TableModel and + * {@link org.netbeans.spi.viewmodel.TableModelFilter}. + * + * @param originalTableModel a original table model + * @param tableModelFilters a list of table model filters + * + * @returns compund table model + */ + private static TableRendererModel createCompoundTableRendererModel ( + TableRendererModel originalTableModel, + List tableModelFilters + ) { + TableRendererModel tm = originalTableModel; + int i, k = tableModelFilters.size (); + for (i = 0; i < k; i++) + tm = new CompoundTableRendererModel ( + tm, + (TableRendererModelFilter) tableModelFilters.get (i) + ); + return tm; + } + /** * Creates {@link org.netbeans.spi.viewmodel.NodeActionsProvider} for given NodeActionsProvider and * {@link org.netbeans.spi.viewmodel.NodeActionsProviderFilter}. @@ -1312,6 +1332,116 @@ } /** + * Creates {@link org.netbeans.spi.viewmodel.TableRendererModel} for given TableRendererModel and + * {@link org.netbeans.spi.viewmodel.TableRendererModelFilter}. + */ + private final static class CompoundTableRendererModel implements TableRendererModel, ModelListener { + + + private TableRendererModel model; + private TableRendererModelFilter filter; + + private final Collection modelListeners = new HashSet(); + + + /** + * Creates {@link org.netbeans.spi.viewmodel.TableRendererModel} for given TableRendererModel and + * {@link org.netbeans.spi.viewmodel.TableRendererModelFilter}. + */ + CompoundTableRendererModel (TableRendererModel model, TableRendererModelFilter filter) { + this.model = model; + this.filter = filter; + } + + @Override + public boolean canRenderCell(Object node, String columnID) throws UnknownTypeException { + return filter.canRenderCell(model, node, columnID); + } + + @Override + public TableCellRenderer getCellRenderer(Object node, String columnID) throws UnknownTypeException { + return filter.getCellRenderer(model, node, columnID); + } + + @Override + public boolean canEditCell(Object node, String columnID) throws UnknownTypeException { + return filter.canEditCell(model, node, columnID); + } + + @Override + public TableCellEditor getCellEditor(Object node, String columnID) throws UnknownTypeException { + return filter.getCellEditor(model, node, columnID); + } + + /** + * Registers given listener. + * + * @param l the listener to add + */ + public void addModelListener (ModelListener l) { + synchronized (modelListeners) { + if (modelListeners.size() == 0) { + filter.addModelListener (this); + model.addModelListener (this); + } + modelListeners.add(l); + } + } + + /** + * Unregisters given listener. + * + * @param l the listener to remove + */ + public void removeModelListener (ModelListener l) { + synchronized (modelListeners) { + modelListeners.remove(l); + if (modelListeners.size() == 0) { + filter.removeModelListener (this); + model.removeModelListener (this); + } + } + } + + public void modelChanged(ModelEvent event) { + if (event instanceof ModelEvent.NodeChanged && (event.getSource() instanceof NodeModel || event.getSource() instanceof NodeModelFilter)) { + // CompoundNodeModel.modelChanged() takes this. + return ; + } + if (event instanceof ModelEvent.TreeChanged && + (event.getSource() instanceof TreeModel || event.getSource() instanceof TreeModelFilter)) { + // CompoundTreeModel.modelChanged() takes this. + return ; + } + ModelEvent newEvent = translateEvent(event, this); + Collection listeners; + synchronized (modelListeners) { + listeners = new ArrayList(modelListeners); + } + for (Iterator it = listeners.iterator(); it.hasNext(); ) { + it.next().modelChanged(newEvent); + } + } + + @Override + public String toString () { + return super.toString () + "\n" + toString (" "); + } + + public String toString (String n) { + if (model instanceof CompoundTableRendererModel) + return n + filter + "\n" + + ((CompoundTableRendererModel) model).toString (n + " "); + if (model instanceof DelegatingTableRendererModel) + return n + filter + "\n" + + ((DelegatingTableRendererModel) model).toString (n + " "); + return n + filter + "\n" + + n + " " + model; + } + + } + + /** * Creates one {@link org.netbeans.spi.viewmodel.TreeModel} * from given list of TreeModels. DelegatingTreeModel asks all underlaying * models for each concrete parameter, and returns first returned value. @@ -1943,6 +2073,195 @@ sb.append (models [i]); return new String (sb); } + } + + /** + * Creates one {@link org.netbeans.spi.viewmodel.TableRendererModel} + * from given list of TableRendererModel. DelegatingTableRendererModel asks all underlaying + * models for each concrete parameter, and returns first returned value. + */ + private final static class DelegatingTableRendererModel implements TableRendererModel { + + private TableRendererModel[] models; + private HashMap classNameToModel = new HashMap(); + + + /** + * Creates new instance of DelegatingTableModel for given list of + * TableModels. + * + * @param models a list of TableModels + */ + DelegatingTableRendererModel (List models) { + this (convert (models)); + } + + private static TableRendererModel[] convert (List l) { + TableRendererModel[] models = new TableRendererModel [l.size ()]; + return l.toArray (models); + } + + /** + * Creates new instance of DelegatingTableModel for given array of + * TableModels. + * + * @param models a array of TableModels + */ + DelegatingTableRendererModel (TableRendererModel[] models) { + this.models = models; + } + + @Override + public boolean canRenderCell(Object node, String columnID) throws UnknownTypeException { + TableRendererModel model = classNameToModel.get ( + node.getClass ().getName () + ); + if (model != null) + try { + return model.canRenderCell (node, columnID); + } catch (UnknownTypeException e) { + } + int i, k = models.length; + for (i = 0; i < k; i++) { + try { + boolean cr = models [i].canRenderCell (node, columnID); + classNameToModel.put (node.getClass ().getName (), models [i]); + return cr; + } catch (UnknownTypeException e) { + } + } + throw new UnknownTypeException (node); + } + + @Override + public TableCellRenderer getCellRenderer(Object node, String columnID) throws UnknownTypeException { + TableRendererModel model = classNameToModel.get ( + node.getClass ().getName () + ); + if (model != null) + try { + return model.getCellRenderer (node, columnID); + } catch (UnknownTypeException e) { + } + int i, k = models.length; + for (i = 0; i < k; i++) { + try { + TableCellRenderer cr = models [i].getCellRenderer (node, columnID); + classNameToModel.put (node.getClass ().getName (), models [i]); + return cr; + } catch (UnknownTypeException e) { + } + } + throw new UnknownTypeException (node); + } + + @Override + public boolean canEditCell(Object node, String columnID) throws UnknownTypeException { + TableRendererModel model = classNameToModel.get ( + node.getClass ().getName () + ); + if (model != null) + try { + return model.canEditCell (node, columnID); + } catch (UnknownTypeException e) { + } + int i, k = models.length; + for (i = 0; i < k; i++) { + try { + boolean ce = models [i].canEditCell (node, columnID); + classNameToModel.put (node.getClass ().getName (), models [i]); + return ce; + } catch (UnknownTypeException e) { + } + } + throw new UnknownTypeException (node); + } + + @Override + public TableCellEditor getCellEditor(Object node, String columnID) throws UnknownTypeException { + TableRendererModel model = classNameToModel.get ( + node.getClass ().getName () + ); + if (model != null) + try { + return model.getCellEditor (node, columnID); + } catch (UnknownTypeException e) { + } + int i, k = models.length; + for (i = 0; i < k; i++) { + try { + TableCellEditor ce = models [i].getCellEditor (node, columnID); + classNameToModel.put (node.getClass ().getName (), models [i]); + return ce; + } catch (UnknownTypeException e) { + } + } + throw new UnknownTypeException (node); + } + + /** + * Registers given listener. + * + * @param l the listener to add + */ + @Override + public void addModelListener (ModelListener l) { + int i, k = models.length; + for (i = 0; i < k; i++) + models [i].addModelListener (l); + } + + /** + * Registers given listener. + * + * @param l the listener to add + */ + void addModelListener (ModelListener l, Set modelsListenersAddedTo) { + int i, k = models.length; + for (i = 0; i < k; i++) { + TableRendererModel m = models [i]; + if (!modelsListenersAddedTo.add(m)) { + continue; + } + if (m instanceof DelegatingTableRendererModel) { + ((DelegatingTableRendererModel) m).addModelListener(l, modelsListenersAddedTo); + } else { + m.addModelListener (l); + } + } + } + + /** + * Unregisters given listener. + * + * @param l the listener to remove + */ + @Override + public void removeModelListener (ModelListener l) { + int i, k = models.length; + for (i = 0; i < k; i++) + models [i].removeModelListener (l); + } + + @Override + public String toString () { + return super.toString () + "\n" + toString (" "); + } + + public String toString (String n) { + int i, k = models.length - 1; + if (k == -1) return ""; + StringBuffer sb = new StringBuffer (); + for (i = 0; i < k; i++) { + sb.append (n); + sb.append (models [i]); + sb.append ('\n'); + } + sb.append (n); + sb.append (models [i]); + return new String (sb); + } + } /** @@ -3340,7 +3659,13 @@ * @author Jan Jancura */ public static final class CompoundModel implements ReorderableTreeModel, - ExtendedNodeModel, CheckNodeModel, DnDNodeModel, NodeActionsProvider, TableModel, TreeExpansionModel { + ExtendedNodeModel, + CheckNodeModel, + DnDNodeModel, + NodeActionsProvider, + TableModel, + TreeExpansionModel, + TableRendererModel { private ReorderableTreeModel treeModel; private ExtendedNodeModel nodeModel; @@ -3349,6 +3674,7 @@ private NodeActionsProvider nodeActionsProvider; private ColumnModel[] columnModels; private TableModel tableModel; + private TableRendererModel tableRendererModel; private TreeExpansionModel treeExpansionModel; private AsynchronousModel asynchModel; @@ -3380,6 +3706,7 @@ List columnModels, TableModel tableModel, AsynchronousModel asynchModel, + TableRendererModel tableRendererModel, String propertiesHelpID ) { if (treeModel == null) throw new NullPointerException (); @@ -3398,6 +3725,7 @@ this.dndNodeModel = (DnDNodeModel) nodeModel; } this.tableModel = tableModel; + this.tableRendererModel = tableRendererModel; this.nodeActionsProvider = nodeActionsProvider; this.columnModels = columnModels.toArray ( new ColumnModel [columnModels.size ()] @@ -3860,6 +4188,44 @@ public Executor asynchronous(CALL asynchCall, Object node) throws UnknownTypeException { return asynchModel.asynchronous(asynchCall, node); + } + + // TableRendererModel + + @Override + public boolean canRenderCell(Object node, String columnID) throws UnknownTypeException { + if (tableRendererModel != null) { + return tableRendererModel.canRenderCell(node, columnID); + } else { + return false; + } + } + + @Override + public TableCellRenderer getCellRenderer(Object node, String columnID) throws UnknownTypeException { + if (tableRendererModel != null) { + return tableRendererModel.getCellRenderer(node, columnID); + } else { + return null; + } + } + + @Override + public boolean canEditCell(Object node, String columnID) throws UnknownTypeException { + if (tableRendererModel != null) { + return tableRendererModel.canEditCell(node, columnID); + } else { + return false; + } + } + + @Override + public TableCellEditor getCellEditor(Object node, String columnID) throws UnknownTypeException { + if (tableRendererModel != null) { + return tableRendererModel.getCellEditor(node, columnID); + } else { + return null; + } } } @@ -3879,6 +4245,8 @@ public List columnModels = Collections.emptyList(); //public List asynchModels = Collections.emptyList(); public List asynchModelFilters = Collections.emptyList(); + public List tableRendererModels = Collections.emptyList(); + public List tableRendererModelFilters = Collections.emptyList(); public void addOtherModels(List otherModels) { Iterator it = otherModels.iterator (); @@ -3929,6 +4297,17 @@ else tableModelFilters.add(0, (TableModelFilter) model); } + if (model instanceof TableRendererModel && !tableRendererModels.contains((TableRendererModel) model)) { + tableRendererModels = new ArrayList(tableRendererModels); + tableRendererModels.add((TableRendererModel) model); + } + if (model instanceof TableRendererModelFilter && !tableRendererModelFilters.contains((TableRendererModelFilter) model)) { + tableRendererModelFilters = new ArrayList(tableRendererModelFilters); + if (first) + tableRendererModelFilters.add((TableRendererModelFilter) model); + else + tableRendererModelFilters.add(0, (TableRendererModelFilter) model); + } if (model instanceof NodeActionsProvider && !nodeActionsProviders.contains((NodeActionsProvider) model)) { nodeActionsProviders = new ArrayList(nodeActionsProviders); nodeActionsProviders.add((NodeActionsProvider) model); diff -r 3659afb5fe5b -r f400de1faf47 spi.viewmodel/src/org/netbeans/spi/viewmodel/TableRendererModel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/spi.viewmodel/src/org/netbeans/spi/viewmodel/TableRendererModel.java Mon May 31 22:59:21 2010 +0200 @@ -0,0 +1,107 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +package org.netbeans.spi.viewmodel; + +import javax.swing.table.TableCellEditor; +import javax.swing.table.TableCellRenderer; + +/** + * Model that provides custom cell renderer and cell editor for table cells. + * + * @author Martin Entlicher + * @since 1.28 + */ +public interface TableRendererModel extends Model { + + /** + * Test whether this renderer can render the given cell. + * @param node Tree node representing the row + * @param columnID The column name + * @return true if the implementation can render the given cell, false otherwise + * @throws UnknownTypeException If the implementation can not decide whether to render the given cell. + */ + public boolean canRenderCell(Object node, String columnID) throws UnknownTypeException; + + /** + * Get the renderer of the given cell + * @param node Tree node representing the row + * @param columnID The column name + * @return The cell renderer + * @throws UnknownTypeException If the implementation can not render the given cell. + */ + public TableCellRenderer getCellRenderer(Object node, String columnID) throws UnknownTypeException; + + /** + * Test whether this renderer can edit the given cell. + * @param node Tree node representing the row + * @param columnID The column name + * @return true if the implementation can edit the given cell, false otherwise + * @throws UnknownTypeException If the implementation can not decide whether to edit the given cell. + */ + public boolean canEditCell(Object node, String columnID) throws UnknownTypeException; + + /** + * Get the editor of the given cell + * @param node Tree node representing the row + * @param columnID The column name + * @return The cell editor + * @throws UnknownTypeException If the implementation can not edit the given cell. + */ + public TableCellEditor getCellEditor(Object node, String columnID) throws UnknownTypeException; + + /** + * Registers given listener. + * + * @param l the listener to add + */ + public abstract void addModelListener (ModelListener l); + + /** + * Unregisters given listener. + * + * @param l the listener to remove + */ + public abstract void removeModelListener (ModelListener l); +} diff -r 3659afb5fe5b -r f400de1faf47 spi.viewmodel/src/org/netbeans/spi/viewmodel/TableRendererModelFilter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/spi.viewmodel/src/org/netbeans/spi/viewmodel/TableRendererModelFilter.java Mon May 31 22:59:21 2010 +0200 @@ -0,0 +1,115 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +package org.netbeans.spi.viewmodel; + +import javax.swing.table.TableCellEditor; +import javax.swing.table.TableCellRenderer; + +/** + * Model filter that can override custom cell renderer and cell editor for table cells. + * + * @author Martin Entlicher + * @since 1.28 + */ +public interface TableRendererModelFilter extends Model { + + /** + * Test whether this renderer can render the given cell. + * @param original The original table cell renderer implementation + * @param node Tree node representing the row + * @param columnID The column name + * @return true if the implementation can render the given cell, false otherwise + * @throws UnknownTypeException If the implementation can not decide whether to render the given cell. + */ + public boolean canRenderCell(TableRendererModel original, Object node, String columnID) + throws UnknownTypeException; + + /** + * Get the renderer of the given cell + * @param original The original table cell renderer implementation + * @param node Tree node representing the row + * @param columnID The column name + * @return The cell renderer + * @throws UnknownTypeException If the implementation can not render the given cell. + */ + public TableCellRenderer getCellRenderer(TableRendererModel original, Object node, String columnID) + throws UnknownTypeException; + + /** + * Test whether this renderer can edit the given cell. + * @param original The original table cell renderer implementation + * @param node Tree node representing the row + * @param columnID The column name + * @return true if the implementation can edit the given cell, false otherwise + * @throws UnknownTypeException If the implementation can not decide whether to edit the given cell. + */ + public boolean canEditCell(TableRendererModel original, Object node, String columnID) + throws UnknownTypeException; + + /** + * Get the editor of the given cell + * @param original The original table cell renderer implementation + * @param node Tree node representing the row + * @param columnID The column name + * @return The cell editor + * @throws UnknownTypeException If the implementation can not edit the given cell. + */ + public TableCellEditor getCellEditor(TableRendererModel original, Object node, String columnID) + throws UnknownTypeException; + + /** + * Registers given listener. + * + * @param l the listener to add + */ + public abstract void addModelListener (ModelListener l); + + /** + * Unregisters given listener. + * + * @param l the listener to remove + */ + public abstract void removeModelListener (ModelListener l); +}