0001: package Schmortopf.Main;
0002:
0003: import java.awt.*;
0004: import java.awt.event.*;
0005: import javax.swing.*;
0006: import javax.swing.event.*;
0007: import javax.swing.border.*;
0008: import javax.swing.tree.DefaultMutableTreeNode;
0009: import javax.swing.plaf.metal.*;
0010: import java.util.*;
0011: import java.beans.*;
0012:
0013: import Schmortopf.Utility.IniFile.IniFile;
0014: import Schmortopf.Utility.gui.*;
0015: import Schmortopf.Utility.ThreadEngine.ThreadEngine;
0016: import Schmortopf.JavaSourceEditor.*;
0017: import Schmortopf.JavaSourceEditor.TextSearch.ClassMethodSearch;
0018: import Schmortopf.ProjectFiles.*;
0019: import Schmortopf.ProjectFiles.ProjectFilesTree.*;
0020: import Schmortopf.Main.ProjectDefinition.ProjectDefinition;
0021: import Schmortopf.Main.ProjectDefinition.ProjectDefinitionEntry;
0022: import Schmortopf.Main.ProjectDefinition.ProjectDefinitionDialog;
0023: import Schmortopf.FileComponents.View.*;
0024: import Schmortopf.Libraries.*;
0025: import Schmortopf.SearchResults.*;
0026: import Schmortopf.OutputManager.*;
0027: import Schmortopf.FileStructure.*;
0028: import Schmortopf.FileStructure.Descriptions.*;
0029: import Schmortopf.Main.OutputComponents.*;
0030: import Schmortopf.Main.OutputComponents.JarCreation.*;
0031: import Schmortopf.UML.UMLManager;
0032: import Schmortopf.JavaSourceEditor.DocumentHistoryTracker.EditorDocumentHistoryTracker;
0033: import Language.Language;
0034: import Shared.Logging.Log;
0035:
0036: /**
0037: * The JInternalFrame combined view-controler, which holds a project.
0038: */
0039: public class IDE_ProjectFrame extends JInternalFrame implements
0040: DataChangeListener, IDE_ProjectFrameProvider {
0041:
0042: private static String IniFileMaximizedProperty = "ProjectFrame_IniFileMaximizedProperty";
0043:
0044: // The Schmortopf MDI mainframe :
0045: private IDE_MainFrameProvider mainFrame;
0046:
0047: // Panel, which contains all files of the actual project
0048: private JPanel projectFilesPanel;
0049:
0050: // Shows the methods and attributes of the file,
0051: // which is displayed in the fileSourcePanel
0052: private JPanel fileComponentsPanel;
0053:
0054: // Shows text search results
0055: private SearchResultsPanel searchResultsPanel;
0056:
0057: // Shows the additional project libraries including src.jar or zip file
0058: private JPanel librariesPanel;
0059:
0060: // Displays the source of the file, which currently is
0061: // selected in the projectFilesPanel
0062: private JPanel fileSourcePanel;
0063:
0064: // Holds the tabs for the outputmanager view, javadoc etc.
0065: private OutputPane outputPane;
0066:
0067: // This one holds the left splitpane content.
0068: private JPanel leftMainPanel;
0069:
0070: // Holds project infos, is located in the menubarpanel on the right.
0071: private ProjectInfoPanel projectInfoPanel;
0072:
0073: // The additional feature panels:
0074: private JavaDocManager javaDocManager;
0075: private JarCreationManager jarCreationManager;
0076: private UMLManager umlManager;
0077:
0078: private String projectDirectoryPath;
0079:
0080: // This one is updated by the fileComponentsTreeModel,
0081: // which sets a blue point, when the JavaCC parser could
0082: // parse the current text, and a red one otherwise.
0083: private JContrastLabel fileComponentsTitleLabel = new JContrastLabel();
0084:
0085: // The title associated panels :
0086: private JPanel fileComponentsTitleWrapPanel;
0087: private JPanel librariesTitleWrapPanel;
0088: private JPanel projectFilesTitleWrapPanel;
0089: private JPanel projectFilesTitlePanel;
0090:
0091: private ImageIcon greenPointIcon; // used for the fileComponentsTitleLabel
0092: private ImageIcon bluePointIcon; // used for the fileComponentsTitleLabel
0093: private ImageIcon redPointIcon; // used for the fileComponentsTitleLabel
0094:
0095: // The editor contact object
0096: private EditorPanel editorPanel;
0097:
0098: // The tree's :
0099: private ProjectFilesManager projectFilesManager = null;
0100: private FileComponentsTree fileComponentsTree = null;
0101: private LibrariesTree librariesTree = null;
0102:
0103: // The manager which controls access to java,javac and holds the
0104: // output panel as gui object.
0105: private OutputManager outputManager;
0106:
0107: private ProjectDefinition projectDefinition;
0108:
0109: private IDE_ProjectFrame this Frame;
0110:
0111: private JMenuBar menuBar;
0112: private JPanel menuBarPanel;
0113: private IniFile iniFile;
0114:
0115: private JSplitPane horizontalSplitPane; // fills the whole contentpane
0116: private JSplitPane verticalSplitPane; // The outer splitpane on the left
0117:
0118: private JSplitPane upperSplitPane;
0119: private JSplitPane middleSplitPane;
0120: private JSplitPane rightVerticalSplitPane;
0121: private JSplitPane projectFilesLinkSplitPane;
0122:
0123: // This one contains the FileStructureData off ALL files -
0124: // java sourcefiles, java files inside the src.jar or zip file as well as
0125: // the class files of all current user jar libraries.
0126: private FileStructureDescriptionManager fileStructureDescriptionManager = null;
0127:
0128: // Flag, which controls correct application shutdown :
0129: private boolean frameWasTerminated = false;
0130:
0131: private JSenseButton compileProjectButton;
0132: private JSenseButton executeProjectButton;
0133: private JSenseButton projectSelectionButton;
0134: private JSenseButton projectSynchronizationButton;
0135:
0136: // See SchmortopfStarter. Activated by the applicationparameter -debug.
0137: private boolean isDebugModus;
0138:
0139: // FullScreen frame and state attributes :
0140: private JSenseButton fullScreenSwitchButton = null;
0141: // fullscreen JFrame: Is null, except if a fullscreen view is open.
0142: private FullScreenProjectView fullScreenFrame = null;
0143:
0144: // This flag is set, if the user cancels the save operation when this
0145: // frame closes. The mainframe can check this value and if its set,
0146: // it won't ask again.
0147: private boolean saveHasBeenCancelledOnClose = false;
0148:
0149: public IDE_ProjectFrame(final IDE_MainFrameProvider theMainFrame,
0150: final ProjectDefinition projectDefinition,
0151: final IniFile iniFile, final int projectCreationCounter, // used for positioning
0152: final boolean isDebugModus) {
0153: super ("Project", true, true, true, true);
0154: // parms are: String title, boolean resizable, boolean closable,
0155: // boolean maximizable, boolean iconifiable) {
0156: this .this Frame = this ;
0157: this .mainFrame = theMainFrame;
0158: this .projectDefinition = projectDefinition;
0159: this .iniFile = iniFile;
0160: this .isDebugModus = isDebugModus;
0161:
0162: this .setFrameIcon(this .mainFrame
0163: .loadImageIcon("pics/schmortopf_frame.jpg"));
0164:
0165: this .setTitle(projectDefinition.getFilePathName());
0166: this .greenPointIcon = this .mainFrame
0167: .loadImageIcon("pics/menupics/greenpointselected.gif");
0168: this .bluePointIcon = this .mainFrame
0169: .loadImageIcon("pics/menupics/bluepointselected.gif");
0170: this .redPointIcon = this .mainFrame
0171: .loadImageIcon("pics/menupics/redpointselected.gif");
0172:
0173: // Debug: Measure startuptime:
0174: final long startupStartTime = System.currentTimeMillis();
0175:
0176: System.gc();
0177:
0178: // Make sure, that the required directories for the projectdefinition do exist.
0179: // If project directories don't exist, they are created. If required directories
0180: // which cannot be just created (like the JDK directory) don't exist or have
0181: // not the required content, a warning is displayed.
0182: this .projectDefinition.checkProjectDefinitionValues(this );
0183:
0184: // Tree panel border size [ dependent from fontsize ]
0185: int fs = UIManager.getFont("Tree.font").getSize();
0186: int treeBorderThickness = 1 + fs / 6; // See the projectfilestree constructor too
0187:
0188: // Create the mainpanels:
0189: this .projectFilesPanel = new JPanel(new BorderLayout(0, 0));
0190: this .librariesPanel = new JPanel(new BorderLayout(0, 0));
0191: this .fileComponentsPanel = new JPanel(new BorderLayout(0, 0));
0192: this .fileSourcePanel = new JPanel(new BorderLayout(0, 0));
0193: this .leftMainPanel = new JPanel(new BorderLayout(0, 0));
0194:
0195: // The titlePanels :
0196:
0197: // We must use a wrapper for the line border at its bottom,
0198: // which is updated in updateSpecialUI(), because the
0199: // EFCNSmoothBackgroundPanel wtake all place overwriting any borders.
0200:
0201: this .projectFilesTitleWrapPanel = new JPanel(new BorderLayout(
0202: 0, 0));
0203: this .librariesTitleWrapPanel = new JPanel(
0204: new BorderLayout(0, 0));
0205: this .fileComponentsTitleWrapPanel = new JPanel(
0206: new BorderLayout(0, 0));
0207:
0208: // projectFilesTitlePanel has a special border, which needs to be updated too :
0209: this .projectFilesTitlePanel = new JPanel(new BorderLayout(0, 0));
0210:
0211: // Give the 4 panels their functionality :
0212:
0213: this .projectInfoPanel = new ProjectInfoPanel(this .mainFrame,
0214: this );
0215:
0216: this .javaDocManager = new JavaDocManager(this ,
0217: this .projectDefinition);
0218: this .jarCreationManager = new JarCreationManager(this ,
0219: this .projectDefinition);
0220: this .umlManager = new UMLManager(this , this .projectDefinition);
0221:
0222: this .editorPanel = new EditorPanel(this , this .iniFile,
0223: this .javaDocManager, this .umlManager, this .isDebugModus);
0224: this .fileSourcePanel.add(this .editorPanel, BorderLayout.CENTER);
0225:
0226: final ProjectDefinitionEntry outputEntry = this .projectDefinition
0227: .getProjectDefinitionEntry(ProjectDefinition.UseSchmortopfOutputWindow_Key);
0228: this .outputManager = new OutputManager(this .projectDefinition,
0229: this , this .projectInfoPanel);
0230:
0231: this .fileComponentsTree = new FileComponentsTree(this ,
0232: this .editorPanel);
0233: fileComponentsTree.setBorder(BorderFactory.createEmptyBorder(0,
0234: 0, 0, 0));
0235: this .build_fileComponentsPanel(
0236: this .fileComponentsTitleWrapPanel,
0237: this .fileComponentsPanel, this .fileComponentsTree);
0238:
0239: ProjectDefinitionEntry entry = this .projectDefinition
0240: .getProjectDefinitionEntry(ProjectDefinition.ProjectDirectoryPath_Key);
0241: this .projectDirectoryPath = (String) entry.getValue();
0242: // The projectdirectory is readonly in a project, so we can cache it here.
0243:
0244: // The projectFilesTree and the LibrariesTree go into one panel :
0245: // The projectfilestree is managed by the ProjectFilesManager :
0246:
0247: this .projectFilesManager = new ProjectFilesManager(this ,
0248: this .projectDefinition, this .projectDirectoryPath,
0249: this .editorPanel, this .projectInfoPanel,
0250: this .editorPanel);
0251: final int numberOfProjectSourceFiles = this .projectFilesManager
0252: .getNumberOfSourceFiles();
0253:
0254: this .build_projectFilesPanel(this .projectFilesTitleWrapPanel,
0255: this .projectFilesTitlePanel, this .projectFilesPanel,
0256: this .projectFilesManager);
0257:
0258: this .searchResultsPanel = new SearchResultsPanel(this );
0259:
0260: this .librariesTree = new LibrariesTree(this .editorPanel,
0261: this .fileComponentsTree, this , this .outputManager,
0262: this .projectDefinition);
0263:
0264: ProjectDefinitionEntry definitionEntry = projectDefinition
0265: .getProjectDefinitionEntry(ProjectDefinition.SourceJarFilePath_Key);
0266: final String srcJarFileName = (String) definitionEntry
0267: .getValue();
0268: ProjectDefinitionEntry additionalJarFilesEntry = projectDefinition
0269: .getProjectDefinitionEntry(ProjectDefinition.AdditionalJarLibrariesPaths_Key);
0270: final String[] additionalJarLibraries = (String[]) additionalJarFilesEntry
0271: .getValue();
0272:
0273: // Create the creationInfoDialog. Note, that this one will
0274: // be closed in the FileStructureDescriptionManager's FSDManagerCreationThread,
0275: // which then also will reenable this frame.
0276: final FileStructureDescriptionSynchronizeDialog creationInfoDialog = new FileStructureDescriptionSynchronizeDialog(
0277: this .mainFrame);
0278:
0279: // Add all projectdefinition libraries to the librariesTree.
0280: // We do this delayed, so the GUI is created more smoothly :
0281: Runnable libraryStartUpRunnable = new Runnable() {
0282: public void run() {
0283: // Time for the GUI :
0284: try {
0285: Thread.sleep(100);
0286: } catch (Exception e324867) {
0287: }
0288:
0289: // Add the src.jar or zip file content to the librariesTree :
0290: EventQueue.invokeLater(new Runnable() {
0291: public void run() {
0292: librariesTree.addJarFilePath(srcJarFileName);
0293: }
0294: });
0295: // Add all additional projectdefinition libraries to the librariesTree.
0296: for (int i = 0; i < additionalJarLibraries.length; i++) {
0297: final int iFinal = i;
0298: EventQueue.invokeLater(new Runnable() {
0299: public void run() {
0300: librariesTree
0301: .addJarFilePath(additionalJarLibraries[iFinal]);
0302: }
0303: });
0304: }
0305:
0306: // The FileStructureDescriptionManager needs the tree's, so we
0307: // must construct it delayed too, and after the tree startups.
0308: fileStructureDescriptionManager = new FileStructureDescriptionManager(
0309: this Frame, projectFilesManager, librariesTree,
0310: fileComponentsTree, umlManager,
0311: projectDefinition, mainFrame,
0312: projectDirectoryPath,
0313: numberOfProjectSourceFiles, creationInfoDialog);
0314: // Manages all FileStructureData objects of all java and class files.
0315: // All tasks above in the constructor are carried out in the ThreadEngine queue too,
0316: // so we can add the last task, which updates the historytracker models
0317: // to the ThreadEngine too and have this processed at the end :
0318: Runnable historyTrackerUpdateRunnable = new Runnable() {
0319: public void run() {
0320: // syncModelsWithFileSystem() needs the filesystem (source nd jar files)
0321: editorPanel.getDocumentHistoryTracker()
0322: .syncModelsWithFileSystem();
0323:
0324: // Finally : If the projectfiles tree is completely empty ( that is,
0325: // the user has created a new project, we autocreate the main file
0326: // given by the projectdefinition including a static main method :
0327: ProjectFilesTree pTree = projectFilesManager
0328: .getProjectFilesTree();
0329: if (pTree.getNumberOfJavaSourceFiles() == 0) {
0330: String[] packagePath = projectDefinition
0331: .getProjectMainClassPackagePath();
0332: String className = projectDefinition
0333: .getProjectMainClassName();
0334: pTree.addNewProjectFile(className,
0335: packagePath, pTree
0336: .getSourceTemplateForClass(
0337: className,
0338: packagePath, true));
0339: }
0340: }
0341: };
0342: ThreadEngine.getInstance().addRunnable(
0343: historyTrackerUpdateRunnable,
0344: "HistoryTrackerUpdateRunnable");
0345: historyTrackerUpdateRunnable = null; // help the GC
0346:
0347: // Finally dispose the creationdialog and assist the GC :
0348: Runnable creationDialogCleanup = new Runnable() {
0349: public void run() {
0350: EventQueue.invokeLater(new Runnable() {
0351: public void run() {
0352: creationInfoDialog.freeMemory();
0353: creationInfoDialog.dispose();
0354:
0355: /* Debug: Write out startuptime: */
0356: long startupTime = (System
0357: .currentTimeMillis()
0358: - startupStartTime + 500) / 1000;
0359: String s = Language
0360: .Translate("Startup time");
0361: getOutputManager().printLine(
0362: s + " = " + startupTime
0363: + " [s]");
0364: }
0365: });
0366: }
0367: };
0368: ThreadEngine.getInstance().addRunnable(
0369: creationDialogCleanup,
0370: "CreationInfoDialog Cleanup");
0371: creationDialogCleanup = null; // help the GC
0372:
0373: EventQueue.invokeLater(new Runnable() {
0374: public void run() {
0375: // ThreadEngine should now be filled with all loader tasks, so
0376: // the user is allowed to start compile/execute tasks
0377: // ( which come into the ThreadEngine queue, therefore are executed serially )
0378: Runnable actionsActivationRunnable = new Runnable() {
0379: public void run() {
0380: EventQueue.invokeLater(new Runnable() {
0381: public void run() {
0382: compileProjectButton
0383: .setEnabled(true);
0384: executeProjectButton
0385: .setEnabled(true);
0386: projectSynchronizationButton
0387: .setEnabled(true);
0388: projectSelectionButton
0389: .setEnabled(true);
0390: editorPanel.enableButtons();
0391: }
0392: });
0393: }
0394: };
0395: ThreadEngine.getInstance().addRunnable(
0396: actionsActivationRunnable,
0397: Language.Translate("Activate Actions"));
0398: actionsActivationRunnable = null; // help the GC
0399: }
0400: });
0401:
0402: }
0403: };
0404: ThreadEngine.getInstance().addRunnable(libraryStartUpRunnable,
0405: "ProjectFrame Library Startup Task");
0406: libraryStartUpRunnable = null; // help the GC
0407:
0408: this .librariesTree.setBorder(BorderFactory.createEmptyBorder(
0409: treeBorderThickness, treeBorderThickness,
0410: treeBorderThickness, treeBorderThickness));
0411: this .build_librariesPanel(this .librariesTitleWrapPanel,
0412: this .librariesPanel, this .librariesTree);
0413:
0414: this .outputPane = new OutputPane(this .outputManager,
0415: this .javaDocManager, this .jarCreationManager,
0416: this .umlManager);
0417:
0418: // We put the projectFilesPanel and the librariesPanel in a,
0419: // vertical dividing splitpane :
0420: this .upperSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
0421: true, projectFilesPanel, librariesPanel);
0422: upperSplitPane.setOneTouchExpandable(true);
0423: upperSplitPane.setBorder(BorderFactory.createEmptyBorder(0, 0,
0424: 0, 0));
0425:
0426: this .middleSplitPane = new JSplitPane(
0427: JSplitPane.VERTICAL_SPLIT, true, upperSplitPane,
0428: fileComponentsPanel);
0429: middleSplitPane.setOneTouchExpandable(true);
0430: middleSplitPane.setBorder(BorderFactory.createEmptyBorder(0, 0,
0431: 0, 0));
0432:
0433: // Insert the 4 mainpanels, using splitpanes :
0434: this .verticalSplitPane = new JSplitPane(
0435: JSplitPane.VERTICAL_SPLIT, true, middleSplitPane,
0436: searchResultsPanel);
0437: this .verticalSplitPane.setBorder(BorderFactory
0438: .createEmptyBorder(0, 0, 0, 0));
0439: verticalSplitPane.setOneTouchExpandable(true);
0440: // leave original border for this splitpane
0441: leftMainPanel.add(verticalSplitPane, BorderLayout.CENTER);
0442:
0443: this .rightVerticalSplitPane = new JSplitPane(
0444: JSplitPane.VERTICAL_SPLIT, true, this .fileSourcePanel,
0445: outputPane);
0446: this .rightVerticalSplitPane.setBorder(BorderFactory
0447: .createEmptyBorder(0, 0, 0, 0));
0448: rightVerticalSplitPane.setOneTouchExpandable(true);
0449: // leave original border for this splitpane
0450:
0451: this .horizontalSplitPane = new JSplitPane(
0452: JSplitPane.HORIZONTAL_SPLIT, true, leftMainPanel,
0453: rightVerticalSplitPane);
0454: horizontalSplitPane.setOneTouchExpandable(true);
0455: horizontalSplitPane.setBorder(BorderFactory.createEmptyBorder(
0456: 0, 0, 0, 0));
0457:
0458: this .menuBar = this .createTheMenuBar();
0459: this .menuBarPanel = new EFCNGradientPanel(
0460: new BorderLayout(0, 0),
0461: EFCNGradientPanel.ApplyVerticalHighLight,
0462: EFCNGradientPanel.StrongGradientStrength,
0463: EFCNGradientPanel.ActiveTitleBackground);
0464:
0465: Color menuBarDarkerColor = UIManager
0466: .getColor("Menu.background").darker();
0467: Color menuBarbBrighterColor = UIManager.getColor(
0468: "Menu.background").brighter();
0469: this .menuBarPanel.setBorder(new CustomEtchedBorder(false,
0470: false, true, true, menuBarbBrighterColor,
0471: menuBarDarkerColor));
0472:
0473: this .menuBarPanel.add(this .menuBar, BorderLayout.WEST);
0474: this .menuBarPanel.add(this .projectInfoPanel,
0475: BorderLayout.CENTER);
0476:
0477: this .fullScreenSwitchButton = new JSenseButton(Language
0478: .Translate("Fullscreen"), true, true, this
0479: .getMainFrameProvider());
0480: this .fullScreenSwitchButton.setFont(UIManager
0481: .getFont("Label.font"));
0482:
0483: Border inb = BorderFactory.createEmptyBorder(0, fs / 2, 0,
0484: fs / 4);
0485: Border outb = BorderFactory.createEtchedBorder();
0486: this .fullScreenSwitchButton.setBorder(BorderFactory
0487: .createCompoundBorder(outb, inb));
0488:
0489: this .setIsFullScreen(false); // power up in normal state
0490: this .fullScreenSwitchButton
0491: .addActionListener(new ActionListener() {
0492:
0493: public void actionPerformed(ActionEvent e) {
0494: setCursor(new Cursor(Cursor.WAIT_CURSOR));
0495: EventQueue.invokeLater(new Runnable() {
0496: public void run() {
0497: if (getIsFullScreen()) {
0498: if (fullScreenFrame.isVisible()) {
0499: getFullScreenFrame()
0500: .switchBackToNormalMode();
0501: setIsFullScreen(false);
0502: destroyFullScreenFrame();
0503: }
0504: } else {
0505: fullScreenSwitchButton
0506: .setEnabled(false);
0507: createAndShowFullScreenFrame();
0508: }
0509: EventQueue.invokeLater(new Runnable() {
0510: public void run() {
0511: setCursor(new Cursor(
0512: Cursor.DEFAULT_CURSOR));
0513: }
0514: });
0515: }
0516: });
0517: }
0518: });
0519: this .menuBarPanel
0520: .add(fullScreenSwitchButton, BorderLayout.EAST);
0521:
0522: this .getContentPane().setLayout(new BorderLayout(0, 0));
0523: this .getContentPane()
0524: .add(this .menuBarPanel, BorderLayout.NORTH);
0525: this .getContentPane().add(horizontalSplitPane,
0526: BorderLayout.CENTER);
0527:
0528: // Position and size : The user can click the fullscreen button to
0529: // get the full view of a project, therefore we don't fill all space,
0530: // and vary the location using the passed projectCreationCounter :
0531: Dimension parentDimension = this .mainFrame.getContentPane()
0532: .getSize();
0533: int locationNumber = projectCreationCounter % 4; // repeat positions all 4 frames
0534: int hBorder = parentDimension.width / 150;
0535: int vBorder = parentDimension.height / 150;
0536: int hOffset = locationNumber * parentDimension.width / 50;
0537: int vOffset = locationNumber * parentDimension.height / 50;
0538: int width = (19 * parentDimension.width) / 20;
0539: int height = (19 * parentDimension.height) / 20;
0540: this .setLocation(hBorder + hOffset, vBorder + vOffset);
0541: this .setSize(width, height);
0542:
0543: // -------------------------- SET VISIBLE IS HERE -------------------
0544: this .setVisible(true);
0545: // -------------------------- SET VISIBLE IS HERE -------------------
0546: this .setCursor(new Cursor(Cursor.WAIT_CURSOR));
0547: // We set the default cursor, as soon as all has been loaded.
0548:
0549: // Show the creationInfoDialog, after the mainframe is visible :
0550: SwingUtilities.invokeLater(new Runnable() {
0551: public void run() {
0552: creationInfoDialog.setCurrentFileInformation(Language
0553: .Translate("Loading..."));
0554: creationInfoDialog.showCentered();
0555: }
0556: });
0557:
0558: // Set the dividerlocations, when the main panels have
0559: // their sizes set, so delay it :
0560: SwingUtilities.invokeLater(new Runnable() {
0561: public void run() {
0562: setDefaultDividerLocations();
0563: }
0564: });
0565:
0566: this .addInternalFrameListener(new InternalFrameAdapter() {
0567: public void internalFrameClosing(InternalFrameEvent e) {
0568: if (!frameWasTerminated) {
0569: frameWasTerminated = true;
0570: terminateFrame(true); // flag: do garbage colletion [is important]
0571: }
0572: }
0573:
0574: public void internalFrameClosed(InternalFrameEvent e) {
0575: if (!frameWasTerminated) {
0576: frameWasTerminated = true;
0577: terminateFrame(true);// flag: do garbage colletion [is important]
0578: }
0579: }
0580: });
0581:
0582: // If this projectframe has been maximized on the last run, we maximize it again.
0583: boolean showMaximized = this .projectDefinition
0584: .getProjectIniFile().getBooleanValue(
0585: IniFileMaximizedProperty, false);
0586: if (showMaximized) {
0587: Runnable maximizeRunnable = new Runnable() {
0588: public void run() {
0589: EventQueue.invokeLater(new Runnable() {
0590: public void run() {
0591: try {
0592: setMaximum(true);
0593: } catch (Exception e234876) {
0594: e234876.printStackTrace();
0595: }
0596: }
0597: });
0598: }
0599: };
0600: ThreadEngine.getInstance().addRunnable(maximizeRunnable,
0601: "maximizeRunnable");
0602: maximizeRunnable = null; // help the GC
0603: }
0604:
0605: // Set the default cursor, after all ThreadEngine threads
0606: // and tasks in the EventQueue have been processed :
0607: Runnable cursorActivationRunnable = new Runnable() {
0608: public void run() {
0609: EventQueue.invokeLater(new Runnable() {
0610: public void run() {
0611: setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
0612: }
0613: });
0614: }
0615: };
0616: ThreadEngine.getInstance().addRunnable(
0617: cursorActivationRunnable,
0618: Language.Translate("Set DefaultCursor"));
0619: cursorActivationRunnable = null; // help the GC
0620:
0621: // GUI:
0622: EventQueue.invokeLater(new Runnable() {
0623: public void run() {
0624: updateSpecialUI(); // needed initially
0625: }
0626: });
0627: } // Constructor
0628:
0629: public void setDefaultDividerLocations() {
0630: int charSize = UIManager.getFont("TextField.font").getSize();
0631: int verticalHeight = horizontalSplitPane.getHeight();
0632:
0633: horizontalSplitPane.setDividerLocation(25 * charSize);
0634:
0635: rightVerticalSplitPane
0636: .setDividerLocation((44 * verticalHeight) / 50);
0637:
0638: final int searchStartLocation = verticalHeight - (8 * charSize)
0639: / 2;
0640: final int middleStartLocation = (26 * verticalHeight) / 50; // relative
0641: final int projectFilesStartLocation = middleStartLocation
0642: - (10 * charSize) / 2;
0643: // The splitpanes are cascaded: One needs the previous evaluated :
0644: verticalSplitPane.setDividerLocation(searchStartLocation);
0645: EventQueue.invokeLater(new Runnable() {
0646: public void run() {
0647: middleSplitPane.setDividerLocation(middleStartLocation);
0648: EventQueue.invokeLater(new Runnable() {
0649: public void run() {
0650: upperSplitPane
0651: .setDividerLocation(projectFilesStartLocation);
0652:
0653: EventQueue.invokeLater(new Runnable() {
0654: public void run() {
0655: // keep the relative dividerlocation of this one constant on resizings :
0656: // Actually the value set here isn't important, because the set
0657: // operation anyway will trigger the splitpanes change listener :
0658: projectFilesLinkSplitPane
0659: .setDividerLocation(200);
0660: }
0661: });
0662:
0663: }
0664: });
0665: }
0666: });
0667: // Note: Also update the values in popupSearchResultsTreePanel(),
0668: // and checkPopupLibrariesTreePanel() if values here are changed.
0669: }
0670:
0671: /**
0672: * This is called by SearchResultsTree.searchTheCompleteProjectForText(),
0673: * after a search, if something was found. It should make sure,
0674: * that the panel with the searchresultstree inside is visible by
0675: * moving the splitpane a bit, if needed.
0676: */
0677: public void popupSearchResultsTreePanel() {
0678: // The searchresults tree panel starts at this.verticalSplitPane.getDividerLocation()
0679: // and takes all space below to the bottom.
0680: int verticalHeight = this .horizontalSplitPane.getHeight();
0681: int charSize = UIManager.getFont("TextField.font").getSize();
0682: int requiredSearchStartLocation = verticalHeight - 10
0683: * charSize;
0684: int currentSearchStartLocation = this .verticalSplitPane
0685: .getDividerLocation();
0686: if (requiredSearchStartLocation < currentSearchStartLocation) {
0687: this .verticalSplitPane
0688: .setDividerLocation(requiredSearchStartLocation);
0689: }
0690: } // popupSearchResultsTreePanel
0691:
0692: /**
0693: * Returns true, if a fullscreen frame is displayed.
0694: */
0695: public boolean getIsFullScreen() {
0696: return (this .fullScreenFrame != null);
0697: }
0698:
0699: /**
0700: * Returns the fullscreen frame.
0701: * If no fullscreen frame is displayed, it isn't created neither,
0702: * and null will be returned.
0703: */
0704: public FullScreenProjectView getFullScreenFrame() {
0705: return this .fullScreenFrame;
0706: }
0707:
0708: /**
0709: * Creates and shows the fullscreen frame.
0710: * It's done in a separate thread, so when this method returns,
0711: * the frame is in the process of being created and becoming visible.
0712: */
0713: private void createAndShowFullScreenFrame() {
0714: // Note: By design, the fullscreen frame mustn't exist, when this is called :
0715: if (this .fullScreenFrame != null) {
0716: Log
0717: .Error("DesignError: createFullScreenFrame() called, but a fullscreen frame already exists.");
0718: JOptionPane
0719: .showMessageDialog(
0720: this .getParentFrameForChildren(),
0721: Language
0722: .Translate("DesignError: createFullScreenFrame() called, but a fullscreen frame already exists."));
0723: }
0724: // Change into a thread, so Swing can update freely :
0725: Runnable fullScreenCreator = new Runnable() {
0726: public void run() {
0727: // FullScreenProjectView: Select the first device and first configurations for this one :
0728: GraphicsEnvironment ge = GraphicsEnvironment
0729: .getLocalGraphicsEnvironment();
0730: GraphicsDevice[] gs = ge.getScreenDevices();
0731: //Log.Info("Number of display devices "+gs.length);
0732:
0733: GraphicsDevice fullScreenDevice = null;
0734: GraphicsConfiguration fullScreenConfiguration = null;
0735: Rectangle fullScreenBounds = null;
0736: if (gs.length > 0) {
0737: fullScreenDevice = gs[0];
0738: fullScreenConfiguration = gs[0]
0739: .getDefaultConfiguration();
0740: GraphicsConfiguration[] gc = fullScreenDevice
0741: .getConfigurations();
0742: if (gc.length > 0) {
0743: fullScreenBounds = gc[0].getBounds();
0744: }
0745: }
0746:
0747: for (int i = 0; i < gs.length; i++) {
0748:
0749: GraphicsConfiguration[] graphicsConfs = gs[i]
0750: .getConfigurations();
0751: //Log.Info(" \tDevice "+i+ " has "+graphicsConfs.length+" graphics configurations");
0752: for (int j = 0; j < graphicsConfs.length; j++) {
0753: GraphicsConfiguration graphicsConf = graphicsConfs[j];
0754: Log.Info(graphicsConf.toString());
0755: Log.Info(graphicsConf.getBounds().toString());
0756: }
0757:
0758: }
0759:
0760: fullScreenFrame = new FullScreenProjectView(mainFrame,
0761: this Frame, fullScreenDevice,
0762: fullScreenConfiguration);
0763:
0764: try {
0765: Thread.sleep(44);
0766: } catch (Exception e234876) {
0767: }
0768:
0769: final Rectangle finalFullScreenBounds = fullScreenBounds;
0770: EventQueue.invokeLater(new Runnable() {
0771: public void run() {
0772: // set it :
0773: fullScreenFrame.switchToFullScreenMode();
0774: setIsFullScreen(true);
0775: fullScreenSwitchButton.setEnabled(true);
0776: fullScreenFrame.setVisible(true);
0777: }
0778: });
0779:
0780: try {
0781: Thread.sleep(44);
0782: } catch (Exception e23654576) {
0783: }
0784:
0785: EventQueue.invokeLater(new Runnable() {
0786: public void run() {
0787: setDefaultDividerLocations();
0788: }
0789: });
0790: }
0791: };
0792: ThreadEngine.getInstance().addRunnable(fullScreenCreator,
0793: "fullScreenCreator");
0794: }
0795:
0796: public void destroyFullScreenFrame() {
0797: // Note: By design, the fullscreen frame mustn't exist, when this is called :
0798: if (this .fullScreenFrame == null) {
0799: Log
0800: .Error("DesignError: destroyFullScreenFrame() called, but fullscreen frame is null.");
0801: JOptionPane
0802: .showMessageDialog(
0803: this .getParentFrameForChildren(),
0804: Language
0805: .Translate("DesignError: destroyFullScreenFrame() called, but no frame exists."));
0806: }
0807: if (this .fullScreenFrame != null) {
0808: this .fullScreenFrame.terminate();
0809: this .fullScreenFrame.dispose();
0810: this .fullScreenFrame = null; // This is used by switches.
0811: EventQueue.invokeLater(new Runnable() {
0812: public void run() {
0813: setDefaultDividerLocations();
0814: }
0815: });
0816: }
0817: }
0818:
0819: /**
0820: * Called by the mainframe, when it is activated.
0821: * In this case, the fullscreen frame should be closed and
0822: * the captured contentpane be returned to the projectframe,
0823: * which is done here :
0824: */
0825: public void checkCloseFullScreenView() {
0826: if (this .getIsFullScreen()) {
0827: fullScreenFrame.setVisible(false);
0828: fullScreenFrame.switchBackToNormalMode();
0829: setIsFullScreen(false);
0830: this .destroyFullScreenFrame();
0831: }
0832: } // checkCloseFullScreenView
0833:
0834: public void setIsFullScreen(final boolean is_FullScreen) {
0835: if (is_FullScreen) {
0836: this .fullScreenSwitchButton.setText(Language
0837: .Translate(" Normal View "));
0838: this .fullScreenSwitchButton.setIcon(this .mainFrame
0839: .loadImageIcon("pics/menupics/blackdownarrow.jpg"));
0840: this .fullScreenSwitchButton
0841: .setRolloverIcon(this .mainFrame
0842: .loadImageIcon("pics/menupics/blackdownarrowactive.jpg"));
0843: this .fullScreenSwitchButton.normalize();
0844: } else {
0845: fullScreenSwitchButton.setText(Language
0846: .Translate(" Fullscreen "));
0847: this .fullScreenSwitchButton.setIcon(this .mainFrame
0848: .loadImageIcon("pics/menupics/blackuparrow.jpg"));
0849: this .fullScreenSwitchButton
0850: .setRolloverIcon(this .mainFrame
0851: .loadImageIcon("pics/menupics/blackuparrowactive.jpg"));
0852: this .fullScreenSwitchButton.normalize();
0853: }
0854: } // setIsFullScreen
0855:
0856: /**
0857: * For any child-frame or dialog, we must take the fullscreen frame
0858: * as parent, if the user is working with this one in fullscreenmode,
0859: * otherwise we return the mainframe as parent.
0860: */
0861: public JFrame getParentFrameForChildren() {
0862: if (this .getIsFullScreen())
0863: return this .fullScreenFrame;
0864: return this .mainFrame.getJFrame();
0865: }
0866:
0867: public String getProjectDirectoryPath() {
0868: return this .projectDirectoryPath;
0869: }
0870:
0871: /**
0872: * Terminates all in a ThreadEngine Thread.
0873: * The ThreadEngine guarantees, that no other thread
0874: * accesses the filesystem too, and it also guarantees,
0875: * that the program doesnt interrupt it on the end,
0876: * because the program too is terminated in a ThreadEngine thread,
0877: * and all threads of the ThreadEngine are processed one after the other.
0878: *
0879: * doForceGarbageColletion: If set, the garbagecollector is started
0880: * multiple times in this threadcontext and delayed in the swing edt.
0881: *
0882: * It should be true, when only this frame is going to be closed and
0883: * the ide remains running (prevent memory explosions), but can be
0884: * cleared when the ide anyway is shutting down, which makes the shutdown
0885: * process faster.
0886: *
0887: */
0888: public void terminateFrame(final boolean doForceGarbageColletion) {
0889: setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
0890: // Do it in a thread, so Swing stays reacting :
0891: Runnable closeRunnable = new Runnable() {
0892: public void run() {
0893: // write to the project ini file :
0894: boolean isMaximized = this Frame.isMaximum();
0895: projectDefinition.getProjectIniFile().setBooleanValue(
0896: IniFileMaximizedProperty, isMaximized);
0897:
0898: // Save the state of the JarCreation Manager
0899: jarCreationManager.saveSettingsInInifile();
0900:
0901: // Save the history to the project inifile :
0902: editorPanel.getDocumentHistoryTracker().save();
0903:
0904: // save the projectDefinition to file :
0905: boolean userHasConfirmed = checkSaveProjectFiles(true); // this one creates EDT entries
0906: projectDefinition.saveToIniFile(this Frame);
0907:
0908: // If the user has cancelled the save operation, we store it and
0909: // this way, the mainframe can be informed about this too and
0910: // won't ask again :
0911: if (!userHasConfirmed) {
0912: setSaveHasBeenCancelledOnClose();
0913: }
0914:
0915: // remove this frame from the parent list :
0916: mainFrame.removeFromProjectFrames(this Frame);
0917: // Now start the finalizer thread, if required :
0918: if (doForceGarbageColletion) {
0919: final Runnable cleanUpRunnable = new Runnable() {
0920: public void run() {
0921: try {
0922: Thread.sleep(99);
0923: } catch (Exception e2876) {
0924: }
0925: doFinalCleanUp();
0926: }
0927: };
0928: ThreadEngine.getInstance().addRunnable(
0929: cleanUpRunnable, "Clean up ProjectFrame");
0930: }
0931: }
0932: };
0933: ThreadEngine.getInstance().addRunnable(closeRunnable,
0934: "Close ProjectFrame");
0935: } // terminateFrame
0936:
0937: /**
0938: * Called by the mainframe on exit, so it won't ask if it should save
0939: * this twice. The flag is set in terminateFrame, if the user cancels the save operation
0940: * in the save dialog, which of course only is displayed, if there have been changes.
0941: */
0942: public boolean getSaveHasBeenCancelledOnClose() {
0943: return this .saveHasBeenCancelledOnClose;
0944: }
0945:
0946: public void setSaveHasBeenCancelledOnClose() {
0947: //ystem.out.println("setSaveHasBeenCancelledOnClose");
0948: this .saveHasBeenCancelledOnClose = true;
0949: }
0950:
0951: /**
0952: * Called from a threadengine thread context by terminateFrame()
0953: * as very last action, which helps the GC by releasing connections
0954: * and starts the GC at the end.
0955: *
0956: * Note that the fsdManager uses this call to shutdown its updater threads,
0957: * which is important for a proper shutdown.
0958: */
0959: private void doFinalCleanUp() {
0960: this .mainFrame = null;
0961: this .projectFilesPanel.removeAll();
0962: this .projectFilesPanel = null;
0963:
0964: this .javaDocManager.terminate();
0965: this .javaDocManager = null;
0966:
0967: this .jarCreationManager.terminate();
0968: this .jarCreationManager = null;
0969:
0970: this .umlManager.terminate();
0971: this .umlManager = null;
0972:
0973: this .fileComponentsPanel.removeAll();
0974: this .fileComponentsPanel = null;
0975:
0976: this .librariesPanel.removeAll();
0977: this .librariesPanel = null;
0978:
0979: this .fileSourcePanel.removeAll();
0980: this .fileSourcePanel = null;
0981:
0982: this .outputPane.removeAll();
0983: this .outputPane = null;
0984:
0985: this .leftMainPanel = null;
0986:
0987: this .projectInfoPanel = null;
0988:
0989: this .fileComponentsTitleWrapPanel = null;
0990:
0991: if (this .searchResultsPanel != null) {
0992: this .searchResultsPanel.clear();
0993: }
0994: this .searchResultsPanel = null;
0995:
0996: this .librariesTitleWrapPanel = null;
0997: this .projectFilesTitleWrapPanel = null;
0998: this .projectFilesTitlePanel = null;
0999:
1000: this .greenPointIcon = null;
1001: this .bluePointIcon = null;
1002: this .redPointIcon = null;
1003:
1004: this .editorPanel.terminate();
1005: this .editorPanel = null;
1006:
1007: this .projectFilesManager.terminate();
1008: this .projectFilesManager = null;
1009:
1010: this .fileComponentsTree.terminate();
1011: this .fileComponentsTree = null;
1012:
1013: this .librariesTree.terminate();
1014: this .librariesTree = null;
1015:
1016: this .outputManager.terminate();
1017: this .outputManager = null;
1018:
1019: this .projectDefinition.terminate();
1020: this .projectDefinition = null;
1021:
1022: this .this Frame = null;
1023:
1024: this .menuBar.removeAll();
1025: this .menuBar = null;
1026:
1027: this .menuBarPanel.removeAll();
1028: this .menuBarPanel = null;
1029:
1030: this .iniFile = null;
1031:
1032: if (this .fileStructureDescriptionManager != null) {
1033: this .fileStructureDescriptionManager.terminate_fsdManager(); // Shuts down its updater threads.
1034: this .fileStructureDescriptionManager = null;
1035: }
1036:
1037: this .compileProjectButton = null;
1038: this .executeProjectButton = null;
1039: this .projectSelectionButton = null;
1040: this .projectSynchronizationButton = null;
1041:
1042: if (this .fullScreenSwitchButton != null) {
1043: this .fullScreenSwitchButton.removeAll();
1044: this .fullScreenSwitchButton = null;
1045: }
1046:
1047: if (this .fullScreenFrame != null) {
1048: this .fullScreenFrame.removeAll();
1049: this .fullScreenFrame = null;
1050: }
1051:
1052: // And start the GC a couple of times :
1053: // 1) Immediately :
1054: System.gc();
1055: System.gc();
1056: System.gc();
1057: // 2) Delayed in EDT :
1058: EventQueue.invokeLater(new Runnable() {
1059: public void run() {
1060: System.gc();
1061: System.gc();
1062: System.gc();
1063: }
1064: });
1065: // 3) More delayed from a thread :
1066: final Runnable finalGCRunnable = new Runnable() {
1067: public void run() {
1068: for (int i = 0; i < 8; i++) {
1069: try {
1070: Thread.sleep(99);
1071: } catch (Exception e2876) {
1072: }
1073: System.gc();
1074: System.gc();
1075: System.gc();
1076: System.gc();
1077: }
1078: }
1079: };
1080: ThreadEngine.getInstance().addRunnable(finalGCRunnable,
1081: "GC cleanup");
1082: } // doFinalCleanUp
1083:
1084: /**
1085: * Creates the button bar containing compile and execute buttons.
1086: */
1087: private JPanel createCompileExecuteButtonBarPanel() {
1088: final int hGap = UIManager.getFont("TextField.font").getSize() / 2;
1089: // buttonBorder is the border, which changes colors on mouseover :
1090: JPanel buttonPanel = new JPanel();
1091: BoxLayout buttonPanelLayout = new BoxLayout(buttonPanel,
1092: BoxLayout.X_AXIS);
1093: buttonPanel.setLayout(buttonPanelLayout);
1094: buttonPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0,
1095: 0));
1096:
1097: final int buttonBorderThickness = 1 + UIManager.getFont(
1098: "TextField.font").getSize() / 8;
1099: this .compileProjectButton = new JSenseButton(this .mainFrame
1100: .loadImageIcon("pics/menupics/compilebutton.jpg"),
1101: false, true, this .getMainFrameProvider());
1102: this .compileProjectButton
1103: .setRolloverIcon(this .mainFrame
1104: .loadImageIcon("pics/menupics/compilebuttonactive.jpg"));
1105: this .compileProjectButton.setBorder(BorderFactory
1106: .createEmptyBorder(buttonBorderThickness,
1107: buttonBorderThickness, buttonBorderThickness,
1108: buttonBorderThickness));
1109: this .compileProjectButton.setToolTipText(Language
1110: .Translate("Compile Project")
1111: + " F9");
1112:
1113: buttonPanel.add(compileProjectButton);
1114: this .executeProjectButton = new JSenseButton(this .mainFrame
1115: .loadImageIcon("pics/menupics/executebutton.jpg"),
1116: false, true, this .getMainFrameProvider());
1117: this .executeProjectButton
1118: .setRolloverIcon(this .mainFrame
1119: .loadImageIcon("pics/menupics/executebuttonactive.jpg"));
1120: this .executeProjectButton.setBorder(BorderFactory
1121: .createEmptyBorder(buttonBorderThickness,
1122: buttonBorderThickness, buttonBorderThickness,
1123: buttonBorderThickness));
1124: this .executeProjectButton.setToolTipText(Language
1125: .Translate("Execute Project")
1126: + " F10");
1127:
1128: // Initially we must wait, until all threadengine runnables at least have
1129: // been started, so we disable the compile/execute actions, until
1130: // the loader threads at least all are running, so that compile
1131: // actions are added after them in the ThreadEngine queue.
1132: // They will be enabled in the constructor.
1133: this .compileProjectButton.setEnabled(false);
1134: this .executeProjectButton.setEnabled(false);
1135:
1136: // The actions :
1137: this .compileProjectButton
1138: .addActionListener(new ActionListener() {
1139: public void actionPerformed(ActionEvent e) {
1140: compileProjectButton.setEnabled(false); // prevent multiple launches
1141: executeProjectButton.setEnabled(false); // prevent multiple launches
1142: // Clear any text in the compilerinfolabel and start the color animation
1143: // to tell the user, that the compile/execute task is active:
1144: outputManager.setCompilerInfoLabel(Language
1145: .Translate("Compile Project"), true);
1146: // Changed: We perform this in a ThreadEngine thread, which guarantees
1147: // sequential execution. Note, that inside this ThreadEngine thread,
1148: // the compiler Runnable is launched, which again is a ThreadEngine thread
1149: // and therefore will start only, after this thread has been finished.
1150: final Runnable compileButtonRunnable = new Runnable() {
1151: public void run() {
1152: outputManager.clearTextArea();
1153: outputManager
1154: .printLine("Saving changes");
1155: // We must save, otherwise compilerfile lists get out of sync,
1156: // therefore flag false :
1157: checkSaveProjectFiles(false);
1158: // Pass the buttons for being enabled again when
1159: // compiling is finished. Compiling is carried out
1160: // in a thread, therefore the method below returns
1161: // while compiling is in progress.
1162: final ProjectDefinitionEntry projectMainFileEntry = projectDefinition
1163: .getProjectDefinitionEntry(ProjectDefinition.ProjectMainFileName_Key);
1164: final String projectMainSourceFilePath = (String) projectMainFileEntry
1165: .getValue();
1166: outputManager
1167: .doCompile(
1168: compileProjectButton,
1169: executeProjectButton,
1170: true,
1171: false,
1172: projectMainSourceFilePath,
1173: fileStructureDescriptionManager);
1174: }
1175: };
1176: ThreadEngine.getInstance().addRunnable(
1177: compileButtonRunnable,
1178: "Compiler Launch Task");
1179: }
1180: });
1181:
1182: this .executeProjectButton
1183: .addActionListener(new ActionListener() {
1184: public void actionPerformed(ActionEvent e) {
1185: compileProjectButton.setEnabled(false); // prevent multiple launches
1186: executeProjectButton.setEnabled(false); // prevent multiple launches
1187: // Clear any text in the compilerinfolabel and start the color animation
1188: // to tell the user, that the compile/execute task is active:
1189: outputManager.setCompilerInfoLabel(Language
1190: .Translate("Execute Project"), true);
1191: // Changed: We perform this in a ThreadEngine thread, which guarantees
1192: // sequential execution. Note, that inside this ThreadEngine thread,
1193: // the compiler Runnable is launched, which again is a ThreadEngine thread
1194: // and therefore will start only, after this thread has been finished.
1195: final Runnable executeButtonRunnable = new Runnable() {
1196: public void run() {
1197: outputManager.clearTextArea();
1198: outputManager
1199: .printLine("Saving changes");
1200: // We must save, otherwise compilerfile lists get out of sync,
1201: // therefore flag false :
1202: checkSaveProjectFiles(false);
1203: // Pass the buttons for being enabled again when
1204: // compiling is finished. Compiling is carried out
1205: // in a thread, therefore the method below returns
1206: // while compiling is in progress.
1207: final ProjectDefinitionEntry projectMainFileEntry = projectDefinition
1208: .getProjectDefinitionEntry(ProjectDefinition.ProjectMainFileName_Key);
1209: final String projectMainSourceFilePath = (String) projectMainFileEntry
1210: .getValue();
1211: outputManager
1212: .doCompile(
1213: compileProjectButton,
1214: executeProjectButton,
1215: true,
1216: true,
1217: projectMainSourceFilePath,
1218: fileStructureDescriptionManager);
1219: }
1220: };
1221: ThreadEngine
1222: .getInstance()
1223: .addRunnable(
1224: executeButtonRunnable,
1225: Language
1226: .Translate("Compile/Execute Launch Task"));
1227: }
1228: });
1229: buttonPanel.add(executeProjectButton);
1230:
1231: return buttonPanel;
1232: } // createCompileExecuteButtonBarPanel
1233:
1234: /**
1235: * Creates the panel containing the project selection button.
1236: */
1237: private JPanel createProjectSelectionButtonPanel() {
1238: final int hGap = UIManager.getFont("TextField.font").getSize() / 2;
1239: // buttonBorder is the border, which changes colors on mouseover :
1240: JPanel buttonPanel = new JPanel(new FlowLayout(
1241: FlowLayout.CENTER, 0, 0));
1242: buttonPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0,
1243: 0));
1244: final int buttonBorderThickness = 1 + UIManager.getFont(
1245: "TextField.font").getSize() / 8;
1246:
1247: // The projectSynchronizationButton :
1248: this .projectSynchronizationButton = new JSenseButton(
1249: this .mainFrame
1250: .loadImageIcon("pics/menupics/projectsync.jpg"),
1251: false, true, this .getMainFrameProvider());
1252: this .projectSynchronizationButton
1253: .setRolloverIcon(this .mainFrame
1254: .loadImageIcon("pics/menupics/projectsyncactive.jpg"));
1255: this .projectSynchronizationButton.setBorder(BorderFactory
1256: .createEmptyBorder(buttonBorderThickness,
1257: buttonBorderThickness, buttonBorderThickness,
1258: buttonBorderThickness));
1259: this .projectSynchronizationButton.setToolTipText(Language
1260: .Translate("Saves and reloads the project from disk"));
1261: buttonPanel.add(this .projectSynchronizationButton);
1262: // The action :
1263: this .projectSynchronizationButton
1264: .addActionListener(new ActionListener() {
1265: public void actionPerformed(ActionEvent e) {
1266: synchronizeTheProject();
1267: }
1268: });
1269:
1270: // The projectSelectionButton :
1271: this .projectSelectionButton = new JSenseButton(this .mainFrame
1272: .loadImageIcon("pics/menupics/projectselection.jpg"),
1273: false, true, this .getMainFrameProvider());
1274: this .projectSelectionButton
1275: .setRolloverIcon(this .mainFrame
1276: .loadImageIcon("pics/menupics/projectselectionactive.jpg"));
1277: this .projectSelectionButton.setBorder(BorderFactory
1278: .createEmptyBorder(buttonBorderThickness,
1279: buttonBorderThickness, buttonBorderThickness,
1280: buttonBorderThickness));
1281: this .projectSelectionButton.setToolTipText(Language
1282: .Translate("Select project files"));
1283: buttonPanel.add(this .projectSelectionButton);
1284: // The action :
1285: this .projectSelectionButton
1286: .addActionListener(new ActionListener() {
1287: public void actionPerformed(ActionEvent e) {
1288: projectSelectionButton.setEnabled(false); // prevent multiple launches
1289: // Do it in a user thread. Don't use the thread engine,
1290: // because this one will be used by the compiler. It wouldn't hurt,
1291: // but it could lead to side effects in future enhancements maybe.
1292: final Thread creationThread = new Thread() {
1293: public void run() {
1294: this
1295: .setName("IDE_ProjectFrame.projectSelectionButton thread");
1296: // Time for Swing :
1297: try {
1298: Thread.sleep(99);
1299: } catch (Exception ee5159876) {
1300: }
1301: // We must save, otherwise compilerfile lists get out of sync,
1302: // therefore flag false :
1303: checkSaveProjectFiles(false);
1304: // Start The selection (displays a modal dialog) :
1305: projectFilesManager
1306: .displayTheProjectFilesSelectionDialog(getParentFrameForChildren());
1307: // Cleanup:
1308: projectSelectionButton.setEnabled(true); // reenable it again
1309: }
1310: };
1311: creationThread.start();
1312: }
1313: });
1314:
1315: // Initially we must wait, until all threadengine runnables at least have
1316: // been started, so we disable the actions, until
1317: // the loader threads at least all are running, so that compile
1318: // actions are added after them in the ThreadEngine queue.
1319: // They will be enabled in the constructor.
1320: this .projectSynchronizationButton.setEnabled(false);
1321: this .projectSelectionButton.setEnabled(false);
1322:
1323: return buttonPanel;
1324: } // createProjectSelectionButtonPanel
1325:
1326: /**
1327: * If no tab with searchName exists, a new tab is created in the search results
1328: * panel, otherwise the existing tab is selected.
1329: * Then a single node is created for the associated searchresults tree and
1330: * initialized with the passed nodeTitle.
1331: */
1332: public void initializeSearchResults(final String searchName,
1333: final String nodeTitle) {
1334: // delegated to searchResultsPanel:
1335: this .searchResultsPanel.initializeSearchResults(searchName,
1336: nodeTitle);
1337: }
1338:
1339: /**
1340: * Synchronizes the project with the files on disk.
1341: * Saves and reloads all.
1342: */
1343: public void synchronizeTheProject() {
1344: projectSynchronizationButton.setEnabled(false); // prevent multiple launches
1345: final Runnable syncRunnable = new Runnable() {
1346: public void run() {
1347: // Time for Swing :
1348: try {
1349: Thread.sleep(99);
1350: } catch (Exception ee5159876) {
1351: }
1352: synchronizeProjectFilesTree(); // saves and reloads all from disk
1353: // Cleanup:
1354: projectSynchronizationButton.setEnabled(true); // reenable it again
1355: }
1356: };
1357: ThreadEngine.getInstance().addRunnable(syncRunnable,
1358: "Project Synchronisation Thread");
1359: }
1360:
1361: /**
1362: * Programmatically pushes the compile project button.
1363: * Used by the EditorPanel for the F9 keystroke.
1364: */
1365: public void compileProject() {
1366: this .compileProjectButton.doClick();
1367: }
1368:
1369: /**
1370: * Programmatically pushes the execute project button.
1371: * Used by the EditorPanel for the F10 keystroke.
1372: */
1373: public void executeProject() {
1374: this .executeProjectButton.doClick();
1375: }
1376:
1377: /**
1378: * Programmatically pushes the execute file button.
1379: * Used by the EditorPanel for the Shift F10 keystroke.
1380: */
1381: public void executeCurrentFile() {
1382: this .editorPanel.executeCurrentFile();
1383: }
1384:
1385: private void build_projectFilesPanel(
1386: final JPanel projectFilesTitleWrapPanel,
1387: final JPanel projectFilesTitlePanel,
1388: final JPanel basePanel,
1389: final ProjectFilesManager theProjectFilesManager) {
1390: int fontSize = UIManager.getFont("Tree.font").getSize();
1391: // The projectselection button :
1392: this .projectFilesTitlePanel.setBorder(BorderFactory
1393: .createEmptyBorder(0, 0, 0, 0));
1394: this .projectFilesTitleWrapPanel.setBorder(BorderFactory
1395: .createEmptyBorder(0, 0, 0, 0));
1396:
1397: // Note: projectFilesTitlePanel has a BorderLayout.
1398: JPanel innerPanel = new EFCNSmoothBackgroundPanel(
1399: new FlowLayout(FlowLayout.CENTER, 0, 0),
1400: EFCNSmoothBackgroundPanel.PanelBackGroundColorIdentifier,
1401: EFCNSmoothBackgroundPanel.SmoothCenterMode);
1402: projectFilesTitlePanel.add(innerPanel, BorderLayout.CENTER);
1403:
1404: innerPanel.add(this .createProjectSelectionButtonPanel());
1405:
1406: // the title :
1407: JContrastLabel titleLabel = new JContrastLabel(Language
1408: .Translate(" Project Files "));
1409: titleLabel.setHorizontalAlignment(SwingConstants.CENTER);
1410: titleLabel.setBorder(BorderFactory
1411: .createEmptyBorder(0, 0, 0, 0));
1412: innerPanel.add(titleLabel);
1413: // The project buttonBar :
1414: innerPanel.add(this .createCompileExecuteButtonBarPanel());
1415: projectFilesTitleWrapPanel.add(projectFilesTitlePanel,
1416: BorderLayout.CENTER);
1417: // add it :
1418: basePanel.add(projectFilesTitleWrapPanel, BorderLayout.NORTH);
1419: // add the two trees into one panel inside a scrollpane :
1420: final JPanel innerTreePanel = new JPanel(new BorderLayout(0, 0));
1421: innerTreePanel.setBorder(BorderFactory.createEmptyBorder(0, 0,
1422: 0, 0));
1423: innerTreePanel.add(
1424: theProjectFilesManager.getProjectFilesTree(),
1425: BorderLayout.CENTER);
1426:
1427: final JScrollPane treeScrollPane = new JScrollPane(
1428: innerTreePanel);
1429: treeScrollPane.setBorder(BorderFactory.createEmptyBorder(0, 0,
1430: 0, 0));
1431: treeScrollPane.getVerticalScrollBar()
1432: .setUnitIncrement(fontSize);
1433: treeScrollPane.getVerticalScrollBar().setBlockIncrement(
1434: 4 * fontSize);
1435: treeScrollPane.getHorizontalScrollBar().setUnitIncrement(
1436: fontSize);
1437: treeScrollPane.getHorizontalScrollBar().setBlockIncrement(
1438: 4 * fontSize);
1439:
1440: // Allow Swing to decrease this size to zero :
1441: treeScrollPane.setMinimumSize(new Dimension(0, 0));
1442:
1443: JScrollPane linkScrollPane = new JScrollPane(this .editorPanel
1444: .getDocumentHistoryTracker().getDepositoryViewPanel());
1445: linkScrollPane.setBorder(BorderFactory.createEmptyBorder(0, 0,
1446: 0, 0));
1447: linkScrollPane.getVerticalScrollBar()
1448: .setUnitIncrement(fontSize);
1449: linkScrollPane.getVerticalScrollBar().setBlockIncrement(
1450: 4 * fontSize);
1451: linkScrollPane.getHorizontalScrollBar().setUnitIncrement(
1452: fontSize);
1453: linkScrollPane.getHorizontalScrollBar().setBlockIncrement(
1454: 4 * fontSize);
1455:
1456: this .projectFilesLinkSplitPane = new JSplitPane(
1457: JSplitPane.VERTICAL_SPLIT, treeScrollPane,
1458: linkScrollPane);
1459: this .projectFilesLinkSplitPane.setOneTouchExpandable(true);
1460: this .projectFilesLinkSplitPane.setBorder(BorderFactory
1461: .createEmptyBorder(0, 0, 0, 0));
1462: this .projectFilesLinkSplitPane.setDividerLocation(400);
1463:
1464: // keep the relative dividerlocation of this one constant on resizings :
1465: this .projectFilesLinkSplitPane.setResizeWeight(0.75);
1466: // and if needed reduze the size of the space for the ptojectfiles link
1467: // panel to the actally required space :
1468: this .projectFilesLinkSplitPane
1469: .addComponentListener(new ComponentAdapter() {
1470: public void componentResized(ComponentEvent e) {
1471: final int requiredHeight = editorPanel
1472: .getDocumentHistoryTracker()
1473: .getRequiredDepositoryViewHeight();
1474: final int requiredLocation = projectFilesLinkSplitPane
1475: .getHeight()
1476: - requiredHeight;
1477: if (projectFilesLinkSplitPane
1478: .getDividerLocation() < requiredLocation) {
1479: EventQueue.invokeLater(new Runnable() {
1480: public void run() {
1481: projectFilesLinkSplitPane
1482: .setDividerLocation(requiredLocation);
1483: }
1484: });
1485: }
1486: }
1487: });
1488: basePanel.add(projectFilesLinkSplitPane, BorderLayout.CENTER);
1489: } // build_projectFilesPanel
1490:
1491: private void build_librariesPanel(
1492: final JPanel librariesTitleWrapPanel,
1493: final JPanel basePanel, final LibrariesTree theLibrariesTree) {
1494: // the title :
1495: JPanel librariesTitlePanel = new EFCNSmoothBackgroundPanel(
1496: new FlowLayout(FlowLayout.CENTER, 0, 0),
1497: EFCNSmoothBackgroundPanel.PanelBackGroundColorIdentifier,
1498: EFCNSmoothBackgroundPanel.SmoothCenterMode);
1499: JContrastLabel titleLabel = new JContrastLabel(Language
1500: .Translate("Library Files"));
1501: titleLabel.setHorizontalAlignment(SwingConstants.CENTER);
1502: titleLabel.setBorder(BorderFactory
1503: .createEmptyBorder(0, 0, 0, 0));
1504: librariesTitlePanel.add(titleLabel);
1505: // add it :
1506: librariesTitleWrapPanel.add(librariesTitlePanel,
1507: BorderLayout.CENTER);
1508: basePanel.add(librariesTitleWrapPanel, BorderLayout.NORTH);
1509: final JScrollPane treeScrollPane = new JScrollPane(
1510: theLibrariesTree);
1511: treeScrollPane.setBorder(BorderFactory.createEmptyBorder(0, 0,
1512: 0, 0));
1513:
1514: // Allow Swing to decrease this size to zero :
1515: treeScrollPane.setMinimumSize(new Dimension(0, 0));
1516:
1517: basePanel.add(treeScrollPane, BorderLayout.CENTER);
1518: } // build_librariesPanel
1519:
1520: private void build_fileComponentsPanel(
1521: final JPanel fileComponentsTitleWrapPanel,
1522: final JPanel basePanel,
1523: final FileComponentsTree theFileComponentsTree) {
1524: // the title : Use the member attribute fileComponentsTitleLabel,
1525: // because this one is used by the parser to signalize
1526: // success or errors by setting a red or blue point as icon :
1527: // using the method this.setFileComponentsTitleLabelState( state);
1528:
1529: JPanel fileComponentsTitlePanel = new EFCNSmoothBackgroundPanel(
1530: new FlowLayout(FlowLayout.CENTER, 0, 0),
1531: EFCNSmoothBackgroundPanel.PanelBackGroundColorIdentifier,
1532: EFCNSmoothBackgroundPanel.SmoothCenterMode);
1533: this .fileComponentsTitleLabel = new JContrastLabel(Language
1534: .Translate("File Components"));
1535: this .fileComponentsTitleLabel.setBorder(BorderFactory
1536: .createEmptyBorder(0, 0, 0, 0));
1537: fileComponentsTitlePanel.add(this .fileComponentsTitleLabel);
1538:
1539: fileComponentsTitleWrapPanel.add(fileComponentsTitlePanel,
1540: BorderLayout.CENTER);
1541: basePanel.add(fileComponentsTitleWrapPanel, BorderLayout.NORTH);
1542:
1543: final JScrollPane treeScrollPane = new JScrollPane(
1544: theFileComponentsTree);
1545: treeScrollPane.setBorder(BorderFactory.createEmptyBorder(0, 0,
1546: 0, 0));
1547:
1548: // Allow Swing to decrease this size to zero :
1549: treeScrollPane.setMinimumSize(new Dimension(0, 0));
1550:
1551: basePanel.add(treeScrollPane, BorderLayout.CENTER);
1552: } // build_fileComponentsPanel
1553:
1554: private JMenuBar createTheMenuBar() {
1555:
1556: // Create the menuBar :
1557: final JMenuBar menuBar = new JMenuBar();
1558: Font theFont = UIManager.getFont("TextField.font");
1559: int fontSize = theFont.getSize();
1560: menuBar.setMargin(new Insets(0, fontSize, 0, fontSize));
1561:
1562: JMenuItem item; // temporary worker attribute used below
1563: String menuIconName;
1564:
1565: // Create the projectmenu :
1566: final JSenseMenu projectMenu = new JSenseMenu(Language
1567: .Translate(" Project "), this
1568: .getMainFrameProvider());
1569: projectMenu.setMnemonic('p');
1570: // and add actions:
1571:
1572: item = projectMenu.add(new JMenuItem(Language
1573: .Translate(" Select project files")));
1574: item.setIcon(this .mainFrame
1575: .loadImageIcon("pics/menupics/projectselection.jpg"));
1576: item.addActionListener(new java.awt.event.ActionListener() {
1577: public void actionPerformed(ActionEvent e) {
1578: projectSelectionButton.setEnabled(false); // prevent multiple launches
1579: // Do it in a user thread. Don't use the thread engine,
1580: // because this one will be used by the compiler. It wouldn't hurt,
1581: // but it could lead to side effects in future enhancements maybe.
1582: final Thread creationThread = new Thread() {
1583: public void run() {
1584: this
1585: .setName("IDE_ProjectFrame.CreationThread[2]");
1586: // Time for Swing :
1587: try {
1588: Thread.sleep(99);
1589: } catch (Exception ee5159876) {
1590: }
1591: // We must save, otherwise compilerfile lists get out of sync,
1592: // therefore flag false :
1593: checkSaveProjectFiles(false);
1594: // Start The selection (displays a modal dialog) :
1595: projectFilesManager
1596: .displayTheProjectFilesSelectionDialog(getParentFrameForChildren());
1597: // Cleanup:
1598: projectSelectionButton.setEnabled(true); // reenable it again
1599: }
1600: };
1601: creationThread.start();
1602: }
1603: });
1604:
1605: projectMenu.addSeparator();
1606:
1607: item = projectMenu.add(new JMenuItem(Language
1608: .Translate(" Compile Project")));
1609: item.setIcon(this .mainFrame
1610: .loadImageIcon("pics/menupics/compilebutton.jpg"));
1611: item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F9, 0,
1612: true));
1613: item.addActionListener(new java.awt.event.ActionListener() {
1614: public void actionPerformed(ActionEvent e) {
1615: compileProject();
1616: }
1617: });
1618: item = projectMenu.add(new JMenuItem(Language
1619: .Translate(" Execute Project")));
1620: item.setIcon(this .mainFrame
1621: .loadImageIcon("pics/menupics/executebutton.jpg"));
1622: item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F10, 0,
1623: true));
1624: item.addActionListener(new java.awt.event.ActionListener() {
1625: public void actionPerformed(ActionEvent e) {
1626: executeProject();
1627: }
1628: });
1629:
1630: projectMenu.addSeparator();
1631:
1632: item = projectMenu.add(new JMenuItem(Language
1633: .Translate(" Save Project ")));
1634: item.setIcon(this .mainFrame
1635: .loadImageIcon("pics/menupics/save.gif"));
1636: item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,
1637: KeyEvent.CTRL_MASK, true));
1638: item.addActionListener(new java.awt.event.ActionListener() {
1639: public void actionPerformed(ActionEvent e) {
1640: this Frame.setCursor(new Cursor(Cursor.WAIT_CURSOR));
1641: Runnable checkSaveRunnable = new Runnable() {
1642: public void run() {
1643: try {
1644: Thread.sleep(9);
1645: } catch (Exception e293476) {
1646: }
1647: checkSaveProjectFiles(false);
1648: this Frame.setCursor(new Cursor(
1649: Cursor.DEFAULT_CURSOR));
1650: }
1651: };
1652: ThreadEngine.getInstance().addRunnable(
1653: checkSaveRunnable, "checkSaveTask");
1654: }
1655: });
1656:
1657: projectMenu.addSeparator();
1658: item = projectMenu.add(new JMenuItem(Language
1659: .Translate(" Close Project ")));
1660: item.setIcon(this .mainFrame
1661: .loadImageIcon("pics/menupics/cancel.gif"));
1662: item.addActionListener(new java.awt.event.ActionListener() {
1663: public void actionPerformed(ActionEvent e) {
1664: checkCloseFullScreenView();
1665: setVisible(false);
1666: dispose();
1667: }
1668: });
1669:
1670: // Create the settingsmenu :
1671: JSenseMenu settingsMenu = new JSenseMenu(Language
1672: .Translate(" Settings "), this
1673: .getMainFrameProvider());
1674: settingsMenu.setMnemonic('s');
1675: // and add actions:
1676: item = settingsMenu.add(new JMenuItem(Language
1677: .Translate(" Project Settings ")));
1678: item.setIcon(this .mainFrame
1679: .loadImageIcon("pics/menupics/info.gif"));
1680: item.addActionListener(new java.awt.event.ActionListener() {
1681: public void actionPerformed(ActionEvent e) {
1682: // prevent menu cleanup problems
1683: // If started directly, the fropdownmenu isnt removed
1684: // and after the dialog has been closed, partially still visible.
1685: Thread diaThread = new Thread(new Runnable() {
1686: public void run() {
1687: setName("IDE_ProjectFrame.DiaThread");
1688: try {
1689: Thread.sleep(99); // cleanup time for the menu
1690: } catch (Exception eeeee) {
1691: }
1692: SwingUtilities.invokeLater(new Runnable() {
1693: public void run() {
1694: // Open the projectdefinitiondialog *without* possibility to
1695: // set or change the project directory (last parm false)
1696: // as we have the project open here.
1697: // Pass the reference to this frame as last parameter,
1698: // so that we are informed about changes in the definition :
1699: final ProjectDefinitionDialog pDialog = new ProjectDefinitionDialog(
1700: projectDefinition,
1701: getParentFrameForChildren(),
1702: this Frame,
1703: this Frame
1704: .getMainFrameProvider(),
1705: false);
1706: pDialog.showCentered();
1707: // If the project has been changed, we tell the
1708: // compiler to invalidate all files and recompile all
1709: // on the next request.
1710: if (pDialog
1711: .getDoChangesNeedRecompilation()) {
1712: outputManager
1713: .setClassesWereCompiledAFirstTime(false);
1714: }
1715: // If additional library components (or the src lib) have been changed
1716: // we have to reload the library tree :
1717: if (pDialog
1718: .getLibraryContentHasChanged()) {
1719: reloadLibraryTree();
1720: }
1721: // Make sure, that the required directories for the projectdefinition do exist.
1722: // If project directories don't exist, they are created. If required directories
1723: // which cannot be just created (like the JDK directory) don't exist or have
1724: // not the required content, a warning is displayed.
1725: projectDefinition
1726: .checkProjectDefinitionValues(this Frame);
1727: }
1728: });
1729: }
1730: });
1731: diaThread.start();
1732: }
1733: });
1734:
1735: // Add a submenu to the settingsmenu, which allows to get the total number of dependencies
1736: // and allows to refresh all dependency data of the project:
1737: JSenseMenu dependencyMenu = new JSenseMenu(Language
1738: .Translate("Dependency Checks"), this
1739: .getMainFrameProvider());
1740:
1741: item = dependencyMenu.add(new JMenuItem(Language
1742: .Translate("Total Number Of Dependencies")));
1743: item.addActionListener(new java.awt.event.ActionListener() {
1744: public void actionPerformed(ActionEvent e) {
1745: getFileStructureDescriptionManager()
1746: .printTotalNumberOfDepedencies("", true);
1747: }
1748: });
1749: item = dependencyMenu.add(new JMenuItem(Language
1750: .Translate("Refresh All Dependencies")));
1751: item.addActionListener(new java.awt.event.ActionListener() {
1752: public void actionPerformed(ActionEvent e) {
1753: getFileStructureDescriptionManager()
1754: .refreshAllDepedencies(
1755: getOutputManager()
1756: .getClassesWereCompiledWithoutErrors());
1757: }
1758: });
1759: settingsMenu.addSeparator();
1760: settingsMenu.add(dependencyMenu);
1761:
1762: // add the menues to the menuBar :
1763: menuBar.add(projectMenu);
1764: menuBar.add(settingsMenu);
1765: // Create and add the debugmenu, if the application has been started
1766: // with parameter -debug :
1767: if (this .isDebugModus) {
1768: JSenseMenu debugMenu = new JSenseMenu(Language
1769: .Translate(" Debug "), this
1770: .getMainFrameProvider());
1771: debugMenu.setMnemonic('d');
1772: // and add actions:
1773: item = debugMenu.add(new JMenuItem(Language
1774: .Translate(" All FileStructure Descriptions ")));
1775: item.addActionListener(new java.awt.event.ActionListener() {
1776: public void actionPerformed(ActionEvent e) {
1777: fileStructureDescriptionManager
1778: .showCurrentFSDListContent(this Frame
1779: .getTitle(), false);
1780: }
1781: });
1782: item = debugMenu
1783: .add(new JMenuItem(
1784: Language
1785: .Translate(" Project FileStructure Descriptions ")));
1786: item.addActionListener(new java.awt.event.ActionListener() {
1787: public void actionPerformed(ActionEvent e) {
1788: fileStructureDescriptionManager
1789: .showCurrentFSDListContent(this Frame
1790: .getTitle(), true);
1791: }
1792: });
1793: item = debugMenu.add(new JMenuItem(Language
1794: .Translate(" File Dependencies Tree ")));
1795: item.addActionListener(new java.awt.event.ActionListener() {
1796: public void actionPerformed(ActionEvent e) {
1797: DebugDependenciesTreeDialog depDia = new DebugDependenciesTreeDialog(
1798: this Frame);
1799: depDia.show();
1800: }
1801: });
1802: menuBar.add(debugMenu);
1803: } // if
1804:
1805: // Get rid of the complicating border :
1806: menuBar.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
1807:
1808: menuBar.setOpaque(false); // because otherwise we wouldn't see
1809: // the underlying GradientPanel
1810:
1811: // Return it :
1812: return menuBar;
1813: } // createTheMenuBar
1814:
1815: /**
1816: * Saves all changed projectfiles, if there exist changed files at all.
1817: * If doDisplayDialog is set however, a dialog is displayed and
1818: * the user can cancel the save operation.
1819: * If doDisplayDialog is false, changed files are saved automatically.
1820: *
1821: * MUST be called outside the Swing EventDispatchThread.
1822: *
1823: * Returns true, if the user has affirmed, false if he had cancelled it.
1824: */
1825: public boolean checkSaveProjectFiles(final boolean doDisplayDialog) {
1826: // Develop security :
1827: if (EventQueue.isDispatchThread()) {
1828: Log
1829: .Error("DesignError: checkSaveProjectFiles() should be processed outside the EDT");
1830: }
1831: // Test and if needed save the projectfiles :
1832: boolean affirmative = false;
1833: // this.saveHasBeenCancelledOnClose can be set by the mainframe, when the user
1834: // directly closes the mainframe. In this case, the first call comes from the
1835: // mainframe, and the second one comes from the onclose method from the projectframe.
1836: if (!this .saveHasBeenCancelledOnClose) {
1837: affirmative = this .projectFilesManager
1838: .checkSave_ProjectFiles(doDisplayDialog);
1839: if (affirmative) {
1840: this .editorPanel.saveContents();
1841: }
1842: }
1843: return affirmative;
1844: } // saveProjectFiles
1845:
1846: /**
1847: * Saves the projectfiles cache datafile. Must be called outside the EDT.
1848: * Currently, it's only called from the MainFrame TerminatorThread.
1849: */
1850: public void saveProjectFilesDataFile() {
1851: this .fileStructureDescriptionManager
1852: .checkSaveProjectFilesDataFile();
1853: } // saveProjectFiles
1854:
1855: public OutputManager getOutputManager() {
1856: return this .outputManager;
1857: }
1858:
1859: public ProjectFilesManager getProjectFilesManager() {
1860: return this .projectFilesManager;
1861: }
1862:
1863: public FileComponentsTree getFileComponentsTree() {
1864: return this .fileComponentsTree;
1865: }
1866:
1867: public LibrariesTree getLibrariesTree() {
1868: return this .librariesTree;
1869: }
1870:
1871: public FileStructureDescriptionManager getFileStructureDescriptionManager() {
1872: return this .fileStructureDescriptionManager;
1873: }
1874:
1875: public EditorPanel getEditorPanel() {
1876: return this .editorPanel;
1877: }
1878:
1879: public ProjectDefinition getProjectDefinition() {
1880: return this .projectDefinition;
1881: }
1882:
1883: public IniFile getProjectIniFile() {
1884: return this .projectDefinition.getProjectIniFile();
1885: }
1886:
1887: public void initializeFileComponentsTreeFrom(
1888: final FileStructureDescription fsd) {
1889: this .getFileComponentsTree().initializeTreeFrom(fsd);
1890: }
1891:
1892: /**
1893: * Called by the fileComponentsTreeModel after a JavaCC parser run
1894: * has been completed on a new sourcefile text, after the user had changed
1895: * this text while programming.
1896: */
1897: public void setFileComponentsParserState(
1898: final boolean parsingSuccessful) {
1899: if (parsingSuccessful) {
1900: this .fileComponentsTitleLabel.setIcon(this .greenPointIcon);
1901: } else {
1902: this .fileComponentsTitleLabel.setIcon(this .redPointIcon);
1903: }
1904: }
1905:
1906: /**
1907: * Called when a projectfile is selected in the projectfiles tree,
1908: * which causes the selections on the links tree to get out of sync.
1909: */
1910: public void clearSelectionsInProjectFilesLinkTree() {
1911: this .editorPanel.clearSelectionsInProjectFilesLinkTree();
1912: }
1913:
1914: /**
1915: * Called by the CompilerThread on errors.
1916: * Like the one parameter version, but this one additionally
1917: * jumps to the passed line and sets the cursor to the passed column.
1918: */
1919: public boolean selectProjectFilesTreeNodeFor(
1920: final String sourceFilePathName, final int line,
1921: final int column, final boolean doSelectLine) {
1922: // delegate :
1923: return this .projectFilesManager.selectProjectFilesTreeNodeFor(
1924: sourceFilePathName, line, column, doSelectLine);
1925: } // selectNodeFor
1926:
1927: /**
1928: * In the LibrariesTree it should expand the node and show the document
1929: * associated with the passed arguments, as if one had cklicked
1930: * on that node with the mouse.
1931: * Delegated to the LibrariesTree controler.
1932: * Returns false, if the associated leaf has not been found.
1933: */
1934: public boolean selectLibrariesTreeNodeFor(final String jarFileName,
1935: final String fileName, final int lineNumber,
1936: final int columnNumber) {
1937: this .checkPopupLibrariesTreePanel();
1938: return this .librariesTree.showLeafFor(jarFileName, fileName,
1939: lineNumber, columnNumber, true);
1940: } // selectLibrariesTreeNodeFor
1941:
1942: /**
1943: * Called by selectLibrariesTreeNodeFor to make sure, at least one entry
1944: * of the librariestree is visible, once the selection of it changes.
1945: */
1946: public void checkPopupLibrariesTreePanel() {
1947: EventQueue.invokeLater(new Runnable() {
1948: public void run() {
1949: int charSize = UIManager.getFont("TextField.font")
1950: .getSize();
1951: int verticalHeight = horizontalSplitPane.getHeight();
1952:
1953: final int middleStartLocation = middleSplitPane
1954: .getDividerLocation(); // relative
1955: final int requiredLibFilesStartLocation = middleStartLocation
1956: - (10 * charSize) / 2;
1957: if (upperSplitPane.getDividerLocation() > requiredLibFilesStartLocation) {
1958: upperSplitPane
1959: .setDividerLocation(requiredLibFilesStartLocation);
1960: }
1961: }
1962: });
1963: } // checkPopupLibrariesTreePanel
1964:
1965: /**
1966: * Called by the compiler when it has found syntax errors
1967: * to make sure, at least one entry of the librariestree is visible,
1968: * once the selection of it changes.
1969: */
1970: public void checkPopupCompilerOutputPanel() {
1971: EventQueue.invokeLater(new Runnable() {
1972: public void run() {
1973: int charSize = UIManager.getFont("TextField.font")
1974: .getSize();
1975: int verticalHeight = horizontalSplitPane.getHeight();
1976: // The error messages (with buttons) need some space, therefore
1977: // give it enough, if the threshold isnt reached. Keep the threshold
1978: // low, so the user can optionally hold it very small, but once we popup,
1979: // we give it enough height to see some messages learly :
1980: int thresholdHeight = verticalHeight - 8 * charSize;
1981: if (rightVerticalSplitPane.getDividerLocation() > thresholdHeight) {
1982: rightVerticalSplitPane
1983: .setDividerLocation(verticalHeight - 16
1984: * charSize);
1985: }
1986: }
1987: });
1988: } // checkPopupCompilerOutputPanel
1989:
1990: /**
1991: * Called from the ProjectFilesTreePopupMenu on rightclicks.
1992: * Adds a depository button for this projectfiles.
1993: */
1994: public void addNewProjectFileToDepository(
1995: final ProjectFilesTreeLeafObject fileObject) {
1996: EditorDocumentHistoryTracker historyTracker = getEditorPanel()
1997: .getDocumentHistoryTracker();
1998: historyTracker.addNewProjectFileDocumentTo(
1999: EditorDocumentHistoryTracker.DepositoryType, fileObject
2000: .getFilePathName(), fileObject.getName(),
2001: fileObject.getIsEditable(), fileObject.getIsChanged(),
2002: true, false);
2003: }
2004:
2005: /**
2006: *
2007: * This is called, when additional library files have been added or removed
2008: * or if the src file has been changed in the projectdefinition dialog.
2009: *
2010: */
2011: private void reloadLibraryTree() {
2012: ProjectDefinitionEntry definitionEntry = projectDefinition
2013: .getProjectDefinitionEntry(ProjectDefinition.SourceJarFilePath_Key);
2014: final String srcJarFileName = (String) definitionEntry
2015: .getValue();
2016: ProjectDefinitionEntry additionalJarFilesEntry = projectDefinition
2017: .getProjectDefinitionEntry(ProjectDefinition.AdditionalJarLibrariesPaths_Key);
2018: final String[] additionalJarLibraries = (String[]) additionalJarFilesEntry
2019: .getValue();
2020: Runnable libraryReloadRunnable = new Runnable() {
2021: public void run() {
2022: FileStructureDescriptionSynchronizeDialog creationInfoDialog = new FileStructureDescriptionSynchronizeDialog(
2023: this Frame.getMainFrameProvider());
2024: creationInfoDialog
2025: .setCurrentFileInformation(Language
2026: .Translate("Reloading the library tree contents..."));
2027: creationInfoDialog.setProgressBarValue(0);
2028: creationInfoDialog.showCentered();
2029:
2030: // Remove all children first :
2031: librariesTree.removeAllNodes();
2032: // Add all projectdefinition libraries to the librariesTree.
2033: // We do this delayed, so the GUI is created more smoothly :
2034:
2035: // Time for the GUI :
2036: try {
2037: Thread.sleep(100);
2038: } catch (Exception e324867) {
2039: }
2040:
2041: // Add the src.jar or zip file content to the librariesTree :
2042: EventQueue.invokeLater(new Runnable() {
2043: public void run() {
2044: librariesTree.addJarFilePath(srcJarFileName);
2045: // outputmanager compiler info:
2046: outputManager
2047: .setCompilerInfoLabel(
2048: Language
2049: .Translate("The compiler has not been started yet."),
2050: false);
2051: }
2052: });
2053: // Add all additional projectdefinition libraries to the librariesTree.
2054: for (int i = 0; i < additionalJarLibraries.length; i++) {
2055: final int iFinal = i;
2056: EventQueue.invokeLater(new Runnable() {
2057: public void run() {
2058: librariesTree
2059: .addJarFilePath(additionalJarLibraries[iFinal]);
2060: }
2061: });
2062: }
2063: // Update the fsdManager's contents now :
2064: fileStructureDescriptionManager
2065: .reloadLibraryFileStructures(creationInfoDialog);
2066: // Manages all FileStructureData objects of all java and class files.
2067: // All tasks above in the constructor are carried out in the ThreadEngine queue too,
2068: // so we can add the last task, which updates the historytracker models
2069: // to the ThreadEngine too and have this processed at the end :
2070: final Runnable historyTrackerUpdateRunnable = new Runnable() {
2071: public void run() {
2072: // syncModelsWithFileSystem() needs the filesystem (source nd jar files)
2073: editorPanel.getDocumentHistoryTracker()
2074: .syncModelsWithFileSystem();
2075: }
2076: };
2077: ThreadEngine.getInstance().addRunnable(
2078: historyTrackerUpdateRunnable,
2079: "HistoryTrackerUpdateRunnable");
2080: creationInfoDialog.setVisible(false);
2081: creationInfoDialog.freeMemory(); // GC assistance
2082: creationInfoDialog.dispose();
2083: }
2084: };
2085: ThreadEngine.getInstance().addRunnable(libraryReloadRunnable,
2086: "ProjectFrame Library Reload Task");
2087: } // reloadLibraryTree
2088:
2089: /**
2090: * Saves the project and reloads it completely from disk after this.
2091: * Called in a ThreadEngine thread context.
2092: */
2093: private void synchronizeProjectFilesTree() {
2094: // First: Save the project :
2095: checkSaveProjectFiles(false);
2096: // Clear components:
2097: this .editorPanel.clear();
2098:
2099: // Reload the project files completely :
2100: FileStructureDescriptionSynchronizeDialog creationInfoDialog = new FileStructureDescriptionSynchronizeDialog(
2101: this .getMainFrameProvider());
2102: creationInfoDialog.setCurrentFileInformation(Language
2103: .Translate("Reloading the project..."));
2104: creationInfoDialog.setProgressBarValue(0);
2105: creationInfoDialog.showCentered();
2106:
2107: // Remove all children first :
2108: this .projectFilesManager.getProjectFilesTree().removeAllNodes();
2109:
2110: // Time for the GUI :
2111: try {
2112: Thread.sleep(66);
2113: } catch (Exception e324867) {
2114: }
2115:
2116: // Reload :
2117: projectFilesManager.getProjectFilesTree().reloadTree(); // this must be delayed
2118:
2119: // Update the fsdManager's contents now :
2120: fileStructureDescriptionManager
2121: .reloadProjectFileStructures(creationInfoDialog);
2122:
2123: // Manages all FileStructureData objects of all java and class files.
2124: // All tasks above in the constructor are carried out in the ThreadEngine queue too,
2125: // so we can add the last task, which updates the historytracker models
2126: // to the ThreadEngine too and have this processed at the end :
2127: final Runnable historyTrackerUpdateRunnable = new Runnable() {
2128: public void run() {
2129: // syncModelsWithFileSystem() needs the filesystem (source nd jar files)
2130: editorPanel.getDocumentHistoryTracker()
2131: .syncModelsWithFileSystem();
2132: }
2133: };
2134: ThreadEngine.getInstance().addRunnable(
2135: historyTrackerUpdateRunnable,
2136: "HistoryTrackerUpdateRunnable");
2137:
2138: creationInfoDialog.setVisible(false);
2139: creationInfoDialog.freeMemory(); // GC assistance
2140: creationInfoDialog.dispose();
2141:
2142: EventQueue.invokeLater(new Runnable() {
2143: public void run() {
2144: // outputmanager compiler info:
2145: outputManager
2146: .setCompilerInfoLabel(
2147: Language
2148: .Translate("The compiler has not been started yet."),
2149: false);
2150: outputManager.setClassesWereCompiledAFirstTime(false);
2151: }
2152: });
2153: } // synchronizeProjectFilesTree
2154:
2155: /**
2156: * Implementation of the ChangeListener.
2157: * It's called, when the projectdefinition has been changed.
2158: *
2159: * Source is the ProjectDefinitionDialog.
2160: */
2161: public void dataChanged() {
2162: // Nothing to do
2163: } // dataChanged
2164:
2165: /**
2166: * Called by the editorpanel.
2167: * Controler method, delegated to the searchResultsTree.
2168: * Information goes from editorpanel (back) to the searchResultsTree.
2169: */
2170: public void searchTheCompleteProjectForText(String searchText,
2171: boolean doCaseSensitiveSearch, boolean doApproximateSearch,
2172: boolean doWholeWordsSearch, final boolean doSearchComments,
2173: final boolean doIncludeProjectFiles,
2174: final boolean doIncludeLibraries,
2175: final int approximateSearchMethodIndex,
2176: final int approximateSearchTolerance) {
2177: // Delegate:
2178: String searchName = "Text";
2179: this .searchResultsPanel.searchTheCompleteProjectForText(
2180: searchName, searchText, doCaseSensitiveSearch,
2181: doWholeWordsSearch, doApproximateSearch,
2182: doSearchComments, doIncludeProjectFiles,
2183: doIncludeLibraries, approximateSearchMethodIndex,
2184: approximateSearchTolerance);
2185: } // searchTheCompleteProjectForText
2186:
2187: /**
2188: * Called by the ProjectFilesTreePopupMenu.
2189: * Controller method, delegated to the searchResultsTree.
2190: * Information goes to the searchResultsTree.
2191: */
2192: public void searchProjectDirectoryForText(
2193: final DefaultMutableTreeNode directoryNode) {
2194: // delegate:
2195: this .searchResultsPanel.searchProjectDirectoryForText("Text",
2196: directoryNode);
2197: }
2198:
2199: /**
2200: * Same for libraries
2201: */
2202: public void searchLibraryDirectoryForText(
2203: final DefaultMutableTreeNode directoryNode) {
2204: // delegate:
2205: this .searchResultsPanel.searchLibraryDirectoryForText("Text",
2206: directoryNode);
2207: }
2208:
2209: /**
2210: * Called by the ProjectFilesTreePopupMenu.
2211: * Controler method, delegated to the searchResultsTree.
2212: * Information goes to the searchResultsTree.
2213: */
2214: public void searchProjectDirectoryForFilename(
2215: final DefaultMutableTreeNode directoryNode) {
2216: this .searchResultsPanel.searchProjectDirectoryForFilename(
2217: "file", directoryNode);
2218: }
2219:
2220: /**
2221: * Same for libraries
2222: */
2223: public void searchLibraryDirectoryForFilename(
2224: final DefaultMutableTreeNode directoryNode) {
2225: this .searchResultsPanel.searchLibraryDirectoryForFilename(
2226: "file", directoryNode);
2227: }
2228:
2229: /**
2230: * Searches the source of the passed qualifiedClassName, which must be a classname of
2231: * a (member or local) attribute of the passed basisFSD.
2232: * The search combines the qualifiedClassName with all import statements
2233: * of the basisFSD for this purpose.
2234: * If the class isn't in the same package and not part of a wildcard or
2235: * specific import statement, it must be qualified ( f.ex. jawa.awt.frame )
2236: * The search is made, like the javac compiler also performs it on compiling.
2237: * If the basisFSD was made from a syntactically correct (=compilable) source,
2238: * this method will find and display the associated source
2239: * (or decompiled class view) for sure.
2240: *
2241: * If the fsd associated with the qualifiedClassName is found,
2242: * the source will be displayed automatically.
2243: */
2244: public void displayClassPartOfFSD(
2245: final FileStructureDescription basisFSD,
2246: final String qualifiedClassName) {
2247: // For having all executed in series, we use the ThreadEngine :
2248: final Runnable classMethodSearchTask = new Runnable() {
2249: public void run() {
2250: final ClassMethodSearch searchObject = new ClassMethodSearch(
2251: basisFSD, qualifiedClassName, this Frame);
2252: searchObject.performSearch();
2253: searchObject.freeMemory(); // GC assistance
2254: }
2255: };
2256: ThreadEngine.getInstance().addRunnable(classMethodSearchTask,
2257: "ClassMethodSearch for " + qualifiedClassName);
2258: } // displayClassPartOfFSD
2259:
2260: /**
2261: * Loads an imageicon. Works when this application
2262: * was started in a JAR file, as well when started
2263: * from the main class file.
2264: */
2265: public ImageIcon loadImageIcon(String name) {
2266: return this .mainFrame.loadImageIcon(name);
2267: }
2268:
2269: public String getSchmortopfMainDirectory() {
2270: return this .mainFrame.getSchmortopfMainDirectory();
2271: }
2272:
2273: /**
2274: * Implementation of the IDE_ProjectFrameProvider interface method.
2275: * Called from the projectfilestree, after the file with the given path
2276: * has been removed. Required for synchronizing the compiler list in
2277: * the output manager.
2278: */
2279: public void removeSourceFilePathFromCompilerList(
2280: String sourceFilePath) {
2281: this .outputManager
2282: .removeSourceFilePathFromCompilerList(sourceFilePath);
2283: }
2284:
2285: /**
2286: * Implementation of the IDE_ProjectFrameProvider interface method.
2287: * Called from the projectfilestree, after the file with the given path
2288: * has been added (also after a rename). Required for synchronizing the compiler list in
2289: * the output manager.
2290: */
2291: public void addSourceFileAndDependentFilesToCompilerList(
2292: final String filePath) {
2293: this .outputManager
2294: .addSourceFileAndDependentFilesToCompilerList(filePath);
2295: }
2296:
2297: /**
2298: * This is called from the SymbolUsageLocationSearch, which passes
2299: * its results to this tree.
2300: */
2301: public void setSearchResultsTreeContentWithObjectSearchResults(
2302: final String searchName,
2303: final SearchResultsUserObject[] searchResultsUserObjects) {
2304: this .searchResultsPanel.setObjectSearchResults(searchName,
2305: searchResultsUserObjects);
2306: EventQueue.invokeLater(new Runnable() {
2307: public void run() {
2308: popupSearchResultsTreePanel();
2309: }
2310: });
2311: } // setSearchResultsTreeContentWithObjectSearchResults
2312:
2313: public IDE_MainFrameProvider getMainFrameProvider() {
2314: return this .mainFrame;
2315: }
2316:
2317: /**
2318: * Just calls <code>paint(g)</code>. This method was overridden to
2319: * prevent an unnecessary call to clear the background.
2320: *
2321: * @param g the Graphics context in which to paint
2322: */
2323: public void update(Graphics g) {
2324: this .paint(g);
2325: }
2326:
2327: /**
2328: * Called by the main JFrame on LF theme changes.
2329: * Used for updating components, which wouldnt update automatically.
2330: */
2331: public void updateSpecialUI() {
2332: if (this .editorPanel != null) {
2333: this .editorPanel.updateSpecialUI();
2334: }
2335: if (this .outputManager != null) {
2336: this .outputManager.updateSpecialUI();
2337: }
2338: // Update the line borders of the titlepanels :
2339: // We ONLY need a contrast line at the bottom, anything
2340: // more complicates the view. We take the average of Menu.background
2341: // and Menu.foreground :
2342: final Color c1 = UIManager.getColor("Menu.foreground");
2343: final Color c2 = UIManager.getColor("Menu.background");
2344: final int av_r = (c1.getRed() + 2 * c2.getRed()) / 3;
2345: final int av_g = (c1.getGreen() + 2 * c2.getGreen()) / 3;
2346: final int av_b = (c1.getBlue() + 2 * c2.getBlue()) / 3;
2347: // We mustn't share UI references, but must create them for each panel:
2348: final Border b1 = BorderFactory.createMatteBorder(0, 0, 1, 0,
2349: new Color(av_r, av_g, av_b));
2350: this .fileComponentsTitleWrapPanel.setBorder(b1);
2351: final Border b2 = BorderFactory.createMatteBorder(0, 0, 1, 0,
2352: new Color(av_r, av_g, av_b));
2353: this .librariesTitleWrapPanel.setBorder(b2);
2354: final Border b3 = BorderFactory.createMatteBorder(0, 0, 1, 0,
2355: new Color(av_r, av_g, av_b));
2356: this .searchResultsPanel.setBorder(b3);
2357:
2358: final Border b4 = BorderFactory.createMatteBorder(0, 0, 1, 0,
2359: new Color(av_r, av_g, av_b));
2360: this .projectFilesTitleWrapPanel.setBorder(b4);
2361:
2362: // The projectfiles panel has an additional custom etched border at the top only
2363: // so the transition to the menu above is ok :
2364: Color darkerColor = UIManager.getColor("Menu.background")
2365: .darker();
2366: Color brighterColor = UIManager.getColor("Menu.background")
2367: .brighter();
2368: this .projectFilesTitlePanel.setBorder(new CustomEtchedBorder(
2369: true, false, false, false, brighterColor, darkerColor));
2370:
2371: } // updateSpecialUI
2372:
2373: // --------- CC signature test methods
2374: public void test() {
2375: Integer iob = this .getObject(2);
2376:
2377: // JBuilder IntelliSense fails - it doesnt display
2378: // the Double signature, but it does compile :
2379: Double dob = this .getObject(2.3);
2380: }
2381:
2382: public Integer getObject(int i) {
2383: return new Integer(i);
2384: }
2385:
2386: public Double getObject(double d) {
2387: return new Double(d);
2388: }
2389:
2390: } // IDE_ProjectFrame
|