001: /*
002: * Author: Chris Seguin
003: *
004: * This software has been developed under the copyleft
005: * rules of the GNU General Public License. Please
006: * consult the GNU General Public License for more
007: * details about use and distribution of this software.
008: */
009: package org.acm.seguin.pretty;
010:
011: import java.util.StringTokenizer;
012: import java.util.Vector;
013: import org.acm.seguin.util.FileSettings;
014: import org.acm.seguin.util.MissingSettingsException;
015:
016: /**
017: * Stores the java doc components
018: *
019: * @author Chris Seguin
020: * @author Mike Atkinson
021: * @date April 15, 1999
022: */
023: public class JavaDocableImpl implements JavaDocable {
024: private Vector docs;
025: private boolean printed;
026:
027: /** Constructor */
028: public JavaDocableImpl() {
029: docs = new Vector();
030: printed = false;
031: }
032:
033: /**
034: * Checks to see if it was printed
035: *
036: * @return true if it still needs to be printed
037: */
038: public boolean isRequired() {
039: return !printed;
040: }
041:
042: /**
043: * Determines if the javadoc comments were printed
044: *
045: * @return The Printed value
046: */
047: public boolean isPrinted() {
048: return printed;
049: }
050:
051: /**
052: * Allows you to add a java doc component
053: *
054: * @param component the component that can be added
055: */
056: public void addJavaDocComponent(JavaDocComponent component) {
057: if (component != null) {
058: docs.addElement(component);
059: }
060: }
061:
062: /**
063: * Allows you to sort the javadoc tags.
064: *
065: * @param type The "@"tag to sort (e.g. "@param").
066: * @param names The order of identifies desired after sort (e.g. for this method {"type", "names"} ).
067: * @since JRefactory 2.7.00
068: *
069: */
070: public void sort(String type, String[] names) {
071: Vector newDocs = new Vector();
072: Vector typeDocs = new Vector();
073:
074: // Iterate through the components adding those that are not of type.
075: for (int ndx = 0; ndx < docs.size(); ndx++) {
076: Object next = docs.elementAt(ndx);
077: if (next instanceof NamedJavaDocComponent) {
078: NamedJavaDocComponent jdc = (NamedJavaDocComponent) next;
079: if (jdc.getType().equalsIgnoreCase(type)) {
080: typeDocs.add(next);
081: continue;
082: }
083: }
084: newDocs.add(next);
085: }
086: boolean[] added = new boolean[typeDocs.size()];
087: for (int i = 0; i < names.length; i++) {
088: for (int ndx = 0; ndx < typeDocs.size(); ndx++) {
089: NamedJavaDocComponent jdc = (NamedJavaDocComponent) typeDocs
090: .elementAt(ndx);
091: if (jdc.getID().equals(names[i])) {
092: newDocs.add(jdc);
093: added[ndx] = true;
094: }
095: }
096: }
097: for (int ndx = 0; ndx < typeDocs.size(); ndx++) {
098: if (!added[ndx]) {
099: newDocs.add(typeDocs.elementAt(ndx));
100: }
101: }
102:
103: docs = newDocs;
104: }
105:
106: /**
107: * Prints all the java doc components
108: *
109: * @param printData the print data
110: */
111: public void printJavaDocComponents(PrintData printData) {
112: printJavaDocComponents(printData, "");
113: }
114:
115: /**
116: * Prints all the java doc components
117: *
118: * @param printData the print data
119: * @param order the order for the tags
120: */
121: public void printJavaDocComponents(PrintData printData, String order) {
122: // Saying that we are done
123: printed = true;
124:
125: // Abort if there is nothing
126: if (docs.size() == 0) {
127: return;
128: }
129:
130: // Adjust the spacing for the IDs
131: setLongest(getLongest());
132:
133: // Make sure we are indented
134: if (!printData.isLineIndented()) {
135: printData.indent();
136: }
137:
138: // Start the comment
139: int loop = printData.getJavadocStarCount() - 2;
140: printData.appendComment("/**", PrintData.JAVADOC_COMMENT);
141: for (int ndx = 0; ndx < loop; ndx++) {
142: printData.appendComment("*", PrintData.JAVADOC_COMMENT);
143: }
144: boolean onSingleLine = isOnSingleLine(printData);
145: boolean firstLineOnCommentStart = printData
146: .isFirstLineOnCommentStart();
147: if (!onSingleLine && !firstLineOnCommentStart) {
148: printData.newline();
149: }
150:
151: // Print all the components
152: print(printData, order, onSingleLine);
153:
154: // Finish the comment
155: if (!onSingleLine) {
156: printData.indent();
157: }
158: if (!printData.isStarsAlignedWithSlash()) {
159: printData.space();
160: }
161: for (int ndx = 0; ndx < loop; ndx++) {
162: printData.appendComment("*", PrintData.JAVADOC_COMMENT);
163: }
164: printData.appendComment("*/", PrintData.JAVADOC_COMMENT);
165:
166: // Newline
167: printData.newline();
168:
169: // Reset once they have been printed
170: docs = new Vector();
171: }
172:
173: /** Makes sure all the java doc components are present */
174: public void finish() {
175: }
176:
177: /**
178: * Contains a particular item
179: *
180: * @param type the type we are looking for
181: * @return true if we found a tag with that name
182: */
183: public boolean contains(String type) {
184: boolean found = false;
185:
186: // Iterate through the components
187: for (int ndx = 0; ndx < docs.size(); ndx++) {
188: JavaDocComponent jdc = ((JavaDocComponent) docs
189: .elementAt(ndx));
190: String typeName = jdc.getType();
191: if (typeName.equalsIgnoreCase(type)) {
192: jdc.setRequired(true);
193: found = true;
194:
195: if (typeName.equals("param")
196: || typeName.equals("return")
197: || typeName.equals("exception")
198: || typeName.equals("throws")
199: || typeName.equals("")) {
200: return true;
201: }
202: }
203: }
204:
205: return found; // Not found
206: }
207:
208: /**
209: * Contains a particular item
210: *
211: * @param type the type we are looking for
212: * @param id the id
213: * @return Description of the Returned Value
214: */
215: public boolean contains(String type, String id) {
216: // Iterate through the components
217: for (int ndx = 0; ndx < docs.size(); ndx++) {
218: Object next = docs.elementAt(ndx);
219: if (next instanceof NamedJavaDocComponent) {
220: NamedJavaDocComponent jdc = (NamedJavaDocComponent) next;
221: if ((jdc.getType().equalsIgnoreCase(type))
222: && (jdc.getID().equals(id))) {
223: jdc.setRequired(true);
224: return true;
225: }
226: }
227: }
228:
229: return false; // Not found
230: }
231:
232: /**
233: * Make a required field
234: *
235: * @param tag the tag
236: * @param descr the default description
237: */
238: public void require(String tag, String descr) {
239: if (descr != null && !contains(tag)) {
240: JavaDocComponent jdc = new JavaDocComponent();
241: jdc.setType(tag);
242: jdc.setDescription(descr);
243: addJavaDocComponent(jdc);
244: jdc.setRequired(true);
245: }
246: }
247:
248: /**
249: * Make a required field
250: *
251: * @param tag the tag
252: * @param id the id
253: * @param descr the default description
254: */
255: public void require(String tag, String id, String descr) {
256: if (descr != null && !contains(tag, id)) {
257: NamedJavaDocComponent jdc = new NamedJavaDocComponent();
258: jdc.setType(tag);
259: jdc.setID(id);
260: jdc.setDescription(descr);
261: addJavaDocComponent(jdc);
262: jdc.setRequired(true);
263: }
264: }
265:
266: /**
267: * Set the longest id
268: *
269: * @param length the longest length
270: */
271: private void setLongest(int length) {
272: int last = docs.size();
273: for (int ndx = 0; ndx < last; ndx++) {
274: ((JavaDocComponent) docs.elementAt(ndx))
275: .setLongestLength(length);
276: }
277: }
278:
279: /**
280: * Determine the maximum length
281: *
282: * @return the maximum length
283: */
284: private int getLongest() {
285: int longest = 0;
286: int last = docs.size();
287: for (int ndx = 0; ndx < last; ndx++) {
288: int next = ((JavaDocComponent) docs.elementAt(ndx))
289: .getLongestLength();
290: longest = Math.max(next, longest);
291: }
292: return longest;
293: }
294:
295: /**
296: * Determines if a particular component is a description
297: *
298: * @param current the current tag
299: * @return true if it is a description
300: */
301: private boolean isDescription(JavaDocComponent current) {
302: return current.getType().length() == 0;
303: }
304:
305: /**
306: * Gets the TagRequired attribute of the JavaDocableImpl object
307: *
308: * @param tag Description of Parameter
309: * @return The TagRequired value
310: */
311: private boolean isTagRequired(String tag) {
312: try {
313: FileSettings bundle = FileSettings
314: .getRefactoryPrettySettings();
315: bundle.getString(tag + ".descr");
316: return true;
317: } catch (MissingSettingsException mse) {
318: return false;
319: }
320: }
321:
322: /**
323: * Determines if the javadoc will fit on a single line
324: *
325: * @param printData the print data
326: * @return true if it can fit (and is allowed to fit) on a single line
327: */
328: private boolean isOnSingleLine(PrintData printData) {
329: if (!printData.isAllowSingleLineJavadoc()) {
330: return false;
331: }
332:
333: if (docs.size() > 1) {
334: return false;
335: }
336:
337: JavaDocComponent single = (JavaDocComponent) docs.elementAt(0);
338: if (!single.isDescription()) {
339: return false;
340: }
341:
342: String text = single.getDescription();
343: if (text.length() > printData.getJavadocWordWrapMaximum()) {
344: return false;
345: }
346:
347: text = text.toUpperCase();
348: if ((text.indexOf("<P>") >= 0) || (text.indexOf("<BR") >= 0)
349: || (text.indexOf("<DL") >= 0)
350: || (text.indexOf("<OL") >= 0)
351: || (text.indexOf("<UL") >= 0)) {
352: return false;
353: }
354:
355: return true;
356: }
357:
358: /**
359: * Actually prints the components
360: *
361: * @param printData the print data
362: * @param order the order that stuff should be printed in
363: * @param singleLine Description of Parameter
364: */
365: private void print(PrintData printData, String order,
366: boolean singleLine) {
367: StringTokenizer tok = new StringTokenizer(order, ", \t\r\n");
368:
369: // First print the description
370: printDescription(printData, singleLine);
371:
372: // Now order the tags we know about
373: while (tok.hasMoreTokens()) {
374: String next = tok.nextToken();
375:
376: boolean isRequired = isTagRequired(next);
377: tagPass("@" + next, printData, isRequired);
378: }
379:
380: // Now print everything else
381: finalPass(printData);
382: }
383:
384: /**
385: * Prints all the components that have a particular tag
386: *
387: * @param next the component
388: * @param printData the print data
389: * @param req Description of Parameter
390: */
391: private void tagPass(String next, PrintData printData, boolean req) {
392: JavaDocComponent current;
393: int last = docs.size();
394:
395: for (int ndx = 0; ndx < last; ndx++) {
396: // Get the next element
397: current = ((JavaDocComponent) docs.elementAt(ndx));
398:
399: // Does it go here
400: boolean now = next.equals(current.getType());
401: boolean required = !req || current.isRequired();
402:
403: // If it is time, print it
404: if (now) {
405: if (required) {
406: printCurrentTag(current, printData, false, false);
407: } else if (printData.isKeepErroneousJavadocTags()) {
408: current.setType(current.getType() + "-error");
409: } else {
410: current.setPrinted(true);
411: }
412: }
413: }
414: }
415:
416: /**
417: * Prints the description
418: *
419: * @param printData the print data
420: * @param singleLine Description of Parameter
421: */
422: private void printDescription(PrintData printData,
423: boolean singleLine) {
424: JavaDocComponent current;
425:
426: for (int ndx = 0; ndx < docs.size(); ndx++) {
427: // Get the next element
428: current = ((JavaDocComponent) docs.elementAt(ndx));
429:
430: if (current.getType().equals("")) {
431: String descr = current.getDescription();
432: if (JavadocTokenizer.hasContent(descr)) {
433: printCurrentTag(current, printData,
434: docs.size() == 1, singleLine);
435: }
436: current.setPrinted(true);
437: }
438: }
439: }
440:
441: /**
442: * Prints all unknown tags
443: *
444: * @param printData the print data
445: */
446: private void finalPass(PrintData printData) {
447: JavaDocComponent current;
448:
449: for (int ndx = 0; ndx < docs.size(); ndx++) {
450: // Get the next element
451: current = ((JavaDocComponent) docs.elementAt(ndx));
452:
453: // If it is time, print it
454: if (!current.isPrinted()) {
455: printCurrentTag(current, printData, false, false);
456: }
457: }
458: }
459:
460: /**
461: * Prints the current tag
462: *
463: * @param current the tag
464: * @param printData the print data
465: * @param onlyDescription if it is the only tag
466: * @param singleLine Description of Parameter
467: */
468: private void printCurrentTag(JavaDocComponent current,
469: PrintData printData, boolean onlyDescription,
470: boolean singleLine) {
471: // Print the element
472: printData.setCurrentIsSingle(singleLine);
473: current.print(printData);
474: printData.setCurrentIsSingle(false);
475: if (!onlyDescription && isDescription(current)) {
476: printSpaceAfterDescription(printData);
477: }
478: }
479:
480: /**
481: * Prints a blank line after a description
482: *
483: * @param printData the print data
484: */
485: private void printSpaceAfterDescription(PrintData printData) {
486: printData.indent();
487: if (!printData.isStarsAlignedWithSlash()) {
488: printData.space();
489: }
490: printData.appendComment("*", PrintData.JAVADOC_COMMENT);
491: printData.newline();
492: }
493: }
|