001: package tide.javadocgen;
002:
003: import java.awt.FlowLayout;
004: import java.awt.Insets;
005: import tide.project.*;
006: import tide.editor.*;
007: import tide.editor.linemessages.*;
008: import tide.javadocgen.*;
009: import javax.swing.*;
010: import java.awt.BorderLayout;
011: import java.awt.event.*;
012: import javax.swing.border.*;
013: import java.util.*;
014: import java.io.*;
015: import snow.utils.*;
016: import snow.utils.storage.*;
017: import snow.utils.gui.*;
018: import snow.Basics;
019:
020: /** Todo: avoid passing project ignored files.
021: */
022: public class JavaDocCreationDialog extends JDialog {
023: public static final String defaultOptions = "-J-Xmx512m";// -tag todo:a:\"To Do:\""; not working...
024: private final FileField destination = new FileField("", true,
025: "Choose the javaDoc destination directory",
026: JFileChooser.DIRECTORIES_ONLY);
027: final private JButton viewOpts = new JButton("available options");
028:
029: private final ProgressModalDialog pmd;
030: private int numberOfWarnings = 0;
031:
032: public JavaDocCreationDialog(final JFrame parent,
033: final ProjectSettings settings) {
034: super (parent, "JavaDoc generation", true);
035:
036: pmd = new ProgressModalDialog(parent, "Javadoc creation");
037:
038: JComponent ta = GUIUtils
039: .createReadOnlyDescriptionArea("Javadoc generates the HTML documentation for the project."
040: + "\nThis documentation is also used for the completion dialog help text."
041: + "\nYou can restrict the doc to some packages, but be aware that Javadoc doesn't support"
042: + "\nincremental mode. Previous docs are erased, so you always need to generate"
043: + "\nall the docs you want at the same time.");
044: add(ta, BorderLayout.NORTH);
045:
046: JPanel inputPanel = new JPanel();
047: add(inputPanel, BorderLayout.CENTER);
048: GridLayout3 gl3 = new GridLayout3(2, inputPanel);
049:
050: gl3.addSeparator();
051:
052: gl3.add("JavaDoc destination");
053: gl3.add(destination);
054: File dest = new File(settings.getProperty(
055: "JavaDoc_DESTINATION", settings.getSources_Home()
056: + "/../docs/JavaDoc"));
057: try // remove the ..
058: {
059: dest = dest.getCanonicalFile();
060: } catch (Exception ignore) {
061: Basics.ignore(ignore);
062: }
063:
064: destination.setPath(dest.getAbsolutePath());
065: destination.setComponentWidth(300);
066:
067: JTextField includedPackages = new JTextField(settings
068: .getProperty("JavaDoc_includedPackages", ""), 30);
069: gl3.add("Included packages (empty=all)");
070: gl3.add(includedPackages);
071:
072: gl3.add("Standard Doclet Arguments");
073: JPanel argumentsPanel = new JPanel(new FlowLayout(
074: FlowLayout.LEFT, 0, 0));
075: viewOpts.setMargin(new Insets(0, 2, 0, 2));
076: viewOpts.setFocusPainted(false);
077: JTextField argsField = new JTextField(settings.getProperty(
078: "JavaDoc_Options", defaultOptions), 20);
079: gl3.add(argumentsPanel);
080: argumentsPanel.add(argsField);
081: argumentsPanel.add(viewOpts);
082: viewOpts.addActionListener(new ActionListener() {
083: public void actionPerformed(ActionEvent ae) {
084: displayOptions();
085: }
086: });
087:
088: gl3.addSeparator();
089:
090: JButton viewDocs = new JButton("View current javadocs");
091: gl3.add(viewDocs);
092: long lmi = lastModIndex(destination.getPath());
093: if (lmi > 0) {
094: viewDocs
095: .setToolTipText("shows the previously generated javadoc ("
096: + DateUtils.formatDateAndTimeHuman(lmi)
097: + ")");
098: } else {
099: viewDocs
100: .setToolTipText("shows the previously generated javadoc.");
101: }
102: viewDocs.setFocusPainted(false);
103: viewDocs.setMargin(new Insets(0, 2, 0, 2));
104: viewDocs.addActionListener(new ActionListener() {
105: public void actionPerformed(ActionEvent ae) {
106: File root = destination.getPath();
107: if (root == null || !root.exists()) {
108: JOptionPane.showMessageDialog(
109: JavaDocCreationDialog.this ,
110: "You must specify a valid folder !",
111: "Warning", JOptionPane.WARNING_MESSAGE);
112: return;
113: }
114:
115: File index = new File(root, "index.html");
116: if (!index.exists()) {
117: JOptionPane.showMessageDialog(
118: JavaDocCreationDialog.this ,
119: "No javadoc were found in the folder\n\n "
120: + root, "No javadoc",
121: JOptionPane.WARNING_MESSAGE);
122: return;
123: }
124:
125: try {
126: SysUtils.openDocumentInSystem(index
127: .getAbsolutePath(), true);
128: } catch (Exception e) {
129: e.printStackTrace();
130: }
131: }
132: });
133:
134: final JButton viewDocs2 = new JButton("View other javadocs");
135: gl3.add(viewDocs2);
136: /*viewDocs2.setToolTipText(
137: "shows the previously generated javadoc.");*/
138: viewDocs2.setFocusPainted(false);
139: viewDocs2.setMargin(new Insets(0, 2, 0, 2));
140: viewDocs2.addActionListener(new ActionListener() {
141: public void actionPerformed(ActionEvent ae) {
142: JPopupMenu pop = new JPopupMenu();
143:
144: final File jdkd = settings.getJDKDoc_Home();
145: if (jdkd.exists()) {
146: pop
147: .add("<html><body><small>JDK Javadocs root declared in this project's settings :");
148: pop.addSeparator();
149: final File jdkdi = new File(jdkd, "index.html");
150: JMenuItem pi = new JMenuItem("View " + jdkdi);
151: pop.add(pi);
152: pi.addActionListener(new ActionListener() {
153: public void actionPerformed(ActionEvent ae) {
154: try {
155: SysUtils.openDocumentInSystem(jdkdi
156: .getAbsolutePath(), true);
157: } catch (Exception e) {
158: e.printStackTrace();
159: }
160: }
161: });
162:
163: final File jdkdi2 = new File(jdkd, "api/index.html");
164: JMenuItem pi2 = new JMenuItem("View " + jdkdi2);
165: pop.add(pi2);
166: pi2.addActionListener(new ActionListener() {
167: public void actionPerformed(ActionEvent ae) {
168: try {
169: SysUtils.openDocumentInSystem(jdkdi2
170: .getAbsolutePath(), true);
171: } catch (Exception e) {
172: e.printStackTrace();
173: }
174: }
175: });
176:
177: pop.addSeparator();
178: }
179:
180: List<File> ejd = settings.getExternalJavaDocsRoots();
181: if (!ejd.isEmpty()) {
182: pop
183: .add("<html><body><small>Other Javadocs roots declared in this project's settings :");
184: pop.addSeparator();
185:
186: for (File fi : ejd) {
187: if (!fi.exists())
188: continue;
189: final File ini = new File(fi, "index.html");
190: JMenuItem pi = new JMenuItem("View " + fi);
191: pop.add(pi);
192: pi.addActionListener(new ActionListener() {
193: public void actionPerformed(ActionEvent ae) {
194: try {
195: SysUtils.openDocumentInSystem(ini
196: .getAbsolutePath(), true);
197: } catch (Exception e) {
198: e.printStackTrace();
199: }
200: }
201: });
202: }
203: }
204:
205: // add the other jdoc roots from other projects.
206:
207: List<File> others = FileUtils.getFilesFromList(
208: MainEditorFrame.instance.globalProperties
209: .getProperty(
210: "Global_jdkExtDocsRoot_hist",
211: ""), true);
212: if (!others.isEmpty()) {
213: pop.addSeparator();
214: pop
215: .add("<html><body><small>Other javadocs (not in this project's docs) :");
216: pop.addSeparator();
217: }
218:
219: for (File fi : others) {
220: if (!fi.exists())
221: continue;
222: if (ejd.contains(fi))
223: continue;
224:
225: final File ini = new File(fi, "index.html");
226: JMenuItem pi = new JMenuItem("View " + fi);
227: pop.add(pi);
228: pi.addActionListener(new ActionListener() {
229: public void actionPerformed(ActionEvent ae) {
230: try {
231: SysUtils.openDocumentInSystem(ini
232: .getAbsolutePath(), true);
233: } catch (Exception e) {
234: e.printStackTrace();
235: }
236:
237: }
238: });
239: }
240:
241: pop.show(viewDocs2, 0, viewDocs2.getHeight());
242: }
243: });
244:
245: final CloseControlPanel ccp = new CloseControlPanel(this , true,
246: true, "Generate JavaDoc");
247: ccp.getOkButton().setIcon(Icons.sharedRightArrow);
248: add(ccp, BorderLayout.SOUTH);
249:
250: pack();
251: this .setLocationRelativeTo(parent);
252: this .setVisible(true); // MODAL => waits
253:
254: if (ccp.getWasCancelled())
255: return;
256: if (!ccp.getWasAccepted())
257: return;
258:
259: // save settings
260: settings.setProperty("JavaDoc_DESTINATION", destination
261: .getPath().getAbsolutePath());
262: settings.setProperty("JavaDoc_Options", argsField.getText());
263: settings.setProperty("JavaDoc_includedPackages",
264: includedPackages.getText());
265:
266: // let the user directly benefit from the new generated javadocs !
267: try {
268: settings.reloadJavaDocManager().call();
269: } catch (Exception e) {
270: e.printStackTrace();
271: }
272:
273: int topCount = MainEditorFrame.instance.sourcesTreePanel
274: .getTreeModel().getTopLevelSources().size();
275: if (topCount > 0) {
276: JOptionPane
277: .showMessageDialog(
278: null,
279: "Caution: you have "
280: + topCount
281: + " source"
282: + (topCount == 1 ? "" : "s")
283: + " in the unnamed scope (root package)"
284: + "\nJavadoc ignore them !"
285: + "\nFurthermore, these classes are not accessible from any other package."
286: + "\nSo, it is a good hint for you avoiding defining such sources.",
287:
288: "Warning", JOptionPane.WARNING_MESSAGE);
289:
290: }
291:
292: Runnable r = new Runnable() {
293: public void run() {
294:
295: pmd.setModal(false);
296: pmd.start();
297:
298: try {
299: generateJavaDoc(pmd);
300: } catch (Exception e) {
301: JOptionPane.showMessageDialog(parent, ""
302: + e.getMessage(),
303: "JavaDoc generation failed",
304: JOptionPane.ERROR_MESSAGE);
305: e.printStackTrace();
306: } finally {
307: pmd.closeDialog();
308: }
309: }
310: };
311:
312: // ensure that the task run once a time
313: MainEditorFrame.instance.executeTask(r);
314:
315: } // Constructor
316:
317: private long lastModIndex(File root) {
318: if (root == null || !root.exists())
319: return -1;
320: File index = new File(root, "index.html");
321: if (!index.exists())
322: return -1;
323: return index.lastModified();
324: }
325:
326: private void generateJavaDoc(ProgressModalDialog pmd)
327: throws Exception {
328: ProjectSettings actualProject = MainEditorFrame.instance
329: .getActualProject();
330: LineMessagesManager.getInstance().removeMessages(
331: JavaDocLineMessage.class);
332:
333: // may be null !
334: File dest = new File(actualProject.getProperty(
335: "JavaDoc_DESTINATION", null));
336:
337: pmd.setCommentLabel("Loading sources...");
338: Process proc = JavaDocCreation.javaDocCreation(actualProject
339: .getJavaDoc_TOOL(), actualProject.getSources_Home(),
340: dest, actualProject.getClassPath(false, true), // user classpath (the system is already known by the javadoc tool
341: actualProject.getProperty("JavaDoc_includedPackages",
342: ""), actualProject.getProperty(
343: "JavaDoc_Options", defaultOptions));
344:
345: MainEditorFrame.instance.outputPanels.processesManager
346: .addProcess("Generating JavaDoc for "
347: + JavaDocCreation.guessedNumberOfJavaFiles
348: + " sources", proc, true);
349: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
350: .setText("");
351: MainEditorFrame.instance.outputPanels.selectToolsTab(false);
352: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
353: .appendDatedLine("Generating JavaDoc for "
354: + JavaDocCreation.guessedNumberOfJavaFiles
355: + " sources, in " + dest + "\n");
356:
357: pmd.setProgressBounds(JavaDocCreation.guessedNumberOfJavaFiles);
358: pmd.setProcessToOptionalKill(proc);
359: MainEditorFrame.debugOut(""
360: + JavaDocCreation.guessedNumberOfJavaFiles
361: + " source files to analyse");
362: pmd.setCommentLabel("Generating javadoc for "
363: + JavaDocCreation.guessedNumberOfJavaFiles
364: + " source files...");
365:
366: // monitors the progress
367: OutGobbler sg = new OutGobbler(proc.getInputStream()); //, (MainEditorFrame.debug ? System.out : null), "");
368: sg.start();
369:
370: // the warnings
371: ErrGobbler eg = new ErrGobbler(proc.getErrorStream());
372: eg.start();
373:
374: sg.join();
375: eg.join();
376: proc.waitFor();
377:
378: // store (not used now,...) maybe useful to warn the user if >10Hrs
379: actualProject.setProperty("lastDocGen_activeTime", ""
380: + actualProject.getActiveTime());
381:
382: // don't forget to add the last warning:
383: String lm = lastMessage.toString().trim();
384: if (lm.length() > 0) {
385: numberOfWarnings++;
386: JavaDocLineMessage.createAndAdd(lm);
387: }
388:
389: if (numberOfWarnings > 0) {
390: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
391: .appendLine("\n" + numberOfWarnings
392: + " Warnings (see Messages tab)");
393: } else {
394: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
395: .appendLine("\nJavaDoc generation done without warnings.");
396: }
397:
398: LineMessagesManager.getInstance().refreshView();
399: }
400:
401: /** Used to monitor the progress.
402: */
403: private void procOutLineRead(String line) {
404: if (line.startsWith("Generating")) {
405: pmd.incrementProgress(1);
406: } else if (line.startsWith("Loading")
407: || line.startsWith("Building")) {
408: pmd.setProgressComment(line);
409: } else {
410: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc
411: .appendLine("Javadoc> " + line);
412: }
413: }
414:
415: final private StringBuilder lastMessage = new StringBuilder();
416:
417: /** All messages and errors are passed here. We collect them in lastMessage
418: * and add them at new message start.
419: * Don't forget to add the last at the end, if any.
420: * This also adds the read messages in the manager.
421: */
422: private void procErrLineRead(String line) {
423: int pos = line.indexOf(".java:"); // NOT precise enough ???, ==> don't accept ".java:ddd)" ??
424: if (pos > 0) {
425: // a new message starts => add the last one
426: String lm = lastMessage.toString().trim();
427: if (lm.length() > 0) {
428: numberOfWarnings++;
429: JavaDocLineMessage.createAndAdd(lm);
430: }
431: lastMessage.setLength(0);
432: }
433: /*else
434: {
435: MainEditorFrame.instance.outputPanels.toolsOutputPanel.doc.appendLine(line);
436: }*/
437:
438: lastMessage.append(line + "\n");
439: }
440:
441: private void displayOptions() {
442: ProjectSettings actualProject = MainEditorFrame.instance
443: .getActualProject();
444: StringBuilder comp = new StringBuilder();
445: try {
446: java.util.List<String> args = new ArrayList<String>();
447: args.add(actualProject.getJavaDoc_TOOL().getAbsolutePath());
448: args.add("-help");
449: comp.append(ProcessUtils.readWholeProcessStack(args));
450: comp
451: .append("\r\nYou can also pass the option -J-Xmx512m to increase the memory for large projects doc creation");
452:
453: } catch (Exception e) {
454: comp.append("\r\nError: " + e.getMessage());
455: e.printStackTrace();
456: }
457:
458: JDialog optionsDialog = new JDialog(this , "Available options",
459: false);
460: JTextPane tp = new JTextPane();
461: tp.setFont(MainEditorFrame.fixedWidthFontForProcesses);
462: tp.setText(comp.toString().trim());
463: optionsDialog.add(new JScrollPane(tp), BorderLayout.CENTER);
464: CloseControlPanel ccp = new CloseControlPanel(optionsDialog,
465: false, true, "Close");
466: optionsDialog.add(ccp, BorderLayout.SOUTH);
467: tp.setEditable(false);
468: tp.setCaretPosition(0);
469: optionsDialog.setSize(800, 600);
470: optionsDialog.setLocationRelativeTo(viewOpts);
471: optionsDialog.setVisible(true);
472:
473: }
474:
475: class OutGobbler extends Thread {
476: private final InputStream input;
477:
478: public OutGobbler(InputStream input) {
479: this .input = input;
480: setName("JavaDoc in gobbler");
481: }
482:
483: @Override
484: public void run() {
485: try {
486: final InputStreamReader isr = new InputStreamReader(
487: this .input);
488: final BufferedReader br = new BufferedReader(isr);
489: String line;
490: while ((line = br.readLine()) != null) {
491: procOutLineRead(line);
492: }
493: } catch (IOException ioe) {
494: ioe.printStackTrace();
495: }
496: }
497: }
498:
499: class ErrGobbler extends Thread {
500: private final InputStream input;
501:
502: public ErrGobbler(InputStream input) {
503: this .input = input;
504: setName("JavaDoc err gobbler");
505: }
506:
507: @Override
508: public void run() {
509: try {
510: final InputStreamReader isr = new InputStreamReader(
511: this .input);
512: final BufferedReader br = new BufferedReader(isr);
513: String line;
514: while ((line = br.readLine()) != null) {
515: procErrLineRead(line);
516: }
517: } catch (IOException ioe) {
518: ioe.printStackTrace();
519: }
520: }
521: }
522:
523: }
|