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-2006 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: package org.netbeans.tax;
042:
043: import org.netbeans.tax.event.TreeEventManager; // import org.netbeans.tax.grammar.Grammar; // will be ...
044:
045: import org.netbeans.tax.spec.Document;
046: import org.netbeans.tax.event.TreeEventManager;
047:
048: /**
049: *
050: * @author Libor Kramolis
051: * @version 0.1
052: */
053: public class TreeDocument extends AbstractTreeDocument implements
054: TreeDocumentRoot {
055:
056: /** */
057: public static final String PROP_VERSION = "version"; // NOI18N
058: /** */
059: public static final String PROP_ENCODING = "encoding"; // NOI18N
060: /** */
061: public static final String PROP_STANDALONE = "standalone"; // NOI18N
062:
063: /** Own event manager. */
064: private TreeEventManager eventManager;
065:
066: /** -- can be null. */
067: private String version;
068:
069: /** -- can be null. */
070: private String encoding;
071:
072: /** -- can be null. */
073: private String standalone;
074:
075: /** -- can be null. */
076: // private Grammar grammar; // will be ...
077: /** -- can be null. */
078: private TreeDocumentType documentType; //cache of some child node
079:
080: /** -- can be null. */
081: private TreeElement rootElement; //cache of some child node
082:
083: //
084: // init
085: //
086:
087: /**
088: * Creates new TreeDocument.
089: * @throws InvalidArgumentException
090: */
091: public TreeDocument(String version, String encoding,
092: String standalone) throws InvalidArgumentException {
093: super ();
094:
095: checkVersion(version);
096: checkEncoding(encoding);
097: checkStandalone(standalone);
098: checkHeader(version, encoding, standalone);
099:
100: this .version = version;
101: this .encoding = encoding;
102: this .standalone = standalone;
103: this .eventManager = new TreeEventManager();
104:
105: this .documentType = null;
106: this .rootElement = null;
107: }
108:
109: /**
110: * Creates new TreeDocument.
111: * @throws InvalidArgumentException
112: */
113: public TreeDocument() throws InvalidArgumentException {
114: this (null, null, null); // Q: is it valid? A: yes, header is not mandatory
115: }
116:
117: /** Creates new TreeDocument -- copy constructor. */
118: protected TreeDocument(TreeDocument document, boolean deep) {
119: super (document, deep);
120:
121: this .version = document.version;
122: this .encoding = document.encoding;
123: this .standalone = document.standalone;
124: this .eventManager = new TreeEventManager(document.eventManager);
125: }
126:
127: //
128: // from TreeObject
129: //
130:
131: /**
132: */
133: public Object clone(boolean deep) {
134: return new TreeDocument(this , deep);
135: }
136:
137: /**
138: */
139: public boolean equals(Object object, boolean deep) {
140: if (!!!super .equals(object, deep))
141: return false;
142:
143: TreeDocument peer = (TreeDocument) object;
144: if (!!!Util.equals(this .getVersion(), peer.getVersion()))
145: return false;
146: if (!!!Util.equals(this .getEncoding(), peer.getEncoding()))
147: return false;
148: if (!!!Util.equals(this .getStandalone(), peer.getStandalone()))
149: return false;
150: if (!!!Util.equals(this .documentType, peer.documentType))
151: return false;
152: if (!!!Util.equals(this .rootElement, peer.rootElement))
153: return false;
154:
155: return true;
156: }
157:
158: /*
159: * Merges following paroperties: version, encoding and standlaone.
160: * Reassignes caches (root, doctype) since all events are already fired
161: * during merging superclass TreeObjectList.
162: */
163: public void merge(TreeObject treeObject)
164: throws CannotMergeException {
165: if (Util.THIS.isLoggable()) /* then */
166: Util.THIS.debug("TreeDocument::merge: " + treeObject);//, new RuntimeException ()); // NOI18N
167:
168: super .merge(treeObject);
169:
170: TreeDocument peer = (TreeDocument) treeObject;
171:
172: try {
173: setVersionImpl(peer.getVersion());
174: setEncodingImpl(peer.getEncoding());
175: setStandaloneImpl(peer.getStandalone());
176: } catch (Exception exc) {
177: throw new CannotMergeException(treeObject, exc);
178: }
179:
180: // just to be sure that we never miss
181: TreeEventManager manager = getEventManager();
182: if (manager != null) {
183: manager.setFirePolicy(TreeEventManager.FIRE_NOW);
184: }
185:
186: }
187:
188: //
189: // itself
190: //
191:
192: /**
193: */
194: public final String getVersion() {
195: return version;
196: }
197:
198: /**
199: */
200: private final void setVersionImpl(String newVersion) {
201: String oldVersion = this .version;
202:
203: this .version = newVersion;
204:
205: firePropertyChange(PROP_VERSION, oldVersion, newVersion);
206: }
207:
208: /**
209: * @throws ReadOnlyException
210: * @throws InvalidArgumentException
211: */
212: public final void setVersion(String newVersion)
213: throws ReadOnlyException, InvalidArgumentException {
214: //
215: // check new value
216: //
217: if (Util.equals(this .version, newVersion))
218: return;
219: checkReadOnly();
220: checkVersion(newVersion);
221: checkHeader(newVersion, this .encoding, this .standalone);
222:
223: //
224: // set new value
225: //
226: setVersionImpl(newVersion);
227: }
228:
229: /**
230: */
231: protected final void checkVersion(String version)
232: throws InvalidArgumentException {
233: TreeUtilities.checkDocumentVersion(version);
234: }
235:
236: /**
237: */
238: public final String getEncoding() {
239: return encoding;
240: }
241:
242: /**
243: */
244: private final void setEncodingImpl(String newEncoding) {
245: String oldEncoding = this .encoding;
246:
247: this .encoding = newEncoding;
248:
249: firePropertyChange(PROP_ENCODING, oldEncoding, newEncoding);
250: }
251:
252: /**
253: * @throws ReadOnlyException
254: * @throws InvalidArgumentException
255: */
256: public final void setEncoding(String newEncoding)
257: throws ReadOnlyException, InvalidArgumentException {
258: //
259: // check new value
260: //
261: if (Util.equals(this .encoding, newEncoding))
262: return;
263: checkReadOnly();
264: checkEncoding(newEncoding);
265: checkHeader(this .version, newEncoding, this .standalone);
266:
267: //
268: // set new value
269: //
270: setEncodingImpl(newEncoding);
271: }
272:
273: /**
274: */
275: protected final void checkEncoding(String encoding)
276: throws InvalidArgumentException {
277: TreeUtilities.checkDocumentEncoding(encoding);
278: }
279:
280: /**
281: */
282: public final String getStandalone() {
283: return standalone;
284: }
285:
286: /**
287: */
288: private final void setStandaloneImpl(String newStandalone) {
289: String oldStandalone = this .standalone;
290:
291: this .standalone = newStandalone;
292:
293: firePropertyChange(PROP_STANDALONE, oldStandalone,
294: newStandalone);
295: }
296:
297: /**
298: * @throws ReadOnlyException
299: * @throws InvalidArgumentException
300: */
301: public final void setStandalone(String newStandalone)
302: throws ReadOnlyException, InvalidArgumentException {
303: //
304: // check new value
305: //
306: if (Util.equals(this .standalone, newStandalone))
307: return;
308: checkReadOnly();
309: checkStandalone(newStandalone);
310: checkHeader(this .version, this .encoding, newStandalone);
311:
312: //
313: // set new value
314: //
315: setStandaloneImpl(newStandalone);
316: }
317:
318: /**
319: */
320: protected final void checkStandalone(String standalone)
321: throws InvalidArgumentException {
322: TreeUtilities.checkDocumentStandalone(standalone);
323: }
324:
325: /**
326: */
327: /* private final void setHeaderImpl (String newVersion, String newEncoding, String newStandalone) {
328: String oldVersion = this.version;
329: String oldEncoding = this.encoding;
330: String oldStandalone = this.standalone;
331:
332: this.version = newVersion;
333: this.encoding = newEncoding;
334: this.standalone = newStandalone;
335:
336: firePropertyChange (PROP_VERSION, oldVersion, newVersion);
337: firePropertyChange (PROP_ENCODING, oldEncoding, newEncoding);
338: firePropertyChange (PROP_STANDALONE, oldStandalone, newStandalone);
339: }*/
340:
341: /**
342: * @throws ReadOnlyException
343: * @throws InvalidArgumentException
344: */
345: public final void setHeader(String newVersion, String newEncoding,
346: String newStandalone) throws ReadOnlyException,
347: InvalidArgumentException {
348: //
349: // check new value
350: //
351: boolean setVersion = !!!Util.equals(this .version, newVersion);
352: boolean setEncoding = !!!Util
353: .equals(this .encoding, newEncoding);
354: boolean setStandalone = !!!Util.equals(this .standalone,
355: newStandalone);
356: if (!!!setVersion && !!!setEncoding && !!!setStandalone) {
357: return;
358: }
359: checkReadOnly();
360: if (setVersion) {
361: checkVersion(newVersion);
362: }
363: if (setEncoding) {
364: checkEncoding(newEncoding);
365: }
366: if (setStandalone) {
367: checkStandalone(newStandalone);
368: }
369: checkHeader(newVersion, newEncoding, newStandalone);
370:
371: //
372: // set new value
373: //
374: if (setVersion) {
375: setVersionImpl(newVersion);
376: }
377: if (setEncoding) {
378: setEncodingImpl(newEncoding);
379: }
380: if (setStandalone) {
381: setStandaloneImpl(newStandalone);
382: }
383: }
384:
385: /**
386: */
387: protected final void checkHeader(String version, String encoding,
388: String standalone) throws InvalidArgumentException {
389: if ((version == null)
390: && ((encoding != null) || (standalone != null))) {
391: throw new InvalidArgumentException(Util.THIS
392: .getString("EXC_invalid_document_header"),
393: new NullPointerException());
394: }
395: }
396:
397: //
398: // grammar // will be ...
399: //
400:
401: // /**
402: // */
403: // public final Grammar getGrammar () {
404: // return grammar;
405: // }
406:
407: //
408: // event model
409: //
410:
411: /**
412: */
413: public final TreeEventManager getRootEventManager() {
414: return eventManager;
415: }
416:
417: //
418: // itself
419: //
420:
421: /**
422: */
423: public final TreeDocumentType getDocumentType() {
424: return documentType;
425: }
426:
427: /**
428: * Update cache and propagate new DOCTYPE into children.
429: * @throws ReadOnlyException
430: * @throws InvalidArgumentException
431: */
432: public final void setDocumentType(TreeDocumentType newDocumentType)
433: throws ReadOnlyException, InvalidArgumentException {
434: if (newDocumentType == null) {
435: removeChild(this .documentType);
436: } else if (this .documentType == null) {
437: if (this .rootElement == null) {
438: appendChild(newDocumentType);
439: } else {
440: insertChildAt(newDocumentType, 0);
441: }
442: } else {
443: replaceChild(this .documentType, newDocumentType);
444: }
445: }
446:
447: /**
448: */
449: public final TreeElement getDocumentElement() {
450: return rootElement;
451: }
452:
453: /**
454: * Update cache and propagate new root element into children.
455: * @throws ReadOnlyException
456: * @throws InvalidArgumentException
457: */
458: public final void setDocumentElement(TreeElement newElement)
459: throws ReadOnlyException, InvalidArgumentException {
460: if (Util.THIS.isLoggable()) /* then */
461: Util.THIS
462: .debug("\nTreeDocument::setDocumentElement: oldDocumentElement = "
463: + this .rootElement); // NOI18N
464: if (Util.THIS.isLoggable()) /* then */
465: Util.THIS
466: .debug(" ::setDocumentElement: newDocumentElement = "
467: + newElement); // NOI18N
468:
469: if (newElement == null) {
470: removeChild(this .rootElement);
471: } else if (this .rootElement == null) {
472: appendChild(newElement);
473: } else {
474: replaceChild(this .rootElement, newElement);
475: }
476: }
477:
478: //
479: // TreeObjectList.ContentManager
480: //
481:
482: /**
483: */
484: protected TreeObjectList.ContentManager createChildListContentManager() {
485: return new ChildListContentManager();
486: }
487:
488: /**
489: *
490: */
491: protected class ChildListContentManager extends
492: AbstractTreeDocument.ChildListContentManager {
493:
494: /**
495: */
496: public TreeNode getOwnerNode() {
497: return TreeDocument.this ;
498: }
499:
500: /**
501: */
502: public void checkAssignableObject(Object obj) {
503: super .checkAssignableObject(obj);
504: checkAssignableClass(Document.Child.class, obj);
505: }
506:
507: /**
508: */
509: public void objectInserted(TreeObject obj) {
510: super .objectInserted(obj);
511:
512: try {
513: if (obj instanceof TreeDocumentType) {
514: if (TreeDocument.this .documentType != null
515: && TreeDocument.this .documentType != obj) {
516: removeChild(TreeDocument.this .documentType);
517: }
518: TreeDocument.this .documentType = (TreeDocumentType) obj;
519: } else if (obj instanceof TreeElement) {
520: if (Util.THIS.isLoggable()) /* then */
521: Util.THIS
522: .debug("\nTreeDocument::ChildListContentManager::objectInserted: obj = "
523: + obj); // NOI18N
524: if (Util.THIS.isLoggable()) /* then */
525: Util.THIS
526: .debug(" :: ::objectInserted: old root element = "
527: + TreeDocument.this .rootElement); // NOI18N
528:
529: if (TreeDocument.this .rootElement != null
530: && TreeDocument.this .rootElement != obj) {
531: removeChild(TreeDocument.this .rootElement);
532: }
533: TreeDocument.this .rootElement = (TreeElement) obj;
534:
535: if (Util.THIS.isLoggable()) /* then */
536: Util.THIS
537: .debug(" :: ::objectInserted: NEW root element = "
538: + TreeDocument.this .rootElement);//, new RuntimeException ()); // NOI18N
539: }
540: } catch (Exception exc) {
541: if (Util.THIS.isLoggable()) /* then */
542: Util.THIS
543: .debug(
544: "TreeDocument::ChildListContentManager.objectInserted",
545: exc); // NOI18N
546: }
547: }
548:
549: /**
550: */
551: public void objectRemoved(TreeObject obj) {
552: super .objectRemoved(obj);
553:
554: if (TreeDocument.this .documentType == obj) {
555: TreeDocument.this .documentType = null;
556: } else if (TreeDocument.this .rootElement == obj) {
557: TreeDocument.this .rootElement = null;
558: }
559: }
560:
561: } // end: class ChildListContentManager
562:
563: }
|