001: package tide.editor;
002:
003: import tide.outputtabs.OutputTextPanel;
004: import java.awt.Color;
005: import java.awt.FlowLayout;
006: import java.awt.Insets;
007: import snow.utils.gui.Icons;
008: import java.awt.EventQueue;
009: import tide.project.*;
010: import tide.compiler.*;
011: import tide.execute.*;
012: import tide.sources.FileItem;
013: import snow.utils.storage.*;
014: import snow.texteditor.SimpleDocument;
015: import tide.editor.linemessages.*;
016: import tide.outputtabs.search.*;
017: import javax.swing.*;
018: import java.awt.event.*;
019: import javax.swing.border.*;
020: import java.util.*;
021: import java.util.regex.*;
022: import java.io.*;
023: import java.text.*;
024:
025: /** Output panels (compiler, warnings, tools, search, processes manager, custom...
026: */
027: final public class OutputPanels extends JTabbedPane {
028: public final CompilerOutputPanel tideOutputPanel = new CompilerOutputPanel();
029: public final CompilerOutputPanel compilerOutputPanel = new CompilerOutputPanel();
030: public final CompilerOutputPanel toolsOutputPanel = new CompilerOutputPanel();
031: public final ExecutionOutputPanel executionOutputPanel = new ExecutionOutputPanel(
032: false);
033: public final ProcessesManager processesManager = new ProcessesManager();
034: private final MessagesTable lineMessagesPanel = MessagesTable
035: .getInstance();
036: public final ExecutionOutputPanel customPanel = new ExecutionOutputPanel(
037: true);
038: private final SearchTab searchTab = SearchTab.getInstance();
039:
040: // Added if -logtab app arg present...
041: // redirects System out and err.
042: public final ExecutionOutputPanel tideConsoleOutputPanel = new ExecutionOutputPanel(
043: false);
044:
045: public void clearConsoleLog() {
046: tideConsoleOutputPanel.doc.clearDocument();
047: }
048:
049: private final static String compilerTabTitle = "Compiler";
050:
051: public OutputPanels() {
052: super ();
053: this .setBorder(null);
054:
055: this .addTab("Execution", executionOutputPanel);
056: this .addTab(compilerTabTitle, compilerOutputPanel); // 1
057: this .addTab("Messages", lineMessagesPanel); // 2
058:
059: this .addTab("Tools", toolsOutputPanel);
060: this .addTab("Search", searchTab);
061:
062: this .addTab("tIDE", tideOutputPanel);
063: this .addTab("Custom", customPanel);
064: customPanel.setEditable(true);
065: this .addTab("Processes", processesManager); // 7
066:
067: if (MainEditorFrame.redirectConsoleInTab) {
068: this .addTab("Log", tideConsoleOutputPanel);
069: JPanel rp = new JPanel(
070: new FlowLayout(FlowLayout.LEFT, 0, 0));
071: rp.setOpaque(false);
072: rp.add(new JLabel("Log "));
073: JButton cb = new JButton(new Icons.CrossIcon(8, 8, true));
074: rp.add(cb);
075: cb.setFocusPainted(false);
076: cb.setMargin(new Insets(0, 0, 0, 0));
077: cb.setBorder(new LineBorder(Color.lightGray, 1, true)); //null);
078: final PrintStream o_out = System.out;
079: final PrintStream o_err = System.err;
080: cb.addActionListener(new ActionListener() {
081: public void actionPerformed(ActionEvent ae) {
082:
083: System.setOut(o_out);
084: System.setErr(o_err);
085: System.out
086: .println("tIDE log tab has been closed, restoring the original System.out and err");
087: //remove( tideConsoleOutputPanel );
088: removeTabAt(8);
089: }
090: });
091: this .setTabComponentAt(8, rp);
092: }
093:
094: // just some init text here:
095: // This disapears ! ?
096: tideOutputPanel.doc.appendLine(MainEditorFrame._VERSION
097: + ", started "
098: + SimpleDateFormat.getDateTimeInstance().format(
099: new Date()) + "\n");
100:
101: MainEditorFrame.instance
102: .addProjectListener(new ProjectListener() {
103: // public void projectWillBeLoaded() {}
104: public void projectHasBeenLoaded(
105: final ProjectSettings ps) {
106: Thread t = new Thread() {
107: public void run() {
108: try {
109: loadContentsFromSavedStates(ps);
110: } catch (Exception e) {
111: e.printStackTrace();
112: }
113: }
114: };
115: t.setName("restoring output tabs");
116: t.start();
117: }
118:
119: public void projectIsSaving(ProjectSettings ps) {
120: }
121:
122: public void projectHasBeenClosed(ProjectSettings ps) {
123: // don't wait
124: try {
125: saveContents_(ps);
126: } catch (Exception e) {
127: e.printStackTrace();
128: }
129: }
130: });
131:
132: } // Constructor
133:
134: public void addNewTab(String name, JComponent comp) {
135: addTab(name, comp);
136: setSelectedIndex(getTabCount() - 1);
137: }
138:
139: /* Displays the compilation progress. NOT USED NOW.
140: *
141: public void setCompilationCompletionPercent(final int perc)
142: {
143: if(perc==100 || perc<0)
144: {
145: this.setTitleAt(1, "Compiler");
146: }
147: else
148: {
149: this.setTitleAt(1, "Compiling... ("+ perc+"%)");
150: }
151: }*/
152:
153: public void setNumberOfRunningProcesses(int n) {
154: if (n == 1) {
155: this .setTitleAt(indexOfComponent(processesManager),
156: "1 Process");
157: } else {
158: this .setTitleAt(indexOfComponent(processesManager), "" + n
159: + " Processes");
160: }
161: }
162:
163: public void clearAllOutputs() {
164: // todo: also reset the undo buffer => call document deep clear
165: toolsOutputPanel.setText("");
166: SearchResultsManager.getInstance().clear();
167: compilerOutputPanel.setText("");
168: customPanel.setText("");
169: }
170:
171: /** Recovers contents. This is called when the project has been loaded...
172: */
173: private void loadContentsFromSavedStates(ProjectSettings ps) {
174: clearAllOutputs();
175:
176: // [Jan2007] the new search tab
177: boolean hasNewSearchLoaded = false;
178: try {
179: hasNewSearchLoaded = SearchResultsManager.getInstance()
180: .restoreFromFile(ps);
181: } catch (Exception e) {
182: e.printStackTrace();
183: }
184:
185: File apf = MainEditorFrame.instance.getActualProjectFile();
186: if (apf == null) {
187: // new Throwable().printStackTrace();
188: return;
189: }
190:
191: File dir = ps.getProjectSettingsFolder();
192: File file = new File(dir, ".outputs");
193:
194: if (!file.exists()) {
195: // try the old one !
196: file = new File(apf.getAbsolutePath()
197: + ".outputpanelscontents");
198: file.deleteOnExit();
199: }
200:
201: if (file.exists()) {
202: try {
203: StorageVector v = FileUtils.loadVectorFromFile(file);
204: String txt = (String) v.get(0);
205: txt = txt.replace("\r", ""); // IMPORTANT ! (and be careful, these are regexs)
206: toolsOutputPanel.setText(txt);
207:
208: txt = (String) v.get(1);
209: txt = txt.replace("\r", ""); // IMPORTANT ! (and be careful, these are regexs)
210: if (!hasNewSearchLoaded) {
211: SearchResultsManager.getInstance()
212: .setOldSearchResults(txt);
213: }
214:
215: if (v.size() > 2) {
216: txt = (String) v.get(2);
217: txt = txt.replace("\r", ""); // IMPORTANT ! (and be careful, these are regexs)
218: compilerOutputPanel.setText(txt);
219: }
220:
221: if (v.size() > 3) {
222: txt = (String) v.get(3);
223: txt = txt.replace("\r", ""); // IMPORTANT ! (and be careful, these are regexs)
224: customPanel.setText(txt);
225: }
226:
227: } catch (Exception e) {
228: e.printStackTrace();
229: }
230: } else {
231: System.out.println("no output file found: " + file);
232: //new Throwable().printStackTrace();
233: }
234: }
235:
236: /** Call this before shutdown to save the tools output.
237: * Or at project change.
238: */
239: private void saveContents_(final ProjectSettings ps) {
240: //String tt = toolsOutputPanel.getText();
241: File apf = MainEditorFrame.instance.getActualProjectFile();
242: if (apf == null)
243: return; // only for saved projects
244:
245: File dir = ps.getProjectSettingsFolder();
246: if (!dir.exists())
247: dir.mkdirs();
248:
249: File file = new File(dir, ".outputs");
250:
251: List<Object> contents = new ArrayList<Object>();
252: contents.add(toolsOutputPanel.getText());
253: contents.add(""); // old search panel...
254: contents.add(this .compilerOutputPanel.getText());
255: contents.add(this .customPanel.getText());
256:
257: try {
258: SearchResultsManager.getInstance().storeToFile_(ps);
259: } catch (Exception e) {
260: e.printStackTrace();
261: }
262:
263: try {
264: FileUtils.saveVectorToFile(file, contents);
265: } catch (Exception e) {
266: e.printStackTrace();
267: }
268: }
269:
270: public SimpleDocument getExecutionOutputDoc() {
271: return this .executionOutputPanel.doc;
272: }
273:
274: public void selectCompilerTab() {
275: EventQueue.invokeLater(new Runnable() {
276: public void run() {
277: setSelectedComponent(compilerOutputPanel);
278: }
279: });
280:
281: }
282:
283: public OutputTextPanel selectToolsTab(boolean jumpToEnd) {
284: EventQueue.invokeLater(new Runnable() {
285: public void run() {
286: setSelectedComponent(toolsOutputPanel);
287: }
288: });
289:
290: if (jumpToEnd) {
291: toolsOutputPanel.setCaretEnd();
292: }
293: return toolsOutputPanel;
294: }
295:
296: /** Also called "execution tab".
297: */
298: public OutputTextPanel selectOutputTab(boolean jumpToEnd) {
299: EventQueue.invokeLater(new Runnable() {
300: public void run() {
301: setSelectedComponent(executionOutputPanel);
302: }
303: });
304:
305: if (jumpToEnd) {
306: executionOutputPanel.setCaretEnd();
307: }
308:
309: return executionOutputPanel;
310: }
311:
312: public void selectSearchTab() {
313: EventQueue.invokeLater(new Runnable() {
314: public void run() {
315: setSelectedComponent(searchTab);
316: }
317: });
318: }
319:
320: public CompilerOutputPanel select_tIDE_Tab(boolean jumpToEnd) {
321: EventQueue.invokeLater(new Runnable() {
322: public void run() {
323: setSelectedComponent(tideOutputPanel);
324: }
325: });
326:
327: if (jumpToEnd) {
328: tideOutputPanel.setCaretEnd();
329: }
330:
331: return tideOutputPanel;
332: }
333:
334: public void select_LineMessages() {
335: EventQueue.invokeLater(new Runnable() {
336: public void run() {
337: setSelectedComponent(lineMessagesPanel);
338: lineMessagesPanel.requestFocusForSearch();
339: }
340: });
341:
342: }
343:
344: public void setCompilerResult(boolean compileSuccess, int errors,
345: int warnings) {
346: final StringBuilder sb = new StringBuilder(compilerTabTitle);
347: if (errors > 0) {
348: sb.append(" (" + errors + " error"
349: + (errors == 1 ? "" : "s") + ")");
350: } else if (!compileSuccess) {
351: sb.append(" (fail)");
352: }
353:
354: EventQueue.invokeLater(new Runnable() {
355: public void run() {
356: int pos = indexOfComponent(compilerOutputPanel);
357: if (pos == -1)
358: pos = 1;
359: setTitleAt(pos, sb.toString());
360: }
361: });
362:
363: }
364:
365: public void setCompilingInProgress() {
366: EventQueue.invokeLater(new Runnable() {
367: public void run() {
368: setTitleAt(indexOfComponent(compilerOutputPanel),
369: "Compiling...");
370: }
371: });
372:
373: }
374:
375: public void setMessagesCount(int mess) {
376: final StringBuilder sb = new StringBuilder();
377: if (mess > 0) {
378: sb.append("" + mess);
379: }
380:
381: sb.append(" Message" + (mess == 1 ? "" : "s"));
382: EventQueue.invokeLater(new Runnable() {
383: public void run() {
384: int pos = 2;
385: //indexOfComponent(lineMessagesPanel)
386: setTitleAt(2, sb.toString());
387: }
388: });
389: }
390:
391: public void setSearchCount(int hits) {
392: final StringBuilder sb = new StringBuilder();
393: if (hits >= 0) {
394: sb.append("" + hits);
395: sb.append(" Search hit" + (hits == 1 ? "" : "s"));
396: } else {
397: sb.append("Search");
398: }
399:
400: EventQueue.invokeLater(new Runnable() {
401: public void run() {
402: int pos = indexOfComponent(searchTab);
403: if (pos < 0) {
404: System.out.println("pos of searchTab NOT found in "
405: + getComponentCount() + " tabs");
406: pos = 4;
407: }
408: setTitleAt(pos, sb.toString());
409: }
410: });
411: }
412:
413: public void filterMessages(String filter) {
414: this .select_LineMessages();
415: this .lineMessagesPanel.setFilter(filter);
416: }
417:
418: // Utils
419: //
420:
421: /** for example PMD generates such lines as in
422: */
423: public static FileItem recognizeLineWithAbsoluteSourceName_AndSelectInEditorIfFound(
424: String line) {
425: int pos = line.indexOf("\tat ");
426: if (pos == -1) {
427: // second chance, ALSO with 4 chars !! (used below), so don't remove the space or perform IF
428: pos = line.indexOf(" at ");
429: if (pos == -1)
430: return null;
431: }
432:
433: line = line.substring(4).trim();
434:
435: pos = line.indexOf(".java:");
436: if (pos <= 0) {
437: return null;
438: }
439:
440: String absFileName = line.substring(0, pos).replace('\\', '/');
441:
442: String sp = MainEditorFrame.instance.getActualProject()
443: .getSources_Home().getAbsolutePath().replace('\\', '/');
444: if (!sp.endsWith("/")) {
445: sp += "/";
446: }
447: if (!absFileName.startsWith(sp))
448: return null;
449:
450: String javaName = absFileName.substring(sp.length()).replace(
451: '/', '.');
452: System.out.println("relFileName=" + javaName);
453: String lineNbS = line.substring(pos + 6);
454: int lineNb = -1;
455: try {
456: lineNb = Integer.parseInt(lineNbS);
457: } catch (NumberFormatException ignored) {
458: }
459:
460: FileItem sf = MainEditorFrame.instance
461: .getFileItem(javaName, "");
462: if (sf == null) {
463: return null;
464: }
465:
466: MainEditorFrame.instance.setSourceOrItemToEditOrView(sf, true);
467:
468: if (lineNb >= 1) {
469: // highlight line
470: MainEditorFrame.instance.editorPanel.selectLine(lineNb - 1);
471:
472: }
473:
474: return sf;
475: }
476:
477: /** @return a non null source file if found
478: * used from execution output panel when a line is clicked
479:
480: [May2006]: also sometimes
481: Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
482: at javax.swing.plaf.basic.BasicTreeUI$Handler.isNavigationKey(Unknown Source)
483: at javax.swing.plaf.basic.BasicTreeUI$Handler.keyPressed(Unknown Source)
484: at java.awt.AWTEventMulticaster.keyPressed(Unknown Source)
485: at java.awt.Component.processKeyEvent(Unknown Source)
486:
487: [Aug2006]: hprof:
488: TRACE 302089:
489: javax.swing.tree.DefaultMutableTreeNode.getChildCount(DefaultMutableTreeNode.java:242)
490: tide.syntaxtree.DependenciesDetector.analyseRecuse(DependenciesDetector.java:177)
491: tide.syntaxtree.DependenciesDetector.analyseRecuse(DependenciesDetector.java:211)
492: tide.syntaxtree.DependenciesDetector.analyseRecuse(DependenciesDetector.java:211)
493:
494: sometimes
495:
496: tide.hello.test(Listener.java:Unknown line)
497:
498: */
499: public static FileItem recognizeStackTraceLine_AndSelectInEditorIfFound(
500: String line) {
501: // maybe we have a source to show as in at aaa.c.main(c.java:15)
502: // or aaa.d.main(d.java:15)
503: // or javax.swing.plaf.basic.BasicTreeUI$Handler.keyPressed(Unknown Source)
504:
505: String foundStart = "\tat ";
506: int pos = line.indexOf(foundStart);
507: if (pos == -1) {
508: // second chance
509: foundStart = " at ";
510: pos = line.indexOf(foundStart);
511: if (pos == -1) {
512: // third chance
513: foundStart = "\t";
514: pos = line.indexOf(foundStart);
515: if (pos == -1) {
516: foundStart = " ";
517: pos = line.indexOf(foundStart);
518: if (pos == -1) {
519: return null;
520: }
521: }
522: }
523: }
524:
525: if (line.indexOf(".java:") <= 0) {
526: // second chance
527: if (line.indexOf("(Unknown Source)") <= 0
528: && line.indexOf(".java)") <= 0) {
529: return null;
530: }
531: }
532:
533: String javaName = line.substring(pos + foundStart.length())
534: .trim();
535: String fileName = "";
536: String internalClassName = "";
537:
538: pos = javaName.indexOf('(');
539: if (pos >= 0) {
540: if (line.indexOf("(Unknown Source)") == -1) {
541: fileName = javaName.substring(pos + 1).trim();
542: int pos2 = fileName.indexOf(':');
543: if (pos2 > 0)
544: fileName = fileName.substring(0, pos2);
545: }
546:
547: javaName = javaName.substring(0, pos);
548: }
549:
550: // stop at internal class start
551: pos = javaName.indexOf('$');
552: if (pos >= 0) {
553: internalClassName = javaName.substring(pos + 1);
554: javaName = javaName.substring(0, pos);
555: }
556:
557: //MainEditorFrame.debugOut("clicked stack: " + javaName+" ("+fileName+"), "+internalClassName);
558:
559: // get first matching aaa.c.main ==> aaa.c
560: //SourceFile sf = MainEditorFrame.instance.sourcesTreePanel.getTreeModel().getSourceFileContaining(javaName);
561: FileItem sf = MainEditorFrame.instance.getFileItem(javaName,
562: fileName);
563:
564: if (sf == null) {
565: //MainEditorFrame.debugOut("not found");
566: return null;
567: }
568:
569: // eventually (normally !) line number
570:
571: //OLD pos = line.indexOf(':'); // [Feb2008]: stacks from logfiles with dates at beginning makes line detection fail !
572: pos = line.indexOf(".java:") + 5;
573: int lineNb = 0;
574: if (pos >= 0) {
575: String n = line.substring(pos + 1);
576: pos = n.indexOf(')');
577: if (pos >= 0) {
578: try {
579: n = n.substring(0, pos);
580: if (n.equals("Unknown line")) {
581: lineNb = 0;
582: } else {
583: lineNb = Integer.parseInt(n);
584: }
585: } catch (NumberFormatException e) {
586: System.out.println("Can't read an int in " + n);
587: }
588: }
589:
590: }
591:
592: if (lineNb >= 1) {
593: // highlight line
594: MainEditorFrame.instance.setSourceOrItemToEditOrView(sf,
595: true);
596: MainEditorFrame.instance.editorPanel.selectLine(lineNb - 1);
597: } else {
598: // look at the name of some method to highlight
599: /* MainEditorFrame.debugOut("=== No line number found =====, will look for method");
600: MainEditorFrame.debugOut(" line: "+line);
601: MainEditorFrame.debugOut(" found class: "+sf.getJavaName());
602: MainEditorFrame.debugOut(" full java name: "+javaName+", internal: '"+internalClassName+"'");
603: */
604:
605: // try the rest ( i.e. method, internal classes, ...)
606: if (javaName.length() > sf.getJavaName().length()) {
607: String diff = javaName.substring(sf.getJavaName()
608: .length() + 1); // without starting "."
609: //MainEditorFrame.debugOut(" method candidate = "+diff); // $Internal.run for example
610: // normally this is a method name !
611:
612: // show method
613: MainEditorFrame.instance.setMethodToView(sf, diff);
614:
615: } else {
616: // just show the first line
617: MainEditorFrame.instance.setSourceOrItemToEditOrView(
618: sf, true);
619: MainEditorFrame.instance.editorPanel.selectLine(0);
620: }
621: }
622:
623: return sf;
624: }
625:
626: /** May be tryed if no success by other tries.
627: *
628: * 1) "\tat javaName:line"
629: * 2) "\t at javaName" (Used by tIDE itself.)
630: * 3) "contains javaname:line" (ProGuard)
631: */
632: public static FileItem recognizeSimpleSyntaxLine_AndSelectInEditorIfFound(
633: final String line) {
634: if (line.trim().length() == 0)
635: return null; // [Feb2008]
636:
637: String javaName = line;
638: int pos = line.indexOf("\tat ");
639: if (pos < 0) {
640: // second chance
641: pos = line.indexOf("contains ");
642: }
643: if (pos >= 0) {
644: javaName = line.substring(pos + 4);
645: }
646:
647: javaName = javaName.trim();
648:
649: pos = javaName.indexOf(':');
650: int linen = -1;
651: if (pos > 0) {
652: String rest = javaName.substring(pos + 1);
653: javaName = javaName.substring(0, pos);
654: try {
655: linen = Integer.parseInt(rest);
656: } catch (NumberFormatException nfe) {
657: }
658: }
659:
660: FileItem sf = MainEditorFrame.instance
661: .getFileItem(javaName, "");
662: if (sf == null) {
663: return null;
664: }
665:
666: MainEditorFrame.instance.setSourceOrItemToEditOrView(sf, true);
667: if (linen >= 0) {
668: MainEditorFrame.instance.editorPanel.selectLine(linen);
669: }
670: return sf;
671: }
672: }
|