diff --git a/spi.viewmodel/apichanges.xml b/spi.viewmodel/apichanges.xml --- a/spi.viewmodel/apichanges.xml +++ b/spi.viewmodel/apichanges.xml @@ -399,6 +399,39 @@ + + + Separate the value and HTML value and allow custom property editors. + + + + + + So far the HTML value is automatically retrieved from the value provided + by the TableModel when the value is a String + and contains HTML code. This is not flexible enough and therefore + we separate the value and HTML value by introduction of TableHTMLModel + and TableHTMLModelFilter.
+ In addition to that, this API change also brings a prossibility + to provide custom property editor, separately for every value. + Two interfaces are introduced for this purpose: TablePropertyEditorsModel + and TablePropertyEditorsModelFilter.
+ This also implies, that Models.CompoundModel now implements + TableHTMLModel and TablePropertyEditorsModel.
+ In order to be able to fire changes in HTML value and also in r/w state, + an additional constructor of ModelEvent.TableValueChanged + is added, which takes the change mask. Three change masks are defined: + VALUE_MASK, HTML_VALUE_MASK and IS_READ_ONLY_MASK. + To get the change mask, ModelEvent.TableValueChanged.getChange() + method is added. +
+ + + + + + +
diff --git a/spi.viewmodel/manifest.mf b/spi.viewmodel/manifest.mf --- a/spi.viewmodel/manifest.mf +++ b/spi.viewmodel/manifest.mf @@ -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.41 +OpenIDE-Module-Specification-Version: 1.42 diff --git a/spi.viewmodel/src/org/netbeans/modules/viewmodel/TreeModelNode.java b/spi.viewmodel/src/org/netbeans/modules/viewmodel/TreeModelNode.java --- a/spi.viewmodel/src/org/netbeans/modules/viewmodel/TreeModelNode.java +++ b/spi.viewmodel/src/org/netbeans/modules/viewmodel/TreeModelNode.java @@ -951,11 +951,17 @@ firePropertyChange(null, null, null); } - void refreshColumn(String column) { + void refreshColumn(String column, int changeMask) { synchronized (properties) { - properties.remove(column); - properties.remove(column + "#html"); - properties.remove(column + "#canWrite"); + if ((ModelEvent.TableValueChanged.VALUE_MASK & changeMask) != 0) { + properties.remove(column); + } + if ((ModelEvent.TableValueChanged.HTML_VALUE_MASK & changeMask) != 0) { + properties.remove(column + "#html"); + } + if ((ModelEvent.TableValueChanged.IS_READ_ONLY_MASK & changeMask) != 0) { + properties.remove(column + "#canWrite"); + } } firePropertyChange(column, null, null); } @@ -1869,14 +1875,19 @@ public void run() { Object value = ""; String htmlValue = null; - String nonHtmlValue = null; + Object nonHtmlValue = null; try { //System.err.println("getValueAt("+object+", "+id+") of node "+TreeModelNode.this); value = model.getValueAt (object, id); + nonHtmlValue = value; + boolean hasHTML = model.hasHTMLValueAt(object, id); + if (hasHTML) { + htmlValue = model.getHTMLValueAt(object, id); + } //System.err.println(" Value of ("+object+") executed in "+Thread.currentThread()+" is "+value); //System.out.println(" evaluateLazily("+TreeModelNode.this.getDisplayName()+", "+id+"): have value = "+value); //System.out.println(" object = "+object+" class = "+((object != null) ? object.getClass().toString() : "null")); - if (value instanceof String) { + if (!hasHTML && (value instanceof String)) { // For backward compatibility htmlValue = htmlValue ((String) value); nonHtmlValue = removeHTML ((String) value); } @@ -1893,12 +1904,8 @@ //evaluatedNotify.run(); boolean fire; synchronized (properties) { - if (value instanceof String) { - properties.put (id, nonHtmlValue); - properties.put (id + "#html", htmlValue); - } else { - properties.put (id, value); - } + properties.put (id, nonHtmlValue); + properties.put (id + "#html", htmlValue); synchronized (evaluated) { fire = evaluated[0] == -1; evaluated[0] = 1; @@ -1992,13 +1999,18 @@ private Object getTheValue() { Object value = ""; String htmlValue = null; - String nonHtmlValue = null; + Object nonHtmlValue = null; try { value = model.getValueAt (object, id); + nonHtmlValue = value; + boolean hasHTML = model.hasHTMLValueAt(object, id); + if (hasHTML) { + htmlValue = model.getHTMLValueAt(object, id); + } //System.err.println(" Value of ("+object+") executed in "+Thread.currentThread()+" is "+value); //System.out.println(" evaluateLazily("+TreeModelNode.this.getDisplayName()+", "+id+"): have value = "+value); //System.out.println(" object = "+object+" class = "+((object != null) ? object.getClass().toString() : "null")); - if (value instanceof String) { + if (!hasHTML && (value instanceof String)) { // For backward compatibility htmlValue = htmlValue ((String) value); nonHtmlValue = removeHTML ((String) value); } @@ -2008,12 +2020,8 @@ } } finally { synchronized (properties) { - if (value instanceof String) { - properties.put (id, nonHtmlValue); - properties.put (id + "#html", htmlValue); - } else { - properties.put (id, value); - } + properties.put (id, nonHtmlValue); + properties.put (id + "#html", htmlValue); } } return value; @@ -2124,13 +2132,19 @@ Object v = value; model.setValueAt (object, id, v); v = model.getValueAt(object, id); // Store the new value + String htmlValue = null; + Object nonHtmlValue = v; + boolean hasHTML = model.hasHTMLValueAt(object, id); + if (hasHTML) { + htmlValue = model.getHTMLValueAt(object, id); + } + if (!hasHTML && (v instanceof String)) { // For backward compatibility + htmlValue = htmlValue ((String) v); + nonHtmlValue = removeHTML ((String) v); + } synchronized (properties) { - if (v instanceof String) { - properties.put (id, removeHTML ((String) v)); - properties.put (id + "#html", htmlValue ((String) v)); - } else { - properties.put (id, v); - } + properties.put (id, nonHtmlValue); + properties.put (id + "#html", htmlValue); } firePropertyChange (propertyId, null, null); } catch (UnknownTypeException e) { @@ -2140,11 +2154,19 @@ @Override public PropertyEditor getPropertyEditor () { - PropertyEditor pe = columnModel.getPropertyEditor (); + PropertyEditor pe = null; + try { + pe = model.getPropertyEditor(object, id); + } catch (UnknownTypeException ex) { + Logger.getLogger(TreeModelNode.class.getName()).log(Level.CONFIG, "Column id:" + columnModel.getID ()+"\nModel: "+model, ex); + } if (pe == null) { + pe = columnModel.getPropertyEditor (); + } + if (pe != null) { + return pe; + } else { return super.getPropertyEditor(); - } else { - return pe; } } diff --git a/spi.viewmodel/src/org/netbeans/modules/viewmodel/TreeModelRoot.java b/spi.viewmodel/src/org/netbeans/modules/viewmodel/TreeModelRoot.java --- a/spi.viewmodel/src/org/netbeans/modules/viewmodel/TreeModelRoot.java +++ b/spi.viewmodel/src/org/netbeans/modules/viewmodel/TreeModelRoot.java @@ -334,10 +334,11 @@ if (node != null) { TreeModelNode[] tmNodes = findNode(node); //System.err.println(" nodes = "+Arrays.toString(tmNodes)); + int change = tvEvent.getChange(); for (TreeModelNode tmNode : tmNodes) { String column = tvEvent.getColumnID(); if (column != null) { - tmNode.refreshColumn(column); + tmNode.refreshColumn(column, change); } else { tmNode.refresh(model); } diff --git a/spi.viewmodel/src/org/netbeans/spi/viewmodel/ModelEvent.java b/spi.viewmodel/src/org/netbeans/spi/viewmodel/ModelEvent.java --- a/spi.viewmodel/src/org/netbeans/spi/viewmodel/ModelEvent.java +++ b/spi.viewmodel/src/org/netbeans/spi/viewmodel/ModelEvent.java @@ -87,8 +87,25 @@ */ public static class TableValueChanged extends ModelEvent { + /** + * The mask for value change. + * @since 1.42 + */ + public static final int VALUE_MASK = 1; + /** + * The mask for HTML value change. + * @since 1.42 + */ + public static final int HTML_VALUE_MASK = 2; + /** + * The mask for change of the read only state. + * @since 1.42 + */ + public static final int IS_READ_ONLY_MASK = 4; + private Object node; private String columnID; + private int change; /** * Creates a new instance of TableValueChanged event. @@ -104,9 +121,28 @@ Object node, String columnID ) { + this(source, node, columnID, 0xffffffff); + } + + /** + * Creates a new instance of TableValueChanged event. + * + * @param source a source if event. + * @param node a changed node instance + * @param columnID a changed column name + * @param change one of the *_MASK constants or their aggregation. + * @since 1.42 + */ + public TableValueChanged ( + Object source, + Object node, + String columnID, + int change + ) { super (source); this.node = node; this.columnID = columnID; + this.change = change; } /** @@ -130,6 +166,16 @@ public String getColumnID () { return columnID; } + + /** + * Get the change mask. + * + * @return the change mask, one of the *_MASK constants or their aggregation. + * @since 1.42 + */ + public int getChange() { + return change; + } } /** diff --git a/spi.viewmodel/src/org/netbeans/spi/viewmodel/Models.java b/spi.viewmodel/src/org/netbeans/spi/viewmodel/Models.java --- a/spi.viewmodel/src/org/netbeans/spi/viewmodel/Models.java +++ b/spi.viewmodel/src/org/netbeans/spi/viewmodel/Models.java @@ -48,6 +48,7 @@ import java.awt.datatransfer.Transferable; import java.awt.dnd.DnDConstants; import java.awt.event.ActionEvent; +import java.beans.PropertyEditor; import java.io.IOException; import java.lang.ref.Reference; import java.lang.ref.WeakReference; @@ -266,7 +267,7 @@ // ; or the models directly boolean hasLists = false; int modelsSize = models.size(); - if (11 <= modelsSize && modelsSize <= 15) { + if (11 <= modelsSize && modelsSize <= 18) { Iterator it = models.iterator (); boolean failure = false; while (it.hasNext ()) { @@ -306,6 +307,18 @@ ml.tableRendererModels = (List) models.get(13); if (modelsSize > 14) { ml.tableRendererModelFilters = (List) models.get(14); + //if (modelsSize > 15) { + // ml.tableHtmlModels = (List) models.get(15); + if (modelsSize > 15) { + ml.tableHtmlModelFilters = (List) models.get(15); + if (modelsSize > 16) { + ml.tablePropertyEditorsModels = (List) models.get(16); + if (modelsSize > 17) { + ml.tablePropertyEditorsModelFilters = (List) models.get(17); + } + } + } + //} } } } @@ -400,7 +413,7 @@ new DefaultAsynchronousModel(),//new DelegatingAsynchronousModel (ml.asynchModels), ml.asynchModelFilters ), - null, + null, null, propertiesHelpID ); } else { @@ -424,7 +437,8 @@ ml.columnModels, createCompoundTableModel ( new DelegatingTableModel (ml.tableModels), - ml.tableModelFilters + ml.tableModelFilters, + ml.tableHtmlModelFilters ), createCompoundAsynchronousModel ( new DefaultAsynchronousModel(),//new DelegatingAsynchronousModel (ml.asynchModels), @@ -434,6 +448,14 @@ new DelegatingTableRendererModel(ml.tableRendererModels), ml.tableRendererModelFilters ), + /*createCompoundTableHTMLModel ( + new DelegatingTableHTMLModel(ml.tableHtmlModels), + ml.tableHtmlModelFilters + ),*/ + createCompoundTablePropertyEditorModel ( + new DelegatingTablePropertyEditorsModel(ml.tablePropertyEditorsModels), + ml.tablePropertyEditorsModelFilters + ), propertiesHelpID ); } @@ -557,11 +579,12 @@ * * @returns compound table model */ - private static TableModel createCompoundTableModel ( - TableModel originalTableModel, - List tableModelFilters + private static TableHTMLModel createCompoundTableModel ( + TableHTMLModel originalTableModel, + List tableModelFilters, + List tableHtmlModelFilters ) { - TableModel tm = originalTableModel; + TableHTMLModel tm = originalTableModel; int i, k = tableModelFilters.size (); for (i = 0; i < k; i++) { tm = new CompoundTableModel ( @@ -569,6 +592,13 @@ (TableModelFilter) tableModelFilters.get (i) ); } + k = tableHtmlModelFilters.size (); + for (i = 0; i < k; i++) { + tm = new CompoundTableModel ( + tm, + (TableHTMLModelFilter) tableHtmlModelFilters.get (i) + ); + } return tm; } @@ -595,6 +625,21 @@ } return tm; } + + private static TablePropertyEditorsModel createCompoundTablePropertyEditorModel ( + TablePropertyEditorsModel originalTableModel, + List tableModelFilters + ) { + TablePropertyEditorsModel tm = originalTableModel; + int i, k = tableModelFilters.size (); + for (i = 0; i < k; i++) { + tm = new CompoundTablePropertyEditorsModel ( + tm, + (TablePropertyEditorsModelFilter) tableModelFilters.get (i) + ); + } + return tm; + } /** * Creates {@link org.netbeans.spi.viewmodel.NodeActionsProvider} for given NodeActionsProvider and @@ -1031,7 +1076,8 @@ } else if (event instanceof ModelEvent.TableValueChanged) { newEvent = new ModelEvent.TableValueChanged(newSource, ((ModelEvent.TableValueChanged) event).getNode(), - ((ModelEvent.TableValueChanged) event).getColumnID()); + ((ModelEvent.TableValueChanged) event).getColumnID(), + ((ModelEvent.TableValueChanged) event).getChange()); } else if (event instanceof ModelEvent.TreeChanged) { newEvent = new ModelEvent.TreeChanged(newSource); } else { @@ -1357,11 +1403,12 @@ * * @author Jan Jancura */ - private final static class CompoundTableModel implements TableModel, ModelListener { - - - private TableModel model; + private final static class CompoundTableModel implements TableHTMLModel, ModelListener { + + + private TableHTMLModel model; private TableModelFilter filter; + private TableHTMLModelFilter htmlFilter; private final Collection modelListeners = new HashSet(); @@ -1370,11 +1417,16 @@ * Creates {@link org.netbeans.spi.viewmodel.TableModel} for given TableModel and * {@link org.netbeans.spi.viewmodel.TableModelFilter}. */ - CompoundTableModel (TableModel model, TableModelFilter filter) { + CompoundTableModel (TableHTMLModel model, TableModelFilter filter) { this.model = model; this.filter = filter; } + CompoundTableModel (TableHTMLModel model, TableHTMLModelFilter htmlFilter) { + this.model = model; + this.htmlFilter = htmlFilter; + } + /** * Returns value to be displayed in column columnID * and row node. Column ID is defined in by @@ -1391,7 +1443,29 @@ @Override public Object getValueAt (Object node, String columnID) throws UnknownTypeException { - return filter.getValueAt (model, node, columnID); + if (filter != null) { + return filter.getValueAt (model, node, columnID); + } else { + return model.getValueAt(node, columnID); + } + } + + @Override + public boolean hasHTMLValueAt(Object node, String columnID) throws UnknownTypeException { + if (htmlFilter != null) { + return htmlFilter.hasHTMLValueAt(model, node, columnID); + } else { + return model.hasHTMLValueAt(node, columnID); + } + } + + @Override + public String getHTMLValueAt(Object node, String columnID) throws UnknownTypeException { + if (htmlFilter != null) { + return htmlFilter.getHTMLValueAt(model, node, columnID); + } else { + return model.getHTMLValueAt(node, columnID); + } } /** @@ -1410,7 +1484,11 @@ @Override public boolean isReadOnly (Object node, String columnID) throws UnknownTypeException { - return filter.isReadOnly (model, node, columnID); + if (filter != null) { + return filter.isReadOnly (model, node, columnID); + } else { + return model.isReadOnly(node, columnID); + } } /** @@ -1428,7 +1506,11 @@ @Override public void setValueAt (Object node, String columnID, Object value) throws UnknownTypeException { - filter.setValueAt (model, node, columnID, value); + if (filter != null) { + filter.setValueAt (model, node, columnID, value); + } else { + model.setValueAt(node, columnID, value); + } } /** @@ -1440,7 +1522,9 @@ public void addModelListener (ModelListener l) { synchronized (modelListeners) { if (modelListeners.isEmpty()) { - filter.addModelListener (this); + if (filter != null) { + filter.addModelListener (this); + } model.addModelListener (this); } modelListeners.add(l); @@ -1457,7 +1541,9 @@ synchronized (modelListeners) { modelListeners.remove(l); if (modelListeners.isEmpty()) { - filter.removeModelListener (this); + if (filter != null) { + filter.removeModelListener (this); + } model.removeModelListener (this); } } @@ -1490,15 +1576,16 @@ } public String toString (String n) { + Model theFilter = (filter != null) ? filter : htmlFilter; if (model instanceof CompoundTableModel) { - return n + filter + "\n" + + return n + theFilter + "\n" + ((CompoundTableModel) model).toString (n + " "); } if (model instanceof DelegatingTableModel) { - return n + filter + "\n" + + return n + theFilter + "\n" + ((DelegatingTableModel) model).toString (n + " "); } - return n + filter + "\n" + + return n + theFilter + "\n" + n + " " + model; } } @@ -1899,6 +1986,40 @@ } } + private final static class CompoundTablePropertyEditorsModel implements TablePropertyEditorsModel { + + private TablePropertyEditorsModel model; + private TablePropertyEditorsModelFilter filter; + + CompoundTablePropertyEditorsModel(TablePropertyEditorsModel model, TablePropertyEditorsModelFilter filter) { + this.model = model; + this.filter = filter; + } + + @Override + public PropertyEditor getPropertyEditor(Object node, String columnID) throws UnknownTypeException { + return filter.getPropertyEditor(model, node, columnID); + } + + @Override + public String toString () { + return super.toString () + "\n" + toString (" "); + } + + public String toString (String n) { + if (model instanceof CompoundTablePropertyEditorsModel) { + return n + filter + "\n" + + ((CompoundTablePropertyEditorsModel) model).toString (n + " "); + } + if (model instanceof DelegatingTablePropertyEditorsModel) { + return n + filter + "\n" + + ((DelegatingTablePropertyEditorsModel) model).toString (n + " "); + } + return n + filter + "\n" + + n + " " + model; + } + } + /** * Creates {@link org.netbeans.spi.viewmodel.NodeActionsProvider} * for given NodeActionsProvider and @@ -2078,7 +2199,7 @@ * * @author Jan Jancura */ - private final static class DelegatingTableModel implements TableModel { + private final static class DelegatingTableModel implements TableModel, TableHTMLModel { private TableModel[] models; private HashMap classNameToModel = new HashMap(); @@ -2286,6 +2407,94 @@ sb.append (models [i]); return new String (sb); } + + // HTML extension: + + private boolean defaultHasHTMLValueAt() { + return false; + } + + @Override + public boolean hasHTMLValueAt(Object node, String columnID) throws UnknownTypeException { + UnknownTypeException uex = null; + TableModel model = classNameToModel.get ( + node.getClass ().getName () + ); + if (model != null) { + if (model instanceof TableHTMLModel) { + try { + return ((TableHTMLModel) model).hasHTMLValueAt(node, columnID); + } catch (UnknownTypeException e) { + uex = e; + } + } else { + return defaultHasHTMLValueAt(); + } + } + int i, k = models.length; + boolean isHTML = false; + for (i = 0; i < k; i++) { + if (models[i] instanceof TableHTMLModel) { + try { + boolean has = ((TableHTMLModel) models [i]).hasHTMLValueAt(node, columnID); + classNameToModel.put (node.getClass ().getName (), models [i]); + return has; + } catch (UnknownTypeException e) { + uex = e; + } + isHTML = true; + } + } + if (!isHTML) { + return defaultHasHTMLValueAt(); + } + if (uex != null) { + throw uex; + } else { + throw new UnknownTypeException (node); + } + } + + @Override + public String getHTMLValueAt(Object node, String columnID) throws UnknownTypeException { + UnknownTypeException uex = null; + TableModel model = classNameToModel.get ( + node.getClass ().getName () + ); + if (model != null) { + if (model instanceof TableHTMLModel) { + try { + return ((TableHTMLModel) model).getHTMLValueAt(node, columnID); + } catch (UnknownTypeException e) { + uex = e; + } + } else { + return null; + } + } + int i, k = models.length; + boolean isHTML = false; + for (i = 0; i < k; i++) { + if (models[i] instanceof TableHTMLModel) { + try { + String htmlValue = ((TableHTMLModel) models [i]).getHTMLValueAt(node, columnID); + classNameToModel.put (node.getClass ().getName (), models [i]); + return htmlValue; + } catch (UnknownTypeException e) { + uex = e; + } + isHTML = true; + } + } + if (!isHTML) { + return null; + } + if (uex != null) { + throw uex; + } else { + throw new UnknownTypeException (node); + } + } } /** @@ -2484,6 +2693,79 @@ } } + + private final static class DelegatingTablePropertyEditorsModel implements TablePropertyEditorsModel { + + private TablePropertyEditorsModel[] models; + private HashMap classNameToModel = new HashMap(); + + DelegatingTablePropertyEditorsModel(List models) { + this(convert(models)); + } + + private static TablePropertyEditorsModel[] convert(List l) { + TablePropertyEditorsModel[] models = new TablePropertyEditorsModel[l.size()]; + return l.toArray(models); + } + + DelegatingTablePropertyEditorsModel(TablePropertyEditorsModel[] models) { + this.models = models; + } + + @Override + public PropertyEditor getPropertyEditor(Object node, String columnID) throws UnknownTypeException { + UnknownTypeException utex = null; + TablePropertyEditorsModel model = classNameToModel.get( + node.getClass().getName() + ); + if (model != null) { + try { + return model.getPropertyEditor(node, columnID); + } catch (UnknownTypeException e) { + utex = e; + } + } + int i, k = models.length; + for (i = 0; i < k; i++) { + try { + PropertyEditor pe = models [i].getPropertyEditor(node, columnID); + classNameToModel.put (node.getClass ().getName (), models [i]); + return pe; + } catch (UnknownTypeException e) { + utex = e; + } + } + if (k == 0) { + return null; + } + if (utex != null) { + throw utex; + } else { + throw new UnknownTypeException (node); + } + } + + @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); + } + } /** * Creates one {@link org.netbeans.spi.viewmodel.TableModel} @@ -3955,9 +4237,10 @@ CheckNodeModel, DnDNodeModel, NodeActionsProvider, - TableModel, + TableHTMLModel, TreeExpansionModel, - TableRendererModel { + TableRendererModel, + TablePropertyEditorsModel { private ReorderableTreeModel treeModel; private ExtendedNodeModel nodeModel; @@ -3965,8 +4248,9 @@ private DnDNodeModel dndNodeModel; private NodeActionsProvider nodeActionsProvider; private ColumnModel[] columnModels; - private TableModel tableModel; + private TableHTMLModel tableModel; private TableRendererModel tableRendererModel; + private TablePropertyEditorsModel tablePropertyEditorsModel; private TreeExpansionModel treeExpansionModel; private AsynchronousModel asynchModel; @@ -3997,9 +4281,10 @@ ExtendedNodeModel nodeModel, NodeActionsProvider nodeActionsProvider, List columnModels, - TableModel tableModel, + TableHTMLModel tableModel, AsynchronousModel asynchModel, TableRendererModel tableRendererModel, + TablePropertyEditorsModel tablePropertyEditorsModel, String propertiesHelpID ) { if (treeModel == null || nodeModel == null || tableModel == null || @@ -4024,6 +4309,7 @@ } this.tableModel = tableModel; this.tableRendererModel = tableRendererModel; + this.tablePropertyEditorsModel = tablePropertyEditorsModel; this.nodeActionsProvider = nodeActionsProvider; this.columnModels = columnModels.toArray ( new ColumnModel [columnModels.size ()] @@ -4582,6 +4868,31 @@ return null; } } + + // TableHTMLModel + + @Override + public boolean hasHTMLValueAt(Object node, String columnID) throws UnknownTypeException { + return tableModel.hasHTMLValueAt(node, columnID); + } + + @Override + public String getHTMLValueAt(Object node, String columnID) throws UnknownTypeException { + return tableModel.getHTMLValueAt(node, columnID); + } + + // TablePropertyEditorsModel + + @Override + public PropertyEditor getPropertyEditor(Object node, String columnID) throws UnknownTypeException { + if (tablePropertyEditorsModel != null) { + return tablePropertyEditorsModel.getPropertyEditor(node, columnID); + } else { + return null; + } + } + + } @@ -4602,6 +4913,10 @@ public List asynchModelFilters = Collections.emptyList(); public List tableRendererModels = Collections.emptyList(); public List tableRendererModelFilters = Collections.emptyList(); + public List tableHtmlModels = Collections.emptyList(); + public List tableHtmlModelFilters = Collections.emptyList(); + public List tablePropertyEditorsModels = Collections.emptyList(); + public List tablePropertyEditorsModelFilters = Collections.emptyList(); public void addOtherModels(List otherModels) { Iterator it = otherModels.iterator (); @@ -4668,6 +4983,30 @@ tableRendererModelFilters.add(0, (TableRendererModelFilter) model); } } + if (model instanceof TableHTMLModel && !tableHtmlModels.contains((TableHTMLModel) model)) { + tableHtmlModels = new ArrayList(tableHtmlModels); + tableHtmlModels.add((TableHTMLModel) model); + } + if (model instanceof TableHTMLModelFilter && !tableHtmlModelFilters.contains((TableHTMLModelFilter) model)) { + tableHtmlModelFilters = new ArrayList(tableHtmlModelFilters); + if (first) { + tableHtmlModelFilters.add((TableHTMLModelFilter) model); + } else { + tableHtmlModelFilters.add(0, (TableHTMLModelFilter) model); + } + } + if (model instanceof TablePropertyEditorsModel && !tablePropertyEditorsModels.contains((TablePropertyEditorsModel) model)) { + tablePropertyEditorsModels = new ArrayList(tablePropertyEditorsModels); + tablePropertyEditorsModels.add((TablePropertyEditorsModel) model); + } + if (model instanceof TablePropertyEditorsModelFilter && !tablePropertyEditorsModelFilters.contains((TablePropertyEditorsModelFilter) model)) { + tablePropertyEditorsModelFilters = new ArrayList(tablePropertyEditorsModelFilters); + if (first) { + tablePropertyEditorsModelFilters.add((TablePropertyEditorsModelFilter) model); + } else { + tablePropertyEditorsModelFilters.add(0, (TablePropertyEditorsModelFilter) model); + } + } if (model instanceof NodeActionsProvider && !nodeActionsProviders.contains((NodeActionsProvider) model)) { nodeActionsProviders = new ArrayList(nodeActionsProviders); nodeActionsProviders.add((NodeActionsProvider) model); diff --git a/spi.viewmodel/src/org/netbeans/spi/viewmodel/TableHTMLModel.java b/spi.viewmodel/src/org/netbeans/spi/viewmodel/TableHTMLModel.java new file mode 100644 --- /dev/null +++ b/spi.viewmodel/src/org/netbeans/spi/viewmodel/TableHTMLModel.java @@ -0,0 +1,90 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 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]" + * + * 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. + * + * Contributor(s): + * + * Portions Copyrighted 2013 Sun Microsystems, Inc. + */ +package org.netbeans.spi.viewmodel; + +/** + * Use this to separate value and the HTML value. + * When displaying a property value, then if the value is a String and if it contains + * a HTML code, it's automatically rendered as HTML. The HTML code is then + * stripped out to get the raw value. + * If this is not desired or if it's necessary to provide a value and HTML code + * that differs from each other, implement this model. + * + * @author Martin Entlicher + * @since 1.42 + * @see TableHTMLModelFilter + */ +public interface TableHTMLModel extends TableModel { + + /** + * Test if the model has a HTML value. + * For backward compatibility, if it returns false, + * HTML value is is taken from the String value, if it contains some. + * If this is not desired, return true here and null from + * {@link #getHTMLValueAt(java.lang.Object, java.lang.String)}. + * @param node an object returned from {@link TreeModel#getChildren(java.lang.Object, int, int) } + * for this row + * @param columnID an id of column defined by {@link ColumnModel#getID()} + * @return true if there is some HTML value to be returned + * from {@link #getHTMLValueAt(java.lang.Object, java.lang.String)}, + * false otherwise. + * When false is returned, + * {@link #getHTMLValueAt(java.lang.Object, java.lang.String)} is not called. + * @throws UnknownTypeException if there is nothing to be provided for the given + * parameter type + */ + boolean hasHTMLValueAt(Object node, String columnID) throws UnknownTypeException; + + /** + * Get the HTML value. + * + * @param node an object returned from {@link TreeModel#getChildren(java.lang.Object, int, int) } + * for this row + * @param columnID an id of column defined by {@link ColumnModel#getID()} + * @return The HTML value, or null when no HTML value is provided. + * @throws UnknownTypeException if there is nothing to be provided for the given + * parameter type + * @see #hasHTMLValueAt(java.lang.Object, java.lang.String) + */ + String getHTMLValueAt(Object node, String columnID) throws UnknownTypeException; + +} diff --git a/spi.viewmodel/src/org/netbeans/spi/viewmodel/TableHTMLModelFilter.java b/spi.viewmodel/src/org/netbeans/spi/viewmodel/TableHTMLModelFilter.java new file mode 100644 --- /dev/null +++ b/spi.viewmodel/src/org/netbeans/spi/viewmodel/TableHTMLModelFilter.java @@ -0,0 +1,102 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 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]" + * + * 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. + * + * Contributor(s): + * + * Portions Copyrighted 2013 Sun Microsystems, Inc. + */ +package org.netbeans.spi.viewmodel; + +/** + * Use this to separate value and the HTML value. + * Implement this filter to override the behavior of any registered {@link TableHTMLModel}s. + * + * @author Martin Entlicher + * @since 1.42 + * @see TableHTMLModel + */ +public interface TableHTMLModelFilter extends Model { + + /** + * Test if the model has a HTML value. + * For backward compatibility, if it returns false, + * HTML value is is taken from the String value, if it contains some. + * If this is not desired, return true here and null from + * {@link #getHTMLValueAt(org.netbeans.spi.viewmodel.TableHTMLModel, java.lang.Object, java.lang.String)}. + * @param original The original {@link TableHTMLModel} + * @param node an object returned from {@link TreeModel#getChildren(java.lang.Object, int, int) } + * for this row + * @param columnID an id of column defined by {@link ColumnModel#getID()} + * @return true if there is some HTML value to be returned + * from {@link #getHTMLValueAt(org.netbeans.spi.viewmodel.TableHTMLModel, java.lang.Object, java.lang.String)}, + * false otherwise. + * When false is returned, + * {@link #getHTMLValueAt(org.netbeans.spi.viewmodel.TableHTMLModel, java.lang.Object, java.lang.String)} + * is not called. + * @throws UnknownTypeException if there is nothing to be provided for the given + * parameter type + */ + boolean hasHTMLValueAt(TableHTMLModel original, Object node, String columnID) throws UnknownTypeException; + + /** + * Get the HTML value. + * + * @param original The original {@link TableHTMLModel} + * @param node an object returned from {@link TreeModel#getChildren(java.lang.Object, int, int) } + * for this row + * @param columnID an id of column defined by {@link ColumnModel#getID()} + * @return The HTML value, or null when no HTML value is provided. + * @throws UnknownTypeException if there is nothing to be provided for the given + * parameter type + * @see #hasHTMLValueAt(org.netbeans.spi.viewmodel.TableHTMLModel, java.lang.Object, java.lang.String) + */ + String getHTMLValueAt(TableHTMLModel 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); +} diff --git a/spi.viewmodel/src/org/netbeans/spi/viewmodel/TablePropertyEditorsModel.java b/spi.viewmodel/src/org/netbeans/spi/viewmodel/TablePropertyEditorsModel.java new file mode 100644 --- /dev/null +++ b/spi.viewmodel/src/org/netbeans/spi/viewmodel/TablePropertyEditorsModel.java @@ -0,0 +1,67 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 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]" + * + * 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. + * + * Contributor(s): + * + * Portions Copyrighted 2013 Sun Microsystems, Inc. + */ +package org.netbeans.spi.viewmodel; + +import java.beans.PropertyEditor; + +/** + * Use this to provide different property editors for different table cells. + * + * @author Martin Entlicher + * @since 1.42 + * @see TablePropertyEditorsModelFilter + */ +public interface TablePropertyEditorsModel extends Model { + + /** + * Get the property editor for the given table cell. + * + * @param node an object returned from {@link TreeModel#getChildren(java.lang.Object, int, int) } + * for this row + * @param columnID an id of column defined by {@link ColumnModel#getID()} + * @return The property editor or null to use the column default one. + * @throws UnknownTypeException if there is nothing to be provided for the given + * parameter type + */ + PropertyEditor getPropertyEditor(Object node, String columnID) throws UnknownTypeException; + +} diff --git a/spi.viewmodel/src/org/netbeans/spi/viewmodel/TablePropertyEditorsModelFilter.java b/spi.viewmodel/src/org/netbeans/spi/viewmodel/TablePropertyEditorsModelFilter.java new file mode 100644 --- /dev/null +++ b/spi.viewmodel/src/org/netbeans/spi/viewmodel/TablePropertyEditorsModelFilter.java @@ -0,0 +1,70 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 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]" + * + * 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. + * + * Contributor(s): + * + * Portions Copyrighted 2013 Sun Microsystems, Inc. + */ +package org.netbeans.spi.viewmodel; + +import java.beans.PropertyEditor; + +/** + * Use this to provide different property editors for different table cells. + * Implement this filter to override the behavior of any registered {@link TablePropertyEditorsModel}s. + * + * @author Martin Entlicher + * @since 1.42 + * @see TablePropertyEditorsModel + */ +public interface TablePropertyEditorsModelFilter extends Model { + + /** + * Get the property editor for the given table cell. + * + * @param original The original {@link TablePropertyEditorsModel} + * @param node an object returned from {@link TreeModel#getChildren(java.lang.Object, int, int) } + * for this row + * @param columnID an id of column defined by {@link ColumnModel#getID()} + * @return The property editor or null to use the column default one. + * @throws UnknownTypeException if there is nothing to be provided for the given + * parameter type + */ + PropertyEditor getPropertyEditor(TablePropertyEditorsModel original, + Object node, String columnID) throws UnknownTypeException; + +}