diff --git a/openide.explorer/apichanges.xml b/openide.explorer/apichanges.xml --- a/openide.explorer/apichanges.xml +++ b/openide.explorer/apichanges.xml @@ -47,6 +47,29 @@ Explorer API + + + OutlineView.setPropertyColumns, + OutlineView.addPropertyColumn and + OutlineView.removePropertyColumn added. + + + + + + + Added methods to manipulate the displayed columns of an OutlineView + without needing to create prototype property objects, both making + it simpler to use, and avoiding the common problem of properties + not appearing because the prototype property does not use the + exact type required. +

+ Deprecated OutlineView.setProperties(), as this was + only needed for ease of replacement of TreeTableView. + + + +

OutlineView.setTreeSortable added. diff --git a/openide.explorer/nbproject/project.properties b/openide.explorer/nbproject/project.properties --- a/openide.explorer/nbproject/project.properties +++ b/openide.explorer/nbproject/project.properties @@ -44,4 +44,4 @@ javadoc.arch=${basedir}/arch.xml javadoc.apichanges=${basedir}/apichanges.xml -spec.version.base=6.24.0 +spec.version.base=6.25.0 diff --git a/openide.explorer/src/org/openide/explorer/view/OutlineView.java b/openide.explorer/src/org/openide/explorer/view/OutlineView.java --- a/openide.explorer/src/org/openide/explorer/view/OutlineView.java +++ b/openide.explorer/src/org/openide/explorer/view/OutlineView.java @@ -54,11 +54,14 @@ import java.beans.PropertyEditor; import java.beans.PropertyVetoException; import java.beans.VetoableChangeListener; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.EventObject; +import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Properties; import java.util.logging.Logger; @@ -95,9 +98,11 @@ import org.openide.explorer.ExplorerManager; import org.openide.explorer.propertysheet.PropertyPanel; import org.openide.nodes.Node; -import org.openide.util.Exceptions; +import org.openide.nodes.Node.Property; +import org.openide.nodes.PropertySupport; import org.openide.util.Lookup; import org.openide.util.NbBundle; +import org.openide.util.Parameters; import org.openide.util.WeakListeners; /** @@ -260,10 +265,97 @@ return popupListener != null; } + /** + * Set the properties which are shown in the non-tree columns of this + * Outline view. + *

+ * The passed set of properties are typically + * prototypes - for a given Node's + * property to be shown in a given column, that Node must have a Property + * which equals() one of the prototype properties. By default, + * this means that the return values of the prototype property's getName() + * and getValueType() must exactly match. + *

+ * It is also possible to use the actual Property objects from one Node + * being shown, if they are available. + * + * @deprecated This method is here to enable easy replacement + * of TreeTableView with OutlineView. + * Use setPropertyColumns, addPropertyColumn and + * removePropertyColumn instead. + * @param newProperties An array of prototype properties + */ + @Deprecated public void setProperties(Node.Property[] newProperties) { rowModel.setProperties(newProperties); outline.tableChanged(null); } + + /** + * Adds a property column which will match any property with the passed + * name. + * + * @param name The programmatic name of the property + * @param displayName A localized display name for the property which can + * be shown in the table header + * @since 6.25 + */ + public void addPropertyColumn(String name, String displayName) { + Parameters.notNull("name", name); //NOI18N + Parameters.notNull("displayName", displayName); //NOI18N + Property[] p = rowModel.getProperties(); + Property[] nue = new Property[p.length + 1]; + System.arraycopy(p, 0, nue, 0, p.length); + nue[p.length] = new PrototypeProperty(name, displayName); + setProperties (nue); + } + + /** + * Remove the first property column for properties named name + * @param name The programmatic name of the Property, i.e. the + * return value of Property.getName() + * + * @return true if a column was removed + * @since 6.25 + */ + public boolean removePropertyColumn(String name) { + Parameters.notNull("name", name); //NOI18N + Property[] props = rowModel.getProperties(); + List nue = new LinkedList(Arrays.asList(props)); + boolean found = false; + for (Iterator i=nue.iterator(); i.hasNext();) { + Property p = i.next(); + if (name.equals(p.getName())) { + found = true; + i.remove(); + break; + } + } + if (found) { + props = nue.toArray(new Property[props.length - 1]); + setProperties (props); + } + return found; + } + + /** + * Set all of the non-tree columns property names and display names. + * + * @param namesAndDisplayNames An array, divisible by 2, of + * programmatic name, display name, programmatic name, display name... + * @since 6.25 + */ + public void setPropertyColumns(String... namesAndDisplayNames) { + if (namesAndDisplayNames.length % 2 != 0) { + throw new IllegalArgumentException("Odd number of names and " + //NOI18N + "display names: " + Arrays.asList(namesAndDisplayNames)); //NOI18N + } + Property[] props = new Property[namesAndDisplayNames.length / 2]; + for (int i = 0; i < namesAndDisplayNames.length; i+=2) { + props[i / 2] = new PrototypeProperty (namesAndDisplayNames[i], namesAndDisplayNames[i+1]); + } + setProperties (props); + } /** Enable/disable displaying popup menus on tree view items. * Default is enabled. @@ -1158,4 +1250,29 @@ } } + static final class PrototypeProperty extends PropertySupport.ReadWrite { + PrototypeProperty (String name, String displayName) { + super (name, Object.class, displayName, null); + } + + @Override + public Object getValue() throws IllegalAccessException, InvocationTargetException { + throw new AssertionError(); + } + + @Override + public void setValue(Object val) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { + throw new AssertionError(); + } + + @Override + public boolean equals(Object o) { + return o != null && o instanceof Property && getName().equals(((Property)o).getName()); + } + + @Override + public int hashCode() { + return getName().hashCode(); + } + } } diff --git a/openide.explorer/src/org/openide/explorer/view/PropertiesRowModel.java b/openide.explorer/src/org/openide/explorer/view/PropertiesRowModel.java --- a/openide.explorer/src/org/openide/explorer/view/PropertiesRowModel.java +++ b/openide.explorer/src/org/openide/explorer/view/PropertiesRowModel.java @@ -337,6 +337,10 @@ return prop[column].getValue(propName); } + Node.Property[] getProperties() { + return prop; + } + /** * Changes the value of the boolean property. */ diff --git a/openide.explorer/test/unit/src/org/openide/explorer/view/OutlineView179397Test.java b/openide.explorer/test/unit/src/org/openide/explorer/view/OutlineView179397Test.java new file mode 100644 --- /dev/null +++ b/openide.explorer/test/unit/src/org/openide/explorer/view/OutlineView179397Test.java @@ -0,0 +1,224 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved. + * + * 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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-2009 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.openide.explorer.view; + +import java.awt.BorderLayout; +import java.lang.reflect.InvocationTargetException; +import javax.swing.JPanel; +import javax.swing.table.TableModel; +import org.netbeans.junit.NbTestCase; +import org.netbeans.swing.etable.ETableColumn; +import org.netbeans.swing.etable.ETableColumnModel; +import org.openide.explorer.ExplorerManager; +import org.openide.nodes.AbstractNode; +import org.openide.nodes.Children; +import org.openide.nodes.Node; +import org.openide.nodes.Node.Property; +import org.openide.nodes.Sheet; +import org.openide.util.Exceptions; + +public final class OutlineView179397Test extends NbTestCase { + + private OutlineViewComponent component; + private OutlineView view; + private Node toExpand200_299, toExpand0_99; + + public OutlineView179397Test (String testName) { + super (testName); + } + + @Override + protected boolean runInEQ () { + return true; + } + + @Override + public void setUp () { + TestNode[] childrenNodes = new TestNode[3]; + for (int i = 0; i < childrenNodes.length; i ++) { + TestNode[] leafNodes = new TestNode[100]; + for (int j = 0; j < leafNodes.length; j ++) { + leafNodes[j] = new TestNode ("[" + (100 * i + j) + "]"); + } + Children.Array leafs = new Children.Array (); + leafs.add (leafNodes); + //childrenNodes [i] = new TestNode (leafs, "[" + (i * 100) + "-" + ((i + 1) *100 - 1) + "]"); + switch (i) { + case 0: + childrenNodes[i] = new TestNode (leafs, "[1-index from 0 to 99]"); + break; + case 1: + childrenNodes[i] = new TestNode (leafs, "[10-index from 100 to 199]"); + break; + case 2: + childrenNodes[i] = new TestNode (leafs, "[2-index from 200 to 299]"); + break; + default: + fail ("Unexcepted value " + i); + } + if (toExpand0_99 == null) { + toExpand0_99 = childrenNodes[i]; + } + toExpand200_299 = childrenNodes[i]; + } + + Children.Array children = new Children.Array (); + children.add (childrenNodes); + + Node rootNode = new TestNode (children, "[0 - 1000]"); + + component = new OutlineViewComponent (rootNode); + view = component.getOutlineView (); + } + + public void testPropertyColumnNameMethods() throws Exception { + view.expandNode (toExpand0_99); + ETableColumnModel etcm = (ETableColumnModel) view.getOutline ().getColumnModel (); + TableModel mdl = view.getOutline().getModel(); + assertEquals (2, mdl.getColumnCount()); + view.addPropertyColumn("Prop2", "Prop 2"); + assertEquals (3, mdl.getColumnCount()); + view.removePropertyColumn("Prop1"); + assertEquals (2, mdl.getColumnCount()); + view.setPropertyColumns ("Prop3", "Prop 3", "Prop4", "Prop 4", "Prop5", "Prop 5"); + assertEquals (4, mdl.getColumnCount()); + IllegalArgumentException iae = null; + try { + view.setPropertyColumns("A", "B", "C"); + } catch (IllegalArgumentException x) { + iae = x; + } + assertNotNull ("Odd number of arguments not allowed", iae); + } + private class OutlineViewComponent extends JPanel implements ExplorerManager.Provider { + + private final ExplorerManager manager = new ExplorerManager (); + private OutlineView view; + + private OutlineViewComponent (Node rootNode) { + setLayout (new BorderLayout ()); + manager.setRootContext (rootNode); + + Node.Property[] props = rootNode.getPropertySets ()[0].getProperties (); + view = new OutlineView ("test-outline-view-component"); + view.setProperties (new Property[] { props[0] }); + + view.getOutline ().setRootVisible (false); + + add (view, BorderLayout.CENTER); + } + + public ExplorerManager getExplorerManager () { + return manager; + } + + public OutlineView getOutlineView () { + return view; + } + } + + static class TestNode extends AbstractNode { + + public TestNode (String name) { + super (Children.LEAF); + setName (name); + } + + public TestNode (Children children, String name) { + super (children); + setName (name); + } + + @Override + protected Sheet createSheet () { + Sheet s = super.createSheet (); + Sheet.Set ss = s.get (Sheet.PROPERTIES); + if (ss == null) { + ss = Sheet.createPropertiesSet (); + s.put (ss); + } + ss.put (new DummyProperty ("Prop1")); + ss.put (new DummyProperty ("Prop2")); + ss.put (new DummyProperty ("Prop3")); + ss.put (new DummyProperty ("Prop4")); + ss.put (new DummyProperty ("Prop5")); + return s; + } + + class DummyProperty extends Property { + + public DummyProperty (String name) { + super (String.class); + setName (name); + setDisplayName(name); + try { + setValue (name); + } catch (IllegalAccessException ex) { + Exceptions.printStackTrace (ex); + } catch (IllegalArgumentException ex) { + Exceptions.printStackTrace (ex); + } catch (InvocationTargetException ex) { + Exceptions.printStackTrace (ex); + } + } + + public boolean canRead () { + return true; + } + + public String getValue () throws IllegalAccessException, + InvocationTargetException { + return (String) getValue ("unitTestPropName"); + } + + public boolean canWrite () { + return true; + } + + public void setValue (String val) throws IllegalAccessException, + IllegalArgumentException, + InvocationTargetException { + setValue ("unitTestPropName", val); + } + } + } + +}