KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > properties > Element


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
21 package org.netbeans.modules.properties;
22
23
24 import java.beans.*;
25 import java.io.*;
26 import javax.swing.text.BadLocationException JavaDoc;
27
28 import org.openide.nodes.Node;
29 import org.openide.ErrorManager;
30 import org.openide.text.PositionBounds;
31
32
33 /**
34  * Base class for representations of elements in properties files.
35  *
36  * @author Petr Jiricka
37  * @author Petr Kuzel - moved to nonescaped strings level
38  * //!!! why is it serializable?
39  */

40 public abstract class Element implements Serializable {
41
42     /** Property change support */
43     private transient PropertyChangeSupport support = new PropertyChangeSupport(this);
44
45     /** Position of the begin and the end of the element. Could
46      * be null indicating the element is not part of properties structure yet. */

47     protected PositionBounds bounds;
48
49     
50     /** Create a new element. */
51     protected Element(PositionBounds bounds) {
52         this.bounds = bounds;
53     }
54
55     
56     /** Getter for bounds property. */
57     public PositionBounds getBounds() {
58         return bounds;
59     }
60
61     /**
62      * Updates the element fields. This method is called after reparsing.
63      * @param elem the element to merge with
64      */

65     void update(Element elem) {
66         this.bounds = elem.bounds;
67     }
68
69     /** Fires property change event.
70      * @param name property name
71      * @param o old value
72      * @param n new value
73      */

74     protected final void firePropertyChange(String JavaDoc name, Object JavaDoc o, Object JavaDoc n) {
75         support.firePropertyChange (name, o, n);
76     }
77
78     /** Adds property listener */
79     public void addPropertyChangeListener (PropertyChangeListener l) {
80         support.addPropertyChangeListener (l);
81     }
82
83     /** Removes property listener */
84     public void removePropertyChangeListener (PropertyChangeListener l) {
85         support.removePropertyChangeListener (l);
86     }
87
88     /** Prints this element (and all its subelements) by calling <code>bounds.setText(...)</code>
89      * If <code>bounds</code> is null does nothing.
90      * @see #bounds */

91     public final void print() {
92         if (bounds == null) {
93             return;
94         }
95         try {
96             bounds.setText(getDocumentString());
97         } catch (BadLocationException JavaDoc e) {
98             ErrorManager.getDefault().notify(e);
99         } catch (IOException e) {
100             ErrorManager.getDefault().notify(e);
101         }
102     }
103
104     /**
105      * Get a string representation of the element for printing into Document.
106      * It currently means that it's properly escaped.
107      * @return the string in its Document form
108      */

109     public abstract String JavaDoc getDocumentString();
110
111     /**
112      * Get debug string of the element.
113      * @return the string
114      */

115     public String JavaDoc toString() {
116         if (bounds == null) {
117             return "(no bounds)";
118         }
119         return new StringBuffer JavaDoc(16)
120                 .append('(')
121                 .append(bounds.getBegin().getOffset())
122                 .append(", ") //NOI18N
123
.append(bounds.getEnd().getOffset())
124                 .append(')')
125                 .toString();
126     }
127
128     
129     /** General class for basic elements, which contain value directly. */
130     public static abstract class Basic extends Element {
131
132         /** Parsed value of the element */
133         protected String JavaDoc value;
134
135         /** Create a new basic element. */
136         protected Basic(PositionBounds bounds, String JavaDoc value) {
137             super(bounds);
138             this.value = value;
139         }
140
141         /**
142          * Updates the element fields. This method is called after reparsing.
143          * @param elem elemnet to merge with
144          */

145         void update(Element elem) {
146             super.update(elem);
147             this.value = ((Basic)elem).value;
148         }
149
150         /** Get a string representation of the element.
151          * @return the string + bounds
152          */

153         public String JavaDoc toString() {
154             return value + " " + super.toString(); // NOI18N
155
}
156
157         /**
158          * Get a value of the element.
159          * @return the Java string (no escaping)
160          */

161         public String JavaDoc getValue() {
162             return value;
163         }
164
165         /**
166          * Sets the value. Does not check if the value has changed.
167          * The value is immediately propadated in text Document possibly
168          * triggering DocumentEvents.
169          * @param value Java string (no escaping)
170          */

171         public void setValue(String JavaDoc value) {
172             this.value = value;
173             this.print();
174         }
175
176     } // End of nested class Basic.
177

178
179     /** Class representing key element in properties file. */
180     public static class KeyElem extends Basic {
181
182         /** Generated serial version UID. */
183         static final long serialVersionUID =6828294289485744331L;
184         
185         
186         /** Create a new key element. */
187         protected KeyElem(PositionBounds bounds, String JavaDoc value) {
188             super(bounds, value);
189         }
190
191         
192         /** Get a string representation of the key for printing. Treats the '=' sign as a part of the key
193         * @return the string
194         */

195         public String JavaDoc getDocumentString() {
196             return UtilConvert.saveConvert(value, true) + "=";
197         }
198     } // End of nested class KeyElem.
199

200
201     /** Class representing value element in properties files. */
202     public static class ValueElem extends Basic {
203
204         /** Generated serial version UID. */
205         static final long serialVersionUID =4662649023463958853L;
206         
207         /** Create a new value element. */
208         protected ValueElem(PositionBounds bounds, String JavaDoc value) {
209             super(bounds, value);
210         }
211
212         /** Get a string representation of the value for printing. Appends end of the line after the value.
213         * @return the string
214         */

215         public String JavaDoc getDocumentString() {
216             // escape outerspaces and continious line marks
217
return UtilConvert.saveConvert(value) + "\n";
218         }
219     } // End of nested class ValueElem.
220

221     /**
222      * Class representing comment element in properties files. <code>null</code> values of the
223      * string are legal and indicate that the comment is empty. It should contain
224      * pure comment string without comment markers.
225      */

226     public static class CommentElem extends Basic {
227
228         /** Genererated serial version UID. */
229         static final long serialVersionUID =2418308580934815756L;
230         
231         
232         /**
233          * Create a new comment element.
234          * @param value Comment without its markers (leading '#' or '!'). Markers
235          * are automatically prepended while writing it down to Document.
236          */

237         protected CommentElem(PositionBounds bounds, String JavaDoc value) {
238             super(bounds, value);
239         }
240
241         
242         /** Get a string representation of the comment for printing. Makes sure every non-empty line starts with a # and
243         * that the last line is terminated with an end of line marker.
244         * @return the string
245         */

246         public String JavaDoc getDocumentString() {
247             if (value == null || value.length() == 0)
248                 return ""; // NOI18N
249
else {
250                 // insert #s at the beginning of the lines which contain non-blank characters
251
// holds the last position where we might have to insert a # if this line contains non-blanks
252
StringBuffer JavaDoc sb = new StringBuffer JavaDoc(value);
253                 // append the \n if missing
254
if (sb.charAt(sb.length() - 1) != '\n') {
255                     sb.append('\n');
256                 }
257                 int lineStart = 0;
258                 boolean hasCommentChar = false;
259                 for (int i=0; i<sb.length(); i++) {
260                     char aChar = sb.charAt(i);
261                     // new line
262
if (aChar == '\n') {
263                         String JavaDoc line = sb.substring(lineStart, i);
264                         String JavaDoc convertedLine = UtilConvert.saveConvert(line);
265                         sb.replace(lineStart, i, convertedLine);
266
267                         // shift the index:
268
i += convertedLine.length() - line.length();
269
270                         // the next line starts after \n:
271
lineStart = i + 1;
272
273                         hasCommentChar = false;
274                     } else if (!hasCommentChar
275                           && UtilConvert.whiteSpaceChars.indexOf(aChar) == -1) {
276                         // nonempty symbol
277
if ((aChar == '#') || (aChar == '!')) {
278                             lineStart = i + 1;
279                         } else {
280                             // insert a #
281
sb.insert(lineStart, '#');
282                             i++;
283                             lineStart = i;
284                         }
285                         hasCommentChar = true;
286                     }
287                 }
288                 return sb.toString();
289             }
290         }
291     } // End of nested CommentElem.
292

293
294     /**
295      * Class representing element in properties file. Each element contains comment (preceding the property),
296      * key and value subelement.
297      */

298     public static class ItemElem extends Element implements Node.Cookie {
299
300         /** Key element. */
301         private KeyElem key;
302         
303         /** Value element. */
304         private ValueElem value;
305         
306         /** Comment element. */
307         private CommentElem comment;
308         
309         /** Parent of this element - active element has a non-null parent. */
310         private PropertiesStructure parent;
311
312         /** Name of the Key property */
313         public static final String JavaDoc PROP_ITEM_KEY = "key"; // NOI18N
314
/** Name of the Value property */
315         public static final String JavaDoc PROP_ITEM_VALUE = "value"; // NOI18N
316
/** Name of the Comment property */
317         public static final String JavaDoc PROP_ITEM_COMMENT = "comment"; // NOI18N
318

319         /** Generated serial version UID. */
320         static final long serialVersionUID =1078147817847520586L;
321
322         
323         /** Create a new basic element. <code>key</code> and <code>value</code> may be null. */
324         protected ItemElem(PositionBounds bounds, KeyElem key, ValueElem value, CommentElem comment) {
325             super(bounds);
326             this.key = key;
327             this.value = value;
328             this.comment = comment;
329         }
330
331         
332         /** Sets the parent of this element. */
333         void setParent(PropertiesStructure ps) {
334             parent = ps;
335         }
336
337         /** Gets parent.
338          * @exception IllegalStateException if the parent is <code>null</code>. */

339         private PropertiesStructure getParent() {
340             if(parent == null) {
341                 throw new IllegalStateException JavaDoc("Resource Bundle: Parent is missing"); // NOI18N
342
}
343
344             return parent;
345         }
346
347         /** Get a value string of the element.
348          * @return the string
349          */

350         public String JavaDoc toString() {
351             return comment.toString() + "\n" + // NOI18N
352
((key == null) ? "" : key.toString()) + "\n" + // NOI18N
353
((value == null) ? "" : value.toString()) + "\n"; // NOI18N
354
}
355
356         /** Returns the key element for this item. */
357         public KeyElem getKeyElem() {
358             return key;
359         }
360
361         /** Returns the value element for this item. */
362         public ValueElem getValueElem() {
363             return value;
364         }
365
366         /** Returns the comment element for this item. */
367         public CommentElem getCommentElem() {
368             return comment;
369         }
370
371         void update(Element elem) {
372             super.update(elem);
373             if (this.key == null)
374                 this.key = ((ItemElem)elem).key;
375             else
376                 this.key.update(((ItemElem)elem).key);
377
378             if (this.value == null)
379                 this.value = ((ItemElem)elem).value;
380             else
381                 this.value.update(((ItemElem)elem).value);
382
383             this.comment.update(((ItemElem)elem).comment);
384         }
385
386         public String JavaDoc getDocumentString() {
387             return comment.getDocumentString() +
388                 ((key == null) ? "" : key.getDocumentString()) + // NOI18N
389
((value == null) ? "" : value.getDocumentString()); // NOI18N
390
}
391
392         /** Get a key by which to identify this record
393          * @return nonescaped key
394          */

395         public String JavaDoc getKey() {
396             return (key == null) ? null : key.getValue();
397         }
398
399         /** Set the key for this item
400         * @param newKey nonescaped key
401         */

402         public void setKey(String JavaDoc newKey) {
403             String JavaDoc oldKey = key.getValue();
404             if (!oldKey.equals(newKey)) {
405                 key.setValue(newKey);
406                 getParent().itemKeyChanged(oldKey, this);
407                 this.firePropertyChange(PROP_ITEM_KEY, oldKey, newKey);
408             }
409         }
410
411         /** Get the value of this item */
412         public String JavaDoc getValue() {
413             return (value == null) ? null : value.getValue();
414         }
415
416         /** Set the value of this item
417          * @param newValue the new value
418          */

419         public void setValue(String JavaDoc newValue) {
420             String JavaDoc oldValue = value.getValue();
421             if (!oldValue.equals(newValue)) {
422                 
423                 if(oldValue.equals("")) // NOI18N
424
// Reprint key for the case it's alone yet and doesn't have seprator after (= : or whitespace).
425
key.print();
426                 
427                 value.setValue(newValue);
428                 getParent().itemChanged(this);
429                 this.firePropertyChange(PROP_ITEM_VALUE, oldValue, newValue);
430             }
431         }
432
433         /** Get the comment for this item */
434         public String JavaDoc getComment() {
435             return (comment == null) ? null : comment.getValue();
436         }
437
438         /** Set the comment for this item
439          * @param newComment the new comment (escaped value)
440          * //??? why is required escaped value? I'd expect escapng to be applied during
441          * writing value down to stream no earlier
442          */

443         public void setComment(String JavaDoc newComment) {
444             String JavaDoc oldComment = comment.getValue();
445             if ((oldComment == null && newComment != null) || (oldComment != null && !oldComment.equals(newComment))) {
446                 comment.setValue(newComment);
447                 getParent().itemChanged(this);
448                 this.firePropertyChange(PROP_ITEM_COMMENT, oldComment, newComment);
449             }
450         }
451
452         /** Checks for equality of two ItemElem-s */
453         public boolean equals(Object JavaDoc item) {
454             if (item == null || !(item instanceof ItemElem))
455                 return false;
456             ItemElem ie = (ItemElem)item;
457             if ( ((key==null && ie.getKeyElem()==null) || (key!=null && ie.getKeyElem()!=null && getKey().equals(ie.getKey())) ) &&
458                  ((value==null && ie.getValueElem()==null) || (value!=null && ie.getValueElem()!=null && getValue().equals(ie.getValue())) ) &&
459                  ((comment==null && ie.getCommentElem()==null) || (comment!=null && ie.getCommentElem()!=null && getComment().equals(ie.getComment())) ) )
460                 return true;
461             return false;
462         }
463     } // End of nested class ItemElem.
464
}
465
Popular Tags