001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: /*
043: * TestOutlineDynamic.java
044: *
045: * Created on February 1, 2004, 12:53 PM
046: */
047:
048: package org.netbeans.swing.outline;
049:
050: import java.awt.BorderLayout;
051: import java.awt.event.ActionListener;
052: import java.util.ArrayList;
053: import java.util.Arrays;
054: import javax.swing.BoxLayout;
055: import javax.swing.JButton;
056: import javax.swing.JFrame;
057: import javax.swing.JLabel;
058: import javax.swing.JPanel;
059: import javax.swing.JScrollPane;
060: import javax.swing.ListSelectionModel;
061: import javax.swing.event.ListSelectionEvent;
062: import javax.swing.event.ListSelectionListener;
063: import javax.swing.tree.DefaultMutableTreeNode;
064: import javax.swing.tree.DefaultTreeModel;
065: import javax.swing.tree.TreeModel;
066: import org.openide.util.Utilities;
067:
068: /** Another Outline test app - this one allows dynamic adding and removal of
069: * nodes and provides an editable column called "comment".
070: *
071: * @author Tim Boudreau
072: */
073: public class TestOutlineDynamic extends JFrame implements
074: ActionListener {
075: private Outline outline;
076: private TreeModel treeMdl;
077: static int nodeCount = 0;
078:
079: /** Creates a new instance of Test */
080: public TestOutlineDynamic() {
081: setDefaultCloseOperation(EXIT_ON_CLOSE);
082: getContentPane().setLayout(new BorderLayout());
083:
084: treeMdl = createModel();
085:
086: OutlineModel mdl = DefaultOutlineModel.createOutlineModel(
087: treeMdl, new NodeRowModel(), true);
088:
089: outline = new Outline();
090:
091: // outline.setRenderDataProvider(new RenderData());
092:
093: outline.setRootVisible(true);
094:
095: outline.setModel(mdl);
096:
097: JPanel buttons = new JPanel();
098:
099: JLabel jl = new JLabel("Read the button tooltips");
100:
101: buttons.setLayout(new BoxLayout(buttons, BoxLayout.Y_AXIS));
102: buttons.add(jl);
103:
104: final JButton add = new JButton("Add child");
105: final JButton remove = new JButton("Delete child");
106: final JButton clear = new JButton("Clear");
107: final JButton addDis = new JButton("Add discontiguous");
108: final JButton removeDis = new JButton("Delete discontiguous");
109:
110: addDis.setEnabled(false);
111: removeDis.setEnabled(false);
112: removeDis
113: .setToolTipText("To enable, select more than one immediate child node of the same parent node");
114: addDis
115: .setToolTipText("To enable, select a node with more than one child");
116: add.setToolTipText("Add a child to the selected node");
117: remove.setToolTipText("Delete the selected node");
118: clear
119: .setToolTipText("Clear the model, leaving only the root node");
120: clear.setEnabled(false);
121:
122: add.addActionListener(this );
123: remove.addActionListener(this );
124: clear.addActionListener(this );
125: addDis.addActionListener(this );
126: removeDis.addActionListener(this );
127: add.setName("add");
128: remove.setName("remove");
129: clear.setName("clear");
130: addDis.setName("addDis");
131: removeDis.setName("removeDis");
132: buttons.add(add);
133: buttons.add(remove);
134: buttons.add(clear);
135: buttons.add(addDis);
136: buttons.add(removeDis);
137:
138: add.setEnabled(false);
139: remove.setEnabled(false);
140:
141: outline.getSelectionModel().addListSelectionListener(
142: new ListSelectionListener() {
143: public void valueChanged(ListSelectionEvent e) {
144: boolean en = outline.getSelectedRow() != -1;
145: add.setEnabled(en);
146: remove.setEnabled(en
147: && outline.getSelectedRow() != 0);
148: clear.setEnabled(outline.getRowCount() > 1);
149:
150: ListSelectionModel m = outline
151: .getSelectionModel();
152: //en = (m.getMinSelectionIndex() != m.getMaxSelectionIndex());
153: en = getSelectedNode() != null;
154: if (en) {
155: DefaultMutableTreeNode nd = getSelectedNode();
156: en = nd.getChildCount() > 1;
157: }
158: addDis.setEnabled(en);
159:
160: en = getSelectedNode() != null;
161: if (en) {
162: int[] sels = getSelectedIndices();
163: en = sels.length > 1;
164: if (sels.length > outline.getRowCount()) {
165: en = false;
166: }
167: if (en) {
168: DefaultMutableTreeNode lastParent = null;
169: for (int i = 0; i < sels.length; i++) {
170: DefaultMutableTreeNode nd = (DefaultMutableTreeNode) outline
171: .getValueAt(sels[i], 0);
172: if (nd == null) {
173: en = false;
174: break;
175: }
176: if (lastParent != null) {
177: en &= nd.getParent() == lastParent;
178: if (!en) {
179: break;
180: }
181: } else {
182: lastParent = (DefaultMutableTreeNode) nd
183: .getParent();
184: }
185: }
186: }
187:
188: }
189:
190: removeDis.setEnabled(en);
191: }
192: });
193:
194: getContentPane().add(new JScrollPane(outline),
195: BorderLayout.CENTER);
196: getContentPane().add(buttons, BorderLayout.EAST);
197:
198: setBounds(20, 20, 700, 400);
199: }
200:
201: public void actionPerformed(java.awt.event.ActionEvent e) {
202: JButton b = (JButton) e.getSource();
203: DefaultMutableTreeNode n = getSelectedNode();
204: DefaultTreeModel mdl = (DefaultTreeModel) treeMdl;
205:
206: if ("add".equals(b.getName())) {
207: Node newNode = new Node();
208: DefaultMutableTreeNode nd = new DefaultMutableTreeNode(
209: newNode, true);
210: n.add(nd);
211:
212: mdl.nodesWereInserted(n,
213: new int[] { n.getChildCount() - 1 });
214:
215: // mdl.insertNodeInto(new DefaultMutableTreeNode(newNode, true), n, n.getChildCount());
216:
217: } else if ("remove".equals(b.getName())) {
218: mdl.removeNodeFromParent(n);
219: } else if ("clear".equals(b.getName())) {
220: DefaultMutableTreeNode root = (DefaultMutableTreeNode) mdl
221: .getRoot();
222: root.removeAllChildren();
223: nodeCount = 1;
224: mdl.reload(root);
225: } else if ("addDis".equals(b.getName())) {
226: DefaultMutableTreeNode nd = getSelectedNode();
227: int ch = nd.getChildCount();
228:
229: DefaultMutableTreeNode atStart = new DefaultMutableTreeNode(
230: new Node(), true);
231: DefaultMutableTreeNode atEnd = new DefaultMutableTreeNode(
232: new Node(), true);
233:
234: nd.insert(atEnd, ch);
235: nd.insert(atStart, 0);
236:
237: mdl.nodesWereInserted(nd, new int[] { 0,
238: nd.getChildCount() - 1 });
239:
240: } else if ("removeDis".equals(b.getName())) {
241: int[] sels = getSelectedIndices();
242:
243: //they all have the same parent if the button is enabled
244: DefaultMutableTreeNode aNode = (DefaultMutableTreeNode) outline
245: .getValueAt(sels[0], 0);
246:
247: DefaultMutableTreeNode parent = (DefaultMutableTreeNode) aNode
248: .getParent();
249:
250: //reverse sort the selections, so we remove nodes from bottom to top
251: for (int i = 0; i < sels.length; i++) {
252: sels[i] *= -1;
253: }
254: Arrays.sort(sels);
255: for (int i = 0; i < sels.length; i++) {
256: sels[i] *= -1;
257: }
258:
259: System.err.println("Going to remove "
260: + Arrays.asList(Utilities.toObjectArray(sels)));
261:
262: ArrayList nodes = new ArrayList();
263: int[] indices = new int[sels.length];
264: //Build the list of nodes we'll play with before we start
265: //modifying the model - we can't do it while we're going
266: for (int i = 0; i < sels.length; i++) {
267: aNode = (DefaultMutableTreeNode) outline.getValueAt(
268: sels[i], 0);
269: System.err.println("To delete user object class "
270: + aNode.getUserObject().getClass() + " = "
271: + aNode.getUserObject());
272: nodes.add(aNode);
273: indices[i] = parent.getIndex(aNode);
274: }
275:
276: System.err.println("Will really remove indices "
277: + Arrays.asList(Utilities.toObjectArray(indices)));
278:
279: for (int i = 0; i < nodes.size(); i++) {
280: aNode = (DefaultMutableTreeNode) nodes.get(i);
281: if (aNode.getParent() != parent) {
282: System.err.println(aNode + " not child of "
283: + parent + " but of " + aNode.getParent());
284: } else {
285: System.err.println("REMOVING " + aNode
286: + " from parent");
287: parent.remove(aNode);
288: nodes.add(aNode);
289: }
290: }
291:
292: mdl.nodesWereRemoved(parent, indices, nodes.toArray());
293:
294: }
295: }
296:
297: private int[] getSelectedIndices() {
298: ListSelectionModel lsm = outline.getSelectionModel();
299: int min = lsm.getMinSelectionIndex();
300: int max = lsm.getMaxSelectionIndex();
301: if (min == max) {
302: return new int[] { min };
303: }
304: ArrayList al = new ArrayList();
305: for (int i = min; i <= max; i++) {
306: if (lsm.isSelectedIndex(i)) {
307: al.add(new Integer(i));
308: }
309: }
310: Integer[] ints = (Integer[]) al.toArray(new Integer[0]);
311: return (int[]) Utilities.toPrimitiveArray(ints);
312: }
313:
314: public DefaultMutableTreeNode getSelectedNode() {
315: return ((DefaultMutableTreeNode) outline.getValueAt(outline
316: .getSelectedRow(), 0));
317: }
318:
319: /** A handy method to create a model to install into a JTree to compare
320: * behavior of a real JTree's layout cache and ours */
321: public static TreeModel createModel() {
322: DefaultMutableTreeNode root = new DefaultMutableTreeNode(
323: new Node());
324: TreeModel treeMdl = new DefaultTreeModel(root, false);
325: return treeMdl;
326: }
327:
328: public static void main(String[] ignored) {
329: try {
330: //UIManager.setLookAndFeel (new javax.swing.plaf.metal.MetalLookAndFeel());
331: } catch (Exception e) {
332: }
333:
334: new TestOutlineDynamic().show();
335: }
336:
337: private class NodeRowModel implements RowModel {
338:
339: public Class getColumnClass(int column) {
340: switch (column) {
341: case 0:
342: return Integer.class;
343: case 1:
344: return String.class;
345: default:
346: assert false;
347: }
348: return null;
349: }
350:
351: public int getColumnCount() {
352: return 2;
353: }
354:
355: public String getColumnName(int column) {
356: return column == 0 ? "Hash code" : "Comment";
357: }
358:
359: public Object getValueFor(Object node, int column) {
360: Node n = (Node) ((DefaultMutableTreeNode) node)
361: .getUserObject();
362: switch (column) {
363: case 0:
364: return new Integer(node.hashCode());
365: case 1:
366: return n.getComment();
367: default:
368: assert false;
369: }
370: return null;
371: }
372:
373: public boolean isCellEditable(Object node, int column) {
374: return column == 1;
375: }
376:
377: public void setValueFor(Object node, int column, Object value) {
378: if (column == 1) {
379: ((Node) ((DefaultMutableTreeNode) node).getUserObject())
380: .setComment(value.toString());
381: }
382: }
383: }
384:
385: private static class Node {
386: int idx;
387: private String comment = "no comment";
388:
389: public Node() {
390: idx = nodeCount++;
391: }
392:
393: public String getComment() {
394: return comment;
395: }
396:
397: public void setComment(String s) {
398: comment = s;
399: }
400:
401: public String toString() {
402: return "Node " + idx;
403: }
404: }
405: }
|