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 java.util.Collection;
044:
045: import org.netbeans.tax.spec.DTD;
046: import org.netbeans.tax.spec.ParameterEntityReference;
047: import org.netbeans.tax.spec.DocumentType;
048: import org.netbeans.tax.spec.ConditionalSection;
049:
050: import org.netbeans.tax.decl.EMPTYType;
051: import org.netbeans.tax.decl.parser.ParserReader;
052: import org.netbeans.tax.decl.parser.ContentSpecParser;
053:
054: /**
055: *
056: * @author Libor Kramolis
057: * @version 0.1
058: */
059: public class TreeElementDecl extends TreeNodeDecl implements DTD.Child,
060: ParameterEntityReference.Child, DocumentType.Child,
061: ConditionalSection.Child {
062: /** */
063: public static final String PROP_NAME = "name"; // NOI18N
064: /** */
065: public static final String PROP_CONTENT_TYPE = "contentType"; // NOI18N
066:
067: /** */
068: private String name;
069:
070: /** */
071: private ContentType contentType;
072:
073: // /** */
074: // private String contentTypeString;
075:
076: //
077: // init
078: //
079:
080: /** Creates new TreeElementDecl.
081: * @throws InvalidArgumentException
082: */
083: public TreeElementDecl(String name, ContentType contentType)
084: throws InvalidArgumentException {
085: super ();
086:
087: checkName(name);
088: checkContentType(contentType);
089:
090: this .name = name;
091: this .contentType = contentType;
092: this .contentType.setNodeDecl(this );
093: }
094:
095: // /** Creates new TreeElementDecl.
096: // * @throws InvalidArgumentException
097: // */
098: // public TreeElementDecl (String name, String contentType) throws InvalidArgumentException {
099: // this (name, new ContentSpecParser().parseModel (new ParserReader (contentType)));
100: // }
101:
102: /** Creates new TreeElementDecl -- copy constructor. */
103: protected TreeElementDecl(TreeElementDecl elementDecl) {
104: super (elementDecl);
105:
106: this .name = elementDecl.name;
107: this .contentType = (ContentType) elementDecl.contentType
108: .clone();
109: }
110:
111: //
112: // from TreeObject
113: //
114:
115: /**
116: */
117: public Object clone() {
118: return new TreeElementDecl(this );
119: }
120:
121: /**
122: */
123: public boolean equals(Object object, boolean deep) {
124: if (!!!super .equals(object, deep))
125: return false;
126:
127: TreeElementDecl peer = (TreeElementDecl) object;
128: if (!!!Util.equals(this .getName(), peer.getName()))
129: return false;
130: if (!!!Util.equals(this .contentType, peer.contentType))
131: return false;
132:
133: return true;
134: }
135:
136: /*
137: * Merges name and content type properties.
138: */
139: public void merge(TreeObject treeObject)
140: throws CannotMergeException {
141: super .merge(treeObject);
142:
143: TreeElementDecl peer = (TreeElementDecl) treeObject;
144:
145: setNameImpl(peer.getName());
146: setContentTypeImpl(peer.getContentType());
147: // contentType.merge (peer.contentType);
148: }
149:
150: //
151: // itself
152: //
153:
154: /**
155: */
156: public final String getName() {
157: return name;
158: }
159:
160: /**
161: */
162: private final void setNameImpl(String newName) {
163: String oldName = this .name;
164:
165: this .name = newName;
166:
167: firePropertyChange(PROP_NAME, oldName, newName);
168: }
169:
170: /**
171: * @throws ReadOnlyException
172: * @throws InvalidArgumentException
173: */
174: public final void setName(String newName) throws ReadOnlyException,
175: InvalidArgumentException {
176: //
177: // check new value
178: //
179: if (Util.equals(this .name, newName))
180: return;
181: checkReadOnly();
182: checkName(newName);
183:
184: //
185: // set new value
186: //
187: setNameImpl(newName);
188: }
189:
190: /**
191: */
192: protected final void checkName(String name)
193: throws InvalidArgumentException {
194: TreeUtilities.checkElementDeclName(name);
195: }
196:
197: /**
198: */
199: public final ContentType getContentType() {
200: return contentType;
201: }
202:
203: /**
204: */
205: private final void setContentTypeImpl(ContentType newContentType) {
206: ContentType oldContentType = this .contentType;
207:
208: this .contentType = newContentType;
209:
210: firePropertyChange(PROP_CONTENT_TYPE, oldContentType,
211: newContentType);
212: }
213:
214: /**
215: * @throws ReadOnlyException
216: * @throws InvalidArgumentException
217: */
218: public final void setContentType(ContentType newContentType)
219: throws ReadOnlyException, InvalidArgumentException {
220: //
221: // check new value
222: //
223: if (Util.equals(this .contentType, newContentType))
224: return;
225: checkReadOnly();
226: checkContentType(newContentType);
227:
228: //
229: // set new value
230: //
231: setContentTypeImpl(newContentType);
232: }
233:
234: /**
235: * @throws ReadOnlyException
236: * @throws InvalidArgumentException
237: */
238: public final void setContentType(String newContentType)
239: throws ReadOnlyException, InvalidArgumentException {
240: setContentType(new ContentSpecParser()
241: .parseModel(new ParserReader(newContentType)));
242: }
243:
244: /**
245: */
246: protected final void checkContentType(ContentType contentType)
247: throws InvalidArgumentException {
248: TreeUtilities.checkElementDeclContentType(contentType);
249: }
250:
251: /** @return true for mixed model. */
252: public boolean isMixed() {
253: return getContentType().isMixed();
254: }
255:
256: /** */
257: public boolean isEmpty() {
258: return !(allowText() || allowElements());
259: }
260:
261: /** */
262: public boolean allowText() {
263: return getContentType().allowText();
264: }
265:
266: /** */
267: public boolean allowElements() {
268: return getContentType().allowElements();
269: }
270:
271: /** */
272: public Collection getAttributeDefs() {
273: if (getOwnerDTD() == null) {
274: return null;
275: }
276: return getOwnerDTD().getAttributeDeclarations(getName());
277: }
278:
279: //
280: // ContentType
281: //
282:
283: /**
284: *
285: */
286: public abstract static class ContentType extends Content implements
287: Comparable {
288: // public static final short TYPE_EMPTY = 0; // EMPTY
289: // public static final short TYPE_ANY = 1; // ANY
290: // public static final short TYPE_MIXED = 2; // (#PCDATA|xxx)*
291: // public static final short TYPE_CHILDREN = 3; // (xxx?,(yyy|zzz*))+
292:
293: // public static final short SEPARATOR_CHOICE = 10; // xxx|yyy
294: // public static final short SEPARATOR_SEQUENCE = 11; // xxx,yyy
295:
296: // public static final short OCCURS_ZERO_OR_ONE = 20; // xxx?
297: // public static final short OCCURS_EXACTLY_ONE = 21; // xxx
298: // public static final short OCCURS_ZERO_OR_MORE = 22; // xxx*
299: // public static final short OCCURS_ONE_OR_MORE = 23; // xxx+
300:
301: /** */
302: private String multiplicity;
303:
304: private int index; // sample value of counter at creation time
305:
306: private static int counter = 0; // to be able to create ordered collections
307:
308: //
309: // init
310: //
311:
312: /** Creates new ContentType. */
313: protected ContentType(TreeElementDecl elementDecl) {
314: super (elementDecl);
315:
316: this .multiplicity = new String();
317:
318: this .index = counter++;
319: }
320:
321: /** Creates new ContentType. */
322: protected ContentType() {
323: this ((TreeElementDecl) null);
324: }
325:
326: /** Creates new ContentType -- copy constructor. */
327: protected ContentType(ContentType contentType) {
328: super (contentType);
329:
330: this .multiplicity = contentType.multiplicity;
331:
332: this .index = counter++;
333: }
334:
335: //
336: // from TreeObject
337: //
338:
339: /**
340: */
341: public boolean equals(Object object, boolean deep) {
342: if (!!!super .equals(object, deep))
343: return false;
344:
345: ContentType peer = (ContentType) object;
346: if (this .index != peer.index)
347: return false;
348: if (!!!Util.equals(this .getMultiplicity(), peer
349: .getMultiplicity()))
350: return false;
351:
352: return true;
353: }
354:
355: /*
356: * Merges changes from passed object to actual object.
357: * @param node merge peer (TreeAttributeDecl)
358: * @throws CannotMergeException if can not merge with given node (invalid class)
359: */
360: public void merge(TreeObject treeObject)
361: throws CannotMergeException {
362: super .merge(treeObject);
363:
364: ContentType peer = (ContentType) treeObject;
365:
366: index = peer.index;
367: setMultiplicity(peer.getMultiplicity());
368: }
369:
370: //
371: // context
372: //
373:
374: /**
375: */
376: public final void removeFromContext() throws ReadOnlyException {
377: if (isInContext()) {
378: getOwnerElementDecl().setContentTypeImpl(
379: new EMPTYType());
380: }
381: }
382:
383: //
384: // itself
385: //
386:
387: /**
388: */
389: public final TreeElementDecl getOwnerElementDecl() {
390: return (TreeElementDecl) getNodeDecl();
391: }
392:
393: /**
394: */
395: public void setMultiplicity(char s) {
396: multiplicity = new String(new char[] { s });
397: }
398:
399: /**
400: */
401: public void setMultiplicity(String s) {
402: multiplicity = s;
403: }
404:
405: /** Combines existing multiplicity with new one.
406: * <pre>
407: * | 1 | ? | + | *
408: * --+---+---+---+---
409: * 1 | 1 | ? | + | *
410: * --+---+---+---+---
411: * ? | ? | ? | * | *
412: * --+---+---+---+---
413: * + | + | * | + | *
414: * --+---+---+---+---
415: * * | * | * | * | *
416: * </pre>
417: */
418: public void addMultiplicity(String s) {
419: if (multiplicity.equals(s))
420: return;
421:
422: if ("".equals(multiplicity)) { // NOI18N
423: multiplicity = s;
424: } else if ("".equals(s)) { // NOI18N
425: // stay intact
426: } else {
427: multiplicity = "*"; // NOI18N
428: }
429: }
430:
431: /** @return multiplicity of given type */
432: public String getMultiplicity() {
433: return multiplicity;
434: }
435:
436: /** @return true if element itself can contain mixed content. */
437: public boolean isMixed() {
438: return allowText() && allowElements();
439: }
440:
441: /** @return true if sub elements are allowed. */
442: public abstract boolean allowElements();
443:
444: /** @return true if text value is allowed. */
445: public abstract boolean allowText();
446:
447: /** @return String representation of type. */
448: public abstract String toString();
449:
450: /** Natural ordering by index. */
451: public int compareTo(final Object obj) {
452: if (this .equals(obj))
453: return 0;
454:
455: ContentType type = (ContentType) obj;
456:
457: return index - type.index;
458: }
459:
460: } // end: class ContentType
461:
462: }
|