KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > viewmodel > TreeModelNode


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.viewmodel;
21
22 import java.awt.event.ActionEvent JavaDoc;
23 import java.awt.event.KeyEvent JavaDoc;
24 import java.beans.PropertyEditor JavaDoc;
25 import java.lang.IllegalAccessException JavaDoc;
26 import java.lang.ref.WeakReference JavaDoc;
27 import java.util.ArrayList JavaDoc;
28 import java.util.Arrays JavaDoc;
29 import java.util.Collections JavaDoc;
30 import java.util.HashMap JavaDoc;
31 import java.util.Iterator JavaDoc;
32 import java.util.LinkedList JavaDoc;
33 import java.util.List JavaDoc;
34 import java.util.Map JavaDoc;
35 import java.util.WeakHashMap JavaDoc;
36 import javax.swing.AbstractAction JavaDoc;
37 import javax.swing.Action JavaDoc;
38 import javax.swing.KeyStroke JavaDoc;
39 import javax.swing.SwingUtilities JavaDoc;
40
41 import org.netbeans.spi.viewmodel.ColumnModel;
42 import org.netbeans.spi.viewmodel.ModelEvent;
43 import org.netbeans.spi.viewmodel.Models;
44 import org.netbeans.spi.viewmodel.TreeModel;
45 import org.netbeans.spi.viewmodel.UnknownTypeException;
46 import org.openide.ErrorManager;
47
48 import org.openide.nodes.AbstractNode;
49 import org.openide.nodes.Children;
50 import org.openide.nodes.Node;
51 import org.openide.nodes.PropertySupport;
52 import org.openide.nodes.Sheet;
53 import org.openide.util.NbBundle;
54 import org.openide.util.RequestProcessor;
55 import org.openide.util.RequestProcessor.Task;
56 import org.openide.util.lookup.Lookups;
57
58
59 /**
60  *
61  * @author Jan Jancura
62  */

63 public class TreeModelNode extends AbstractNode {
64
65     /**
66      * The maximum length of text that is interpreted as HTML.
67      * This is documented at openide/explorer/src/org/openide/explorer/doc-files/propertyViewCustomization.html
68      */

69     private static final int MAX_HTML_LENGTH = 511;
70     
71     // variables ...............................................................
72

73     private Models.CompoundModel model;
74     private TreeModelRoot treeModelRoot;
75     private Object JavaDoc object;
76     
77     private String JavaDoc htmlDisplayName;
78     private Map JavaDoc properties = new HashMap JavaDoc ();
79
80     
81     // init ....................................................................
82

83     /**
84     * Creates root of call stack for given producer.
85     */

86     public TreeModelNode (
87         final Models.CompoundModel model,
88         final TreeModelRoot treeModelRoot,
89         final Object JavaDoc object
90     ) {
91         super (
92             createChildren (model, treeModelRoot, object),
93             Lookups.singleton (object)
94         );
95         this.model = model;
96         this.treeModelRoot = treeModelRoot;
97         this.object = object;
98         
99         // <RAVE>
100
// Use the modified CompoundModel class's field to set the
101
// propertiesHelpID for properties sheets if the model's helpID
102
// has been set
103
if (model.getHelpId() != null) {
104             this.setValue("propertiesHelpID", model.getHelpId()); // NOI18N
105
}
106         // </RAVE>
107

108         treeModelRoot.registerNode (object, this);
109         refreshNode ();
110         initProperties ();
111     }
112
113     
114     // Node implementation .....................................................
115

116     private void initProperties () {
117         Sheet sheet = Sheet.createDefault();
118         Sheet.Set ps = Sheet.createPropertiesSet ();
119         ColumnModel[] columns = model.getColumns ();
120         int i, k = columns.length;
121         for (i = 0; i < k; i++)
122             ps.put (new MyProperty (columns [i], treeModelRoot));
123         sheet.put (ps);
124         setSheet (sheet);
125     }
126     
127     private static Children createChildren (
128         Models.CompoundModel model,
129         TreeModelRoot treeModelRoot,
130         Object JavaDoc object
131     ) {
132         if (object == null)
133             throw new NullPointerException JavaDoc ();
134         try {
135             return model.isLeaf (object) ?
136                 Children.LEAF :
137                 new TreeModelChildren (model, treeModelRoot, object);
138         } catch (UnknownTypeException e) {
139             if (!(object instanceof String JavaDoc)) {
140                 Throwable JavaDoc t = ErrorManager.getDefault().annotate(e, "Model: "+model);
141                 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, t);
142             }
143             return Children.LEAF;
144         }
145     }
146     
147     public String JavaDoc getShortDescription () {
148         try {
149             String JavaDoc shortDescription = model.getShortDescription (object);
150             return shortDescription;
151         } catch (UnknownTypeException e) {
152             if (!(object instanceof String JavaDoc)) {
153                 Throwable JavaDoc t = ErrorManager.getDefault().annotate(e, "Model: "+model);
154                 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, t);
155             }
156             return null;
157         }
158     }
159     
160     public String JavaDoc getHtmlDisplayName () {
161         return htmlDisplayName;
162     }
163     
164     public Action JavaDoc[] getActions (boolean context) {
165         if (context)
166             return treeModelRoot.getRootNode ().getActions (false);
167         try {
168             return model.getActions (object);
169         } catch (UnknownTypeException e) {
170             // NodeActionsProvider is voluntary
171
return new Action JavaDoc [0];
172         }
173     }
174     
175     public Action JavaDoc getPreferredAction () {
176         return new AbstractAction JavaDoc () {
177             public void actionPerformed (ActionEvent JavaDoc e) {
178                 try {
179                     model.performDefaultAction (object);
180                 } catch (UnknownTypeException ex) {
181                     // NodeActionsProvider is voluntary
182
}
183             }
184         };
185     }
186     
187     public boolean canDestroy () {
188         try {
189             Action JavaDoc[] as = model.getActions (object);
190             int i, k = as.length;
191             for (i = 0; i < k; i++) {
192                 if (as [i] == null) continue;
193                 Object JavaDoc key = as [i].getValue (Action.ACCELERATOR_KEY);
194                 if ( (key != null) &&
195                      (key.equals (KeyStroke.getKeyStroke ("DELETE")))
196                 ) return as [i].isEnabled ();
197             }
198             return false;
199         } catch (UnknownTypeException e) {
200             // NodeActionsProvider is voluntary
201
return false;
202         }
203     }
204     
205     public boolean canCopy () {
206         return false;
207     }
208     
209     public boolean canCut () {
210         return false;
211     }
212     
213     public void destroy () {
214         try {
215             Action JavaDoc[] as = model.getActions (object);
216             int i, k = as.length;
217             for (i = 0; i < k; i++) {
218                 if (as [i] == null) continue;
219                 Object JavaDoc key = as [i].getValue (Action.ACCELERATOR_KEY);
220                 if ( (key != null) &&
221                      (key.equals (KeyStroke.getKeyStroke ("DELETE")))
222                 ) {
223                     as [i].actionPerformed (null);
224                     return;
225                 }
226             }
227         } catch (UnknownTypeException e) {
228             Throwable JavaDoc t = ErrorManager.getDefault().annotate(e, "Model: "+model);
229             ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, t);
230         }
231     }
232
233     
234     // other methods ...........................................................
235

236     void setObject (Object JavaDoc o) {
237         setObjectNoRefresh (o);
238         refresh ();
239     }
240     
241     private void setObjectNoRefresh (Object JavaDoc o) {
242         object = o;
243         Children ch = getChildren ();
244         if (ch instanceof TreeModelChildren)
245             ((TreeModelChildren) ch).object = o;
246     }
247     
248     public Object JavaDoc getObject () {
249         return object;
250     }
251
252     private Task task;
253     
254     void refresh () {
255         // 1) empty cache
256
synchronized (properties) {
257             properties.clear();
258         }
259         
260         
261         // 2) refresh name, displayName and iconBase
262
if (task == null) {
263             task = getRequestProcessor ().create (new Runnable JavaDoc () {
264                 public void run () {
265                     refreshNode ();
266                     fireShortDescriptionChange(null, null);
267                     
268                     // 3) refresh children
269
refreshTheChildren(true);
270                 }
271             });
272         }
273         task.schedule(0);
274     }
275     
276     void refresh (int changeMask) {
277         if (changeMask == 0xFFFFFFFF) {
278             refresh();
279             return ;
280         }
281         if ((ModelEvent.NodeChanged.DISPLAY_NAME_MASK & changeMask) != 0) {
282             try {
283                 String JavaDoc name = model.getDisplayName (object);
284                 if (name == null) {
285                     Throwable JavaDoc t =
286                         new NullPointerException JavaDoc (
287                             "Model: " + model + ".getDisplayName (" + object +
288                             ") = null!"
289                         );
290                     ErrorManager.getDefault().notify(t);
291                 }
292                 setName (name, false);
293             } catch (UnknownTypeException e) {
294                 Throwable JavaDoc t = ErrorManager.getDefault().annotate(e, "Model: "+model);
295                 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, t);
296             }
297         } else if ((ModelEvent.NodeChanged.ICON_MASK & changeMask) != 0) {
298             try {
299                 String JavaDoc iconBase = model.getIconBase (object);
300                 if (iconBase != null)
301                     setIconBase (iconBase);
302                 else
303                     setIconBaseWithExtension ("org/openide/resources/actions/empty.gif");
304             } catch (UnknownTypeException e) {
305                 Throwable JavaDoc t = ErrorManager.getDefault().annotate(e, "Model: "+model);
306                 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, t);
307             }
308         } else if ((ModelEvent.NodeChanged.SHORT_DESCRIPTION_MASK & changeMask) != 0) {
309             fireShortDescriptionChange(null, null);
310         } else if ((ModelEvent.NodeChanged.CHILDREN_MASK & changeMask) != 0) {
311             getRequestProcessor ().post (new Runnable JavaDoc () {
312                 public void run () {
313                     refreshTheChildren(false);
314                 }
315             });
316         } else {
317             refresh();
318         }
319     }
320     
321     private static RequestProcessor requestProcessor;
322     public static RequestProcessor getRequestProcessor () {
323         if (requestProcessor == null)
324             requestProcessor = new RequestProcessor ("TreeModel");
325         return requestProcessor;
326     }
327
328     private void setName (String JavaDoc name, boolean italics) {
329         // XXX HACK: HTMLDisplayName is missing in the models!
330
String JavaDoc oldHtmlDisplayName = htmlDisplayName;
331         String JavaDoc oldDisplayName = getDisplayName();
332         
333         String JavaDoc newDisplayName;
334         if (name.startsWith ("<html>")) {
335             htmlDisplayName = name;
336             newDisplayName = removeHTML(name);
337         } else {
338             htmlDisplayName = null;
339             newDisplayName = name;
340         }
341         if ((oldDisplayName == null) || !oldDisplayName.equals(newDisplayName)) {
342             setDisplayName(newDisplayName);
343         } else {
344             if (oldHtmlDisplayName != null && !oldHtmlDisplayName.equals(htmlDisplayName) ||
345                 htmlDisplayName != null && !htmlDisplayName.equals(oldHtmlDisplayName)) {
346                 
347                 // Display names are equal, but HTML display names differ!
348
// We hope that this is sufficient to refresh the HTML display name:
349
fireDisplayNameChange(oldDisplayName + "_HACK", getDisplayName());
350             }
351         }
352     }
353     
354     private void refreshNode () {
355         try {
356             String JavaDoc name = model.getDisplayName (object);
357             if (name == null) {
358                 Throwable JavaDoc t =
359                     new NullPointerException JavaDoc (
360                         "Model: " + model + ".getDisplayName (" + object +
361                         ") = null!"
362                     );
363                 ErrorManager.getDefault().notify(t);
364             }
365             setName (name, false);
366             String JavaDoc iconBase = model.getIconBase (object);
367             if (iconBase != null)
368                 setIconBase (iconBase);
369             else
370                 setIconBaseWithExtension ("org/openide/resources/actions/empty.gif");
371             firePropertyChange(null, null, null);
372         } catch (UnknownTypeException e) {
373             Throwable JavaDoc t = ErrorManager.getDefault().annotate(e, "Model: "+model);
374             ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, t);
375         }
376     }
377     
378     void refreshColumn(String JavaDoc column) {
379         synchronized (properties) {
380             properties.remove(column);
381             properties.remove(column + "#html");
382         }
383         firePropertyChange(column, null, null);
384     }
385     
386     private void refreshTheChildren(boolean refreshSubNodes) {
387         Children ch = getChildren();
388         try {
389             if (ch instanceof TreeModelChildren) {
390                 ((TreeModelChildren) ch).refreshChildren(refreshSubNodes);
391             } else if (!model.isLeaf (object)) {
392                 setChildren(new TreeModelChildren (model, treeModelRoot, object));
393             }
394         } catch (UnknownTypeException utex) {
395             // not known - do not change children
396
if (!(object instanceof String JavaDoc)) {
397                 Throwable JavaDoc t = ErrorManager.getDefault().annotate(utex, "Model: "+model);
398                 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, t);
399             }
400             setChildren(Children.LEAF);
401         }
402     }
403     
404     private static String JavaDoc i (String JavaDoc text) {
405         if (text.startsWith ("<html>")) {
406             if (text.indexOf ("<i>") > 0) return text;
407             text = text.substring (6, text.length () - 7);
408         }
409         return "<html><font color=666666>" + text + "</font></html>";
410     }
411     
412     private static String JavaDoc htmlValue (String JavaDoc name) {
413         if (!name.startsWith ("<html>")) return null;
414         if (name.length() > MAX_HTML_LENGTH) {
415             int endTagsPos = findEndTagsPos(name);
416             String JavaDoc ending = name.substring(endTagsPos + 1);
417             name = name.substring(0, MAX_HTML_LENGTH - 3 - ending.length());
418             // Check whether we haven't cut "&...;" in between:
419
int n = name.length();
420             for (int i = n - 1; i > n - 6; i--) {
421                 if (name.charAt(i) == ';') {
422                     break; // We have an end of the group
423
}
424                 if (name.charAt(i) == '&') {
425                     name = name.substring(0, i);
426                     break;
427                 }
428             }
429             name += "..." + ending;
430         }
431         return name;
432     }
433     
434     private static int findEndTagsPos(String JavaDoc s) {
435         int openings = 0;
436         int i;
437         for (i = s.length() - 1; i >= 0; i--) {
438             if (s.charAt(i) == '>') openings++;
439             else if (s.charAt(i) == '<') openings--;
440             else if (openings == 0) break;
441         }
442         return i;
443     }
444     
445     private static String JavaDoc removeHTML (String JavaDoc text) {
446         text = text.replaceAll ("<i>", "");
447         text = text.replaceAll ("</i>", "");
448         text = text.replaceAll ("<b>", "");
449         text = text.replaceAll ("</b>", "");
450         text = text.replaceAll ("<html>", "");
451         text = text.replaceAll ("</html>", "");
452         text = text.replaceAll ("</font>", "");
453         int i = text.indexOf ("<font");
454         while (i >= 0) {
455             int j = text.indexOf (">", i);
456             text = text.substring (0, i) + text.substring (j + 1);
457             i = text.indexOf ("<font");
458         }
459         text = text.replaceAll ("&lt;", "<");
460         text = text.replaceAll ("&gt;", ">");
461         text = text.replaceAll ("&amp;", "&");
462         return text;
463     }
464     
465     
466     // innerclasses ............................................................
467

468     /** Special locals subnodes (children) */
469     private static final class TreeModelChildren extends Children.Keys
470                                                  implements LazyEvaluator.Evaluable {
471             
472         private boolean initialezed = false;
473         private Models.CompoundModel model;
474         private TreeModelRoot treeModelRoot;
475         private Object JavaDoc object;
476         private WeakHashMap JavaDoc objectToNode = new WeakHashMap JavaDoc ();
477         private int[] evaluated = { 0 }; // 0 - not yet, 1 - evaluated, -1 - timeouted
478
private Object JavaDoc[] children_evaluated;
479         private boolean refreshingSubNodes = true;
480         private boolean refreshingStarted = true;
481         
482         private static final Object JavaDoc WAIT_KEY = new Object JavaDoc();
483         
484         
485         TreeModelChildren (
486             Models.CompoundModel model,
487             TreeModelRoot treeModelRoot,
488             Object JavaDoc object
489         ) {
490             this.model = model;
491             this.treeModelRoot = treeModelRoot;
492             this.object = object;
493         }
494         
495         protected void addNotify () {
496             initialezed = true;
497             refreshChildren (true);
498         }
499         
500         protected void removeNotify () {
501             initialezed = false;
502             setKeys (Collections.EMPTY_SET);
503         }
504         
505         void refreshChildren (boolean refreshSubNodes) {
506             if (!initialezed) return;
507
508             refreshLazyChildren(refreshSubNodes);
509         }
510         
511         public void evaluateLazily(Runnable JavaDoc evaluatedNotify) {
512             synchronized (evaluated) {
513                 refreshingStarted = false;
514             }
515             Object JavaDoc[] ch;
516             try {
517                 int count = model.getChildrenCount (object);
518                 ch = model.getChildren (
519                     object,
520                     0,
521                     count
522                 );
523             } catch (UnknownTypeException e) {
524                 ch = new Object JavaDoc [0];
525                 if (!(object instanceof String JavaDoc)) {
526                     Throwable JavaDoc t = ErrorManager.getDefault().annotate(e, "Model: "+model);
527                     ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, t);
528                 }
529             } catch (ThreadDeath JavaDoc td) {
530                 throw td;
531             } catch (Throwable JavaDoc t) {
532                 // recover from defect in getChildren()
533
// Otherwise there would remain "Please wait..." node.
534
ErrorManager.getDefault().notify(t);
535                 ch = new Object JavaDoc[0];
536             }
537             evaluatedNotify.run();
538             boolean fire;
539             synchronized (evaluated) {
540                 int eval = evaluated[0];
541                 if (refreshingStarted) {
542                     fire = false;
543                 } else {
544                     fire = evaluated[0] == -1;
545                     if (!fire) {
546                         children_evaluated = ch;
547                     }
548                     evaluated[0] = 1;
549                     evaluated.notifyAll();
550                 }
551                 //System.err.println(this.hashCode()+" evaluateLazily() ready, evaluated[0] = "+eval+" => fire = "+fire+", refreshingStarted = "+refreshingStarted+", children_evaluated = "+(children_evaluated != null));
552
}
553             if (fire) {
554                 applyChildren(ch, refreshingSubNodes);
555             }
556         }
557         
558         private void refreshLazyChildren (boolean refreshSubNodes) {
559             synchronized (evaluated) {
560                 evaluated[0] = 0;
561                 refreshingStarted = true;
562                 this.refreshingSubNodes = refreshSubNodes;
563                 //System.err.println(this.hashCode()+" refreshLazyChildren() started = true, evaluated = 0");
564
}
565             // It's refresh => do not check for this children already being evaluated
566
treeModelRoot.getChildrenEvaluator().evaluate(this, false);
567             Object JavaDoc[] ch;
568             synchronized (evaluated) {
569                 if (evaluated[0] != 1) {
570                     try {
571                         evaluated.wait(200);
572                     } catch (InterruptedException JavaDoc iex) {}
573                     if (evaluated[0] != 1) {
574                         evaluated[0] = -1; // timeout
575
ch = null;
576                     } else {
577                         ch = children_evaluated;
578                     }
579                 } else {
580                     ch = children_evaluated;
581                 }
582                 //System.err.println(this.hashCode()+" refreshLazyChildren() ending, evaluated[0] = "+evaluated[0]+", refreshingStarted = "+refreshingStarted+", children_evaluated = "+(children_evaluated != null)+", ch = "+(ch != null));
583
// Do nothing when it's evaluated, but already unset.
584
if (children_evaluated == null && evaluated[0] == 1) return;
585                 children_evaluated = null;
586             }
587             if (ch == null) {
588                 applyWaitChildren();
589             } else {
590                 applyChildren(ch, refreshSubNodes);
591             }
592         }
593         
594         private void applyChildren(final Object JavaDoc[] ch, boolean refreshSubNodes) {
595             //System.err.println(this.hashCode()+" applyChildren("+refreshSubNodes+")");
596
int i, k = ch.length;
597             WeakHashMap JavaDoc newObjectToNode = new WeakHashMap JavaDoc ();
598             for (i = 0; i < k; i++) {
599                 if (ch [i] == null) {
600                     throw (NullPointerException JavaDoc) ErrorManager.getDefault().annotate(
601                             new NullPointerException JavaDoc(),
602                             "model: " + model + "\nparent: " + object);
603                 }
604                 WeakReference JavaDoc wr = (WeakReference JavaDoc) objectToNode.get
605                     (ch [i]);
606                 if (wr == null) continue;
607                 TreeModelNode tmn = (TreeModelNode) wr.get ();
608                 if (tmn == null) continue;
609                 if (refreshSubNodes) {
610                     tmn.setObject (ch [i]);
611                 } else {
612                     tmn.setObjectNoRefresh(ch[i]);
613                 }
614                 newObjectToNode.put (ch [i], wr);
615             }
616             objectToNode = newObjectToNode;
617             setKeys (ch);
618
619             SwingUtilities.invokeLater (new Runnable JavaDoc () {
620                 public void run () {
621                     int i, k = ch.length;
622                     for (i = 0; i < k; i++)
623                         try {
624                             if (model.isExpanded (ch [i])) {
625                                 TreeTable treeTable = treeModelRoot.getTreeTable ();
626                                 if (treeTable.isExpanded(object)) {
627                                     // Expand the child only if the parent is expanded
628
treeTable.expandNode (ch [i]);
629                                 }
630                             }
631                         } catch (UnknownTypeException ex) {
632                         }
633                 }
634             });
635         }
636         
637         private void applyWaitChildren() {
638             //System.err.println(this.hashCode()+" applyWaitChildren()");
639
setKeys(new Object JavaDoc[] { WAIT_KEY });
640         }
641         
642 // protected void destroyNodes (Node[] nodes) {
643
// int i, k = nodes.length;
644
// for (i = 0; i < k; i++) {
645
// TreeModelNode tmn = (TreeModelNode) nodes [i];
646
// String name = null;
647
// try {
648
// name = model.getDisplayName (tmn.object);
649
// } catch (UnknownTypeException e) {
650
// }
651
// if (name != null)
652
// nameToChild.remove (name);
653
// }
654
// }
655

656         protected Node[] createNodes (Object JavaDoc object) {
657             if (object == WAIT_KEY) {
658                 AbstractNode n = new AbstractNode(Children.LEAF);
659                 n.setName(NbBundle.getMessage(TreeModelNode.class, "WaitNode"));
660                 n.setIconBaseWithExtension("org/netbeans/modules/viewmodel/wait.gif");
661                 return new Node[] { n };
662             }
663             if (object instanceof Exception JavaDoc)
664                 return new Node[] {
665                     new ExceptionNode ((Exception JavaDoc) object)
666                 };
667             TreeModelNode tmn = new TreeModelNode (
668                 model,
669                 treeModelRoot,
670                 object
671             );
672             objectToNode.put (object, new WeakReference JavaDoc (tmn));
673             return new Node[] {tmn};
674         }
675     } // ItemChildren
676

677     private class MyProperty extends PropertySupport implements LazyEvaluator.Evaluable {
678         
679         private final String JavaDoc EVALUATING_STR = NbBundle.getMessage(TreeModelNode.class, "EvaluatingProp");
680         private String JavaDoc id;
681         private ColumnModel columnModel;
682         private boolean nodeColumn;
683         private TreeModelRoot treeModelRoot;
684         private int[] evaluated = { 0 }; // 0 - not yet, 1 - evaluated, -1 - timeouted
685

686         
687         MyProperty (
688             ColumnModel columnModel, TreeModelRoot treeModelRoot
689         ) {
690             super (
691                 columnModel.getID (),
692                 (columnModel.getType() == null) ? String JavaDoc.class : columnModel.getType (),
693                 columnModel.getDisplayName (),
694                 columnModel.getShortDescription (),
695                 true,
696                 true
697             );
698             this.columnModel = columnModel;
699             this.nodeColumn = columnModel.getType() == null;
700             this.treeModelRoot = treeModelRoot;
701             id = columnModel.getID ();
702         }
703         
704
705         /* Can write the value of the property.
706         * Returns the value passed into constructor.
707         * @return <CODE>true</CODE> if the read of the value is supported
708         */

709         public boolean canWrite () {
710             if (nodeColumn) return false;
711             try {
712                 return !model.isReadOnly (object, columnModel.getID ());
713             } catch (UnknownTypeException e) {
714                 if (!(object instanceof String JavaDoc)) {
715                     Throwable JavaDoc t = ErrorManager.getDefault().annotate(e, "Column id:" + columnModel.getID ()+"\nModel: "+model);
716                     ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, t);
717                 }
718                 return false;
719             }
720         }
721         
722         public void evaluateLazily(Runnable JavaDoc evaluatedNotify) {
723             Object JavaDoc value = "";
724             String JavaDoc htmlValue = null;
725             String JavaDoc nonHtmlValue = null;
726             try {
727                 value = model.getValueAt (object, id);
728                 //System.out.println(" evaluateLazily("+TreeModelNode.this.getDisplayName()+", "+id+"): have value = "+value);
729
if (value instanceof String JavaDoc) {
730                     htmlValue = htmlValue ((String JavaDoc) value);
731                     nonHtmlValue = removeHTML ((String JavaDoc) value);
732                 }
733             } catch (UnknownTypeException e) {
734                 if (!(object instanceof String JavaDoc)) {
735                     e.printStackTrace ();
736                     System.out.println(" Column id:" + columnModel.getID ());
737                     System.out.println (model);
738                     System.out.println ();
739                 }
740             } catch (Throwable JavaDoc t) {
741                 t.printStackTrace();
742             } finally {
743                 evaluatedNotify.run();
744                 boolean fire;
745                 synchronized (properties) {
746                     if (value instanceof String JavaDoc) {
747                         properties.put (id, nonHtmlValue);
748                         properties.put (id + "#html", htmlValue);
749                     } else {
750                         properties.put (id, value);
751                     }
752                     synchronized (evaluated) {
753                         fire = evaluated[0] == -1;
754                         evaluated[0] = 1;
755                         evaluated.notifyAll();
756                     }
757                 }
758                 //System.out.println("\nTreeModelNode.evaluateLazily("+TreeModelNode.this.getDisplayName()+", "+id+"): value = "+value+", fire = "+fire);
759
if (fire) {
760                     firePropertyChange (id, null, value);
761                     refreshTheChildren(true);
762                 }
763                 
764             }
765         }
766         
767         public synchronized Object JavaDoc getValue () { // Sync the calls
768
if (nodeColumn) {
769                 return TreeModelNode.this.getDisplayName();
770             }
771             // 1) return value from cache
772
synchronized (properties) {
773                 //System.out.println("getValue("+TreeModelNode.this.getDisplayName()+", "+id+"): contains = "+properties.containsKey (id)+", value = "+properties.get (id));
774
if (properties.containsKey (id))
775                     return properties.get (id);
776             }
777             
778             synchronized (evaluated) {
779                 evaluated[0] = 0;
780             }
781             treeModelRoot.getValuesEvaluator().evaluate(this);
782             
783             Object JavaDoc ret = null;
784             boolean refreshChildren = false;
785             
786             synchronized (evaluated) {
787                 if (evaluated[0] != 1) {
788                     try {
789                         evaluated.wait(25);
790                     } catch (InterruptedException JavaDoc iex) {}
791                     if (evaluated[0] != 1) {
792                         evaluated[0] = -1; // timeout
793
ret = EVALUATING_STR;
794                     } else {
795                         refreshChildren = true;
796                     }
797                 }
798             }
799             if (ret == null) {
800                 synchronized (properties) {
801                     ret = properties.get(id);
802                 }
803             }
804             
805             if (refreshChildren) {
806                 RequestProcessor.getDefault().post(new Runnable JavaDoc() {
807                     public void run() {
808                         refreshTheChildren(true);
809                     }
810                 });
811             }
812             if (ret == EVALUATING_STR &&
813                     getValueType() != null && getValueType() != String JavaDoc.class) {
814                 ret = null; // Must not provide String when the property type is different.
815
// htmlDisplayValue attr will assure that the Evaluating str is there.
816
}
817             return ret;
818         }
819         
820         public Object JavaDoc getValue (String JavaDoc attributeName) {
821             if (attributeName.equals ("htmlDisplayValue")) {
822                 if (nodeColumn) {
823                     return TreeModelNode.this.getHtmlDisplayName();
824                 }
825                 synchronized (evaluated) {
826                     if (evaluated[0] != 1) {
827                         return "<html><font color=\"0000CC\">"+EVALUATING_STR+"</font></html>";
828                     }
829                 }
830                 synchronized (properties) {
831                     return properties.get (id + "#html");
832                 }
833             }
834             return super.getValue (attributeName);
835         }
836
837         public String JavaDoc getShortDescription() {
838             if (nodeColumn) {
839                 return TreeModelNode.this.getShortDescription();
840             }
841             synchronized (properties) {
842                 if (!properties.containsKey(id)) {
843                     return null; // The same as value => EVALUATING_STR
844
}
845             }
846             try {
847                 javax.swing.JToolTip JavaDoc tooltip = new javax.swing.JToolTip JavaDoc();
848                 tooltip.putClientProperty("getShortDescription", object); // NOI18N
849
Object JavaDoc tooltipObj = model.getValueAt(tooltip, id);
850                 if (tooltipObj == null) {
851                     return null;
852                 } else {
853                     return tooltipObj.toString();
854                 }
855             } catch (UnknownTypeException e) {
856                 // Ignore models that do not define tooltips for values.
857
return null;
858             }
859         }
860         
861         public void setValue (Object JavaDoc v) throws IllegalAccessException JavaDoc,
862         IllegalArgumentException JavaDoc, java.lang.reflect.InvocationTargetException JavaDoc {
863             try {
864                 model.setValueAt (object, id, v);
865                 synchronized (properties) {
866                     properties.put (id, v);
867                 }
868                 firePropertyChange (id, null, null);
869             } catch (UnknownTypeException e) {
870                 Throwable JavaDoc t = ErrorManager.getDefault().annotate(e, "Column id:" + columnModel.getID ()+"\nModel: "+model);
871                 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, t);
872             }
873         }
874         
875         public PropertyEditor JavaDoc getPropertyEditor () {
876             return columnModel.getPropertyEditor ();
877         }
878     }
879     
880     /** The single-threaded evaluator of lazy models. */
881     static class LazyEvaluator implements Runnable JavaDoc {
882         
883         /** Release the evaluator task after this time. */
884         private static final long EXPIRE_TIME = 60000L;
885
886         private List JavaDoc objectsToEvaluate = new LinkedList JavaDoc();
887         private Evaluable currentlyEvaluating;
888         private Task evalTask;
889         
890         public LazyEvaluator() {
891             evalTask = new RequestProcessor("Debugger Values Evaluator", 1).post(this);
892         }
893         
894         public void evaluate(Evaluable eval) {
895             evaluate(eval, true);
896         }
897         
898         public void evaluate(Evaluable eval, boolean checkForEvaluating) {
899             synchronized (objectsToEvaluate) {
900                 for (Iterator JavaDoc it = objectsToEvaluate.iterator(); it.hasNext(); ) {
901                     if (eval == it.next()) return ; // Already scheduled
902
}
903                 if (checkForEvaluating && currentlyEvaluating == eval) return ; // Is being evaluated
904
objectsToEvaluate.add(eval);
905                 objectsToEvaluate.notify();
906                 if (evalTask.isFinished()) {
907                     evalTask.schedule(0);
908                 }
909             }
910         }
911
912         public void run() {
913             while(true) {
914                 Evaluable eval;
915                 synchronized (objectsToEvaluate) {
916                     if (objectsToEvaluate.size() == 0) {
917                         try {
918                             objectsToEvaluate.wait(EXPIRE_TIME);
919                         } catch (InterruptedException JavaDoc iex) {
920                             return ;
921                         }
922                         if (objectsToEvaluate.size() == 0) { // Expired
923
return ;
924                         }
925                     }
926                     eval = (Evaluable) objectsToEvaluate.remove(0);
927                     currentlyEvaluating = eval;
928                 }
929                 Runnable JavaDoc evaluatedNotify = new Runnable JavaDoc() {
930                     public void run() {
931                         synchronized (objectsToEvaluate) {
932                             currentlyEvaluating = null;
933                         }
934                     }
935                 };
936                 eval.evaluateLazily(evaluatedNotify);
937             }
938         }
939
940         public interface Evaluable {
941
942             public void evaluateLazily(Runnable JavaDoc evaluatedNotify);
943
944         }
945
946     }
947
948 }
949
950
Popular Tags