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.modules.ruby.elements;
042:
043: import java.io.IOException;
044: import java.util.Collections;
045: import java.util.EnumSet;
046: import java.util.Set;
047:
048: import javax.swing.text.Document;
049:
050: import org.netbeans.modules.gsf.api.Modifier;
051: import org.netbeans.modules.gsf.api.ParserFile;
052: import org.netbeans.modules.ruby.NbUtilities;
053: import org.netbeans.modules.ruby.RubyIndex;
054: import org.netbeans.modules.gsf.spi.DefaultParserFile;
055: import org.openide.filesystems.FileObject;
056:
057: /**
058: * A program element coming from the persistent index.
059: *
060: * @author Tor Norbye
061: */
062: public abstract class IndexedElement extends RubyElement {
063: /** This method is documented */
064: public static final int DOCUMENTED = 1 << 0;
065: /** This method is protected */
066: public static final int PROTECTED = 1 << 1;
067: /** This method is private */
068: public static final int PRIVATE = 1 << 2;
069: /** This method is top level (implicit member of Object) */
070: public static final int TOPLEVEL = 1 << 3;
071: /** This element is "static" (e.g. it's a classvar for fields, class method for methods etc) */
072: public static final int STATIC = 1 << 4;
073: /** This element is deliberately not documented (rdoc :nodoc:) */
074: public static final int NODOC = 1 << 5;
075:
076: protected String fileUrl;
077: protected final String clz;
078: protected final String fqn;
079: protected final RubyIndex index;
080: protected final String require;
081: protected final String attributes;
082: protected Set<Modifier> modifiers;
083: protected int flags;
084: protected int docLength = -1;
085: private Document document;
086: private FileObject fileObject;
087:
088: protected IndexedElement(RubyIndex index, String fileUrl,
089: String fqn, String clz, String require, String attributes,
090: int flags) {
091: this .index = index;
092: this .fileUrl = fileUrl;
093: this .fqn = fqn;
094: this .require = require;
095: this .attributes = attributes;
096: // XXX Why do methods need to know their clz (since they already have fqn)
097: this .clz = clz;
098: this .flags = flags;
099: }
100:
101: public abstract String getSignature();
102:
103: public final String getFileUrl() {
104: return fileUrl;
105: }
106:
107: public final String getRequire() {
108: return require;
109: }
110:
111: public final String getFqn() {
112: return fqn;
113: }
114:
115: @Override
116: public String toString() {
117: return getSignature() + ":" + getFileUrl();
118: }
119:
120: public final String getClz() {
121: return clz;
122: }
123:
124: public RubyIndex getIndex() {
125: return index;
126: }
127:
128: public String getIn() {
129: return getClz();
130: }
131:
132: public String getFilenameUrl() {
133: return fileUrl;
134: }
135:
136: public Document getDocument() throws IOException {
137: if (document == null) {
138: FileObject fo = getFileObject();
139:
140: if (fo == null) {
141: return null;
142: }
143:
144: document = NbUtilities.getBaseDocument(fileObject, true);
145: }
146:
147: return document;
148: }
149:
150: public ParserFile getFile() {
151: boolean platform = false; // XXX FIND OUT WHAT IT IS!
152:
153: return new DefaultParserFile(getFileObject(), null, platform);
154: }
155:
156: public FileObject getFileObject() {
157: if ((fileObject == null) && (fileUrl != null)) {
158: fileObject = RubyIndex.getFileObject(fileUrl);
159:
160: if (fileObject == null) {
161: // Don't try again
162: fileUrl = null;
163: }
164: }
165:
166: return fileObject;
167: }
168:
169: public final Set<Modifier> getModifiers() {
170: if (modifiers == null) {
171: Modifier access = Modifier.PUBLIC;
172: if (isPrivate()) {
173: access = Modifier.PRIVATE;
174: } else if (isProtected()) {
175: access = Modifier.PROTECTED;
176: }
177: boolean isStatic = isStatic();
178:
179: if (access != Modifier.PUBLIC) {
180: if (isStatic) {
181: modifiers = EnumSet.of(access, Modifier.STATIC);
182: } else {
183: modifiers = EnumSet.of(access);
184: }
185: } else if (isStatic) {
186: modifiers = EnumSet.of(Modifier.STATIC);
187: } else {
188: modifiers = Collections.emptySet();
189: }
190: }
191: return modifiers;
192: }
193:
194: /** Return the length of the documentation for this class, in characters */
195: public int getDocumentationLength() {
196: return isDocumented() ? 1 : 0;
197: }
198:
199: /** Return a string (suitable for persistence) encoding the given flags */
200: public static char flagToFirstChar(int flags) {
201: char first = (char) (flags >>= 4);
202: if (first >= 10) {
203: return (char) (first - 10 + 'a');
204: } else {
205: return (char) (first + '0');
206: }
207: }
208:
209: /** Return a string (suitable for persistence) encoding the given flags */
210: public static char flagToSecondChar(int flags) {
211: char second = (char) (flags & 0xf);
212: if (second >= 10) {
213: return (char) (second - 10 + 'a');
214: } else {
215: return (char) (second + '0');
216: }
217: }
218:
219: /** Return a string (suitable for persistence) encoding the given flags */
220: public static String flagToString(int flags) {
221: return ("" + flagToFirstChar(flags)) + flagToSecondChar(flags);
222: }
223:
224: /** Return flag corresponding to the given encoding chars */
225: public static int stringToFlag(String s, int startIndex) {
226: return stringToFlag(s.charAt(startIndex), s
227: .charAt(startIndex + 1));
228: }
229:
230: /** Return flag corresponding to the given encoding chars */
231: public static int stringToFlag(char first, char second) {
232: int high = 0;
233: int low = 0;
234: if (first > '9') {
235: high = first - 'a' + 10;
236: } else {
237: high = first - '0';
238: }
239: if (second > '9') {
240: low = second - 'a' + 10;
241: } else {
242: low = second - '0';
243: }
244: return (high << 4) + low;
245: }
246:
247: public boolean isDocumented() {
248: return (flags & DOCUMENTED) != 0;
249: }
250:
251: public boolean isPublic() {
252: return (flags & PRIVATE & PROTECTED) == 0;
253: }
254:
255: public boolean isPrivate() {
256: // XXX hmmm not symmetric, see what the old semantics was for why I needed both?
257: return ((flags & PRIVATE) != 0) || ((flags & PROTECTED) != 0);
258: }
259:
260: public boolean isProtected() {
261: return (flags & PROTECTED) != 0;
262: }
263:
264: public boolean isTopLevel() {
265: return (flags & TOPLEVEL) != 0;
266: }
267:
268: public boolean isStatic() {
269: return (flags & STATIC) != 0;
270: }
271:
272: public boolean isNoDoc() {
273: return (flags & NODOC) != 0;
274: }
275:
276: public static String decodeFlags(int flags) {
277: StringBuilder sb = new StringBuilder();
278: if ((flags & DOCUMENTED) != 0) {
279: sb.append("|DOCUMENTED");
280: }
281: if ((flags & PRIVATE) != 0) {
282: sb.append("|PRIVATE");
283: }
284: if ((flags & PROTECTED) != 0) {
285: sb.append("|PROTECTED");
286: }
287: if ((flags & TOPLEVEL) != 0) {
288: sb.append("|TOPLEVEL");
289: }
290: if ((flags & STATIC) != 0) {
291: sb.append("|STATIC");
292: }
293: if ((flags & NODOC) != 0) {
294: sb.append("|NODOC");
295: }
296:
297: return sb.toString();
298: }
299:
300: }
|