0001: /** tIDE -- a small java IDE.
0002: *
0003: * Copyright (c) 2005-2008 Stephan Heiss (stephan.heiss@gmail.com)
0004: *
0005: * This program is free software; you can redistribute it and/or modify it
0006: * under the terms of the GNU General Public License as published by the Free
0007: * Software Foundation; either version 2 of the License, or (at your option)
0008: * any later version.
0009: *
0010: * This program is distributed in the hope that it will be useful, but WITHOUT
0011: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0012: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
0013: * more details.fff
0014: *
0015: * You should have received a copy of the GNU General Public License along
0016: * with this program; if not, write to the Free Software Foundation, Inc.,
0017: * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0018: */package tide.editor;
0019:
0020: import snow.watchdog.WatchDog;
0021: import java.awt.Color;
0022: import tide.exttools.VariousSimpleTools;
0023: import java.awt.Dimension;
0024: import tide.staticanalysis.StaticAnalysis;
0025: import tide.staticanalysis.StaticAnalysisSettingsDialog;
0026: import tide.exttools.ToolsAutoApplyManager;
0027: import tide.exttools.gsd.GSDSettingsDialog;
0028: import java.util.zip.*;
0029: import java.net.URI;
0030: import java.awt.Desktop;
0031: import snow.Basics;
0032: import java.awt.TrayIcon;
0033: import java.awt.SystemTray;
0034: import javaparser.RAWParserTreeNodeFactory;
0035: import tide.jaranalysis.LibClassesInfo;
0036: import javaparser.ParserTreeNode;
0037: import tide.exttools.AStyle.AStyleSettingsDialog;
0038: import tide.editor.bookmarks.BookmarksManagementDialog;
0039: import tide.bytecode.DecompileManager;
0040: import tide.exttools.SVN.SVNSettingsDialog;
0041: import tide.editor.debugger.BreakpointLineMessage;
0042: import tide.editor.linemessages.*;
0043: import tide.update.UpdaterUtils;
0044: import tide.syntaxtree.SyntaxTreeCache;
0045: import tide.project.*;
0046: import tide.compiler.*;
0047: import tide.execute.*;
0048: import tide.sources.*;
0049: import tide.utils.*;
0050: import tide.export.*;
0051: import tide.syntaxtree.SimplifiedSyntaxTree2;
0052: import tide.exttools.JLint.JLintSettingsDialog;
0053: import tide.exttools.findbugs.FindBugsSettingsDialog;
0054: import tide.exttools.lint4j.Lint4JSettingsDialog;
0055: import tide.exttools.PMD.PMDSettingsDialog;
0056: import tide.javadocgen.JavaDocCreationDialog;
0057: import tide.syntaxtree.SyntaxTreePanel;
0058: import tide.exttools.jad_decompiler.*;
0059: import tide.exttools.checkstyle.*;
0060: import tide.exttools.proguard.*;
0061: import tide.syntaxtree.TreeFunctions;
0062: import tide.profiler.*;
0063: import tide.importtools.*;
0064: import snow.utils.storage.*;
0065: import snow.utils.gui.*;
0066: import snow.files.*;
0067: import snow.utils.*;
0068: import snow.datatransfer.ClipboardUtils;
0069: import snow.lookandfeel.ThemesManager;
0070: import java.text.SimpleDateFormat;
0071: import javax.swing.*;
0072: import java.net.InetAddress;
0073: import java.awt.BorderLayout;
0074: import java.awt.FlowLayout;
0075: import java.awt.Font;
0076: import java.awt.EventQueue;
0077: import java.util.prefs.Preferences;
0078: import java.awt.event.*;
0079: import javax.swing.border.*;
0080: import java.util.*;
0081: import java.io.*;
0082: import java.util.concurrent.*;
0083:
0084: /** The tIDE application top frame.
0085: * Contains also init stuff, management and so on.
0086: */
0087: public class MainEditorFrame extends JFrame {
0088: // may be set at startup, can also be changed from menu
0089: public static boolean debug = false;
0090: public static boolean useNewAST = false;
0091: public static boolean enableExperimental = false;
0092: public static boolean redirectConsoleInTab = false;
0093: public static boolean lowMemoryMode = false;
0094: public static boolean compileAllAtStartup = false;
0095: public static boolean noSearchTab = false;
0096: public static boolean compactUI = false;
0097:
0098: final private JCheckBoxMenuItem shutdownAtEnd;
0099:
0100: public static final String _VERSION = "tIDE 1.51 [19 Mar 2008] by stephan.heiss@gmail.com, distributed under the GPL Licence";
0101: public static final String OfficialTideJarPack200URL = "http://snowmail.sn.funpic.de/tide/tide.jar.pack.gz";
0102: // almost old, but alternatives
0103: public static final String Alt1TideJarPack200URL = "http://www.geocities.com/stephanchaud/tide.jar.pack.gz";
0104: // old !! makes NEVER sense to offer ! ( think about if you can!)
0105: //public static final String Alt2TideJarPack200URL = "http://downloads.sourceforge.net/tide/tide.jar.pack.gz?modtime=1192968126&big_mirror=0";
0106:
0107: public static Font fixedWidthFontForProcesses = new Font(
0108: "Lucida Sans Typewriter", Font.PLAIN, 11);
0109: static final String PROJ_File_Extension = ".tide_project";
0110:
0111: final public AppProperties globalProperties = new AppProperties();
0112: final private File globalPropFile = new File(System
0113: .getProperty("user.home"),
0114: ".tide_global/tide.globalProperties");
0115:
0116: final public JTabbedPane sourcesAndLibsPanel = new JTabbedPane();
0117: final public LibrariesPanel librariesPanel = new LibrariesPanel();
0118: final public SourcesTreePanel sourcesTreePanel = new SourcesTreePanel();
0119: final public SyntaxTreePanel syntaxTreePanel = new SyntaxTreePanel();
0120:
0121: final public EditorPanel editorPanel;
0122: //Task manager, compiler, output, search results
0123: final public OutputPanels outputPanels;
0124:
0125: final private JSplitPane verSplitLeft = new JSplitPane(
0126: JSplitPane.VERTICAL_SPLIT, sourcesAndLibsPanel,
0127: syntaxTreePanel); //parserTreeAndDependenciesPanel
0128: final private JSplitPane verSplitRight;
0129: final private JSplitPane horSplit1;
0130:
0131: final public JCheckBoxMenuItem enableParserWarnings = new JCheckBoxMenuItem(
0132: "Enable parser warnings", false); // currently not good... may be augmented with missing override ?
0133: final public JCheckBoxMenuItem ignoreExecutionOuputs = new JCheckBoxMenuItem(
0134: "Ignore executed program outputs", false);
0135: final public JCheckBoxMenuItem parseDependencies = new JCheckBoxMenuItem(
0136: "Detect dependencies", true);
0137: final public JCheckBoxMenuItem includeRAWCCTree = new JCheckBoxMenuItem(
0138: "Include raw cc tree", false);
0139: final public JCheckBoxMenuItem enableDotCompletion = new JCheckBoxMenuItem(
0140: "Enable completion after \".\"", true);
0141: final public JCheckBoxMenuItem globalDebugFlag = new JCheckBoxMenuItem(
0142: "Debug mode", debug);
0143:
0144: final public JMenu jdkDocsMenu = new JMenu("Local JDK Docs");
0145:
0146: public final JPanel editorControlPanel = new JPanel(new FlowLayout(
0147: FlowLayout.LEFT, 2, 0));
0148:
0149: // contain the actual edited project
0150: private final ProjectSettings actualProject = new ProjectSettings();
0151: // null if none currently open
0152: private File actualProjectFile = null;
0153: public final static String TITLE = "tIDE";
0154:
0155: /** Ensures that compile, load, save, run and clear are queued => 1 in parallel only !
0156: */
0157: final private ExecutorService mainExecutionService = Executors
0158: .newFixedThreadPool(1);
0159:
0160: /** Javadoc and classes libs are executed so. Not currently used as synchronization mechanism => parallel evaluation
0161: */
0162: final private ExecutorService delayedLoadProjectExecutionService = Executors
0163: .newFixedThreadPool(16);
0164:
0165: private final List<ProjectListener> projectListeners = new ArrayList<ProjectListener>();
0166:
0167: public static MainEditorFrame instance;
0168:
0169: public final static String LicenceHTMLBodyText = "<html><body><h2>tIDE -- a small java IDE</h2>"
0170: + "<p>"
0171: + "<h3>Copyright (c) 2005-2008 Stephan Heiss (stephan.heiss@gmail.com)"
0172: + "<br>Homepage: http://snowmail.sn.funpic.de/tide</h3>"
0173: + "<p><small>"
0174: + "This program is free software; you can redistribute it and/or modify it"
0175: + "<br>under the terms of the GNU General Public License as published by the Free"
0176: + "<br>Software Foundation; either version 2 of the License, or (at your option)"
0177: + "<br>any later version."
0178: + "</small></p><p><small>"
0179: + "<br>This program is distributed in the hope that it will be useful, but WITHOUT"
0180: + "<br>ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or"
0181: + "<br>FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for"
0182: + "<br> more details."
0183: + "</small></p><p><small>"
0184: + "<br> You should have received a copy of the GNU General Public License along"
0185: + "<br>with this program; if not, write to the Free Software Foundation, Inc.,"
0186: + "<br>59 Temple Place, Suite 330, Boston, MA 02111-1307 USA"
0187: + "</small></p>";
0188:
0189: /** @param args are the passed applications arguments
0190: */
0191: public MainEditorFrame(String[] args) {
0192: super (TITLE);
0193: instance = this ;
0194:
0195: outputPanels = new OutputPanels();
0196:
0197: if (redirectConsoleInTab) {
0198: //HINT: to redirect to a file, use: SysUtils.redirectSystemOutput(...)
0199:
0200: try {
0201: System.out
0202: .println("Redirecting outputs to tIDE log tab.");
0203:
0204: System
0205: .setOut(new PrintStream(
0206: outputPanels.tideConsoleOutputPanel.doc
0207: .createPrintStreamForThisDocument(false)));
0208: System
0209: .setErr(new PrintStream(
0210: outputPanels.tideConsoleOutputPanel.doc
0211: .createPrintStreamForThisDocument(true)));
0212:
0213: // First line:
0214: System.out.println(MainEditorFrame._VERSION);
0215:
0216: } catch (Exception e) {
0217: e.printStackTrace();
0218: }
0219: }
0220:
0221: this .setIconImage(Icons.createImage(new Icons.StartIcon(20, 20,
0222: true)));
0223:
0224: // Nov2007: move
0225: File oldgpf = new File(System.getProperty("user.home"),
0226: "tide.globalProperties");
0227: if (oldgpf.exists()) {
0228: try {
0229: FileUtils.copy(oldgpf, globalPropFile);
0230: if (!oldgpf.delete()) {
0231: oldgpf.deleteOnExit();
0232: }
0233: } catch (Exception e) {
0234: e.printStackTrace();
0235: }
0236: }
0237:
0238: if (globalPropFile.exists()) {
0239: globalProperties
0240: .loadFromStoredVectorRepresentation(globalPropFile);
0241: }
0242:
0243: if (!Preferences.userRoot().getBoolean("tIDE_lic_acc", false)) {
0244: // first start...
0245: int rep = JOptionPane
0246: .showConfirmDialog(
0247: null,
0248: LicenceHTMLBodyText
0249: + "<br><p><p>Do you agree with that licence ?",
0250: "tIDE Licence Agreement (GPL)",
0251: JOptionPane.YES_NO_OPTION);
0252: if (rep != JOptionPane.YES_OPTION)
0253: System.exit(0);
0254:
0255: Preferences.userRoot().putBoolean("tIDE_lic_acc", true);
0256: }
0257:
0258: syntaxTreePanel.hideInnerTypes.setSelected(globalProperties
0259: .getBoolean("syntaxTreePanel.hide_inner_types", false));
0260:
0261: //parserTreeAndDependenciesPanel.addTab("syntax", syntaxTreePanel);
0262: //parserTreeAndDependenciesPanel.addTab("dependencies", dependenciesPanel);
0263:
0264: sourcesAndLibsPanel.addTab(compactUI ? "Src" : "Sources",
0265: sourcesTreePanel);
0266: sourcesAndLibsPanel.addTab(compactUI ? "CP" : "ClassPath",
0267: librariesPanel);
0268: if (!noSearchTab) {
0269: sourcesAndLibsPanel.addTab("", Icons.sharedSearch,
0270: createSearchPanel());
0271: }
0272:
0273: sourcesAndLibsPanel.setSelectedIndex(0);
0274: sourcesAndLibsPanel.setBorder(null);
0275:
0276: editorPanel = new EditorPanel();
0277: verSplitRight = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
0278: editorPanel, outputPanels);
0279: verSplitRight.setBorder(null);
0280: horSplit1 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
0281: verSplitLeft, verSplitRight);
0282: horSplit1.setBorder(null);
0283:
0284: add(horSplit1, BorderLayout.CENTER);
0285: verSplitLeft.setOneTouchExpandable(true);
0286: verSplitLeft.setBorder(null);
0287: verSplitRight.setOneTouchExpandable(true);
0288: horSplit1.setOneTouchExpandable(true);
0289: verSplitLeft.setDividerLocation(400);
0290:
0291: horSplit1.setDividerLocation(250);
0292:
0293: // discard F10 (open first menu), cause we want to reassign it to execute project
0294: Action doNothing = new AbstractAction() {
0295: public void actionPerformed(ActionEvent e) {
0296: //do nothing
0297: }
0298: };
0299: getRootPane().getInputMap(
0300: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
0301: Accelerators.runProject, "doNothing");
0302: getRootPane().getActionMap().put("doNothing", doNothing);
0303:
0304: shutdownAtEnd = new JCheckBoxMenuItem(
0305: "Shutdown computer at tIDE termination", false); // if created in the constructor => bad look and feel !
0306: installMenu();
0307:
0308: this .getJMenuBar().add(Box.createHorizontalStrut(10));
0309: this .getJMenuBar().add(editorControlPanel);
0310: editorControlPanel.setOpaque(false);
0311:
0312: this .getJMenuBar().add(Box.createHorizontalGlue());
0313: this .getJMenuBar().add(new MemoryInfoPanel());
0314:
0315: // Global key actions
0316: //
0317: this .getRootPane().registerKeyboardAction(new ActionListener() {
0318: public void actionPerformed(ActionEvent ae) {
0319: compileOnlyChangedFiles();
0320: }
0321: }, "Compile changed files", Accelerators.compileChangedFiles,
0322: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
0323:
0324: this .getRootPane().registerKeyboardAction(new ActionListener() {
0325: public void actionPerformed(ActionEvent ae) {
0326: FileItem sf = editorPanel.getActualDisplayedFile();
0327: if (sf != null && sf instanceof SourceFile) {
0328: SourceFile ssf = (SourceFile) sf;
0329: execute(ssf, false, null, null); // without JMX and profiler
0330: }
0331: }
0332: }, "Execute selected class", Accelerators.runSelected,
0333: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
0334:
0335: this .addWindowListener(new WindowAdapter() {
0336: @Override
0337: public void windowClosing(WindowEvent we) {
0338: terminateApp();
0339: }
0340:
0341: @Override
0342: public void windowClosed(WindowEvent we) {
0343: terminateApp();
0344: }
0345: });
0346:
0347: globalProperties.setComponentSizeFromINIFile(this , "MainFrame",
0348: 1024, 750, 0, 0);
0349: if (this .getWidth() < 200 && this .getHeight() < 200) {
0350: this .setSize(1024, 750);
0351: }
0352: verSplitRight.setDividerLocation(this .globalProperties
0353: .getInteger("verSplitRight_loc", 580));
0354: this .setLocationRelativeTo(null); // center
0355: this .setVisible(true);
0356:
0357: // last arg may contain a valid project name => open it
0358:
0359: if (args != null && args.length > 0) {
0360: File pf = new File(args[args.length - 1]);
0361: if (pf.exists()
0362: && pf
0363: .getName()
0364: .toLowerCase(Locale.ENGLISH)
0365: .endsWith(PROJ_File_Extension.toLowerCase())) {
0366: actualProjectFile = pf;
0367: try {
0368: StorageVector sv = FileUtils
0369: .loadVectorFromFile(actualProjectFile);
0370: this .actualProject.createFromVectorRepresentation(
0371: sv, true);
0372: sv.clear();
0373: actualProject.setChangedFalse();
0374:
0375: Runnable ru = new Runnable() {
0376: public void run() {
0377: reloadActualProjectT(false);
0378: }
0379: };
0380: executeTask(ru);
0381: } catch (Exception e) {
0382: actualProjectFile = null;
0383: //System.out.println("Cannot load project passed as argument: "+pf);
0384: this .displayErrorMessage(e,
0385: "Cannot load project passed as argument "
0386: + pf);
0387: e.printStackTrace();
0388: }
0389: }
0390:
0391: else if (pf.getName().toLowerCase().endsWith(".java")) {
0392: try {
0393: createNewProjectGuessingFromSource(pf);
0394: } catch (Exception exe) {
0395: JOptionPane
0396: .showMessageDialog(
0397: MainEditorFrame.this ,
0398: "I cannot guess the project settings from the source passed."
0399: + "\nPlease create the project manually."
0400: + "\nThe error is: "
0401: + exe.getMessage(),
0402: "Cannot create new project",
0403: JOptionPane.ERROR_MESSAGE);
0404: exe.printStackTrace();
0405: System.exit(0);
0406: }
0407: return;
0408: }
0409:
0410: else if (pf.getName().toLowerCase().endsWith(".properties")) {
0411: netBeansImport(pf);
0412: return;
0413: } else if (pf.getName().toLowerCase()
0414: .endsWith(".classpath")) {
0415: this .eclipseImport(pf);
0416: return;
0417: } else if (pf.getName().toLowerCase().endsWith(
0418: ".schmortopf")) {
0419: this .schmortopfImport(pf);
0420: return;
0421: }
0422: }
0423:
0424: // start with loading a project if no defined
0425: if (actualProjectFile == null) {
0426: //Startup choices
0427: final Dimension dim = this .getSize();
0428: this .setSize(10, 10);
0429: final StartupDialog startupDialog = new StartupDialog(this ,
0430: globalProperties); // MODAL
0431: this .setSize(dim);
0432:
0433: if (startupDialog.searchedProj != null) {
0434: if (startupDialog.searchedProj.getName().toLowerCase()
0435: .endsWith(".java")) {
0436: try {
0437: createNewProjectGuessingFromSource(startupDialog.searchedProj);
0438: } catch (Exception exe) {
0439: JOptionPane
0440: .showMessageDialog(
0441: MainEditorFrame.this ,
0442: "I cannot guess the project settings from the source passed."
0443: + "\nPlease create the project manually."
0444: + "\nThe error is: "
0445: + exe.getMessage(),
0446: "Cannot create new project",
0447: JOptionPane.ERROR_MESSAGE);
0448: exe.printStackTrace();
0449: System.exit(0);
0450: }
0451: return;
0452: } else if (startupDialog.searchedProj.getName()
0453: .toLowerCase().endsWith(".properties")) {
0454: this .netBeansImport(startupDialog.searchedProj);
0455: return;
0456: } else if (startupDialog.searchedProj.getName()
0457: .toLowerCase().endsWith(".classpath")) {
0458: this .eclipseImport(startupDialog.searchedProj);
0459: return;
0460: } else if (startupDialog.searchedProj.getName()
0461: .toLowerCase().endsWith(".schmortopf")) {
0462: this .schmortopfImport(startupDialog.searchedProj);
0463: return;
0464: }
0465:
0466: else {
0467: actualProjectFile = startupDialog.searchedProj;
0468: }
0469:
0470: try {
0471: StorageVector sv = FileUtils
0472: .loadVectorFromFile(actualProjectFile);
0473: this .actualProject.createFromVectorRepresentation(
0474: sv, true);
0475:
0476: // Successful => create a backup (cache) just for debug purposes.
0477: File cache = new File(actualProject
0478: .getProjectSettingsFolder(),
0479: "lastProjectFile.cache");
0480: try {
0481: FileUtils.copy(actualProjectFile, cache);
0482: } catch (Exception ignore) {
0483: ignore.printStackTrace(); // but print
0484: }
0485:
0486: String check = "";
0487: if (!actualProject.getJava_Home().exists())
0488: check = "The project's Java Home doesn't exist anymore:\n "
0489: + actualProject.getJava_Home();
0490: else if (!actualProject.getRTJar().exists())
0491: check = "Invalid JDK (missing rt.jar):\n "
0492: + actualProject.getRTJar();
0493:
0494: if (check.length() > 0) {
0495: // User friendly wizard...
0496: SelectJDKDialog sjd = new SelectJDKDialog(
0497: this ,
0498: check
0499: + "\n\nYou can now select a new JDK:"
0500: + "\n (It's time to ensure you've got the newest from java.sun.com)\n");
0501:
0502: File jh = sjd.getSelectedJDKHomeOrNull();
0503: if (jh != null) {
0504: actualProject.setJava_Home(jh);
0505: }
0506: }
0507:
0508: String problem = "";
0509:
0510: // another check: look at source
0511:
0512: if (actualProject.getSources_Home() == null
0513: || !actualProject.getSources_Home()
0514: .exists()) {
0515: problem += "\n - source folder does not exist anymore.";
0516: }
0517:
0518: final List<File> auxCP = actualProject
0519: .getClassPath(false, false);
0520: for (final File fi : auxCP) {
0521: if (!fi.exists()) {
0522: problem += "\n - classpath item not existing: "
0523: + fi;
0524: }
0525: }
0526:
0527: if (problem != null && problem.length() > 0) {
0528: JOptionPane.showMessageDialog(
0529: MainEditorFrame.this ,
0530: "Please check your project settings:\n"
0531: + problem, "Invalid settings",
0532: JOptionPane.ERROR_MESSAGE);
0533: final ProjectSettingsEditorDialog psed = new ProjectSettingsEditorDialog(
0534: MainEditorFrame.this , actualProject,
0535: false, true);
0536: if (!psed.getHasBeenAccepted())
0537: return;
0538: }
0539:
0540: //NOsv.clear(); maybe USED as ref into... (???)
0541: actualProject.setChangedFalse();
0542:
0543: Runnable ru = new Runnable() {
0544: public void run() {
0545: reloadActualProjectT(false);
0546: }
0547: };
0548: executeTask(ru);
0549: } catch (Exception e) {
0550: actualProjectFile = null;
0551: JOptionPane.showMessageDialog(this , ""
0552: + e.getMessage(), "Project load error",
0553: JOptionPane.ERROR_MESSAGE);
0554: System.out.println("Cannot load project : "
0555: + startupDialog.searchedProj);
0556: System.out.println("File: " + actualProjectFile);
0557: e.printStackTrace();
0558: }
0559: } else if (startupDialog.createNew) {
0560: editSettingsDialog(true, true);
0561: } else if (startupDialog.openExisting) {
0562: Runnable load = new Runnable() {
0563: public void run() {
0564: openProjectAction(); // view settings if cancel pressed (create new project), exit if these props are cancelled
0565: }
0566: };
0567: executeTask(load);
0568: }
0569: }
0570:
0571: // clean old temp files...
0572: Thread t = new Thread() {
0573: public void run() {
0574: try {
0575: File tf = File.createTempFile("tide_", "temp"); // just to fetch the temp folder!
0576: File[] fs = tf.getParentFile().listFiles(
0577: new FileFilter() {
0578: public final boolean accept(
0579: final File pathname) {
0580: if (pathname.isFile()
0581: && pathname
0582: .getName()
0583: .toLowerCase()
0584: .startsWith("tide_"))
0585: return true;
0586: return false;
0587: }
0588: });
0589: if (fs != null)
0590: for (File fi : fs)
0591: fi.delete();
0592: } catch (Exception e) {
0593: e.printStackTrace();
0594: }
0595: }
0596: };
0597: t.start();
0598:
0599: } // Constructor
0600:
0601: public void addProjectListener(ProjectListener pl) {
0602: projectListeners.add(pl);
0603: }
0604:
0605: public void removeProjectListener(ProjectListener pl) {
0606: projectListeners.remove(pl);
0607: }
0608:
0609: private void notifyProjectListenersProjectOpened() {
0610: for (ProjectListener pl : projectListeners
0611: .toArray(new ProjectListener[projectListeners.size()])) {
0612: pl.projectHasBeenLoaded(this .actualProject);
0613: }
0614: }
0615:
0616: /** This call may take a "medium" time to execute. Because called at end, it has to wait until all calls have been performed.
0617: * (No thread are created).
0618: */
0619: public void notifyProjectListenersProjectClosed() {
0620: debugOut("Project has been closed: notify "
0621: + projectListeners.size() + " listeners");
0622: for (ProjectListener pl : projectListeners
0623: .toArray(new ProjectListener[projectListeners.size()])) {
0624: pl.projectHasBeenClosed(this .actualProject);
0625: }
0626: }
0627:
0628: /** All listeners saves their data when called. Without thread delay.
0629: * The editor, always listening saves the opened files.
0630: */
0631: public void notifyProjectListenersProjectSaving() {
0632: debugOut("projectIsSaving: notify " + projectListeners.size()
0633: + " listeners");
0634: for (ProjectListener pl : projectListeners
0635: .toArray(new ProjectListener[projectListeners.size()])) {
0636: try {
0637: pl.projectIsSaving(this .actualProject);
0638: } catch (Exception e) {
0639: e.printStackTrace();
0640: }
0641: }
0642: }
0643:
0644: private void eclipseImport(File nbProjPropFile) {
0645: try {
0646: new EclipseImport(nbProjPropFile, this .getActualProject());
0647: editSettingsDialog(true, true);
0648: } catch (Exception exe) {
0649: JOptionPane.showMessageDialog(MainEditorFrame.this ,
0650: "I cannot import the passed Eclipse project."
0651: + "\nPlease create the project manually."
0652: + "\nThe error is: " + exe.getMessage(),
0653: "Cannot import Eclipse project",
0654: JOptionPane.ERROR_MESSAGE);
0655: exe.printStackTrace();
0656: System.exit(0);
0657: }
0658: }
0659:
0660: private void schmortopfImport(File nbProjPropFile) {
0661: try {
0662: Schmortopf nbi = new Schmortopf(nbProjPropFile, this
0663: .getActualProject());
0664: editSettingsDialog(true, true);
0665: } catch (Exception exe) {
0666: JOptionPane.showMessageDialog(MainEditorFrame.this ,
0667: "I cannot import the passed Schmortopf project."
0668: + "\nPlease create the project manually."
0669: + "\nThe error is: " + exe.getMessage(),
0670: "Cannot import Schmortopf project",
0671: JOptionPane.ERROR_MESSAGE);
0672: exe.printStackTrace();
0673: System.exit(0);
0674: }
0675: }
0676:
0677: private void netBeansImport(File nbProjPropFile) {
0678: try {
0679: new NetBeansImport(nbProjPropFile, this .getActualProject());
0680: editSettingsDialog(true, true);
0681: } catch (Exception exe) {
0682: JOptionPane.showMessageDialog(MainEditorFrame.this ,
0683: "I cannot import the passed Netbeans project."
0684: + "\nPlease create the project manually."
0685: + "\nThe error is: " + exe.getMessage(),
0686: "Cannot import NetBeans project",
0687: JOptionPane.ERROR_MESSAGE);
0688: exe.printStackTrace();
0689: System.exit(0);
0690: }
0691: }
0692:
0693: /** Only called at startup when some java file has been choosed instead of a project file.
0694: * Here we an be "clever" and guess the source path and other infos.
0695: */
0696: private void createNewProjectGuessingFromSource(final File srcFile)
0697: throws Exception {
0698: System.out
0699: .println("tIDE started with a java file as argument: "
0700: + srcFile);
0701: try {
0702: String fcont = FileUtils.getFileStringContent(srcFile);
0703: SimplifiedSyntaxTree2 sst = SimplifiedSyntaxTree2.parse2(
0704: new StringReader(fcont), "");
0705: final String packageName;
0706: File sourcePath;
0707: if (sst.packageNode != null
0708: && sst.packageNode.toString().length() > 0) {
0709: packageName = sst.packageNode.toString();
0710: String[] packagePath = packageName.split("\\.");
0711: sourcePath = srcFile.getParentFile();
0712: for (int i = packagePath.length - 1; i >= 0; i--) {
0713: if (!packagePath[i].equals(sourcePath.getName())) {
0714: throw new Exception(
0715: "The passed source declares to be in package '"
0716: + packageName
0717: + "' but the filestructure"
0718: + "\nhas folder '"
0719: + sourcePath.getName()
0720: + "' instead of '"
0721: + packagePath[i] + "'");
0722: }
0723: sourcePath = sourcePath.getParentFile();
0724: }
0725: } else {
0726: packageName = ""; // unnamed scope
0727: sourcePath = srcFile.getParentFile();
0728: }
0729:
0730: actualProject.setSources_Home(sourcePath);
0731: actualProject.setMainSourceFile(srcFile);
0732:
0733: String pn = sourcePath.getName();
0734: String pnl = pn.toLowerCase();
0735: if (pnl.equals("source") || pnl.equals("src")
0736: || pnl.equals("quelle")) {
0737: actualProject.setProjectName(sourcePath.getParentFile()
0738: .getName());
0739: actualProject.setClasses_Home(new File(sourcePath
0740: .getParentFile(), "classes"));
0741: }
0742:
0743: editSettingsDialog(true, true);
0744: } catch (Exception e) {
0745: e.printStackTrace();
0746: throw e;
0747: }
0748: }
0749:
0750: private TrayIcon tideTrayIcon = null;
0751:
0752: /** Created at first call.
0753: */
0754: @edu.umd.cs.findbugs.annotations.CheckForNull
0755: public TrayIcon getTideTrayIcon() {
0756: if (tideTrayIcon != null)
0757: return tideTrayIcon;
0758: if (!SystemTray.isSupported())
0759: return null;
0760: Dimension disi = SystemTray.getSystemTray().getTrayIconSize();
0761: tideTrayIcon = new TrayIcon(Icons
0762: .createImage(new Icons.StartIcon((int) disi.getWidth(),
0763: (int) disi.getHeight(), true)));
0764: tideTrayIcon.addMouseListener(new MouseAdapter() {
0765: @Override
0766: public void mouseClicked(MouseEvent me) {
0767: toFront();
0768: }
0769: });
0770: try {
0771: SystemTray.getSystemTray().add(tideTrayIcon);
0772: } catch (Exception e) {
0773: Basics.ignore(e);
0774: }
0775:
0776: return tideTrayIcon;
0777: }
0778:
0779: /** This is used as the main synchronization engine for global operations like compiling, generating jar, javaDoc.
0780: * This is NOT coupled with the ProcessesManager.
0781: * But you can pass the returned Future in the ProcessesManager.
0782: */
0783: public Future executeTask(Runnable r) {
0784: return this .mainExecutionService.submit(r);
0785: }
0786:
0787: private final void installMenu() {
0788: this .setJMenuBar(new JMenuBar());
0789:
0790: JMenu fileMenu = new JMenu("File");
0791: this .getJMenuBar().add(fileMenu);
0792:
0793: JMenuItem saveModif = new JMenuItem("Save modified sources");
0794: saveModif.setAccelerator(Accelerators.saveChangedFiles);
0795: fileMenu.add(saveModif);
0796: saveModif.addActionListener(new ActionListener() {
0797: public void actionPerformed(ActionEvent ae) {
0798: editorPanel.saveChangedFiles();
0799: //MainEditorFrame.this.sourcesTreePanel.updateTree();
0800:
0801: // why not... ? NO, makes SLOW SLOW execution and other ops...
0802: //System.gc();
0803: }
0804: });
0805:
0806: JMenuItem openProj = new JMenuItem("Open project");
0807: fileMenu.addSeparator();
0808: fileMenu.add(openProj);
0809: openProj.addActionListener(new ActionListener() {
0810: public void actionPerformed(ActionEvent ae) {
0811: Runnable comp = new Runnable() {
0812: public void run() {
0813: //int rep = JOptionPane.showConfirmDialog(MainEditorFrame.this, "Are you sure ?.", "Confirmation", JOptionPane.YES_NO_CANCEL_OPTION);
0814: //if(rep!=JOptionPane.OK_OPTION) { return; }
0815:
0816: saveProjectAction(false);
0817: openProjectAction();
0818: }
0819: };
0820: executeTask(comp);
0821: }
0822: });
0823: JMenuItem saveProj = new JMenuItem("Save project");
0824: fileMenu.add(saveProj);
0825: saveProj.addActionListener(new ActionListener() {
0826: public void actionPerformed(ActionEvent ae) {
0827: Runnable comp = new Runnable() {
0828: public void run() {
0829: saveProjectAction(false);
0830: }
0831: };
0832: executeTask(comp);
0833: }
0834: });
0835:
0836: JMenuItem reloadProj = new JMenuItem("Reload project",
0837: Icons.sharedWiz);
0838: //reloadProj.setToolTipText("Useful if the files have changed from outside (CVS, Subversion, Source Safe, Mercurial)");
0839: fileMenu.addSeparator();
0840: fileMenu.add(reloadProj);
0841: reloadProj.addActionListener(new ActionListener() {
0842: public void actionPerformed(ActionEvent ae) {
0843: reloadProject();
0844: }
0845: });
0846:
0847: JMenuItem reloadProj2 = new JMenuItem(
0848: "Scan for external file changes", Icons.sharedWiz);
0849: reloadProj2.setAccelerator(Accelerators.scanExtFileChanges);
0850: reloadProj2
0851: .setToolTipText("Useful if the files have changed from outside (CVS, Subversion, Source Safe, Mercurial)");
0852: //fileMenu.addSeparator();
0853: fileMenu.add(reloadProj2);
0854: reloadProj2.addActionListener(new ActionListener() {
0855: public void actionPerformed(ActionEvent ae) {
0856: Runnable comp = new Runnable() {
0857: public void run() {
0858: try {
0859: sourcesTreePanel
0860: .refreshTreeBranchFromFileSystem(sourcesTreePanel
0861: .getTreeModel()
0862: .getRootSource());
0863: } catch (Exception e) {
0864: e.printStackTrace();
0865: }
0866: }
0867: };
0868: executeTask(comp);
0869: }
0870: });
0871:
0872: JMenuItem backup = new JMenuItem(
0873: "Create a project files backup", Icons.sharedUpArrow);
0874: backup
0875: .setToolTipText("Just a named and dated zip of all files in the project (sources, resources), created in the project /backup folder");
0876: fileMenu.addSeparator();
0877: fileMenu.add(backup);
0878: backup.addActionListener(new ActionListener() {
0879: public void actionPerformed(ActionEvent ae) {
0880: JDialog d = new JDialog(MainEditorFrame.this ,
0881: "Backup options", true);
0882: JPanel ip = new JPanel();
0883: GridLayout3 gl3 = new GridLayout3(1, ip);
0884: gl3
0885: .addExplanationArea("Please specify which backup kind you want."
0886: + "\nA named and dated backup is always created in <project>/backup folder."
0887: + "\nYou are invited to create folders named tide_backups in the root of some removable media"
0888: + "\n (USB sticks). If wanted, the backups will be automatically copied to each device with such a folder in its root.");
0889: d.add(ip, BorderLayout.CENTER);
0890:
0891: gl3.addSeparator();
0892:
0893: final JCheckBox srcOnly = new JCheckBox(
0894: "Include only sourcefiles", globalProperties
0895: .getBoolean("backup_only_sf", false));
0896: gl3.add(srcOnly);
0897: //gl3.add("");
0898:
0899: final JCheckBox db3 = new JCheckBox(
0900: "Copy to all roots+/tide_backups/",
0901: globalProperties.getBoolean(
0902: "backup_copy_to_roots", true));
0903: //bg.add(db3);
0904: gl3.add(db3);
0905: //gl3.add("");
0906:
0907: final JCheckBox newOnly = new JCheckBox(
0908: "Include only files younger than ", false);
0909: JPanel oyp = new JPanel(new FlowLayout(FlowLayout.LEFT,
0910: 0, 0));
0911: gl3.add(oyp);
0912: oyp.add(newOnly);
0913: final JComboBox yt = new JComboBox(new Object[] {
0914: "30 days", "7 days", "1 day", "12 hours",
0915: "6 hours", "1 hour", "30 min", "5 min" });
0916: yt.addActionListener(new ActionListener() {
0917: public void actionPerformed(ActionEvent ae) {
0918: newOnly.setSelected(true);
0919: }
0920: });
0921: final long[] ts = new long[] { 1000L * 3600 * 24 * 30,
0922: 1000L * 3600 * 24 * 7, 1000L * 3600 * 24,
0923: 1000L * 3600 * 12, 1000L * 3600 * 6,
0924: 1000L * 3600 * 1, 1000L * 60 * 30,
0925: 1000L * 60 * 5 };
0926: oyp.add(yt);
0927: //gl3.add("");
0928:
0929: JPanel labPanel = new JPanel(new FlowLayout(
0930: FlowLayout.LEFT, 5, 0));
0931: final JTextField label = new JTextField(10);
0932: labPanel.add(new JLabel("Opt Label: "));
0933: labPanel.add(label);
0934: gl3.add(labPanel);
0935:
0936: final CloseControlPanel ccp = new CloseControlPanel(d,
0937: true, true, "Create the backup");
0938: d.add(ccp, BorderLayout.SOUTH);
0939: d.pack();
0940: d.setLocationRelativeTo(null);
0941:
0942: label.addActionListener(new ActionListener() {
0943: public void actionPerformed(ActionEvent ae) {
0944: ccp.acceptAndClose();
0945: }
0946: });
0947:
0948: d.setVisible(true);//MODAL
0949:
0950: if (ccp.getWasCancelled())
0951: return;
0952:
0953: globalProperties.setBoolean("backup_only_sf", srcOnly
0954: .isSelected());
0955: globalProperties.setBoolean("backup_copy_to_roots", db3
0956: .isSelected());
0957:
0958: final ProgressModalDialog pmd = new ProgressModalDialog(
0959: MainEditorFrame.this ,
0960: "Project Archive Creation", false);
0961: pmd.start();
0962: Thread t = new Thread() {
0963: public void run() {
0964:
0965: projectBackup(pmd, srcOnly.isSelected(), db3
0966: .isSelected(), newOnly.isSelected(),
0967: ts[yt.getSelectedIndex()], label
0968: .getText().trim());
0969: }
0970: };
0971: t.start();
0972: }
0973: });
0974:
0975: fileMenu.addSeparator();
0976:
0977: fileMenu.add(shutdownAtEnd);
0978: shutdownAtEnd
0979: .setToolTipText("Maybe useful when running long tasks (export, analyses, ...).");
0980: shutdownAtEnd.addActionListener(new ActionListener() {
0981: public void actionPerformed(ActionEvent ae) {
0982: if (shutdownAtEnd.isSelected()) {
0983: int rep = JOptionPane
0984: .showConfirmDialog(
0985: MainEditorFrame.this ,
0986: "The system will be shut down at tIDE termination."
0987: + "\nAll applications will be terminated"
0988: + "\n(Note: only works on Windows 2K+ & Linux)."
0989: + "\n(The Local Security Policy must also allow you to initiate shutdowns)."
0990: + "\n\nAre you sure ?",
0991: "Confirmation",
0992: JOptionPane.YES_NO_CANCEL_OPTION);
0993: if (rep != JOptionPane.YES_OPTION) {
0994: shutdownAtEnd.setSelected(false);
0995: } else {
0996: // ensure it will be "possible". but may fail due to stupid policies errors...
0997:
0998: if (SysUtils.checkShutdown(false)) {
0999: if (getTideTrayIcon() != null) {
1000: getTideTrayIcon()
1001: .displayMessage(
1002: "tIDE",
1003: "tIDE will shutdown the system when terminated",
1004: TrayIcon.MessageType.INFO);
1005: getTideTrayIcon()
1006: .setToolTip(
1007: "tIDE will shutdown the system when terminated");
1008: }
1009: }
1010: }
1011: } else {
1012: if (getTideTrayIcon() != null) {
1013: getTideTrayIcon().setToolTip("tIDE");
1014: }
1015: }
1016: }
1017: });
1018:
1019: JMenuItem quit = new JMenuItem("Quit", Icons.sharedCross);
1020: fileMenu.addSeparator();
1021: fileMenu.add(quit);
1022: quit.addActionListener(new ActionListener() {
1023: public void actionPerformed(ActionEvent ae) {
1024: editorPanel.saveChangedFiles();
1025: terminateApp();
1026: }
1027: });
1028:
1029: JMenu projectMenu = new JMenu("Project");
1030: this .getJMenuBar().add(projectMenu);
1031: JMenuItem settings = new JMenuItem("Project Settings");
1032: settings.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P,
1033: KeyEvent.CTRL_MASK | KeyEvent.SHIFT_MASK));
1034: projectMenu.add(settings);
1035: settings.addActionListener(new ActionListener() {
1036: public void actionPerformed(ActionEvent ae) {
1037: editSettingsDialog(false, false);
1038: }
1039: });
1040:
1041: projectMenu.addSeparator();
1042: JMenuItem compile = new JMenuItem("Compile whole project",
1043: new Icons.LetterIcon("C", true, 16, 16, true));
1044: compile.setAccelerator(Accelerators.compileWholeProject);
1045: projectMenu.add(compile);
1046: compile.addActionListener(new ActionListener() {
1047: public void actionPerformed(ActionEvent ae) {
1048: editorPanel.saveChangedFiles();
1049:
1050: compileAll_queued();
1051: }
1052: });
1053: JMenuItem compileChanged = new JMenuItem(
1054: "Compile changed files only", new Icons.LetterIcon("C",
1055: true, 16, 16, true));
1056: compileChanged.setAccelerator(Accelerators.compileChangedFiles);
1057: projectMenu.add(compileChanged);
1058: compileChanged.addActionListener(new ActionListener() {
1059: public void actionPerformed(ActionEvent ae) {
1060: editorPanel.saveChangedFiles();
1061: compileOnlyChangedFiles();
1062: }
1063: });
1064:
1065: projectMenu.add(ExecuteActions.createProjectRunAction());
1066:
1067: JMenuItem globalSearch = new JMenuItem(
1068: "Search text in whole project", Icons.sharedSearch);
1069: globalSearch.setAccelerator(Accelerators.globalSearch);
1070: projectMenu.addSeparator();
1071: projectMenu.add(globalSearch);
1072: globalSearch.addActionListener(new ActionListener() {
1073: public void actionPerformed(ActionEvent ae) {
1074: List<SourceFile> all = actualProject.sourcesTreeModel
1075: .getAllSourceFiles(false);
1076: new SearchTool(all, false, "Search in all "
1077: + all.size() + " project sources");
1078: }
1079: });
1080:
1081: // created only once, unlike in the popup... so we can't hardcode the current package name here.
1082: JMenuItem searchInPackage = new JMenuItem(
1083: "Search text in current package", Icons.sharedSearch);
1084: searchInPackage.setAccelerator(Accelerators.searchInPackage);
1085: projectMenu.add(searchInPackage);
1086: searchInPackage.addActionListener(new ActionListener() {
1087: public void actionPerformed(ActionEvent ae) {
1088: FileItem actualDisplayedFile = MainEditorFrame.instance.editorPanel
1089: .getActualDisplayedFile();
1090: if (actualDisplayedFile == null)
1091: return;
1092:
1093: String pn = actualDisplayedFile.getPackageName();
1094:
1095: if (actualDisplayedFile instanceof SourceFile) {
1096: List<SourceFile> all = new ArrayList<SourceFile>();
1097: MainEditorFrame.instance.sourcesTreePanel
1098: .getTreeModel().getAllSourceFilesRecurse(
1099: (SourceFile) actualDisplayedFile
1100: .getParent(), all, false,
1101: false);
1102: new SearchTool(all, false, "Search in package "
1103: + pn + " (" + all.size() + " sources)");
1104: } else {
1105: List<LibFileItem> all = new ArrayList<LibFileItem>();
1106: MainEditorFrame.instance.librariesPanel
1107: .getTreeModel().getAllFilesRecurse(
1108: all,
1109: (LibFileItem) actualDisplayedFile
1110: .getParent(), true);
1111: new SearchTool(all, false, "Search in package "
1112: + pn + " (" + all.size() + " lib classes)");
1113: }
1114: }
1115: });
1116:
1117: JMenuItem globalSearchF = new JMenuItem(
1118: "Search filename in whole project", Icons.sharedSearch);
1119: globalSearchF
1120: .setAccelerator(Accelerators.globalProjectFilenameSearch);
1121: projectMenu.add(globalSearchF);
1122: globalSearchF.addActionListener(new ActionListener() {
1123: public void actionPerformed(ActionEvent ae) {
1124: new SearchTool(actualProject.sourcesTreeModel
1125: .getAllSourceFiles(false), true, null);
1126: }
1127: });
1128:
1129: JMenuItem messSearchF = new JMenuItem("Search messages",
1130: Icons.sharedSearch); // [Feb2008]
1131: messSearchF.setAccelerator(Accelerators.viewMessages);
1132: projectMenu.add(messSearchF);
1133: messSearchF.addActionListener(new ActionListener() {
1134: public void actionPerformed(ActionEvent ae) {
1135: outputPanels.select_LineMessages();
1136: }
1137: });
1138:
1139: projectMenu.addSeparator();
1140: JMenuItem manageBookmarks = new JMenuItem("Manage Bookmarks");
1141: manageBookmarks.setAccelerator(Accelerators.manageBookmarks);
1142: projectMenu.add(manageBookmarks);
1143: manageBookmarks.addActionListener(new ActionListener() {
1144: public void actionPerformed(ActionEvent ae) {
1145: // not modal
1146: new BookmarksManagementDialog("");
1147: }
1148: });
1149:
1150: JMenuItem javaDoc = new JMenuItem(
1151: "Generate documentation (JavaDoc)", SourcesTreeIcon
1152: .createSimpleLetterIcon("D"));
1153: javaDoc.setAccelerator(Accelerators.generateDocumentation);
1154: projectMenu.addSeparator();
1155: projectMenu.add(javaDoc);
1156: javaDoc.addActionListener(new ActionListener() {
1157: public void actionPerformed(ActionEvent ae) {
1158: editorPanel.saveChangedFiles();
1159: new JavaDocCreationDialog(MainEditorFrame.this ,
1160: actualProject);
1161: }
1162: });
1163:
1164: JMenuItem jar = new JMenuItem("Create project jar file",
1165: SourcesTreeIcon.createSimpleLetterIcon("J"));
1166: jar.setAccelerator(Accelerators.generateJarFile);
1167: projectMenu.addSeparator();
1168: projectMenu.add(jar);
1169: jar.addActionListener(new ActionListener() {
1170: public void actionPerformed(ActionEvent ae) {
1171: jarCreationAction(true);
1172: }
1173: });
1174:
1175: JMenuItem export = new JMenuItem(
1176: "Export project (file or ftp)", Icons.sharedUpArrow);
1177: export
1178: .setToolTipText("Exports the created jar and associated files (source, jnlp)...");
1179: export.setAccelerator(Accelerators.exportProject);
1180: projectMenu.add(export);
1181: export.addActionListener(new ActionListener() {
1182: public void actionPerformed(ActionEvent ae) {
1183: new ExportDialog(MainEditorFrame.this , actualProject,
1184: false);
1185: }
1186: });
1187:
1188: FileIcon dir2 = new FileIcon(true, 15);
1189: dir2.setType(FileIcon.IconColor.RedGreen);
1190: JMenuItem fex = new JMenuItem("Project files explorer", dir2);
1191: fex.setAccelerator(Accelerators.internalFilesExplorer);
1192: projectMenu.addSeparator();
1193: projectMenu.add(fex);
1194: fex.addActionListener(new ActionListener() {
1195: public void actionPerformed(ActionEvent ae) {
1196: new SourcesExplorer(
1197: MainEditorFrame.instance.sourcesTreePanel
1198: .getTreeModel().getAllSourceFiles(true),
1199: MainEditorFrame.this , null);
1200: }
1201: });
1202:
1203: FileIcon dir3 = new FileIcon(true, 15);
1204: dir3.setType(FileIcon.IconColor.RedGreen);
1205: JMenuItem internalResourceExpl = new JMenuItem(
1206: "Project resources explorer", dir3);
1207: internalResourceExpl
1208: .setAccelerator(Accelerators.internalResourcesExplorer);
1209: //fsMenu.addSeparator();
1210: projectMenu.add(internalResourceExpl);
1211: internalResourceExpl.addActionListener(new ActionListener() {
1212: public void actionPerformed(ActionEvent ae) {
1213: File home = MainEditorFrame.instance.getActualProject()
1214: .getSources_Home();
1215: FileItem viewed = MainEditorFrame.instance.editorPanel
1216: .getActualDisplayedFile();
1217: File editedSrc = (viewed instanceof SourceFile) ? ((SourceFile) viewed)
1218: .getFileOrDirectory()
1219: : null;
1220: new ResourcesExplorer(home, home, editedSrc);
1221: }
1222: });
1223:
1224: FileIcon dir = new FileIcon(true, 15);
1225: dir.setType(FileIcon.IconColor.RedGreen);
1226: JMenuItem pex = new JMenuItem("Project packages explorer", dir);
1227: //pex.setAccelerator( Accelerators.internalFilesExplorer );
1228: //projectMenu.addSeparator();
1229: projectMenu.add(pex);
1230: pex.addActionListener(new ActionListener() {
1231: public void actionPerformed(ActionEvent ae) {
1232: new PackagesExplorer(
1233: MainEditorFrame.instance.sourcesTreePanel
1234: .getTreeModel().getAllSourceFiles(true),
1235: MainEditorFrame.this );
1236: }
1237: });
1238:
1239: JMenuItem clear = new JMenuItem("Clear (delete all classes)",
1240: Icons.sharedCross);
1241: projectMenu.addSeparator();
1242: projectMenu.add(clear);
1243: clear.addActionListener(new ActionListener() {
1244: public void actionPerformed(ActionEvent ae) {
1245: runClear_queued();
1246: }
1247: });
1248:
1249: JMenu tools = new JMenu("Tools");
1250: this .getJMenuBar().add(tools);
1251:
1252: JMenuItem tlint = new JMenuItem("TLint, the internal checker",
1253: new Icons.LetterIcon("T", false, 14, 14, true,
1254: Color.green));
1255:
1256: tools.add(tlint);
1257: tlint.addActionListener(new ActionListener() {
1258: public void actionPerformed(ActionEvent ae) {
1259: new StaticAnalysisSettingsDialog();
1260: }
1261: });
1262:
1263: JMenuItem profSettings = new JMenuItem("JDK profiler settings");
1264: tools.addSeparator();
1265: tools.add(profSettings);
1266: profSettings.addActionListener(new ActionListener() {
1267: public void actionPerformed(ActionEvent ae) {
1268: new ProfilerSettingsDialog(MainEditorFrame.this ,
1269: actualProject);
1270: }
1271: });
1272:
1273: JMenuItem loadProf = new JMenuItem(
1274: "View an old profiler result");
1275: tools.add(loadProf);
1276: loadProf.addActionListener(new ActionListener() {
1277: public void actionPerformed(ActionEvent ae) {
1278: editorPanel.saveChangedFiles();
1279:
1280: JFileChooser fs = new JFileChooser(actualProject
1281: .getProfilerResultsFolder());
1282: FileChooserFilter fsf = new FileChooserFilter(fs);
1283: fs.setAccessory(fsf);
1284:
1285: fs
1286: .setDialogTitle("Open an existing profiler result performed on this project");
1287: fs.setApproveButtonText("Open selected file");
1288: fs.setMultiSelectionEnabled(false);
1289: fs.setFileSelectionMode(JFileChooser.FILES_ONLY);
1290: fs
1291: .setFileFilter(new javax.swing.filechooser.FileFilter() {
1292: public String getDescription() {
1293: return "HProf profiler results";
1294: }
1295:
1296: public boolean accept(java.io.File file) {
1297: if (file.isDirectory())
1298: return true;
1299: // the tool is not made to analyee heap dumps, use HAT instead !
1300: //if( file.getName().toLowerCase().endsWith(".heap_dump.hprof")) return false;
1301: if (file.getName().toLowerCase()
1302: .endsWith(".hprof"))
1303: return true;
1304: return false;
1305:
1306: }
1307: });
1308: int rep = fs.showOpenDialog(MainEditorFrame.this );
1309: if (rep != JFileChooser.APPROVE_OPTION)
1310: return;
1311:
1312: File sel = fs.getSelectedFile();
1313: if (sel.getName().toLowerCase().endsWith(
1314: ".heap_dump.hprof")) {
1315: /*JOptionPane.showMessageDialog(MainEditorFrame.this,
1316: "This tool is not intent to analyse heap dumps, tide can directly analyse"
1317: +"\nCPU and sites usages, please use HAT or jHAT to analyse the heap dumps.",
1318: "Cannot analyse heap dumps", JOptionPane.WARNING_MESSAGE);*/
1319: try {
1320: ProfilerUtils
1321: .analyseProfilerResultWithJHatTool(sel,
1322: null);
1323:
1324: } catch (Exception e) {
1325: JOptionPane.showMessageDialog(
1326: MainEditorFrame.this , ""
1327: + e.getMessage(),
1328: "Cannot analyse profiler result",
1329: JOptionPane.ERROR_MESSAGE);
1330: }
1331: } else {
1332: analyseProfilerResult(sel, null);
1333: }
1334: }
1335: });
1336:
1337: JMenu extTools = new JMenu("Ext Tools");
1338: this .getJMenuBar().add(extTools);
1339:
1340: JMenu analysisTools = new JMenu("Static Analysis Tools");
1341: extTools.add(analysisTools);
1342:
1343: JMenuItem pmd = new JMenuItem("Configure PMD");
1344: analysisTools.add(pmd);
1345: pmd.addActionListener(new ActionListener() {
1346: public void actionPerformed(ActionEvent ae) {
1347: new PMDSettingsDialog(MainEditorFrame.this ,
1348: actualProject);
1349: }
1350: });
1351:
1352: JMenuItem findBugs = new JMenuItem("Configure FindBugs");
1353: analysisTools.add(findBugs);
1354: findBugs.addActionListener(new ActionListener() {
1355: public void actionPerformed(ActionEvent ae) {
1356: new FindBugsSettingsDialog(MainEditorFrame.this ,
1357: actualProject);
1358: }
1359: });
1360:
1361: JMenuItem lint4j = new JMenuItem("Configure Lint4J");
1362: analysisTools.add(lint4j);
1363: lint4j.addActionListener(new ActionListener() {
1364: public void actionPerformed(ActionEvent ae) {
1365: new Lint4JSettingsDialog(MainEditorFrame.this ,
1366: actualProject);
1367: }
1368: });
1369:
1370: JMenuItem jlint = new JMenuItem("Configure JLint");
1371: analysisTools.add(jlint);
1372: jlint.addActionListener(new ActionListener() {
1373: public void actionPerformed(ActionEvent ae) {
1374: new JLintSettingsDialog(MainEditorFrame.this ,
1375: actualProject);
1376: }
1377: });
1378:
1379: JMenuItem checkstyle = new JMenuItem("Configure Checkstyle");
1380: analysisTools.addSeparator();
1381: analysisTools.add(checkstyle);
1382: checkstyle.addActionListener(new ActionListener() {
1383: public void actionPerformed(ActionEvent ae) {
1384: new CheckStyleSettingsDialog(MainEditorFrame.this ,
1385: actualProject);
1386: }
1387: });
1388:
1389: JMenuItem gsd = new JMenuItem("Configure GSD");
1390: gsd.setToolTipText("Google Singleton Detector");
1391: analysisTools.addSeparator();
1392: analysisTools.add(gsd);
1393: gsd.addActionListener(new ActionListener() {
1394: public void actionPerformed(ActionEvent ae) {
1395: new GSDSettingsDialog(MainEditorFrame.this ,
1396: actualProject);
1397: }
1398: });
1399:
1400: JMenuItem decomp = new JMenuItem("Configure JAD Decompiler");
1401: extTools.addSeparator();
1402: extTools.add(decomp);
1403: decomp.addActionListener(new ActionListener() {
1404: public void actionPerformed(ActionEvent ae) {
1405: new JADDecompilerSettingsDialog(MainEditorFrame.this ,
1406: actualProject);
1407: }
1408: });
1409:
1410: JMenuItem tda = new JMenuItem(
1411: "Configure TDA (Thread dump analysis)");
1412: //extTools.addSeparator();
1413: extTools.add(tda);
1414: tda.addActionListener(new ActionListener() {
1415: public void actionPerformed(ActionEvent ae) {
1416: VariousSimpleTools.configureTDA(MainEditorFrame.this ,
1417: actualProject);
1418: }
1419: });
1420:
1421: JMenuItem obfus = new JMenuItem("Configure Proguard obfuscator");
1422: //extTools.addSeparator();
1423: extTools.add(obfus);
1424: obfus.addActionListener(new ActionListener() {
1425: public void actionPerformed(ActionEvent ae) {
1426: new ProGuardSettingsDialog(MainEditorFrame.this ,
1427: actualProject);
1428: }
1429: });
1430:
1431: if (this .enableExperimental) {
1432: //? NO SENSE. sync allow good work with Tortoise SVN...
1433: JMenuItem svn = new JMenuItem("Configure Subversion (SVN)");
1434: //extTools.addSeparator();
1435: extTools.add(svn);
1436: svn.addActionListener(new ActionListener() {
1437: public void actionPerformed(ActionEvent ae) {
1438: new SVNSettingsDialog(MainEditorFrame.this ,
1439: actualProject);
1440: }
1441: });
1442: }
1443:
1444: JMenuItem aStyle = new JMenuItem("Configure AStyle");
1445: extTools.add(aStyle);
1446: aStyle.addActionListener(new ActionListener() {
1447: public void actionPerformed(ActionEvent ae) {
1448: new AStyleSettingsDialog(MainEditorFrame.this ,
1449: actualProject);
1450: }
1451: });
1452:
1453: // Editor
1454: //
1455:
1456: JMenu editorMenu = new JMenu("Editor");
1457: this .getJMenuBar().add(editorMenu);
1458: JMenuItem incrFontSize = new JMenuItem("Increase font size");
1459: incrFontSize.setAccelerator(Accelerators.increaseFontSize);
1460: editorMenu.add(incrFontSize);
1461: incrFontSize.addActionListener(new ActionListener() {
1462: public void actionPerformed(ActionEvent ae) {
1463: editorPanel.doc.increaseFontSize();
1464: }
1465: });
1466:
1467: JMenuItem decrFontSize = new JMenuItem("Decrease font size");
1468: decrFontSize.setAccelerator(Accelerators.decreaseFontSize);
1469: editorMenu.add(decrFontSize);
1470: decrFontSize.addActionListener(new ActionListener() {
1471: public void actionPerformed(ActionEvent ae) {
1472: editorPanel.doc.decreaseFontSize();
1473: }
1474: });
1475:
1476: editorMenu.addSeparator();
1477:
1478: JMenuItem sea = new JMenuItem("Search", Icons.sharedSearch);
1479: sea.setAccelerator(Accelerators.search);
1480: editorMenu.add(sea);
1481: sea.addActionListener(new ActionListener() {
1482: public void actionPerformed(ActionEvent ae) {
1483: editorPanel.searchPanel.CTRL_F_pressed();
1484: }
1485: });
1486:
1487: editorMenu.addSeparator();
1488: this .editorPanel.sourceEditorKit.addActions(editorMenu);
1489:
1490: editorMenu.addSeparator();
1491: JMenu autoReplacesMenu = UserAutoReplacements.getInstance()
1492: .createMenu();
1493: editorMenu.add(autoReplacesMenu);
1494:
1495: if (enableExperimental) {
1496: editorMenu.addSeparator();
1497: editorMenu.add(ThemesManager.getInstance().getThemesMenu()); // not very professionnal now...
1498: }
1499:
1500: JMenu optsTools = new JMenu("Options");
1501: this .getJMenuBar().add(optsTools);
1502: //optsTools.addSeparator();
1503: optsTools.add(enableParserWarnings);
1504:
1505: JMenuItem liberateResources = new JMenuItem(
1506: "Liberate resources");
1507: liberateResources
1508: .setAccelerator(Accelerators.liberateResources);
1509: liberateResources
1510: .setToolTipText("<html><body>clears the cached syntaxtrees and clipboard history.");
1511: optsTools.add(liberateResources);
1512: liberateResources.addActionListener(new ActionListener() {
1513: public void actionPerformed(ActionEvent ae) {
1514: if (debug) {
1515: outputPanels.clearConsoleLog();
1516:
1517: outputPanels.selectToolsTab(true);
1518: outputPanels.toolsOutputPanel.doc
1519: .appendLine("\nLiberating resources (caches and parser nodes):");
1520: outputPanels.toolsOutputPanel.doc
1521: .appendLine("Before: parser nodes: "
1522: + ParserTreeNode.created
1523: + " created, "
1524: + ParserTreeNode.terminated
1525: + " terminated, alive="
1526: + (ParserTreeNode.created - ParserTreeNode.terminated));
1527: outputPanels.toolsOutputPanel.doc
1528: .appendLine(RAWParserTreeNodeFactory
1529: .getInstance().toString());
1530: outputPanels.toolsOutputPanel.setCaretEnd();
1531: }
1532:
1533: editorPanel.saveChangedFiles();
1534: for (SourceFile s : actualProject.sourcesTreeModel
1535: .getAllSourceFilesAndDirectories(true)) {
1536: s.liberateResourcesForGC();
1537: }
1538:
1539: actualProject.getJavaDocManager()
1540: .clearLoadedDocsCache();
1541: ClipboardUtils.getInstance().clearHistory();
1542: SyntaxTreeCache.getInstance().clearCache();
1543: DecompileManager.getInstance().clear();
1544: //editorPanel. // clear the jump history ? no.
1545:
1546: if (debug) {
1547: int rem = (ParserTreeNode.created - ParserTreeNode.terminated);
1548: int perc = 100 * rem / ParserTreeNode.created;
1549: outputPanels.toolsOutputPanel.doc
1550: .appendLine("Parser nodes: "
1551: + ParserTreeNode.created
1552: + " created, "
1553: + ParserTreeNode.terminated
1554: + " terminated, alive=" + rem
1555: + " (" + perc + " %)");
1556: outputPanels.toolsOutputPanel.setCaretEnd();
1557: }
1558:
1559: RAWParserTreeNodeFactory.getInstance()
1560: .liberateResources();
1561:
1562: // two times, required for deeper cleaning...
1563: System.gc();
1564: System.gc();
1565:
1566: }
1567: });
1568:
1569: JMenu debugMenu = new JMenu("Debug");
1570: optsTools.addSeparator();
1571: optsTools.add(debugMenu);
1572:
1573: debugMenu.add(globalDebugFlag);
1574: debugMenu.addSeparator();
1575: debugMenu.add(enableDotCompletion);
1576: debugMenu.addSeparator();
1577: debugMenu.add(ignoreExecutionOuputs);
1578: debugMenu.add(parseDependencies);
1579: debugMenu.add(includeRAWCCTree);
1580:
1581: globalDebugFlag.addActionListener(new ActionListener() {
1582: public void actionPerformed(ActionEvent ae) {
1583: debug = globalDebugFlag.isSelected();
1584: }
1585: });
1586:
1587: JMenuItem clearDependencies = new JMenuItem(
1588: "Clear dependencies", Icons.sharedCross); // To recover from some Memory leak ?
1589: debugMenu.add(clearDependencies);
1590: clearDependencies.addActionListener(new ActionListener() {
1591: public void actionPerformed(ActionEvent ae) {
1592: editorPanel.saveChangedFiles();
1593: for (SourceFile s : actualProject.sourcesTreeModel
1594: .getAllSourceFilesAndDirectories(true)) {
1595: s.sourceFileDependencies.reset_();
1596: }
1597: }
1598: });
1599:
1600: JMenu helpMenu = new JMenu("Help");
1601: this .getJMenuBar().add(helpMenu);
1602:
1603: JMenuItem miMan = new JMenuItem("tIDE manual (online PDF)");
1604: miMan.setToolTipText(Tips.tideManual);
1605: helpMenu.add(miMan);
1606: miMan.addActionListener(new ActionListener() {
1607: public void actionPerformed(ActionEvent ae) {
1608: try {
1609: SysUtils.openBrowser(Tips.tideManual);
1610: } catch (Exception e) {
1611: e.printStackTrace();
1612: }
1613: }
1614: });
1615:
1616: final File localMan = new File("tide_manual.pdf");
1617: if (localMan.exists()) {
1618: JMenuItem miMan2 = new JMenuItem("tIDE manual (local)");
1619: helpMenu.add(miMan2);
1620: miMan2.addActionListener(new ActionListener() {
1621: public void actionPerformed(ActionEvent ae) {
1622: try {
1623: SysUtils.openDocumentInSystem(localMan
1624: .getAbsolutePath(), false);
1625: } catch (Exception e) {
1626: e.printStackTrace();
1627: }
1628: }
1629: });
1630: }
1631:
1632: JMenu helpMenuHints = new JMenu("Some short usage tips");
1633: helpMenu.addSeparator();
1634: helpMenu.add(helpMenuHints);
1635:
1636: for (final String[] tipi : Tips.tips) {
1637: if (tipi == null) {
1638: helpMenuHints.addSeparator();
1639: continue;
1640: }
1641:
1642: JMenuItem mi = new JMenuItem(tipi[0]);
1643: helpMenuHints.add(mi);
1644: mi.addActionListener(new ActionListener() {
1645: public void actionPerformed(ActionEvent ae) {
1646: final JDialog d = new JDialog(MainEditorFrame.this ,
1647: "tIDE usage tip: " + tipi[0], false);
1648: d.setSize(350, 500);
1649: final JEditorPane edp = new JEditorPane(
1650: "text/html", "<html><body><h1>" + tipi[0]
1651: + "</h1><p>" + tipi[1]
1652: + "</body></html>");
1653: edp.setEditable(false);
1654: d.add(new JScrollPane(edp), BorderLayout.CENTER);
1655: d.setLocation(700, 200);
1656:
1657: String[] topics = new String[Tips.tips.length];
1658: for (int ii = 0; ii < Tips.tips.length; ii++) {
1659: topics[ii] = Tips.tips[ii][0];
1660: }
1661: final JComboBox cb = new JComboBox(topics);
1662: cb.setMaximumRowCount(30);
1663: cb.setSelectedItem(tipi[0]);
1664: JPanel p = new JPanel(new FlowLayout(
1665: FlowLayout.LEFT, 5, 2));
1666: p.add(new JLabel("Topic: "));
1667: p.add(cb);
1668: d.add(p, BorderLayout.NORTH);
1669: cb.addActionListener(new ActionListener() {
1670: public void actionPerformed(ActionEvent ae) {
1671: if (cb.getSelectedIndex() >= 0) {
1672: edp.setText("<html><body><h1>"
1673: + Tips.tips[cb
1674: .getSelectedIndex()][0]
1675: + "</h1><p>"
1676: + Tips.tips[cb
1677: .getSelectedIndex()][1]
1678: + "</body></html>");
1679: }
1680: }
1681: });
1682:
1683: globalProperties.setComponentSizeFromINIFile(d,
1684: "TipsFrame", 350, 500, 700, 150);
1685: d.setVisible(true);
1686:
1687: d.addWindowListener(new WindowAdapter() {
1688: @Override
1689: public void windowClosing(WindowEvent we) {
1690: globalProperties
1691: .saveComponentSizeInINIFile(d,
1692: "TipsFrame");
1693: }
1694:
1695: @Override
1696: public void windowClosed(WindowEvent we) {
1697: globalProperties
1698: .saveComponentSizeInINIFile(d,
1699: "TipsFrame");
1700: }
1701: });
1702: }
1703: });
1704:
1705: }
1706:
1707: JMenu linksMenu = new JMenu("Some links");
1708: helpMenu.add(linksMenu);
1709:
1710: tl: for (final String[] linki : Tips.links) {
1711: if (linki == null) {
1712: linksMenu.addSeparator();
1713: continue tl;
1714: }
1715: JMenuItem mi = new JMenuItem(linki[0]);
1716: linksMenu.add(mi);
1717: mi.setToolTipText(linki[1]);
1718: mi.addActionListener(new ActionListener() {
1719: public void actionPerformed(ActionEvent ae) {
1720: try {
1721: SysUtils.openBrowser(linki[1]);
1722: } catch (Exception e) {
1723: e.printStackTrace();
1724: }
1725: }
1726: });
1727: }
1728:
1729: JMenu utilitiesMenu = new JMenu("Some utilities (in tide)");
1730: helpMenu.addSeparator();
1731: helpMenu.add(utilitiesMenu);
1732: /*
1733: JMenuItem uikeys = new JMenuItem("Swing UI Keys explorer");
1734: uikeys.setAccelerator(Accelerators.uiKeysExplorer);
1735: utilitiesMenu.add(uikeys);
1736: uikeys.addActionListener(new ActionListener()
1737: {
1738: public void actionPerformed(ActionEvent ae)
1739: {
1740: new snow.sortabletable.UIKeysViewer(false);
1741: }
1742: });
1743:
1744: JMenuItem props = new JMenuItem("System properties explorer");
1745: props.setAccelerator(Accelerators.systemPropsExplorer);
1746: utilitiesMenu.add(props);
1747: props.addActionListener(new ActionListener()
1748: {
1749: public void actionPerformed(ActionEvent ae)
1750: {
1751: new snow.sortabletable.SystemPropertiesViewer( MainEditorFrame.this);
1752: }
1753: });
1754: JMenuItem unic = new JMenuItem("Unicode explorer", new Icons.LetterIcon("\u03a9",false,17, 17, true));
1755: utilitiesMenu.addSeparator();
1756: utilitiesMenu.add(unic);
1757: unic.addActionListener(new ActionListener()
1758: {
1759: public void actionPerformed(ActionEvent ae)
1760: {
1761: new snow.sortabletable.UnicodeViewer(false);
1762: }
1763: });
1764: */
1765:
1766: for (JMenuItem mi : SharedUtils
1767: .getUtilitiesMenuItems_(actualProject)) {
1768: if (mi == null) {
1769: utilitiesMenu.addSeparator();
1770: } else {
1771: utilitiesMenu.add(mi);
1772: }
1773: }
1774:
1775: // install the Eye and countdown utilities, if wanted
1776: boolean autoc = Preferences.userRoot().getBoolean(
1777: "tide_countdown_autostart", true);
1778: if (autoc) {
1779: Countdown.installTrayIfNecessary();
1780: }
1781:
1782: /* TODO: ONLY LATER, After load */
1783: boolean auto = Preferences.userRoot().getBoolean(
1784: "tide_eye_autostart", true);
1785: if (auto) {
1786: Thread t = new Thread() {
1787: public void run() // SLOW if configured with a lot of watches !
1788: {
1789: try {
1790: Thread.sleep(15000);
1791: } catch (InterruptedException ex) {
1792: }
1793: WatchDog.installTrayIfNecessary();
1794: }
1795: };
1796: t.start();
1797: }
1798:
1799: JMenu extutilitiesMenu = new JMenu("Other Java applications");
1800: helpMenu.add(extutilitiesMenu);
1801:
1802: JMenuItem trestorizer = new JMenuItem(
1803: "T-Restorizer (Zip/unzip)", Icons.LozIcon.shared16Grow);
1804: trestorizer
1805: .setToolTipText("http://snowmail.sn.funpic.de/trestorizer/trestorizer.jnlp");
1806: extutilitiesMenu.add(trestorizer);
1807: trestorizer.addActionListener(new ActionListener() {
1808: public void actionPerformed(ActionEvent ae) {
1809: try {
1810: Process p = Runtime
1811: .getRuntime()
1812: .exec(
1813: actualProject.getJava_WebStart()
1814: .getAbsolutePath()
1815: + " http://snowmail.sn.funpic.de/trestorizer/trestorizer.jnlp");
1816: ProcessUtils.drainProcess(p, false);
1817: } catch (Exception e) {
1818: e.printStackTrace();
1819: }
1820: }
1821: });
1822:
1823: JMenuItem javawscache = new JMenuItem(
1824: "View all cached WebStart applications");
1825: javawscache
1826: .setToolTipText("this is just the command javaws -viewer");
1827: extutilitiesMenu.addSeparator();
1828: extutilitiesMenu.add(javawscache);
1829: javawscache.addActionListener(new ActionListener() {
1830: public void actionPerformed(ActionEvent ae) {
1831: try {
1832: Process p = Runtime.getRuntime().exec(
1833: actualProject.getJava_WebStart()
1834: .getAbsolutePath()
1835: + " -viewer");
1836: ProcessUtils.drainProcess(p, false);
1837: } catch (Exception e) {
1838: e.printStackTrace();
1839: }
1840: }
1841: });
1842:
1843: helpMenu.addSeparator();
1844: helpMenu.add(this .jdkDocsMenu);
1845:
1846: JMenu otherDocsMenu = new JMenu("Documentations & Help");
1847: helpMenu.add(otherDocsMenu);
1848: tl: for (final String[] linki : Tips.docLinks) {
1849: if (linki == null) {
1850: otherDocsMenu.addSeparator();
1851: continue tl;
1852: }
1853: JMenuItem mi = new JMenuItem(linki[0]);
1854: otherDocsMenu.add(mi);
1855: mi.setToolTipText(linki[1]);
1856: mi.addActionListener(new ActionListener() {
1857: public void actionPerformed(ActionEvent ae) {
1858: try {
1859: SysUtils.openBrowser(linki[1]);
1860: } catch (Exception e) {
1861: e.printStackTrace();
1862: }
1863: }
1864: });
1865: }
1866:
1867: if (!TideUtils.isWebStartMode()) {
1868: JMenuItem update = new JMenuItem(
1869: "Look for a new tIDE version",
1870: Icons.sharedSmallStart);
1871: helpMenu.addSeparator();
1872: helpMenu.add(update);
1873: update.addActionListener(UpdaterUtils.getUpdaterAction(
1874: this , false));
1875: }
1876:
1877: NonSense.create(helpMenu);
1878:
1879: JMenuItem ct = new JMenuItem("Feedback or Bug report",
1880: Icons.sharedWiz);
1881: helpMenu.addSeparator();
1882: helpMenu.add(ct);
1883: ct.addActionListener(new ActionListener() {
1884: public void actionPerformed(ActionEvent ae) {
1885: contactMe();
1886: }
1887: });
1888:
1889: JMenuItem you = new JMenuItem("About you");
1890: helpMenu.addSeparator();
1891: helpMenu.add(you);
1892: you.addActionListener(new ActionListener() {
1893: public void actionPerformed(ActionEvent ae) {
1894: JOptionPane.showMessageDialog(MainEditorFrame.this ,
1895: getAboutYouText(), "About you",
1896: JOptionPane.INFORMATION_MESSAGE);
1897: }
1898: });
1899:
1900: JMenuItem about = new JMenuItem("About tIDE", Icons
1901: .createHelpIcon(14, true));
1902: helpMenu.add(about);
1903: about.addActionListener(new ActionListener() {
1904: public void actionPerformed(ActionEvent ae) {
1905: JOptionPane.showMessageDialog(MainEditorFrame.this ,
1906: LicenceHTMLBodyText, _VERSION,
1907: JOptionPane.INFORMATION_MESSAGE);
1908: }
1909: });
1910: }
1911:
1912: public void reloadProject() {
1913: Runnable comp = new Runnable() {
1914: public void run() {
1915: saveProjectAction(false);
1916:
1917: notifyProjectListenersProjectClosed(); // [19.7.2007]: was missing
1918:
1919: reloadActualProjectT(false);
1920: }
1921: };
1922: executeTask(comp);
1923: }
1924:
1925: private String getAboutYouText() {
1926: StringBuilder sb = new StringBuilder();
1927: sb.append("Hello " + System.getProperty("user.name", "Tom"));
1928: sb.append(",\nyou are developping Java applications."
1929: + "\nYou're approximatively 30.");
1930: try {
1931: sb.append("\nYou're working on "
1932: + InetAddress.getLocalHost());
1933: } catch (Exception e) {
1934: e.printStackTrace();
1935: }
1936: return sb.toString();
1937: }
1938:
1939: private void projectBackup(final ProgressModalDialog pmd,
1940: final boolean sourcesOnly,
1941: final boolean copyToAllRootsBackupFolders,
1942: final boolean newOnly, long dt, String label) {
1943: BufferedOutputStream bos = null;
1944: org.apache.tools.zip.ZipOutputStream zos = null;
1945: try {
1946: final File home = actualProject.getSources_Home();
1947: final List<File> allFiles = FileUtils
1948: .getAllResourceFilesRecurse(home, null);
1949:
1950: if (sourcesOnly) {
1951: for (int i = allFiles.size() - 1; i >= 0; i--) // reverse !
1952: {
1953: if (!allFiles.get(i).getName().toLowerCase()
1954: .endsWith(".java")) {
1955: allFiles.remove(i);
1956: }
1957: }
1958: }
1959:
1960: if (newOnly) {
1961: for (int i = allFiles.size() - 1; i >= 0; i--) // reverse !
1962: {
1963: if (System.currentTimeMillis()
1964: - allFiles.get(i).lastModified() > dt) {
1965: allFiles.remove(i);
1966: }
1967: }
1968: }
1969:
1970: if (allFiles.isEmpty()) {
1971: JOptionPane.showMessageDialog(null,
1972: "No files to backup", "Error",
1973: JOptionPane.ERROR_MESSAGE);
1974: return;
1975: }
1976:
1977: pmd.setProgressBounds(allFiles.size());
1978: File bf = actualProject.getBackupFolder();
1979: if (!bf.exists())
1980: bf.mkdirs();
1981: File back = new File(bf, actualProject.getProjectName()
1982: + "_backup_"
1983: + (sourcesOnly ? "onlySrcs_" : "")
1984: + (newOnly ? "onlyNewest_" : "")
1985: + DateUtils.dateFormatMDYhmFileName.format(System
1986: .currentTimeMillis())
1987: + (label.length() > 0 ? "_" + label + "_" : "")
1988: + ".zip");
1989:
1990: pmd.setProgressSection(back.getAbsolutePath());
1991: bos = new BufferedOutputStream(new FileOutputStream(back),
1992: 1024 * 1000); // 1MB !
1993: zos = new org.apache.tools.zip.ZipOutputStream(bos);
1994: int sl = FileUtils.getCanonicalName(home.getParentFile())
1995: .length();
1996: pmd.resetStartTime();
1997: for (final File fi : allFiles) {
1998: pmd.incrementProgress(1);
1999: if (pmd.getWasCancelled()) {
2000: throw new Exception("Cancelled");
2001: }
2002:
2003: String rl = fi.getAbsolutePath().substring(sl);
2004: pmd.setProgressComment(rl);
2005:
2006: FileUtils.addToZip(zos, fi, rl);
2007: }
2008: zos.flush();
2009: bos.flush();
2010: zos.close(); // important
2011:
2012: this .outputPanels.select_tIDE_Tab(true).doc
2013: .appendLine("\nBackup made: " + back);
2014:
2015: if (copyToAllRootsBackupFolders) {
2016: int made = 0;
2017: File[] rts = File.listRoots();
2018: if (rts != null) {
2019: pmd.setProgressBounds(rts.length);
2020: pmd
2021: .setProgressSection("Exporting backup to all roots/tide_backups folders");
2022: for (File ri : rts) {
2023: pmd.incrementProgress(1);
2024:
2025: System.out
2026: .println("Looking for tide backups location on "
2027: + ri);
2028: File bi = new File(ri, "tide_backups");
2029: pmd.setProgressComment("looking for " + bi);
2030:
2031: if (bi.exists()) {
2032: pmd
2033: .setProgressComment("copying the backup to "
2034: + bi);
2035: System.out.println("Writing a backup to "
2036: + bi);
2037: FileUtils.copy(back, new File(bi, back
2038: .getName()));
2039: made++;
2040: }
2041: }
2042: }
2043:
2044: if (made == 0) {
2045: JOptionPane
2046: .showMessageDialog(
2047: null,
2048: "No backups were exported."
2049: + "\nPlease create folders named \"tide_backups\""
2050: + " in each drive root you want to define as backup media (memory stick, HD, ...).",
2051: "Warning",
2052: JOptionPane.WARNING_MESSAGE);
2053: }
2054: }
2055: } catch (Exception ex) {
2056: displayErrorMessage(ex, "Can't create project archive");
2057: } finally {
2058: FileUtils.closeIgnoringExceptions(zos);
2059: pmd.closeDialog();
2060: }
2061: }
2062:
2063: /** This edits the settings of the actual project. If none, starts a save action
2064: * @return true if the dialog was accepted (false if cancelled)
2065: */
2066: public boolean editSettingsDialog(final boolean firstCall,
2067: final boolean exitIfCancelled) {
2068: if (!firstCall && actualProjectFile != null) {
2069: // [Dec2006]: avoid diff message if reloading
2070: this .sourcesTreePanel.getTreeModel().storeFileFlags(
2071: actualProject);
2072: // save ??
2073: // no, this is too long... ??
2074: //this.saveProjectAction(false); // only if mandatory !!
2075: }
2076:
2077: ProjectSettingsEditorDialog psed = new ProjectSettingsEditorDialog(
2078: MainEditorFrame.this , actualProject, firstCall,
2079: exitIfCancelled);
2080: // always
2081: setTitle(TITLE + " [" + actualProject.getProjectName() + "]");
2082:
2083: if (!psed.getHasBeenAccepted())
2084: return false;
2085:
2086: if (actualProjectFile == null) {
2087: // enforce save (ask for a destination)
2088: saveProjectAction(true);
2089: }
2090:
2091: if (psed.mustReloadProjectBecauseOfChanges()) {
2092: Runnable ru = new Runnable() {
2093: public void run() {
2094: System.out.println("reloading project "
2095: + actualProject.getProjectName());
2096: saveProjectAction(false); // Added [Dec2006]
2097: reloadActualProjectT(firstCall);
2098: }
2099: };
2100: executeTask(ru);
2101: }
2102:
2103: return true;
2104: }
2105:
2106: /** This should be called queued in the main executor to ensure all importants tasks are done.
2107: * Here, we again return to the edt.
2108: */
2109: private void openProjectAction() {
2110: EventQueue.invokeLater(new Runnable() {
2111: public void run() {
2112: openProjectActionEDT();
2113: }
2114: });
2115: }
2116:
2117: private void openProjectActionEDT() {
2118: if (actualProjectFile != null && actualProject.hasChanged()) {
2119: // save eventualy opened project
2120: saveProjectAction(false);
2121: }
2122:
2123: JFileChooser fs = new JFileChooser(globalProperties
2124: .getProperty("LastProjDir", System
2125: .getProperty("user.home")));
2126: FileChooserFilter fsf = new FileChooserFilter(fs);
2127: fs.setAccessory(fsf);
2128:
2129: fs
2130: .setDialogTitle("Open an existing tide project or cancel to create a new one");
2131: fs.setApproveButtonText("Open selected project");
2132: fs.setMultiSelectionEnabled(false);
2133: fs.setFileSelectionMode(JFileChooser.FILES_ONLY);
2134: fs.setFileFilter(new javax.swing.filechooser.FileFilter() {
2135: public String getDescription() {
2136: return "tide projects";
2137: }
2138:
2139: public boolean accept(java.io.File file) {
2140: if (file.isDirectory())
2141: return true;
2142: if (file.getName().toLowerCase().endsWith(
2143: PROJ_File_Extension.toLowerCase()))
2144: return true;
2145: return false;
2146:
2147: }
2148: });
2149: int rep = fs.showOpenDialog(this );
2150: if (rep != JFileChooser.APPROVE_OPTION) {
2151: return;
2152: }
2153:
2154: // this waits until all listeners saved their states
2155: this .notifyProjectListenersProjectClosed();
2156: editorPanel.removeAllTabs();
2157:
2158: actualProjectFile = fs.getSelectedFile();
2159: globalProperties.setProperty("LastProjDir", actualProjectFile
2160: .getAbsolutePath());
2161: try {
2162:
2163: actualProject._terminate();
2164:
2165: StorageVector sv = FileUtils
2166: .loadVectorFromFile(actualProjectFile);
2167: this .actualProject.createFromVectorRepresentation(sv, true);
2168: sv.clear();
2169: actualProject.setChangedFalse();
2170: //this.setTitle( TITLE +" ["+actualProject.getProjectName()+"]");
2171:
2172: Runnable ru = new Runnable() {
2173: public void run() {
2174: reloadActualProjectT(false);
2175: }
2176: };
2177: executeTask(ru);
2178:
2179: } catch (Exception e) {
2180: JOptionPane.showMessageDialog(this , "" + e.getMessage(),
2181: "Cannot load project", JOptionPane.ERROR_MESSAGE);
2182: e.printStackTrace();
2183:
2184: // PROBLEM: if not loaded, make sure that this file will not be stored back with an empty content on exit !
2185: //
2186: actualProjectFile = null;
2187:
2188: }
2189: }
2190:
2191: /** Call this after having changed (or loaded) the actualProject content.
2192: Called when settings have changed and after load.
2193: DO NOT CALL FROM EDT !
2194: */
2195: private void reloadActualProjectT(boolean firstLoad) {
2196: final ProgressModalDialog[] pmd = new ProgressModalDialog[1];
2197: Runnable ru = new Runnable() {
2198: public void run() {
2199: pmd[0] = new ProgressModalDialog(MainEditorFrame.this ,
2200: "Loading project "
2201: + actualProject.getProjectName());
2202: pmd[0].setCommentLabel("Analysing sources...");
2203: pmd[0].start();
2204: pmd[0].showCloseTideButtonAfter20sec = false;
2205: }
2206: };
2207:
2208: if (EventQueue.isDispatchThread()) {
2209: new Throwable("SHOULD NOT BE THE EDT !").printStackTrace();
2210: ru.run();
2211: } else {
2212: try {
2213: EventQueue.invokeAndWait(ru);
2214: } catch (Exception e) {
2215: }
2216: }
2217:
2218: reloadActualProjectT(pmd[0], firstLoad);
2219: }
2220:
2221: /** Call this after having changed (or loaded) the actualProject content.
2222: Called when settings have changed and after load.
2223: Uses the storageVectors saved in the project to restore SourceFile datas.
2224: */
2225: private void reloadActualProjectT(final ProgressModalDialog pmd,
2226: boolean firstLoad) {
2227:
2228: DecompileManager.getInstance().clear();
2229: if (!firstLoad) {
2230: editorPanel.saveChangedFiles();
2231: }
2232:
2233: if (this .actualProjectFile != null) {
2234: // update known files to offer quick completion at next startup...
2235: List<String> kp = globalProperties.getArrayProperty(
2236: "KnownTIDEProjects", new String[] {});
2237:
2238: String np = FileUtils.getCanonicalFileWithCase(
2239: actualProjectFile).toString();
2240: Set<String> kps = new HashSet<String>(kp);
2241: if (!kps.contains(np)) {
2242: System.out.println("adding new known project");
2243: kps.add(np);
2244: globalProperties.setArrayProperty("KnownTIDEProjects",
2245: kps.toArray(new String[kps.size()]));
2246: //globalProperties
2247: }
2248: }
2249:
2250: EventQueue.invokeLater(new Runnable() {
2251: public void run() {
2252: setTitle(TITLE + " [" + actualProject.getProjectName()
2253: + "]");
2254: }
2255: });
2256:
2257: StringBuilder descr = new StringBuilder();
2258: descr.append("Loading project "
2259: + actualProject.getProjectName());
2260: long wt = actualProject.getWorkingTime();
2261: if (wt > 0) {
2262: descr.append(" (Opened time = "
2263: + DateUtils.formatTimeDifference(wt, true));
2264: descr.append(", active time = "
2265: + DateUtils.formatTimeDifference(actualProject
2266: .getActiveTime(), true));
2267: descr.append(", since "
2268: + SimpleDateFormat.getDateInstance().format(
2269: new Date(actualProject.getFirstStart())));
2270: descr.append(")");
2271: }
2272: descr.append("\n");
2273: outputPanels.tideOutputPanel.doc.setText(descr.toString()); // resets the text !!
2274:
2275: if (this .lowMemoryMode) {
2276: outputPanels.tideOutputPanel.doc
2277: .appendErrorLine("CAUTION: tIDE is working in low memory mode. (started with the -lowmem flag)."
2278: + "\r\n Some features will not be available, as for example libraries browsing.");
2279: }
2280:
2281: final List<File> exts = actualProject.getClassPath(true, false); // with src.zip and rt.jar! AND ignored
2282: // test
2283: File src_ = actualProject.getJavaAPISourceZIP();
2284: if (src_ == null || !src_.exists()) {
2285: JOptionPane
2286: .showMessageDialog(
2287: this ,
2288: "No src.zip found in the java home directory. Java API sources browsing will not be available.",
2289: "No java sources",
2290: JOptionPane.WARNING_MESSAGE);
2291: }
2292:
2293: // show the summary...
2294: final StringBuilder descre = new StringBuilder();
2295: descre.append("Total working time = "
2296: + DateUtils.formatTimeDifference(actualProject
2297: .getWorkingTime(), true));
2298: descre.append("\nActive time = "
2299: + DateUtils.formatTimeDifference(actualProject
2300: .getActiveTime(), true));
2301: descre.append("\nSince "
2302: + SimpleDateFormat.getDateInstance().format(
2303: new Date(actualProject.getFirstStart())));
2304:
2305: EventQueue.invokeLater(new Runnable() {
2306: public void run() {
2307: pmd.addSomeShortDescriptionLines(descre.toString());
2308: }
2309: });
2310:
2311: pmd.setCommentLabel("Analysing sources...");
2312:
2313: try {
2314: // Sources tree
2315: actualProject.sourcesTreeModel.setProject(actualProject,
2316: pmd, firstLoad);
2317:
2318: EventQueue.invokeAndWait(new Runnable() {
2319: public void run() {
2320: // we are now in the EDT !
2321: sourcesTreePanel
2322: .setModel(actualProject.sourcesTreeModel); // UI
2323: //emptyExecutionMenu();
2324: }
2325: });
2326:
2327: pmd.setCommentLabel("Checking " + exts.size()
2328: + " classpath libraries...");
2329:
2330: EventQueue.invokeAndWait(new Runnable() {
2331: public void run() {
2332: librariesPanel
2333: .setModel(actualProject.librariesTreeModel); // UI
2334: librariesPanel.setLibraries(exts, actualProject
2335: .getSourcesForClassPathLibraries());
2336: }
2337: });
2338:
2339: // this only create the tabs, no selection is performed
2340: pmd.setCommentLabel("Restoring editor settings");
2341:
2342: EventQueue.invokeAndWait(new Runnable() {
2343: public void run() {
2344: String det = actualProject.getProperty(
2345: "DisplayedEditorTabs", "[]");
2346: if (det.length() > 2) {
2347: det = det.substring(1, det.length() - 1);
2348: StringTokenizer st = new StringTokenizer(det,
2349: ",");
2350: List<String> jn = new ArrayList<String>();
2351: while (st.hasMoreTokens()) {
2352: jn.add(st.nextToken().trim()); // important: trim !
2353: }
2354: editorPanel.recreateTabsFromNames(jn);
2355: }
2356:
2357: // this selects in the tree and then the corresponding tab
2358: String ds = actualProject.getProperty(
2359: "DefaultSelectedNode", "");
2360: sourcesTreePanel.setSelectedJavaName(ds, true);
2361:
2362: }
2363: });
2364: } catch (Exception e) {
2365: e.printStackTrace();
2366: } finally {
2367: pmd.closeDialog();
2368: // triggers some lazy initialization processes (messages, ...)
2369: this .notifyProjectListenersProjectOpened();
2370:
2371: //PMDLauncher.getInstance().configureAutoScan();
2372: //CheckStyleLauncher.getInstance().configureAutoScan();
2373: ToolsAutoApplyManager.getInstance();
2374: }
2375:
2376: // some other lazy inits ... (TODO: through listeners)
2377: final Callable<ClassFilesManager> rcm = actualProject
2378: .reloadClassesManager();
2379: Callable<Object> reloadNotify = new Callable<Object>() {
2380: public Object call() throws Exception {
2381: // WAITS until reading of all libs:
2382: Object res = rcm.call();
2383:
2384: // [June 2007]
2385: if (!lowMemoryMode) {
2386: Thread t = new Thread() {
2387: public void run() {
2388: List<LibFileItem> allLibs = librariesPanel
2389: .getTreeModel()
2390: .getAllTopLevelLibs();
2391: LibClassesInfo.update_(allLibs);
2392: }
2393: };
2394: t.setPriority(Thread.MIN_PRIORITY);
2395: t.start();
2396: }
2397:
2398: return res;
2399: }
2400: };
2401:
2402: delayedLoadProjectExecutionService.submit(reloadNotify); // [Jan2007] was missing
2403: delayedLoadProjectExecutionService.submit(actualProject
2404: .reloadJavaDocManager());
2405:
2406: // compile all (only one time)
2407: if (compileAllAtStartup) {
2408: compileAll_queued();
2409: compileAllAtStartup = false; // only one time
2410: } else {
2411: // [March2008]: simple test. if no classes present => mark all project as not compiled !
2412: // this is often the case when working with a "volatile" ramdisk
2413: if (!actualProject.getClasses_Home().exists()
2414: || ArrayUtils.isEmpty(actualProject
2415: .getClasses_Home().list())) {
2416: List<SourceFile> allSources = actualProject.sourcesTreeModel
2417: .getAllSourceFiles(false); // not the ignored ones !
2418: for (SourceFile sfi : allSources) {
2419: sfi.setIsCompiled(false);
2420: }
2421: sourcesTreePanel.updateTree(); // updates the red compilation bars (add/remove)
2422:
2423: actualProject.setIsCompleteBuild(false);
2424: }
2425: }
2426:
2427: // [March208]: after corrected a bug in the dependencies detection:
2428: if (!actualProject.getBooleanProperty(
2429: "hasbeen_march2008_dep_bugfix", false)) {
2430: MainEditorFrame.instance.outputPanels.select_tIDE_Tab(true).doc
2431: .appendErrorLine("Bugfix: All dependencies will be redetected at the next partial recompilation (Shift+F9).");
2432:
2433: // only once !
2434: List<SourceFile> allSources = actualProject.sourcesTreeModel
2435: .getAllSourceFiles(false); // not the ignored ones !
2436: for (SourceFile sfi : allSources) {
2437: sfi.sourceFileDependencies.reset_();
2438: }
2439: actualProject.setBooleanProperty(
2440: "hasbeen_march2008_dep_bugfix", true);
2441: }
2442:
2443: // only once !
2444: if (!Preferences.userRoot().getBoolean("tide_a_day_work_mess2",
2445: false)) {
2446: if (actualProject.getWorkingTime() > 1000L * 3600 * 48
2447: && actualProject.getWorkingTime() < 1000L * 3600 * 24 * 31) // small bug: the first time, the tot working time is 38 years !
2448: {
2449: // a day (24Hrs of cumulated working time)
2450: Preferences.userRoot().putBoolean(
2451: "tide_a_day_work_mess2", true);
2452: EventQueue.invokeLater(new Runnable() {
2453: public void run() {
2454: JOptionPane
2455: .showMessageDialog(
2456: MainEditorFrame.this ,
2457: "Dear developper, you worked "
2458: + DateUtils
2459: .formatTimeDifference(actualProject
2460: .getWorkingTime())
2461: + " on this project. (cumulated active time)"
2462: + ".\n\nIt seems that tIDE is useful for at least one person in the world: YOU."
2463: + "\nIf you like it, don't hesitate to propagate it around, blog, publish, evangelize, proselytize, ..."
2464: + "\nAnd send any suggestions, or just comments per mail to the author."
2465: + "\nTIP: Don't forget to look for new versions and read the manual !"
2466: + "\n\n(This is a unique appearing message)",
2467: "Propagate tIDE!",
2468: JOptionPane.INFORMATION_MESSAGE);
2469: }
2470: });
2471: }
2472: }
2473:
2474: Preferences.userRoot().put("tide_last_opened_proj",
2475: this .getActualProjectFile().getAbsolutePath());
2476: StaticAnalysis.readSettings(actualProject);
2477:
2478: }
2479:
2480: /** Never null, contains the infos about the actual opened project, ...
2481: */
2482: public ProjectSettings getActualProject() {
2483: return actualProject;
2484: }
2485:
2486: /** @param enfoceAskingForNewFile if true, act liks a "Save As...".
2487: * Also called before loading another project.
2488: */
2489: private void saveProjectAction(boolean enfoceAskingForNewFile) {
2490: notifyProjectListenersProjectSaving();
2491:
2492: // just done above... editorPanel.saveChangedFiles();
2493:
2494: this .sourcesTreePanel.getTreeModel().storeFileFlags(
2495: actualProject);
2496:
2497: if (actualProjectFile == null || enfoceAskingForNewFile) {
2498: String name = actualProject.getProjectName();
2499:
2500: File defFile = actualProjectFile;
2501: if (defFile == null) {
2502: defFile = new File(
2503: globalProperties.getProperty("LastProjDir",
2504: System.getProperty("user.home")), name
2505: + PROJ_File_Extension);
2506: }
2507: JFileChooser fs = new JFileChooser(defFile.getParentFile());
2508: fs.setSelectedFile(defFile);
2509: fs.setDialogTitle("Choose the file to store the project "
2510: + name);
2511:
2512: fs.setMultiSelectionEnabled(false);
2513: fs.setFileSelectionMode(JFileChooser.FILES_ONLY);
2514: fs.setFileFilter(new javax.swing.filechooser.FileFilter() {
2515: public String getDescription() {
2516: return "tIDE projects";
2517: }
2518:
2519: public boolean accept(java.io.File file) {
2520: if (file.isDirectory())
2521: return true;
2522: return file.getName().toLowerCase().endsWith(
2523: PROJ_File_Extension.toLowerCase());
2524: }
2525: });
2526: int rep = fs.showSaveDialog(this );
2527: if (rep != JFileChooser.APPROVE_OPTION)
2528: return;
2529:
2530: File newActualProjectFile = fs.getSelectedFile();
2531: if (!newActualProjectFile.getName().toLowerCase().endsWith(
2532: PROJ_File_Extension.toLowerCase())) {
2533: newActualProjectFile = new File(newActualProjectFile
2534: .getAbsolutePath()
2535: + PROJ_File_Extension);
2536: }
2537:
2538: if (newActualProjectFile.exists()) {
2539: rep = JOptionPane
2540: .showConfirmDialog(
2541: this ,
2542: "The project file\n "
2543: + newActualProjectFile
2544: .getAbsolutePath()
2545: + "\nalready exists. Do you want to overwrite it ?",
2546: "Confirm file overwrite",
2547: JOptionPane.YES_NO_OPTION);
2548: if (rep != JOptionPane.YES_OPTION)
2549: return;
2550: }
2551: actualProjectFile = newActualProjectFile;
2552:
2553: globalProperties.setProperty("LastProjDir",
2554: actualProjectFile.getAbsolutePath());
2555: }
2556:
2557: String sel = sourcesTreePanel.getActualSelectedClassName();
2558: if (sel != null && sel.length() > 0) {
2559: actualProject.setProperty("DefaultSelectedNode", sel);
2560: }
2561:
2562: actualProject.setProperty("DisplayedEditorTabs", ""
2563: + this .editorPanel.getTabsJavaNames());
2564:
2565: try {
2566: FileUtils.saveVectorToFile(actualProjectFile, actualProject
2567: ._getVectorRepresentation());
2568: actualProject.setChangedFalse();
2569: System.out.println("Project "
2570: + actualProject.getProjectName() + " saved");
2571: } catch (Exception e) {
2572: JOptionPane.showMessageDialog(this , "" + e.getMessage(),
2573: "Cannot save project", JOptionPane.ERROR_MESSAGE);
2574: }
2575:
2576: try {
2577: actualProject.saveSourcesInfos();
2578: System.out.println("Project "
2579: + actualProject.getProjectName()
2580: + " source infos saved");
2581: } catch (Exception e) {
2582: JOptionPane.showMessageDialog(this , "" + e.getMessage(),
2583: "Cannot save project source infos",
2584: JOptionPane.ERROR_MESSAGE);
2585: }
2586:
2587: System.out.println("Project save done.");
2588: }
2589:
2590: /** @return null if not already saved.
2591: */
2592: public File getActualProjectFile() {
2593: return actualProjectFile;
2594: }
2595:
2596: /** Called from the export dialog, if the checkbox is selected...
2597: * and from any progress dialog that took a long time and where the user selected it.
2598: * Put in the queue, to ensure all enqueued tasks have been terminated.
2599: */
2600: public void terminateTIDE() {
2601: Runnable sdr = new Runnable() {
2602: public void run() {
2603: // don't waits...
2604: EventQueue.invokeLater(new Runnable() {
2605: public void run() {
2606: terminateApp();
2607: }
2608: });
2609: }
2610: };
2611:
2612: mainExecutionService.execute(sdr);
2613: }
2614:
2615: /** Called from windows listener and quit menu item => EDT.
2616: */
2617: private synchronized void terminateApp() {
2618: // EDT...
2619: final ProgressModalDialog pmd = new ProgressModalDialog(
2620: MainEditorFrame.this , "terminating tIDE", true);
2621:
2622: Thread t = new Thread() {
2623: public void run() {
2624: globalProperties.setBoolean(
2625: "syntaxTreePanel.hide_inner_types",
2626: syntaxTreePanel.hideInnerTypes.isSelected());
2627: globalProperties.saveComponentSizeInINIFile(
2628: MainEditorFrame.this , "MainFrame");
2629: globalProperties.setInteger("verSplitRight_loc",
2630: verSplitRight.getDividerLocation());
2631:
2632: //Always save... if(actualProject.changed)
2633: if (actualProjectFile != null) {
2634: pmd.start();
2635: pmd
2636: .setProgressCommentAndKeepIndeterminate("Saving project "
2637: + actualProject.getProjectName()
2638: + "...");
2639: saveProjectAction(false);
2640:
2641: // hmmm: tIDE is too quick ! the user just have no time to see this.
2642: // not really a problem, he see also these times when he starts, in the tide tab.
2643: final StringBuilder descr = new StringBuilder();
2644: descr.append("Total working time = "
2645: + DateUtils.formatTimeDifference(
2646: actualProject.getWorkingTime(),
2647: true));
2648: descr.append("\nActive time = "
2649: + DateUtils
2650: .formatTimeDifference(actualProject
2651: .getActiveTime(), true));
2652: descr.append("\nSince "
2653: + SimpleDateFormat.getDateInstance()
2654: .format(
2655: new Date(actualProject
2656: .getFirstStart())));
2657:
2658: EventQueue.invokeLater(new Runnable() {
2659: public void run() {
2660: pmd.addSomeShortDescriptionLines(descr
2661: .toString());
2662: }
2663: });
2664: } else {
2665: // first ask, then show the progress...
2666: saveProjectAction(false);
2667: pmd.start();
2668: }
2669:
2670: // show centered, even if mainframe is closed.
2671: pmd.setLocationRelativeTo(null);
2672:
2673: pmd
2674: .setProgressCommentAndKeepIndeterminate("Saving properties...");
2675: globalProperties
2676: .storeToFileAsVectorRepresentation(globalPropFile);
2677: //System.out.println("props stored: "+globalPropFile);
2678:
2679: pmd
2680: .setProgressCommentAndKeepIndeterminate("Saving autoreplacements...");
2681: UserAutoReplacements.getInstance().save();
2682:
2683: pmd
2684: .setProgressCommentAndKeepIndeterminate("Other close operations...");
2685: MainEditorFrame.this
2686: .notifyProjectListenersProjectClosed();
2687:
2688: pmd
2689: .setProgressCommentAndKeepIndeterminate("Shutting down...");
2690:
2691: if (shutdownAtEnd.isSelected()) {
2692: System.out
2693: .println("SHUT DOWN COMPUTER (in 30 sec) !!");
2694:
2695: if (getTideTrayIcon() != null) {
2696: getTideTrayIcon()
2697: .displayMessage(
2698: "tIDE is shutting down",
2699: "And tries to shut down the whole system as well...",
2700: TrayIcon.MessageType.INFO);
2701: }
2702:
2703: pmd
2704: .setProgressCommentAndKeepIndeterminate("Shutting computer down...");
2705: try {
2706: SysUtils
2707: .shutdown(
2708: 30,
2709: false,
2710: "System shutdown initiated by tIDE. Can be cancelled with the command 'shutdown -a'",
2711: false);
2712: Thread.sleep(10000); // 10 sec
2713: } catch (Exception e) {
2714: e.printStackTrace();
2715: }
2716: }
2717:
2718: EventQueue.invokeLater(new Runnable() {
2719: public void run() {
2720: // NORMAL TERMINATION
2721: System.exit(0);
2722: }
2723: });
2724: }
2725: };
2726: t.setName("Terminating");
2727: t.start();
2728: }
2729:
2730: public void execute(FileItem src,
2731: final boolean enableRemoteJMXAccess,
2732: final String hprofCommand, final String appArgs) {
2733: execute(src, enableRemoteJMXAccess, false, hprofCommand,
2734: appArgs);
2735: }
2736:
2737: /** Executes the class corresponding to this src file.
2738: Must contain a public static main(String[] a) method AND must be compiled.
2739: This action will be performed later, (just placed in the execution queue now)
2740: */
2741: public void execute(FileItem src,
2742: final boolean enableRemoteJMXAccess,
2743: final boolean launchDebugger, final String hprofCommand,
2744: final String appArgs) {
2745: debugOut("execute " + src);
2746: editorPanel.saveChangedFiles();
2747: if (src == null) {
2748: System.out.println("null file to execute !");
2749: return;
2750: }
2751:
2752: final String name = src.getJavaName();
2753: if (name.length() == 0) {
2754: new Throwable("empty java name to run ").printStackTrace();
2755: return;
2756: }
2757:
2758: // todo: also compile if notuptodate.
2759: if (src instanceof SourceFile) {
2760: final SourceFile sf = (SourceFile) src;
2761: if (!sf.isCompiled()) {
2762: List<SourceFile> sfs = new ArrayList<SourceFile>();
2763: sfs.add(sf);
2764: final Future fut = this .compile_queued(sfs, sf, false);
2765: Thread w = new Thread() {
2766: public void run() {
2767: try {
2768: fut.get(); //waits!!
2769: } catch (Exception e) {
2770: e.printStackTrace();
2771: }
2772:
2773: if (!sf.isCompiled()) {
2774: // failed;
2775: System.out
2776: .println("Cannot execute, compilation failed");
2777: return;
2778: }
2779: runAction_queued(name, enableRemoteJMXAccess,
2780: launchDebugger, hprofCommand, appArgs);
2781: }
2782: };
2783: w.start();
2784:
2785: return;
2786: }
2787: }
2788:
2789: runAction_queued(name, enableRemoteJMXAccess, launchDebugger,
2790: hprofCommand, appArgs);
2791: }
2792:
2793: /** Use this to show internal tIDE errors to the user. Don't abuse !
2794: */
2795: public void writeInternalErrorLine(String error) {
2796: outputPanels.toolsOutputPanel.doc.appendErrorLine(error);
2797: outputPanels.selectToolsTab(true);
2798: }
2799:
2800: /** All runs are started here.
2801: * TODO: offer to start in own console window.
2802: * @param applicationArguments_ if null, use actualProject.getAppArgs()
2803: */
2804: public void runAction_queued(final String mainClassName,
2805: final boolean enableRemoteJMXAccess,
2806: final boolean launchDebugger, final String hprofCommand,
2807: final String applicationArguments_) {
2808: final String applicationArguments = (applicationArguments_ != null ? applicationArguments_
2809: : actualProject.getAppArgs());
2810:
2811: // small helper: collect already executed files
2812: actualProject.addRan(mainClassName);
2813:
2814: final boolean ignoreOutputs = ignoreExecutionOuputs
2815: .isSelected();
2816: Runnable comp = new Runnable() {
2817: public void run() {
2818:
2819: try {
2820: outputPanels.selectOutputTab(false); // not necessary, since we clear the doc just hereafter.
2821:
2822: //outputPanels.getExecutionOutputDoc().setText("Executing "+actualProject.getProjectName()+":\r\n");
2823: outputPanels.getExecutionOutputDoc().setText(
2824: "Executing " + mainClassName + ":\r\n");
2825: if (hprofCommand != null
2826: && hprofCommand.length() > 0) {
2827: // not an error, but error color !
2828: outputPanels
2829: .getExecutionOutputDoc()
2830: .appendError(
2831: "Profiler enabled, command= "
2832: + hprofCommand + "\r\n");
2833: outputPanels
2834: .getExecutionOutputDoc()
2835: .appendError(
2836: "Perform the operation you want to profile, thereafter you can browse the results at application end.\r\n");
2837: }
2838:
2839: final JProcess proc = JavaExecutor.executeClass(
2840: actualProject.getSources_Home(),
2841: actualProject.getJava_TOOL(),
2842: actualProject.getClasses_Home(),
2843: mainClassName,
2844: actualProject.getClassPath(false, true), // user Classpath
2845: actualProject.getRuntimeArgs(),
2846: applicationArguments, //actualProject.getAppArgs(),
2847: actualProject.getJPS_TOOL(),
2848: enableRemoteJMXAccess, hprofCommand,
2849: launchDebugger);
2850:
2851: outputPanels.processesManager.addProcess(
2852: "Executing " + mainClassName, proc, false);
2853:
2854: if (ignoreOutputs) {
2855: outputPanels.getExecutionOutputDoc()
2856: .appendErrorLine(
2857: "Outputs are ignored !");
2858: ProcessUtils.drainProcess(proc.process, false);
2859:
2860: // on Windows, to start a system console for the application: (example)
2861: // Runtime.getRuntime().exec("cmd.exe /C start java -jar C:/abc.jar localhost");
2862: } else {
2863: // [July2007] was actualProject.getProjectName()
2864: String commentName = SyntaxUtils
2865: .makeSingleJavaNameSimple(mainClassName);
2866: StreamReader inReader = new StreamReader(
2867: commentName + "> ", proc.process
2868: .getInputStream(), outputPanels
2869: .getExecutionOutputDoc(),
2870: false, "run "
2871: + actualProject
2872: .getProjectName()
2873: + " (in)");
2874: inReader.start();
2875:
2876: // errors appears red. [Nov2007]: was black, not red.
2877: // TODO: read err immediately, to see print before line break...
2878: StreamReader errReader = new StreamReader(
2879: commentName + "> ", proc.process
2880: .getErrorStream(), outputPanels
2881: .getExecutionOutputDoc(), true,
2882: "run " + actualProject.getProjectName()
2883: + " (err)");
2884: errReader.start();
2885: }
2886:
2887: if (launchDebugger) {
2888: try {
2889: // NOT NICE !!! => enqueue...
2890: Thread.sleep(5000);
2891:
2892: if (SysUtils.is_Windows_OS()) {
2893: File jdbTool = actualProject
2894: .getJDK_Tool("jdb");
2895: // on Windows, start a system console for the jdb app.
2896: ProcessBuilder pb = new ProcessBuilder(
2897: "cmd.exe", "/C", "start",
2898: jdbTool.getAbsolutePath(),
2899: "-attach", "jdbconn");
2900: Process pdeb = pb.start();
2901: StreamReader inReader = new StreamReader(
2902: actualProject.getProjectName()
2903: + " JDB> ",
2904: pdeb.getInputStream(),
2905: outputPanels
2906: .getExecutionOutputDoc(),
2907: false,
2908: "run "
2909: + actualProject
2910: .getProjectName()
2911: + " (in)");
2912: inReader.start();
2913: StreamReader errReader = new StreamReader(
2914: actualProject.getProjectName()
2915: + " JDB> ",
2916: pdeb.getErrorStream(),
2917: outputPanels
2918: .getExecutionOutputDoc(),
2919: false,
2920: "run "
2921: + actualProject
2922: .getProjectName()
2923: + " (err)");
2924: errReader.start();
2925:
2926: } else {
2927: // LINUX !
2928: EventQueue.invokeLater(new Runnable() {
2929: public void run() {
2930: JOptionPane
2931: .showMessageDialog(
2932: MainEditorFrame.this ,
2933: "You have now to connect to the application with the debugger."
2934: + "\nUse the command jdb -attach jdbconn",
2935: "Application started in debug mode",
2936: JOptionPane.INFORMATION_MESSAGE);
2937: }
2938: });
2939:
2940: }
2941:
2942: // temporar: just show the breakpoints
2943: final List<LineMessage> allBreakPoints = LineMessagesManager
2944: .getInstance()
2945: .getAllMessagesOfType(
2946: BreakpointLineMessage.class);
2947: if (allBreakPoints.size() > 0) {
2948: final StringBuilder sb = new StringBuilder();
2949: for (LineMessage lm : allBreakPoints) {
2950: sb
2951: .append(((BreakpointLineMessage) lm)
2952: .toStringJavaForJDB()
2953: + "\r\n");
2954: }
2955: EventQueue.invokeLater(new Runnable() {
2956: public void run() {
2957: JTextArea ta = new JTextArea(sb
2958: .toString().trim());
2959: GUIUtils.displayInDialog(
2960: MainEditorFrame.this ,
2961: "Breakpoints",
2962: new JScrollPane(ta));
2963: }
2964: });
2965: }
2966:
2967: } catch (Exception e) {
2968: e.printStackTrace();
2969: }
2970:
2971: }
2972:
2973: // do NOT wait until completion ! // we want to be able to execute several programs in parallel !
2974: //inReader.join();
2975: //errReader.join();
2976:
2977: if (hprofCommand != null
2978: && hprofCommand.length() > 0) {
2979: final Thread waiter = new Thread() {
2980: public void run() {
2981: try {
2982: int rep = proc.process.waitFor();
2983: if (hprofCommand != null
2984: && hprofCommand.length() > 0) {
2985: System.out
2986: .println("Execution terminated => looking at profiler results");
2987: File pf = getActualProject()
2988: .getProfilerResultsFolder();
2989: if (pf.exists()) {
2990: for (final File f : pf
2991: .listFiles()) {
2992: if (hprofCommand
2993: .indexOf(f
2994: .getName()) > 0) {
2995: EventQueue
2996: .invokeLater(new Runnable() {
2997: public void run() {
2998: analyseProfilerResult(
2999: f,
3000: proc);
3001: }
3002: });
3003: return;
3004: }
3005: }
3006: }
3007: }
3008: } catch (Exception e) {
3009: e.printStackTrace();
3010: }
3011: }
3012: };
3013: waiter.setName("Waiter for execution ond of "
3014: + mainClassName);
3015: waiter.start();
3016: }
3017: } catch (java.lang.InterruptedException e) // not especially useful...
3018: {
3019: outputPanels.getExecutionOutputDoc()
3020: .appendErrorLine(
3021: "Execution of "
3022: + actualProject
3023: .getProjectName()
3024: + " aborted");
3025: } catch (Exception e) {
3026: e.printStackTrace();
3027: outputPanels.getExecutionOutputDoc()
3028: .appendErrorLine(
3029: "Execution of "
3030: + actualProject
3031: .getProjectName()
3032: + " error: "
3033: + e.getMessage());
3034: }
3035: }
3036: };
3037:
3038: // several can be executed in parallel => the comp DOES NOT WAIT UNTIL COMPLETION,
3039: // but we want to start it one at a time, and maybe wait on compilation or other tasks
3040: executeTask(comp);
3041: }
3042:
3043: /** as of 1.5, the format can change without notifications... so don't do too much work...
3044: * @param proc eventually (maybe null) the process used.
3045: */
3046: private void analyseProfilerResult(final File f, final JProcess proc) {
3047: if (f.getName().toLowerCase().indexOf(".heap_dump.hprof") > 0) {
3048: // NO head dump analysis available, we only look at cpu and sites
3049: try {
3050: ProfilerUtils
3051: .analyseProfilerResultWithJHatTool(f, null);
3052: } catch (Exception e) {
3053: outputPanels.getExecutionOutputDoc().appendErrorLine(
3054: "HEAP Dump analysis tool jHAT (only available since 1.6):\n"
3055: + e.getMessage());
3056: }
3057:
3058: return;
3059: }
3060:
3061: ProfilerResultViewer prv = new ProfilerResultViewer(f, proc);
3062: prv.installAsTab();
3063: //outputPanels.addNewTab("Profiler result", prv);
3064: }
3065:
3066: // [Feb2008]
3067: private JPanel createSearchPanel() {
3068: JPanel p = new JPanel(new BorderLayout(2, 2));
3069: p.setBackground(UIManager.getColor("Tree.background"));
3070: JButton jumpBackBT = new JButton(new Icons.LetterIcon("R",
3071: false, 14, 14, true));
3072: GUIUtils.makeNiceButton(jumpBackBT);
3073: jumpBackBT.setAlignmentY(0.75f);
3074:
3075: JButton depBT = new JButton(new Icons.HArrow(14, 14, true,
3076: true, false));
3077: GUIUtils.makeNiceButton(depBT);
3078: depBT.setAlignmentY(0.75f);
3079:
3080: p
3081: .add(
3082: GUIUtils
3083: .createReadOnlyDescriptionArea(
3084: "Some useful search hints:\n"
3085: + "\nCtrl+F brings almost everywhere context search."
3086: + "\nCtrl+G performs global project search."
3087: + "\nCtrl+Shift+G searches project class names."
3088: + "\nCtrl+T search/insert a class."
3089: + "\nCtrl+P search in the current package."
3090: + "\nCtrl+M search in the messages."
3091: + "\nRight-click on trees and textpanes for detailled"
3092: + "\n context-depending searches."
3093: + "\n\nThe recent history $$1 let you jump"
3094: + "\n to the recent files and bookmarks."
3095: + "\nThe dependencies $$2 let you jump to the"
3096: + "\n sources using and used by the displayed source.",
3097:
3098: jumpBackBT, depBT),
3099: BorderLayout.NORTH);
3100:
3101: p.setMinimumSize(new Dimension(10, 10));
3102:
3103: JPanel pan = new JPanel();
3104: pan.setBackground(p.getBackground());
3105:
3106: pan.setLayout(new BoxLayout(pan, BoxLayout.Y_AXIS));
3107: p.add(pan, BorderLayout.CENTER);
3108: pan.setBorder(new EmptyBorder(5, 5, 0, 0));
3109:
3110: //gl3.add(new JLabel(""), true);
3111: /*
3112: JButton gs = new JButton("Global search");
3113: GUIUtils.makeNiceButton(gs);
3114: gl3.add(gs);
3115:
3116: JButton ts = new JButton("Type search");
3117: GUIUtils.makeNiceButton(ts);
3118: gl3.add(ts);
3119:
3120: gl3.addSeparator();
3121:
3122:
3123: pan.add(Box.createVerticalStrut(5));
3124:
3125: final JButton recentViewed = new JButton("Recently viewed", Icons.sharedRightArrow);
3126: GUIUtils.makeNiceButton(recentViewed);
3127: pan.add(recentViewed);
3128: recentViewed.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) {
3129: JPopupMenu pop = new JPopupMenu();
3130: for(JMenuItem mi : MainEditorFrame.instance.editorPanel.jumpManager.getRecentViewedJumpMenuItems(25))
3131: {
3132: pop.add(mi);
3133: }
3134: pop.show(recentViewed, 0, recentViewed.getHeight());
3135: } });
3136:
3137: pan.add(Box.createVerticalStrut(5));
3138:
3139: final JButton recentEdited = new JButton("Recently edited", Icons.sharedRightArrow);
3140: GUIUtils.makeNiceButton(recentEdited);
3141: pan.add(recentEdited);
3142: recentEdited.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) {
3143: JPopupMenu pop = new JPopupMenu();
3144: for(JMenuItem mi : MainEditorFrame.instance.editorPanel.jumpManager.getRecentEditedJumpMenuItems(25))
3145: {
3146: pop.add(mi);
3147: }
3148: pop.show(recentEdited, 0, recentEdited.getHeight());
3149: } });
3150:
3151: pan.add(Box.createVerticalStrut(5));
3152:
3153: final JButton recentBM = new JButton("Recently bookmarked", Icons.sharedRightArrow);
3154: GUIUtils.makeNiceButton(recentBM);
3155: pan.add(recentBM);
3156: recentBM.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) {
3157: JPopupMenu pop = new JPopupMenu();
3158: SharedUtils.addRecentBookmarks(pop, 20);
3159: pop.show(recentBM, 0, recentEdited.getHeight());
3160: } });
3161: */
3162:
3163: return p;
3164: }
3165:
3166: /** Adds to sources all other sources using them.
3167: * (Simplified example: for "String", add "File", because File uses String and a change in
3168: * "String", for example when a member gets private, may have an influence on "File" ).
3169: *
3170: * @return the number of dependencies added.
3171: */
3172: private int augmentWithDependencies(
3173: final Collection<SourceFile> sources) {
3174: Collection<SourceFile> deps = new HashSet<SourceFile>();
3175: for (SourceFile src : sources) {
3176: for (SourceFile srcdep : src.sourceFileDependencies
3177: .getClassesUsingThis_REF_()) {
3178: if (!sources.contains(srcdep)) {
3179: deps.add(srcdep);
3180: }
3181: }
3182: }
3183:
3184: MainEditorFrame.debugOut("Added " + deps.size()
3185: + " dependencies to " + sources.size() + " sources");
3186: sources.addAll(deps);
3187: return deps.size();
3188: }
3189:
3190: /** Deletes all class files in the classes directory, and all empty directories.
3191: */
3192: private void runClear_queued() {
3193:
3194: Runnable comp = new Runnable() {
3195: public void run() {
3196: outputPanels.compilerOutputPanel
3197: .setText("Deleting all classes... "); // clear output, to avoid ugly side effects
3198: outputPanels.selectCompilerTab();
3199:
3200: actualProject.getClassFilesManager()
3201: .deleteAllClassesOnDiskAndWait();
3202: // set sources to "uncompiled"
3203: List<SourceFile> allSources = actualProject.sourcesTreeModel
3204: .getAllSourceFiles(false);
3205: for (SourceFile sf : allSources) {
3206: sf.setIsCompiled(false);
3207: }
3208: outputPanels.compilerOutputPanel.doc
3209: .appendLine("done.");
3210: actualProject.sourcesTreeModel.setFolderColors();
3211: }
3212: };
3213:
3214: executeTask(comp);
3215: }
3216:
3217: /** Called on Shift F9. The displayed file is compiled.
3218: */
3219: public void compileOnlyChangedFiles() {
3220: FileItem sf = editorPanel.getActualDisplayedFile();
3221: SourceFile ssf = null;
3222: if (sf != null && sf instanceof SourceFile) {
3223: ssf = (SourceFile) sf;
3224: }
3225:
3226: editorPanel.saveChangedFiles();
3227: List<SourceFile> sourceFiles = new ArrayList<SourceFile>();
3228: //sourceFiles.add(ssf); // no need to add, if part of the changed files.
3229: // recompile this source
3230: compile_queued(sourceFiles, ssf, // for the UI rebuild
3231: false); // with dependencies
3232:
3233: }
3234:
3235: /** Normally, please store all opened files before compiling...
3236: this first delete all the classes !
3237: */
3238: private Future compileAll_queued() {
3239: List<SourceFile> allSources = actualProject.sourcesTreeModel
3240: .getAllSourceFiles(false); // not the ignored ones !
3241: // delete all classes (important!)
3242: runClear_queued();
3243: // recompile all sources
3244: return compile_queued(allSources, null, true);
3245: }
3246:
3247: /** Inserts a compile command in the executor.
3248: * IMPORTANT: all compilations are started from here.
3249: *
3250: * @param rootOfBranchBuild null for a complete build
3251: * @param sourceFiles the sources not belonging to the project are removed !
3252: *
3253: * TODO: implement a mechanism that remember the state before when compilation failed,
3254: * otherwise, we get rapidly growing number of recompiled files...
3255: */
3256: public Future compile_queued(final List<SourceFile> sourceFiles,
3257: final SourceFile rootOfBranchBuild, final boolean compileAll) {
3258: debugOut("\n\nCOMPILE Action called for " + sourceFiles.size()
3259: + " fixed sources from " + rootOfBranchBuild);
3260:
3261: this .actualProject.setIsCompleteBuild(false);
3262:
3263: Runnable comp = new Runnable() {
3264: public void run() {
3265: outputPanels.selectCompilerTab();
3266: outputPanels.setCompilingInProgress();
3267: outputPanels.compilerOutputPanel.doc
3268: .setText("Preparing compilation...");
3269:
3270: //int numberOfSourcesModified = 0;
3271: int numberOfDependenciesAdded = 0;
3272:
3273: // not necessary if all are compiled
3274: if (!compileAll) {
3275: // in this mode, (partial compile), we first update the dependencies (reparse).
3276: // The detection uses the length of the file to know if changed.
3277: List<SourceFile> withoutDep = actualProject.sourcesTreeModel
3278: .getAllSourceFilesWithoutActualDependencies();
3279:
3280: MainEditorFrame
3281: .debugOut("\n"
3282: + withoutDep.size()
3283: + " invalid dependencies will be actualized");
3284: if (withoutDep.size() < 5 && !withoutDep.isEmpty()) {
3285: MainEditorFrame.debugOut("invalid deps: "
3286: + withoutDep);
3287: }
3288:
3289: if (MainEditorFrame.this .parseDependencies
3290: .isSelected()
3291: && !withoutDep.isEmpty()) {
3292: Thread t = TreeFunctions
3293: .createDetectDependenciesThread(
3294: withoutDep, false);
3295: // waits until completion !
3296: t.start();
3297: try {
3298: t.join();
3299: } catch (InterruptedException e) {
3300: throw new RuntimeException(e);
3301: } // don't pass !!
3302: }
3303:
3304: // and add all files not compiled
3305: List<SourceFile> nc = actualProject.sourcesTreeModel
3306: .getAllSourceFilesNotCompiled(); // from project (not ignored)
3307: MainEditorFrame
3308: .debugOut("adding "
3309: + nc.size()
3310: + " files not compiled (and their dependencies)");
3311: for (SourceFile sf : nc) {
3312: if (!sourceFiles.contains(sf)) {
3313: sourceFiles.add(sf);
3314: }
3315: }
3316:
3317: // and augment all these files with their dependencies !
3318: numberOfDependenciesAdded = augmentWithDependencies(sourceFiles);
3319: }
3320:
3321: // remove the ones not belonging to the project !
3322: List<File> allSourceFiles = new ArrayList<File>();
3323: for (SourceFile sf : sourceFiles) {
3324: if (sf.getIgnoredType() != SourcesTreeIcon.Ignored.Yes) {
3325: allSourceFiles.add(sf.javaFile);
3326: }
3327: }
3328:
3329: if (allSourceFiles.isEmpty()) {
3330: outputPanels.compilerOutputPanel.doc
3331: .setText("No files to compile, use F9 to recompile the whole project.");
3332: outputPanels.setCompilerResult(true, 0, 0);
3333: return;
3334: }
3335:
3336: try {
3337: debugOut("Compiling " + allSourceFiles.size()
3338: + " sources, added "
3339: + numberOfDependenciesAdded
3340: + " dependencies");
3341:
3342: outputPanels.compilerOutputPanel.doc
3343: .setText("Compiling "
3344: + allSourceFiles.size()
3345: + " source"
3346: + (allSourceFiles.size() == 1 ? ""
3347: : "s")
3348: + (compileAll ? " (complete build)"
3349: : "") + "\r\n");
3350: if (debug && allSourceFiles.size() < 3) {
3351: outputPanels.compilerOutputPanel.doc
3352: .appendLine("" + allSourceFiles);
3353: }
3354:
3355: long startTime = System.currentTimeMillis();
3356:
3357: Process proc = JavaCompilerCall.compile_(
3358: actualProject.getJavaC_TOOL(),
3359: allSourceFiles, actualProject
3360: .getSources_Home(), actualProject
3361: .getClasses_Home(), actualProject
3362: .getClassPath(false, true), // aux Classpath
3363: actualProject.getCompilerOptions());
3364:
3365: String descr = "Compiling ";
3366: if (allSourceFiles.size() == 1)
3367: descr += sourceFiles.get(0).getJavaName(); // first
3368: else
3369: descr += ""
3370: + allSourceFiles.size()
3371: + " files"
3372: + (compileAll ? " (complete build)"
3373: : "");
3374: outputPanels.processesManager.addProcess(descr,
3375: proc, true);
3376:
3377: // all data (err and warnings) is sent to the error stream, we not treat this as error...
3378: CompilerProcessGobbler gobbler = new CompilerProcessGobbler(
3379: proc, outputPanels.compilerOutputPanel.doc);
3380: // this also waits until completion
3381:
3382: int compilerExitValue = proc.waitFor(); // must wait to fetch the correct output value !
3383: //System.out.println("Compiler exit value: "+compilerExitValue);
3384:
3385: debugOut("Comp done. ("
3386: + (System.currentTimeMillis() - startTime)
3387: + " ms)");
3388:
3389: // NOT Working well, on comp errors, return 1, on success 0, on interrupt: 1
3390: if (compilerExitValue != 0
3391: && gobbler.getNumberOfErrors() == 0) {
3392: outputPanels.compilerOutputPanel.doc
3393: .appendErrorLine("Compilation aborted.");
3394: debugOut(" ** Aborted ** ");
3395: }
3396:
3397: boolean compileSuccess = true;
3398:
3399: // Compilation end !
3400: if (gobbler.getNumberOfErrors() > 0
3401: || compilerExitValue != 0) {
3402: compileSuccess = false;
3403: //outputPanels.getCompilerDoc().appendErrorLine(""+gobbler.numberOfErrors+" errors");
3404: for (SourceFile sf : sourceFiles) {
3405: sf.setIsCompiled(false);
3406: }
3407: } else {
3408: // no errors:
3409: for (SourceFile sf : sourceFiles) {
3410: sf.setIsCompiled(true);
3411: }
3412:
3413: if (compileAll) {
3414: actualProject.setIsCompleteBuild(true); // set to false at the begining of each compilation
3415: }
3416: }
3417:
3418: sourcesTreePanel.updateTree(); // updates the red compilation bars (add/remove)
3419:
3420: if (gobbler.warningCategoryCount.size() > 0) {
3421: Set<String> types = gobbler.warningCategoryCount
3422: .keySet();
3423: outputPanels.compilerOutputPanel.doc
3424: .append(" (");
3425: boolean first = true;
3426: for (Iterator<String> it = types.iterator(); it
3427: .hasNext();) {
3428: String cat = it.next();
3429: if (!first) {
3430: outputPanels.compilerOutputPanel.doc
3431: .append(", ");
3432: }
3433: first = false;
3434: outputPanels.compilerOutputPanel.doc
3435: .append(""
3436: + cat
3437: + ": "
3438: + gobbler.warningCategoryCount
3439: .get(cat));
3440: }
3441: outputPanels.compilerOutputPanel.doc
3442: .appendLine(")");
3443: }
3444:
3445: long time = System.currentTimeMillis() - startTime;
3446:
3447: if (compileSuccess) {
3448: outputPanels.compilerOutputPanel.doc
3449: .appendLine("Compilation done, duration = "
3450: + (time / 1000) + " s");
3451: } else {
3452: outputPanels.compilerOutputPanel.doc
3453: .appendErrorLine("Compilation failed, duration = "
3454: + (time / 1000) + " s");
3455: }
3456:
3457: outputPanels.setCompilerResult(compileSuccess,
3458: gobbler.getNumberOfErrors(),
3459: gobbler.numberOfWarnings);
3460: outputPanels.compilerOutputPanel.setCaretEnd();
3461:
3462: if (compileSuccess) //[March2008]: false: gobbler.getNumberOfErrors()==0
3463: {
3464: // the class files manager may be null !!! TODO
3465: // because not already loaded !
3466: if (actualProject.getClassFilesManager() == null) {
3467: outputPanels.compilerOutputPanel.doc
3468: .appendErrorLine("ClassFilesManager not fully loaded, try later...");
3469: return;
3470: } else {
3471: actualProject.getClassFilesManager()
3472: .buildWasSuccessful(
3473: rootOfBranchBuild);
3474: }
3475: }
3476:
3477: // actualize the cache for completion !
3478: actualProject.getClassFilesManager()
3479: .analyseGeneratedClasses();
3480:
3481: } catch (java.lang.InterruptedException e) {
3482: outputPanels.compilerOutputPanel.doc
3483: .appendErrorLine("Compilation aborted: "
3484: + e.getMessage());
3485: } catch (Exception e) {
3486: e.printStackTrace();
3487: outputPanels.compilerOutputPanel.doc
3488: .appendErrorLine("Compilation launch error: "
3489: + e.getMessage());
3490: }
3491: }
3492: };
3493:
3494: return executeTask(comp);
3495: }
3496:
3497: /** Causes a jump to the first method with the given name.
3498: * The mecanism goes through the syntax tree at its next refresh.
3499: */
3500: public void setMethodToView(FileItem item, final String methodName) {
3501: boolean isAlreadyDisplayed = editorPanel
3502: .getActualDisplayedFile() == item;
3503: this .syntaxTreePanel.setMethodToJumpAtNextParse(methodName);
3504: setSourceOrItemToEditOrView(item, true); // maybe already selected => will have no effect
3505:
3506: if (isAlreadyDisplayed) // [Nov2007]
3507: {
3508: // must retrigger the parser to allow jumping
3509: this .syntaxTreePanel.setMethodToJumpAtNextParse(methodName);
3510: editorPanel.reparseSyntaxLaterWhenSilent();
3511: }
3512:
3513: }
3514:
3515: public void setFieldToView(FileItem item, final String methodName) {
3516: boolean isAlreadyDisplayed = editorPanel
3517: .getActualDisplayedFile() == item;
3518:
3519: this .syntaxTreePanel.setFieldToJumpAtNextParse(methodName);
3520: setSourceOrItemToEditOrView(item, true);
3521:
3522: if (isAlreadyDisplayed) // [Nov2007]
3523: {
3524: // must retrigger the parser to allow jumping
3525: this .syntaxTreePanel.setFieldToJumpAtNextParse(methodName);
3526: editorPanel.reparseSyntaxLaterWhenSilent();
3527: }
3528:
3529: }
3530:
3531: /** Sourcefile or other text item.
3532: * The tree call this with arg selectInTree=false to avoid infinite recursion !
3533: */
3534: public void setSourceOrItemToEditOrView(FileItem item,
3535: boolean selectInTree) {
3536: if (selectInTree) {
3537: // the trees selections sets the view
3538: if (item instanceof LibFileItem) {
3539: this .sourcesAndLibsPanel.setSelectedIndex(1);
3540: this .librariesPanel.setSelectedItem((LibFileItem) item,
3541: true);
3542: } else if (item instanceof SourceFile) {
3543: this .sourcesAndLibsPanel.setSelectedIndex(0);
3544: this .sourcesTreePanel.setSelectedSource(
3545: (SourceFile) item, true);
3546: }
3547: } else {
3548: // just select the document...
3549: this .editorPanel.setSourceFileToEdit(item);
3550:
3551: // new Throwable("selected").printStackTrace();
3552: }
3553: }
3554:
3555: /** Looks in the sources and if not found, in all libraries
3556: javaName and fileName are normally parsed from a stacktrace in the output.
3557: give empty fileName if the type has the same name. (often the case).
3558: The compiler generate such paths where the name is the fileName.
3559: */
3560: public FileItem getFileItem(final String javaName,
3561: final String fileName) {
3562: // try projects source
3563: SourceFile sf = this .sourcesTreePanel.getTreeModel()
3564: .getSourceFile(javaName, fileName);
3565: if (sf != null) {
3566: return sf;
3567: }
3568:
3569: // try libs
3570: LibFileItem li = this .librariesPanel.getTreeModel().getFile(
3571: javaName, fileName);
3572: if (li != null) {
3573: return li;
3574: }
3575:
3576: return null;
3577: }
3578:
3579: /**
3580: * Called with true only from menu.
3581: * Recalled one time with false after autorecompilation within this method.
3582: * (trick to avoid infinite loops).
3583: */
3584: private void jarCreationAction(boolean calledFromMenu) {
3585: boolean quietMode = actualProject.getBooleanProperty(
3586: "JAR_quietMode", false);
3587:
3588: editorPanel.saveChangedFiles();
3589: boolean areClassesConsistent = false;
3590:
3591: boolean initialteACompleteBuild = false;
3592:
3593: if (actualProject.getIsCompleteBuild()) {
3594: areClassesConsistent = true;
3595:
3596: // look deeper
3597: List<SourceFile> ncf = actualProject.sourcesTreeModel
3598: .getAllSourceFilesNotCompiled();
3599:
3600: if (ncf.size() > 0) {
3601: if (quietMode) {
3602: initialteACompleteBuild = true;
3603: } else {
3604:
3605: // not fatal, there were some new changed files but previously complete build...
3606: // => warn and let pass through...
3607: int rep = JOptionPane
3608: .showConfirmDialog(
3609: this ,
3610: "Some files are not compiled."
3611: + "\nTo create a project jar file, a complete build is required."
3612: + "\nPlease make such a build (F9) before."
3613: + "\n\nDo you still want to make a jar file with the previous consistent classes ?\n",
3614: "The build is not up to date",
3615: JOptionPane.YES_NO_CANCEL_OPTION,
3616: JOptionPane.QUESTION_MESSAGE);
3617:
3618: if (rep != JOptionPane.YES_OPTION) {
3619: if (!quietMode) {
3620: rep = JOptionPane
3621: .showConfirmDialog(
3622: this ,
3623: "Do you want to perform a complete build now ?",
3624: "A complete build is required",
3625: JOptionPane.YES_NO_CANCEL_OPTION,
3626: JOptionPane.WARNING_MESSAGE);
3627: if (rep != JOptionPane.YES_OPTION) {
3628: // abort
3629: return;
3630: }
3631: }
3632:
3633: // DO A COMPLETE BUILD !
3634: initialteACompleteBuild = true;
3635: }
3636: }
3637: }
3638: } else // NOT complete build
3639: {
3640: if (!calledFromMenu) {
3641: //failed...
3642: return;
3643: }
3644:
3645: if (!quietMode) // [March2008]
3646: {
3647:
3648: // Ask if continue (and perform compileAll and wait)...
3649: int rep = JOptionPane
3650: .showConfirmDialog(
3651: this ,
3652: "To create a project jar file, a complete build (F9) is required."
3653: + "\n\nShould tIDE perform such a build now ?\n",
3654: "A complete build is required",
3655: JOptionPane.YES_NO_CANCEL_OPTION,
3656: JOptionPane.WARNING_MESSAGE);
3657: if (rep != JOptionPane.YES_OPTION) {
3658: // abort
3659: return;
3660: }
3661: }
3662:
3663: initialteACompleteBuild = true;
3664: //
3665: }
3666:
3667: if (initialteACompleteBuild) {
3668: Thread t = new Thread() {
3669: public void run() {
3670: Future fut = compileAll_queued();
3671: try {
3672: fut.get(); // WAITS (polls!)
3673: EventQueue.invokeLater(new Runnable() {
3674: public void run() {
3675: // RECURSE CALL (1 time!)
3676: jarCreationAction(false);
3677: }
3678: });
3679: } catch (Exception e) {
3680: e.printStackTrace();
3681: }
3682: }
3683: };
3684: t.setPriority(Thread.MIN_PRIORITY);
3685: t.start();
3686: } else if (areClassesConsistent) // check.
3687: {
3688: new JarCreationDialog(this , actualProject);
3689: }
3690: }
3691:
3692: private void contactMe() {
3693: try {
3694: Desktop
3695: .getDesktop()
3696: .mail(
3697: new URI(
3698: "mailto:stephan.heiss@gmail.com?subject=from%20a%20tIDE%20java%20IDE%20user"
3699: + "&body=...Please%20enter%20your%20remark%20or%20bugfix%20or%20comment%20here...%0D%0A"));
3700: } catch (Exception e) {
3701: JOptionPane
3702: .showMessageDialog(
3703: this ,
3704: "Can't prepare a message to the author"
3705: + "\n\nPlease use stephan.heiss@gmail.com\n\nErr="
3706: + e.getMessage(),
3707: "Can't create a message to the author",
3708: JOptionPane.ERROR_MESSAGE);
3709: e.printStackTrace();
3710: }
3711: /*
3712: JTextField from = new JTextField(30);
3713: JComboBox to = new JComboBox(new String[]{"stephan.heiss@gmail.com", ""});
3714: JTextField subject = new JTextField(30);
3715: JTextArea mess = new JTextArea(8,40);
3716:
3717: final JDialog d = new JDialog(this, "Send a message to the author", false);
3718: JPanel jPanel = new JPanel();
3719: d.add(jPanel, BorderLayout.CENTER);
3720: GridLayout3 gl3 = new GridLayout3(2, jPanel);
3721: gl3.add("to: ");
3722: gl3.add(to, true);
3723: gl3.add("from: ");
3724: gl3.add(from, true);
3725: gl3.add("subject: ");
3726: gl3.add(subject, true);
3727: gl3.add("message: ");
3728: gl3.add(new JScrollPane(mess), true);
3729:
3730: JPanel control = new JPanel();
3731: d.add(control, BorderLayout.SOUTH);
3732:
3733: JButton cancel = new JButton("cancel");
3734: cancel.setMargin(new Insets(0,2,0,2));
3735: control.add(cancel);
3736: cancel.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) {
3737: d.setVisible(false);
3738: d.dispose();
3739: } });
3740:
3741: JButton send = new JButton("send");
3742: send.setMargin(new Insets(0,2,0,2));
3743: control.add(send);
3744: send.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) {
3745:
3746: try
3747: {
3748: // TODO: send using the host (use DNS)
3749: //EasySendMail esm = new EasySendMail();
3750: //esm.sendmsg( from.getText(), to.getText(), null, content, domain);
3751:
3752: JOptionPane.showMessageDialog(d, "Message NOT sent, feature missing (dns not read)");
3753: d.setVisible(false);
3754: d.dispose();
3755: }
3756: catch(Exception e)
3757: {
3758: e.printStackTrace();
3759: JOptionPane.showMessageDialog(d, "Error: "+e.getMessage(), "Cannot send message", JOptionPane.ERROR_MESSAGE);
3760: }
3761: } });
3762:
3763: d.pack();
3764: d.setLocationRelativeTo(this);
3765: d.setVisible(true);
3766: */
3767: }
3768:
3769: /** Starts tIDE.
3770: */
3771: public static void mainmet(String[] args) {
3772: // nice java look
3773: JFrame.setDefaultLookAndFeelDecorated(true);
3774: // also for JOptionPanes !
3775: JDialog.setDefaultLookAndFeelDecorated(true);
3776:
3777: new MainEditorFrame(args);
3778:
3779: /* debug... not really necessary...
3780: try
3781: {
3782: TideControl.installJMXControlService();
3783: }catch(Exception e) {
3784: e.printStackTrace();
3785: }*/
3786: }
3787:
3788: public static void displayErrorMessage(final Throwable t,
3789: final String title) {
3790: JOptionPane.showMessageDialog(instance, "" + t.getMessage(),
3791: title, JOptionPane.ERROR_MESSAGE);
3792: }
3793:
3794: /** toggable System.out.println(s); */
3795: public static void debugOut(String s) {
3796: if (debug) {
3797: System.out.println(s);
3798: }
3799: }
3800:
3801: /** toggable e.printStackTrace(); */
3802: public static void debugOut(Throwable e) {
3803: if (debug) {
3804: e.printStackTrace();
3805: }
3806: }
3807:
3808: }
|