0001: package tide.sources;
0002:
0003: import snow.utils.StringUtils;
0004: import snow.utils.gui.SwingSafeRunnable;
0005: import java.awt.EventQueue;
0006: import snow.utils.DateUtils;
0007: import snow.utils.storage.*;
0008: import snow.utils.gui.ProgressModalDialog;
0009: import tide.compiler.JavaCompilerCall;
0010: import tide.project.*;
0011: import tide.editor.MainEditorFrame;
0012: import snow.texteditor.SimpleDocument;
0013: import javax.swing.*;
0014: import java.awt.event.*;
0015: import javax.swing.border.*;
0016: import javax.swing.tree.*;
0017: import java.util.*;
0018: import java.io.*;
0019: import java.util.regex.*;
0020: import tide.utils.FileUtilities;
0021:
0022: /** The model of the project sources files (not libraries). The method of this model should be use to add/remove nodes,
0023: because this also forward the UI events and manages the folder colors.
0024: The source folders may also contain resources (pictures, ...).
0025: Here, we don't display them, but we allow for marking folders as ignored.
0026: These hints allow to decide if the project jar file contains or not theses folders contents.
0027: */
0028: public class SourcesTreeModel extends DefaultTreeModel implements
0029: JavaFilesTreeModel {
0030: // must be manually kept uptodate ! (key = uppercased javaName()) !!
0031: private final Map<String, SourceFile> quickCache = new HashMap<String, SourceFile>();
0032: // must be manually kept uptodate ! (key = uppercased javaName()) !!
0033: private final Map<String, SourceFile> quickPackageCache = new HashMap<String, SourceFile>();
0034:
0035: // Set lazily from the LibClassesInfo at "project reload"
0036: public final Set<String> knownAnnotations = new HashSet<String>();
0037: public final Set<String> knownInterfaces = new HashSet<String>();
0038:
0039: public SourcesTreeModel() {
0040: super (new SourceFile("", ""));
0041: }
0042:
0043: public SourceFile getRootSource() {
0044: return (SourceFile) getRoot();
0045: }
0046:
0047: /** store the file properties (flags, ignored, ...) in the project
0048: */
0049: public void storeFileFlags(ProjectSettings project) {
0050: List<SourceFile> srcs = getAllSourceFiles(true); // include the ignored ones of course, to store their state !
0051: // [July2006]: also store folders infos...
0052: getAllDirectoriesRecurse_depthFirst(getRootSource(), srcs);
0053:
0054: for (SourceFile sf : srcs) {
0055: project.setStoredSourceInfo(sf);
0056: }
0057: MainEditorFrame.debugOut("storeFileFlags made for project "
0058: + project.getProjectName());
0059: }
0060:
0061: private void addToQuickCache(SourceFile fi) {
0062: quickCache
0063: .put(fi.getJavaName().toUpperCase(Locale.ENGLISH), fi);
0064: }
0065:
0066: public FileItem quickGet(String javaName, boolean caseSensitive) {
0067: if (javaName == null)
0068: throw new NullPointerException("null javaName !");
0069: FileItem it = quickCache.get(javaName
0070: .toUpperCase(Locale.ENGLISH));
0071: if (it != null) {
0072: if (!caseSensitive)
0073: return it; // ok
0074:
0075: if (it.getJavaName().equals(javaName))
0076: return it;
0077: }
0078: return null;
0079: }
0080:
0081: private void addToQuickPackageCache(SourceFile fi) {
0082: //System.out.println("add to package list: "+fi.getJavaName());
0083: quickPackageCache.put(fi.getJavaName().toUpperCase(
0084: Locale.ENGLISH), fi);
0085: }
0086:
0087: public FileItem quickPackageGet(String javaName,
0088: boolean caseSensitive) {
0089: //System.out.println("packages: "+quickPackageCache.keySet());
0090: if (javaName == null)
0091: throw new NullPointerException("null javaName !");
0092: FileItem it = quickPackageCache.get(javaName
0093: .toUpperCase(Locale.ENGLISH));
0094: if (it != null) {
0095: if (!caseSensitive)
0096: return it; // ok
0097:
0098: if (it.getJavaName().equals(javaName))
0099: return it;
0100: }
0101: return null;
0102: }
0103:
0104: /* used in the location of missing imports
0105: *
0106: public List<FileItem> getTypesEndingWith(String name)
0107: {
0108: List<FileItem> lst = new ArrayList<FileItem>();
0109: getAllSourceFilesContainingName(name, false, false);
0110: return lst;
0111: }*/
0112:
0113: /** Currently only removes the first childs level.
0114: */
0115: public void clearModel() {
0116: // empty all the existing files (Call with UI notify)
0117: for (int i = this .root.getChildCount() - 1; i >= 0; i--) {
0118: SourceFile li = this .getRootSource().getChildFileAt(i);
0119: li.liberateResourcesForGC();
0120: //li.removeFromParent(); // TODO: recurse ??
0121: this .removeNodeFromParent(li);
0122: }
0123: quickCache.clear();
0124: quickPackageCache.clear();
0125: knownAnnotations.clear();
0126: knownInterfaces.clear();
0127: }
0128:
0129: /** LAZY: only looks t the toplevel type
0130: */
0131: public void updateAnnotationsCache(SourceFile sf) {
0132: if (sf == null)
0133: return;
0134:
0135: knownAnnotations.remove(sf.getJavaName());
0136: knownInterfaces.remove(sf.getJavaName());
0137:
0138: if (sf.topKind == SourceFile.Kind.Interface) {
0139: knownInterfaces.add(sf.getJavaName());
0140: } else if (sf.topKind == SourceFile.Kind.Annotation) {
0141: knownAnnotations.add(sf.getJavaName());
0142: }
0143: }
0144:
0145: public boolean isEmpty() {
0146: return this .root.getChildCount() > 0;
0147: }
0148:
0149: /** Empty the actual model, reload the whole model.
0150: (look at actual disk files and read their vec rep if present in project)
0151: @param firstLoad if true, don't print out the new files
0152: */
0153: public void setProject(final ProjectSettings project,
0154: final ProgressModalDialog pmd, final boolean firstLoad) {
0155:
0156: final File sourceRootFile = project.getSources_Home();
0157:
0158: pmd.setProgressSection("Clearing actual model");
0159:
0160: if (!isEmpty()) {
0161: // WAITS !
0162: if (EventQueue.isDispatchThread()) {
0163: clearModel();
0164: } else {
0165: try {
0166: EventQueue.invokeAndWait(new Runnable() {
0167: public void run() {
0168: clearModel();
0169: }
0170: });
0171: } catch (Exception e) {
0172: throw new RuntimeException(e);
0173: }
0174: }
0175: }
0176:
0177: pmd.setProgressSection("Scanning root " + sourceRootFile);
0178:
0179: SwingSafeRunnable.invokeAndWait(new Runnable() {
0180: public void run() {
0181: setRoot(new SourceFile(FileUtils
0182: .getCanonicalName(sourceRootFile), "")); // just as name
0183: }
0184: });
0185:
0186: // add all sources recursively
0187:
0188: /* CODE TO USE IF (LATER) Resources are considered:
0189: final List<File> allFiles = new ArrayList<File>();
0190: FileUtils.getAllFilesRecurse( sourceRootFile, allFiles, true, true ); // ignore dirs starting with ".", considered as setting folders
0191:
0192: int lbase = FileUtils.getCanonicalName(sourceRootFile).length();
0193: for(final File f : allFiles)
0194: {
0195: // [July2006]: also add directories, this allow to mark them as ignored, useful for the resource add utility in the jar creation...
0196: if(f.isDirectory())
0197: {
0198: addFolder(f, lbase);
0199: }
0200: else if( f.getName().toLowerCase().endsWith(".java"))
0201: {
0202: SourceFile sf = addSourceFile(f, lbase);
0203: }
0204: else
0205: {
0206: // resource
0207: _addResourceFile(f, lbase);
0208: }
0209: }*/
0210:
0211: // quicker variant, using a filefilter
0212: final List<File> allJFiles = new ArrayList<File>();
0213: FileUtils.getAllJavaFilesRecurse(sourceRootFile, allJFiles,
0214: true, true); // with folders and ignore dirs starting with ".", considered as setting folders
0215:
0216: final int lbase = FileUtils.getCanonicalName(sourceRootFile)
0217: .length();
0218:
0219: SwingSafeRunnable.invokeAndWait(new Runnable() {
0220: public void run() // [March2008]: was not EDT.
0221: {
0222: for (final File f : allJFiles) {
0223: // [July2006]: also add directories, this allow to mark them as ignored, useful for the resource add utility in the jar creation...
0224: if (f.isDirectory()) {
0225: addFolder(f, lbase);
0226: } else {
0227: SourceFile sf = addSourceFile(f, lbase);
0228: }
0229: }
0230: }
0231: });
0232:
0233: // after all sources have been added, restore some stored infos
0234: // as well as the dependencies, if any
0235: final List<SourceFile> allSrcs = getAllSourceFiles(true);
0236: // [July2006]: also store folders...
0237: getAllDirectoriesRecurse_depthFirst(getRootSource(), allSrcs);
0238:
0239: pmd.setProgressSection("Checking " + allSrcs.size()
0240: + " files and directories in source folder");
0241: final Set<String> foundJavaNames = new HashSet<String>();
0242: final Set<String> notFoundJavaNames = new HashSet<String>(); // no dirs
0243: final List<SourceFile> changedFiles = new ArrayList<SourceFile>();
0244: for (final SourceFile sf : allSrcs) {
0245: String jn = sf.getJavaName();
0246:
0247: StorageVector rep = project.getStoredSourceInfo(jn);
0248:
0249: if (rep != null) {
0250: foundJavaNames.add(jn);
0251: try {
0252: if (sf.restoreFromVectorRepr(rep, this )) {
0253: changedFiles.add(sf);
0254: }
0255: } catch (Exception e) {
0256: e.printStackTrace();
0257: }
0258: } else {
0259: //System.out.println("no vec rep for "+jn);
0260: if (!sf.isDirectory()) {
0261: notFoundJavaNames.add(jn);
0262: }
0263: }
0264: sf.setClassRoot(project.getClasses_Home());
0265: }
0266:
0267: final Set<String> oldExisting = project
0268: .getSourcesForWhichRepExist();
0269: final SimpleDocument doc = MainEditorFrame.instance.outputPanels.tideOutputPanel.doc;
0270: if (oldExisting.size() > 0) // otherwise no sense...
0271: {
0272: Set<String> noMoreExisting = new HashSet<String>(
0273: oldExisting);
0274: noMoreExisting.removeAll(foundJavaNames);
0275: if (noMoreExisting.size() > 0) {
0276: int n = 0;
0277: doc
0278: .append("\n"
0279: + noMoreExisting.size()
0280: + " source files or folders are no more present:");
0281: if (noMoreExisting.size() > 1000) {
0282: doc.append("\n(Only the first 1000 are shown)");
0283: }
0284: List<String> sns = new ArrayList<String>(noMoreExisting);
0285: Collections.sort(sns);
0286: for (String sn : sns) {
0287: n++;
0288: if (n < 1000)
0289: doc.append("\n " + sn);
0290:
0291: // mark as deleted, update the dependencies, and so on...
0292: try {
0293: SourceFile sf = new SourceFile("?#", "?#");
0294: sf.restoreFromVectorRepr(project
0295: .getStoredSourceInfo(sn), this );
0296: sf.fileHasBeenDeleted();
0297: if (sf.getLastModifiedJavaFile() > 0
0298: && !firstLoad) {
0299: if (n < 1000)
0300: doc
0301: .append(", last known modified date: "
0302: + DateUtils
0303: .formatDateAndTimeHuman(sf
0304: .getLastModifiedJavaFile()));
0305: }
0306: // say what we knewed, may help !
0307: } catch (Exception e) {
0308: e.printStackTrace();
0309: }
0310: }
0311: if (n < 1000)
0312: doc.append("\n");
0313:
0314: project.removeFileReps(noMoreExisting);
0315: }
0316:
0317: if (notFoundJavaNames.size() > 0 && !firstLoad) {
0318: int n = 0;
0319:
0320: doc.append("\n" + notFoundJavaNames.size()
0321: + " new source file"
0322: + (notFoundJavaNames.size() == 1 ? "" : "s")
0323: + ":");
0324: if (notFoundJavaNames.size() > 1000) {
0325: doc.append("\n(Only the first 1000 are shown)");
0326: }
0327: List<String> sns = new ArrayList<String>(
0328: notFoundJavaNames);
0329: Collections.sort(sns);
0330: for (String sn : sns) {
0331: n++;
0332: if (n < 1000)
0333: doc.append("\n " + sn.trim()); // so we can click them !
0334: //doc.append(":\tlast-modif="+)...
0335: }
0336: if (n < 1000)
0337: doc.append("\n");
0338: }
0339:
0340: if (firstLoad) {
0341: doc.append("\n" + notFoundJavaNames.size()
0342: + " source files were added to the project.\n");
0343: }
0344:
0345: MainEditorFrame.instance.outputPanels
0346: .select_tIDE_Tab(false);
0347: }
0348:
0349: if (changedFiles.size() > 0 && !firstLoad) {
0350: doc.append("\n" + changedFiles.size()
0351: + " changed source file"
0352: + (changedFiles.size() == 1 ? "" : "s") + ":");
0353: if (changedFiles.size() > 1000) {
0354: doc.append("\n(Only the first 1000 are shown)");
0355: }
0356: int n = 0;
0357: for (SourceFile sn : changedFiles) {
0358: n++;
0359: if (n < 1000)
0360: doc.append("\n " + sn.getJavaName()); // so we can click them !
0361:
0362: // TOO LATE for sn.getLastModifiedJavaFile(), the setIsCompiled(false) has deleted this flag...
0363: if (sn.getLastStoredLastModifiedJavaFile() > 0) {
0364: long diff = sn.javaFile.lastModified()
0365: - sn.getLastStoredLastModifiedJavaFile();
0366: if (diff < -2000) // winzip "forget" exact times...
0367: {
0368: // the file was replaced with an older one since last session
0369: if (n < 1000)
0370: doc
0371: .appendError(":\tdiff = "
0372: + DateUtils
0373: .formatTimeDifference(diff));
0374: } else {
0375: if (n < 1000)
0376: doc
0377: .append(":\tdiff = "
0378: + DateUtils
0379: .formatTimeDifference(diff));
0380: }
0381: if (n < 1000)
0382: doc
0383: .append(",\tlast-modif = "
0384: + DateUtils
0385: .formatDateAndTimeHuman(sn.javaFile
0386: .lastModified()));
0387: }
0388: }
0389: doc.append("\n");
0390: MainEditorFrame.instance.outputPanels
0391: .select_tIDE_Tab(false);
0392: }
0393:
0394: // [June2007]
0395: for (SourceFile sfi : allSrcs) {
0396: updateAnnotationsCache(sfi);
0397: // TODO: update (rescan) the Unknown ones.
0398: }
0399:
0400: System.out.println("" + this .knownAnnotations.size()
0401: + " annotations and " + this .knownInterfaces.size()
0402: + " interfaces recognized in the project.");
0403:
0404: markMainProjectSource();
0405: setFolderColors();
0406:
0407: }
0408:
0409: /** @param javaName is like "my.package.name".
0410: * @return non null if found.
0411: */
0412: public FileItem getPackage(String javaName) {
0413: // boost
0414: FileItem fq = quickPackageGet(javaName, true);
0415: if (fq != null)
0416: return fq;
0417:
0418: SourceFile actNode = getRootSource();
0419: if (javaName.equals(""))
0420: return actNode;
0421: String[] path = javaName.split("\\.");
0422: for (int i = 0; i < path.length; i++) {
0423: String ni = path[i];
0424: SourceFile newNode = getJavaPackageChild(actNode, ni);
0425: if (newNode == null) {
0426: //System.out.println("Notfound:"+ni+" first=");
0427: return null;
0428: } else if (newNode.isJavaFile()) {
0429: return null;
0430: }
0431: actNode = newNode;
0432: }
0433: return actNode;
0434: }
0435:
0436: /** @param javaName is the full class name (NOT the package name) "aaa.bbb.ClassA"
0437: @param fileName is the file name (ClassA.java) maybe different if not containing a top level public type
0438: give an empty name in normal cases.
0439:
0440: @return null if not found
0441: */
0442: public SourceFile getSourceFile(String javaName, String fileName) {
0443: // boost
0444: FileItem fq = quickGet(javaName, true);
0445: if (fq != null)
0446: return (SourceFile) fq; // we know this is a source
0447:
0448: SourceFile actNode = getRootSource();
0449: if (javaName.equals(""))
0450: return actNode;
0451: String[] path = javaName.split("\\.");
0452:
0453: // System.out.println("getSourceFile("+javaName+", "+fileName+"), path="+Arrays.toString(path));
0454:
0455: for (int i = 0; i < path.length; i++) {
0456: String ni = path[i];
0457: //if(i==path.length-1) ni+=".java";
0458:
0459: // 1) try to find a source file even if we are not at the end
0460: //if(i==path.length-1)
0461:
0462: // 1) try to find a package
0463: SourceFile newNode = getJavaPackageChild(actNode, ni);
0464: if (newNode != null) {
0465: // ok, continue below
0466: } else {
0467: // not found, try to find a file
0468: newNode = getJavaSourceChild(actNode, ni, fileName);
0469: if (newNode != null) {
0470: return newNode;
0471: } else {
0472: //System.out.println("not found "+ni+" in "+actNode);
0473: //new Throwable().printStackTrace();
0474: // abort
0475: return null;
0476: }
0477: }
0478:
0479: actNode = newNode;
0480: }
0481: return actNode;
0482: }
0483:
0484: /** aaa.a.main => aaa.a
0485: NOT VERY ROBUST ! but very practical for user help, for example in the editor
0486: 1) ignore classes with file different names
0487: 2) in case of files and packages with same name, return the file without further analysis
0488: */
0489: public SourceFile getSourceFileContaining(String javaName) {
0490: SourceFile actNode = getRootSource();
0491: if (javaName.equals(""))
0492: return actNode;
0493: String[] path = javaName.split("\\.");
0494: for (int i = 0; i < path.length; i++) {
0495: String ni = path[i];
0496: //if(i==path.length-1) ni+=".java";
0497:
0498: // 1) try to find a java source file (???)
0499:
0500: SourceFile newNode = getJavaSourceChild(actNode, ni, "");
0501: if (newNode != null)
0502: return newNode;
0503:
0504: // 2) not found, try package
0505: newNode = getJavaPackageChild(actNode, ni);
0506: if (newNode == null) {
0507: // not found => return the last found ! (?)
0508: //System.out.println("Notfound:"+ni+" first=");
0509: return actNode;
0510: }
0511: actNode = newNode;
0512: }
0513: return actNode;
0514: }
0515:
0516: /** Useful, even if empty of java files !
0517: * can also be used to retrieve a folder during resource search
0518: */
0519: private SourceFile addFolder(File file, int sourceRootBaseLength) {
0520: String relName = FileUtils.getCanonicalName(file).substring(
0521: sourceRootBaseLength);
0522:
0523: if (relName.length() == 0 || relName.equals("/")) {
0524: // occurs in getAllResourceFiles when "adding the root folder"...
0525: //new Throwable("relName="+relName).printStackTrace();
0526: return this .getRootSource();
0527: }
0528:
0529: SourceFile actNode = getRootSource();
0530: String[] path = relName.split("/");
0531: String absolutePackageName = "";
0532: for (int i = 0; i < path.length; i++) {
0533: String ni = path[i];
0534: if (i > 0)
0535: absolutePackageName += ".";
0536: absolutePackageName += ni;
0537:
0538: SourceFile newNode = getJavaPackageChild(actNode, ni);
0539: if (newNode == null) {
0540: newNode = new SourceFile(ni, absolutePackageName);
0541: // TODO: put in the edt, because, when reloaded, triggers updates !
0542: final SourceFile fnewNode = newNode;
0543: final SourceFile factNode = actNode;
0544: SwingSafeRunnable.invokeAndWait(new Runnable() {
0545: public void run() {
0546: SourceFileUtils.insertSorted(fnewNode,
0547: factNode, SourcesTreeModel.this );
0548: }
0549: });
0550: addToQuickPackageCache(newNode);
0551: }
0552: actNode = newNode;
0553: }
0554:
0555: return actNode;
0556: }
0557:
0558: /** @return the last added resource (leaf node)
0559: TODO
0560: */
0561: private ResourceFile _addResourceFile(File file,
0562: int sourceRootBaseLength) {
0563: return null;
0564: }
0565:
0566: /** @return the last added source (leaf node)
0567: */
0568: private SourceFile addSourceFile(File file, int sourceRootBaseLength) {
0569: //System.out.println("add "+file);
0570: String relName = FileUtils.getCanonicalName(file).substring(
0571: sourceRootBaseLength);
0572:
0573: if (relName.length() == 0 || relName.equals("/")) {
0574: new Throwable("relName=" + relName).printStackTrace();
0575: }
0576:
0577: SourceFile actNode = getRootSource();
0578: String[] path = relName.split("/");
0579: StringBuilder absolutePackageName = new StringBuilder();
0580: //System.out.println(" path="+Arrays.toString(path));
0581:
0582: for (int i = 0; i < path.length; i++) {
0583: String ni = path[i];
0584:
0585: SourceFile newNode = getJavaPackageChild(actNode, ni);
0586: if (newNode == null) {
0587: if (i == path.length - 1) // last comp
0588: {
0589: String cn = relName.replace('/', '.');
0590: cn = cn.substring(0, cn.length() - 5); // remove ".java"
0591:
0592: newNode = new SourceFile(file, ni, cn,
0593: absolutePackageName.toString());
0594: addToQuickCache(newNode);
0595:
0596: } else {
0597: // NEVER CALLED !!! ???
0598: if (i > 0)
0599: absolutePackageName.append(".");
0600: absolutePackageName.append(ni);
0601: newNode = new SourceFile(ni, absolutePackageName
0602: .toString());
0603: addToQuickPackageCache(newNode);
0604: }
0605:
0606: // append at end ??
0607: //this.insertNodeInto(newNode, actNode, actNode.getChildCount()); // with UI updates
0608: SourceFileUtils.insertSorted(newNode, actNode, this );
0609: } else {
0610: // already exists !
0611: if (i > 0)
0612: absolutePackageName.append(".");
0613: absolutePackageName.append(ni);
0614:
0615: }
0616:
0617: actNode = newNode;
0618: }
0619:
0620: return actNode;
0621: }
0622:
0623: /** Looks only in direct subchilds ! (not recurse !)
0624: name for childs = hello.java
0625: @param fileName is the optional name of the file (without path).
0626: It helps to locate the type when it has not the name of the file ! used when jumping from parsed stacktrace
0627: @return only source files, NOT packages. use getJavaPackageChild for that
0628:
0629: */
0630: private SourceFile getJavaSourceChild(SourceFile parent,
0631: String javaPartName, String fileName) {
0632: // search in childs
0633: for (int i = 0; i < parent.getChildCount(); i++) {
0634: SourceFile pi = parent.getChildFileAt(i);
0635: if (pi.javaPartName.equals(javaPartName)) {
0636: if (pi.isJavaFile()) {
0637: return pi;
0638: }
0639: }
0640: }
0641:
0642: // search filename
0643: if (fileName != null && fileName.length() > 0) {
0644: for (int i = 0; i < parent.getChildCount(); i++) {
0645: SourceFile pi = parent.getChildFileAt(i);
0646: if (pi.isJavaFile()) {
0647: if (pi.getName().equals(fileName)) {
0648: return pi;
0649: }
0650: }
0651: }
0652: }
0653: // not found
0654: return null;
0655: }
0656:
0657: private SourceFile getJavaPackageChild(SourceFile parent,
0658: String javaPartName) {
0659: // (because packages are usually written with small first letters, they are lexicographically at first positions...)
0660:
0661: // search in childs
0662: for (int i = 0; i < parent.getChildCount(); i++) {
0663: SourceFile pi = parent.getChildFileAt(i);
0664: if (pi.isDirectory()) {
0665: if (pi.javaPartName.equals(javaPartName)) {
0666: //if(!pi.isJavaFile())
0667:
0668: return pi;
0669: }
0670: }
0671: }
0672: // not found
0673: return null;
0674: }
0675:
0676: /** only the java source files, present in the loaded project, no directories items (package)
0677: */
0678: public List<SourceFile> getAllSourceFiles(boolean includeIgnored) {
0679: ArrayList<SourceFile> allSrcFiles = new ArrayList<SourceFile>();
0680: getAllSourceFilesRecurse(this .getRootSource(), allSrcFiles,
0681: false, includeIgnored);
0682: return allSrcFiles;
0683: }
0684:
0685: /** only the java source files, present in the loaded project, no directories items (package)
0686: * that have the isCompiled() false (not uptodate, new, ...).
0687: */
0688: public List<SourceFile> getAllSourceFilesNotCompiled() {
0689: ArrayList<SourceFile> allSrcFiles = new ArrayList<SourceFile>();
0690: getAllSourceFilesRecurse(this .getRootSource(), allSrcFiles,
0691: false, false);
0692:
0693: ArrayList<SourceFile> notCompiled = new ArrayList<SourceFile>();
0694: for (SourceFile sf : allSrcFiles) {
0695: if (!sf.isCompiled()) {
0696: notCompiled.add(sf);
0697: }
0698: }
0699: return notCompiled;
0700: }
0701:
0702: /** The length of the files are used to know if changed (=> invalid)
0703: */
0704: public final List<SourceFile> getAllSourceFilesWithoutActualDependencies() {
0705: final ArrayList<SourceFile> allSrcFiles = new ArrayList<SourceFile>();
0706: getAllSourceFilesRecurse(this .getRootSource(), allSrcFiles,
0707: false, false);
0708:
0709: ArrayList<SourceFile> notActual = new ArrayList<SourceFile>();
0710: for (final SourceFile sf : allSrcFiles) {
0711: if (!sf.sourceFileDependencies.areDependenciesActual()) {
0712: notActual.add(sf);
0713: }
0714: }
0715: return notActual;
0716: }
0717:
0718: /** All the java source files and directories, present in the loaded project.
0719: */
0720: public List<SourceFile> getAllSourceFilesAndDirectories(
0721: boolean includeIgnored) {
0722: ArrayList<SourceFile> allSrcFiles = new ArrayList<SourceFile>();
0723: getAllSourceFilesRecurse(this .getRootSource(), allSrcFiles,
0724: true, includeIgnored);
0725: return allSrcFiles;
0726: }
0727:
0728: /** Ignores childs of folders marked as ignored in the project tree (of the sources)
0729: *
0730: * TODO: no possibility to specify which root files should be ignored
0731: */
0732: public List<File> getAllResourceFiles(
0733: java.util.List<String> customIgnoredEndings) {
0734: ArrayList<File> allResourcers = new ArrayList<File>();
0735: FileUtils.getAllFilesRecurse(this .getSourcesRoot(),
0736: allResourcers, false, true); // without dirs entries and ignore dirs starting with "."
0737:
0738: java.util.List<String> ignoredEndingsLow = new ArrayList<String>(
0739: Arrays.asList(".java",
0740: "sources_to_jar", // tide temp
0741: ".scc", // source safe
0742: "thumbs.db", // xp shit
0743: "projectfiles.dat", // some Schmortopf file are named so
0744: //JavaCompilerCall.classesToCompileFileName.toLowerCase(),
0745: "classes_to_compile",
0746: JavaCompilerCall.compilerBatchName
0747: .toLowerCase()));
0748:
0749: if (customIgnoredEndings != null) {
0750: for (String ce : customIgnoredEndings) {
0751: if (ce.trim().length() > 0) {
0752: ignoredEndingsLow.add(ce.trim().toLowerCase());
0753: }
0754: }
0755: }
0756:
0757: // remove ignored files !
0758: // because they are not present in the source model,
0759: // we have to look at their directories to know if they are ignored
0760: int lbase = FileUtils.getCanonicalName(this .getSourcesRoot())
0761: .length();
0762: fi: for (int i = allResourcers.size() - 1; i >= 0; i--) // reverse iter because removing in loop
0763: {
0764: File fi = allResourcers.get(i);
0765: File parentfi = fi.getParentFile();
0766: // create if not found (may have been created since project load)
0767: SourceFile sfi = this .addFolder(parentfi, lbase);
0768: if (sfi.isIgnored()) {
0769: allResourcers.remove(fi);
0770: continue fi;
0771: }
0772:
0773: String nameLow = fi.getAbsolutePath().toLowerCase();
0774: el: for (String e : ignoredEndingsLow) {
0775: if (nameLow.endsWith(e)) {
0776: allResourcers.remove(fi);
0777: continue fi;
0778: }
0779: }
0780:
0781: }
0782: return allResourcers;
0783: }
0784:
0785: public List<SourceFile> getAllSourceFilesWithSimpleNameStartingWith(
0786: String start) {
0787:
0788: List<SourceFile> allSrcFiles = new ArrayList<SourceFile>();
0789: getAllSourceFilesRecurse(this .getRootSource(), allSrcFiles,
0790: false, false); // don't include directories, nor ignored
0791:
0792: List<SourceFile> rep = new ArrayList<SourceFile>();
0793: for (SourceFile sfi : allSrcFiles) {
0794: String partName = sfi.javaPartName; // "Frame"
0795: if (partName.startsWith(start))
0796: rep.add(sfi);
0797: }
0798: return rep;
0799: }
0800:
0801: /** used for the user help, lazy inexact search
0802: * TODO: improve: exact global match with pack, caseless global match with package, ending match ("."+xx) if not in root.
0803: */
0804: public List<SourceFile> getAllSourceFilesContainingName(
0805: String javaPartName, boolean caseSensitive, boolean exact) {
0806: if (!caseSensitive) {
0807: javaPartName = javaPartName.toUpperCase(Locale.ENGLISH);
0808: }
0809:
0810: List<SourceFile> allSrcFiles = new ArrayList<SourceFile>();
0811: getAllSourceFilesRecurse(this .getRootSource(), allSrcFiles,
0812: false, false); // don't include directories, nor ignored
0813:
0814: List<SourceFile> rep = new ArrayList<SourceFile>();
0815: for (SourceFile sfi : allSrcFiles) {
0816: String partName = sfi.javaPartName; // "Frame"
0817: if (!caseSensitive) {
0818: partName = partName.toUpperCase(Locale.ENGLISH);
0819: }
0820:
0821: if (exact) {
0822: if (partName.equals(javaPartName)) {
0823: rep.add(sfi);
0824: }
0825: } else {
0826: if (partName.indexOf(javaPartName) >= 0) {
0827: rep.add(sfi);
0828: }
0829: }
0830: }
0831:
0832: return rep;
0833: }
0834:
0835: /** collects the sourcefiles in the current model (newly added ones in the filesystem are ignored !)
0836: * ignored = ignored in project, marked by the user.
0837: */
0838: public void getAllSourceFilesRecurse(SourceFile troot,
0839: List<SourceFile> files, boolean includeDirectories,
0840: boolean includeIgnoredFiles) {
0841: if (!includeIgnoredFiles) {
0842: if (troot.isIgnored())
0843: return;
0844: }
0845:
0846: if (troot.isJavaFile()) {
0847: files.add(troot); // could return ... is leaf
0848: }
0849:
0850: if (includeDirectories && troot.isDirectory()) {
0851: files.add(troot);
0852: }
0853:
0854: for (int i = 0; i < troot.getChildCount(); i++) {
0855: SourceFile ci = troot.getChildFileAt(i);
0856: getAllSourceFilesRecurse(ci, files, includeDirectories,
0857: includeIgnoredFiles);
0858: }
0859: }
0860:
0861: /** only the directories (packages)
0862: */
0863: public void getAllDirectoriesRecurse_depthFirst(SourceFile troot,
0864: List<SourceFile> dirs) {
0865: for (int i = 0; i < troot.getChildCount(); i++) {
0866: SourceFile ci = troot.getChildFileAt(i);
0867:
0868: //if(ci.getChildCount()>0) // BUG ! was ignoring empty directories
0869: {
0870: getAllDirectoriesRecurse_depthFirst(ci, dirs);
0871: }
0872: }
0873:
0874: if (troot.isDirectory()) {
0875: dirs.add(troot);
0876: }
0877: }
0878:
0879: /** Don't return the ignored ones!
0880: can be used for the documentation for example, where one has to specify the packages to parse
0881: */
0882: public List<String> getFirstLevelPackages() {
0883: List<String> names = new ArrayList<String>();
0884: for (int i = 0; i < root.getChildCount(); i++) {
0885: SourceFile ci = this .getRootSource().getChildFileAt(i);
0886: if (!ci.isIgnored() && ci.isDirectory) {
0887: names.add(ci.getJavaName());
0888: }
0889: }
0890: return names;
0891: }
0892:
0893: /** In the unnamed scope !
0894: * Should be avoided: javadoc ignore them and they are not accessible from any other package
0895: * (either with reflection, tricky...).
0896: * Ignores directories and ignored files.
0897: */
0898: public List<SourceFile> getTopLevelSources() {
0899: List<SourceFile> f = new ArrayList<SourceFile>();
0900: for (int i = 0; i < root.getChildCount(); i++) {
0901: SourceFile ci = this .getRootSource().getChildFileAt(i);
0902: if (!ci.isIgnored() && ci.isSourceFile()) {
0903: f.add(ci);
0904: }
0905: }
0906: return f;
0907: }
0908:
0909: /** Get Or creates a new directory (java package).
0910: * Pass null for the root.
0911: */
0912: public SourceFile createOrGetPackage(SourceFile parentPackage,
0913: final String packageName) throws Exception {
0914:
0915: SourceFile actual = parentPackage;
0916: System.out.println("Create or get package " + packageName
0917: + " in " + actual);
0918: if (actual == null)
0919: actual = this .getRootSource();
0920:
0921: for (final String si : packageName.split(Pattern.quote("."))) {
0922: SourceFile pi = SourceFileUtils
0923: .getDirectPackage(actual, si);
0924: if (pi != null) {
0925: actual = pi;
0926: } else {
0927: // create
0928: System.out.println("create new package " + si);
0929: actual = createNewJavaPackage(actual, si);
0930: }
0931: }
0932:
0933: return actual;
0934: }
0935:
0936: /** Create a new directory (java package).
0937: * ONLY direck childs can be created. Use createNewJavaPackageRec for recursive.
0938: */
0939: public SourceFile createNewJavaPackage(SourceFile parentPackage,
0940: String packageName) throws Exception {
0941: if (packageName.indexOf('.') >= 0) {
0942: throw new Exception(
0943: "The package names should not contain dots");
0944: }
0945: if (packageName.trim().length() == 0) {
0946: throw new Exception("Empty package names not allowed");
0947: }
0948:
0949: File file = new File(parentPackage.getFileOrDirectory(),
0950: packageName);
0951: if (!file.exists()) {
0952: if (!file.mkdirs())
0953: throw new Exception("Cannot create file (on disk) "
0954: + file.getAbsolutePath());
0955: }
0956:
0957: String subName = parentPackage.getJavaName() + "."
0958: + packageName;
0959: if (subName.startsWith("."))
0960: subName = subName.substring(1);
0961: SourceFile newNode = new SourceFile(packageName, subName);
0962: SourceFileUtils.insertSorted(newNode, parentPackage, this );
0963:
0964: setFolderColors();
0965: return newNode;
0966: }
0967:
0968: public void renameInCache(SourceFile file, String oldJavaName) {
0969: if (file.isDirectory()) {
0970: quickPackageCache.remove(oldJavaName
0971: .toUpperCase(Locale.ENGLISH)); // FB: found a bug: was "file", bad type !!
0972: // [Feb2008]: was not UPPER
0973: // ?? TODO
0974: this .addToQuickPackageCache(file);
0975: } else {
0976: quickCache.remove(oldJavaName.toUpperCase(Locale.ENGLISH)); // [Feb2008]: was not UPPER
0977: this .addToQuickCache(file);
0978: }
0979: }
0980:
0981: /** Deletes source or directory (only empty can be removed).
0982: * Called to delete a source or when a source has been found disapeared (in sync).
0983: */
0984: public void delete(final SourceFile file) throws Exception {
0985: if (file.isDirectory()) {
0986: // delete directory, only if empty
0987: File dir = file.getFileOrDirectory();
0988: File[] dc = dir.listFiles();
0989: if (dc != null && dc.length > 0) {
0990: throw new Exception("Folder not empty, cannot delete "
0991: + dir);
0992: }
0993:
0994: if (file.isRoot()) {
0995: throw new Exception("Cannot delete root !");
0996: }
0997:
0998: if (dir.delete()) {
0999: this .removeNodeFromParent(file);
1000: } else {
1001: throw new Exception("Cannot delete " + dir);
1002: }
1003:
1004: } else {
1005: // file
1006: if (file.javaFile.exists()) {
1007: if (file.javaFile.delete()) {
1008: this .removeNodeFromParent(file);
1009: // important: this also update the dependencies
1010: file.fileHasBeenDeleted();
1011: } else {
1012: throw new Exception("Cannot delete "
1013: + file.javaFile);
1014: }
1015: } else {
1016: // not existing => just "delete"
1017: this .removeNodeFromParent(file);
1018: // important: this also update the dependencies
1019: file.fileHasBeenDeleted();
1020: }
1021:
1022: //[Nov2007]
1023: MainEditorFrame.instance.editorPanel.removeTab(file);
1024:
1025: }
1026:
1027: System.out.println("QCC::" + quickCache.size());
1028: if (file.isDirectory()) {
1029: quickPackageCache.remove(file.getJavaName().toUpperCase(
1030: Locale.ENGLISH));
1031: } else {
1032: quickCache.remove(file.getJavaName().toUpperCase(
1033: Locale.ENGLISH)); // [Feb2008]: missing UPPER !
1034: }
1035: //System.out.println("Removed from quick cache: "+file.getJavaName()+" (cache size="+quickCache.size()+")"+quickCache.get(file.getJavaName()));
1036:
1037: MainEditorFrame.instance.getActualProject().sourceFileRemoved(
1038: file.getJavaName());
1039: }
1040:
1041: /** the sources root.
1042: */
1043: public File getSourcesRoot() {
1044: return new File(this .getRootSource().name);
1045: }
1046:
1047: /** Used to create new source files (called from new source dialog).
1048: */
1049: public SourceFile createNewJavaSourceFile(SourceFile packageFile,
1050: String className, String content) throws Exception {
1051: System.out.println("Creating a new java source named "
1052: + className + " in " + packageFile);
1053: String javaName = packageFile.getJavaName() + "." + className;
1054:
1055: String relFileName = javaName.replace('.', '/') + ".java";
1056: if (relFileName.startsWith("/"))
1057: relFileName = relFileName.substring(1);
1058:
1059: if (getSourceFile(javaName, null) != null)
1060: throw new Exception("Source " + className
1061: + " already exists.");
1062:
1063: File file = new File(this .getSourcesRoot(), relFileName);
1064:
1065: // the dirs should exist => directly write the file
1066: PrintWriter pw = null;
1067: try {
1068: pw = new PrintWriter(file);
1069: pw.append(content);
1070: } catch (Exception e) {
1071: throw new Exception("Cannot create the file "
1072: + file.getAbsolutePath());
1073: } finally {
1074: if (pw != null)
1075: pw.close();
1076: }
1077:
1078: // and add the file to the model
1079: int lbase = FileUtils.getCanonicalName(this .getSourcesRoot())
1080: .length();
1081: SourceFile addedFile = this .addSourceFile(file, lbase);
1082: setFolderColors();
1083: return addedFile;
1084: }
1085:
1086: /** Save is not enough, when data has changed on the disk, this must be called.
1087: */
1088: public void deleteCachedEditedContents(final SourceFile branch) {
1089: final List<SourceFile> allModelFiles = new ArrayList<SourceFile>();
1090: this .getAllSourceFilesRecurse(branch, allModelFiles, false,
1091: false); // without ignored files...
1092:
1093: for (final SourceFile sf : allModelFiles) {
1094: //sf.saveContentToFile();
1095: sf.deleteCachedContent();
1096: }
1097: }
1098:
1099: /** Added/removed, changed files are detected.
1100: * Useful when a CVS update was performed. Allow updating without simply closing/reloading.
1101: * + A save must be made prior.
1102: * + after: you must call: MainEditorFrame.instance.editorPanel.replaceContentWithContentOnDisk();
1103: */
1104: public ChangesAnalysisResult scanForDifferencesWithFileSystem(
1105: final SourceFile branch) {
1106: final ChangesAnalysisResult changes = new ChangesAnalysisResult();
1107:
1108: MainEditorFrame.instance.outputPanels.select_tIDE_Tab(true);
1109:
1110: SimpleDocument doc = MainEditorFrame.instance.outputPanels.tideOutputPanel.doc;
1111:
1112: doc.append("\nScan for differences with the filesystem, from "
1113: + branch.getJavaName());
1114: if (branch.getJavaName().length() == 0) {
1115: doc.appendLine("root:");
1116: } else {
1117: doc.appendLine(":");
1118: }
1119:
1120: if (!branch.isDirectory) {
1121: // easy case: a single file is analysed...
1122: if (!branch.javaFile.exists()) {
1123: doc.appendLine(" " + branch.getJavaName()
1124: + " has been removed");
1125: changes.removedFiles.add(branch);
1126: } else if (branch.lookIfJavaFileChangedAndTreat()) {
1127: doc.appendLine(" " + branch.getJavaName()
1128: + ": has changed on disk");
1129: changes.changedFiles.add(branch);
1130: } else {
1131: doc.appendLine("no change");
1132: }
1133:
1134: return changes;
1135: }
1136:
1137: //1: collect all model files and look for disapeared files
1138: List<SourceFile> allModelFilesAndDirs = new ArrayList<SourceFile>();
1139: this .getAllSourceFilesRecurse(branch, allModelFilesAndDirs,
1140: true, false); // without ignored files...
1141:
1142: for (final SourceFile f : allModelFilesAndDirs) {
1143: if (f.isJavaFile()) {
1144: if (!f.javaFile.exists()) {
1145: changes.removedFiles.add(f);
1146: System.out.println("Disapeared " + f);
1147: SwingSafeRunnable.invokeLater(new Runnable() {
1148: public void run() {
1149: try {
1150: delete(f); // CAUTION. if it existed (it do not) it would be deleted. We call this to remove from model.
1151: } catch (Exception e) {
1152: e.printStackTrace();
1153: }
1154: }
1155: });
1156:
1157: } else {
1158: // this sets the state to "not compiled" if changed!!
1159: if (f.lookIfJavaFileChangedAndTreat()) {
1160: changes.changedFiles.add(f);
1161: }
1162: }
1163: } else {
1164: if (!f.getFileOrDirectory().exists()) {
1165: changes.removedFiles.add(f);
1166: System.out.println("Disapeared folder " + f);
1167: try {
1168: this .delete(f);
1169: } catch (Exception e) {
1170: e.printStackTrace();
1171: }
1172: }
1173: }
1174: }
1175:
1176: // collect all files in the system
1177: final List<File> srcFiles = new ArrayList<File>();
1178: //FileUtilities.getAllFilesRecurse_withNameEndingWith(srcFiles, branch.getFileOrDirectory(), ".java");
1179: FileUtils.getAllJavaFilesRecurse(branch.getFileOrDirectory(),
1180: srcFiles, true, true); // with folders !
1181:
1182: System.out.println("Comparing " + allModelFilesAndDirs.size()
1183: + " model files with " + srcFiles.size()
1184: + " java sources on disk");
1185: final int rootNameLen = this .getRootSource().getName().length();
1186:
1187: final List<String> newSourcesJavaNames = new ArrayList<String>();
1188: for (final File fi : srcFiles) {
1189: String javaName = fi.getAbsolutePath().replace('\\', '/');
1190: if (fi.isFile()) {
1191: javaName = javaName.substring(rootNameLen,
1192: javaName.length() - 5).replace('/', '.');
1193: } else {
1194: // [Nov2007]: was missing
1195: javaName = javaName.substring(rootNameLen).replace('/',
1196: '.');
1197:
1198: continue; // TODO: also "add" missing folders. => so we catch empty ones...
1199: }
1200:
1201: SourceFile sfi = (SourceFile) this .quickGet(javaName, true);
1202: if (sfi == null) {
1203: System.out.println("New source: " + javaName);
1204: newSourcesJavaNames.add(javaName);
1205: changes.addedFiles.add(fi);
1206: this .addSourceFile(fi, rootNameLen);
1207: }
1208: }
1209:
1210: // Prints out
1211: //
1212:
1213: if (newSourcesJavaNames.size() > 0) {
1214: System.out.println("" + newSourcesJavaNames.size()
1215: + " new sources");
1216: doc.appendLine("\n" + newSourcesJavaNames.size()
1217: + " new source file"
1218: + (newSourcesJavaNames.size() == 1 ? "" : "s")
1219: + ":");
1220: for (String ns : newSourcesJavaNames) {
1221: doc.appendLine(" " + ns);
1222: }
1223: }
1224:
1225: if (changes.removedFiles.size() > 0) {
1226: doc.appendLine("\n" + changes.removedFiles.size()
1227: + " removed file"
1228: + (changes.removedFiles.size() == 1 ? "" : "s")
1229: + ":");
1230: for (SourceFile ns : changes.removedFiles) {
1231: doc.appendLine(" " + ns.getJavaName());
1232: }
1233: }
1234:
1235: if (changes.changedFiles.size() > 0) {
1236: doc.appendLine("\n" + changes.changedFiles.size()
1237: + " changed file"
1238: + (changes.changedFiles.size() == 1 ? "" : "s")
1239: + ":");
1240: for (SourceFile ns : changes.changedFiles) {
1241: doc.appendLine(" " + ns.getJavaName());
1242: }
1243: }
1244:
1245: if (!changes.hasChanges()) {
1246: System.out.println("No changes");
1247: doc.appendLine("no changes.");
1248: }
1249:
1250: System.out.println("comparaison done.");
1251:
1252: return changes;
1253: }
1254:
1255: /** Must be called after all changes in the files structure.
1256: Sets the red, green or mixed color of the java files based on the read/write state of the files.
1257: [Dec2006]: empty folders (no java files) are white.
1258: */
1259: public void setFolderColors() {
1260: // depth first
1261: List<SourceFile> allDirFiles = new ArrayList<SourceFile>();
1262: this .getAllDirectoriesRecurse_depthFirst(this .getRootSource(),
1263: allDirFiles);
1264:
1265: for (SourceFile dir : allDirFiles) {
1266: boolean hasGreen = false;
1267: boolean hasRed = false;
1268: boolean isOnlyWhite = true;
1269:
1270: boolean hasIgnored = dir.isIgnored(); // [July2006]
1271: boolean hasIncluded = false;
1272:
1273: boolean editedNow = false;
1274:
1275: boolean isCompiled = true;
1276:
1277: for (int i = 0; i < dir.getChildCount(); i++) // files and dirs
1278: {
1279: SourceFile sfi = (SourceFile) dir.getChildAt(i);
1280:
1281: if (sfi.iconColor != SourcesTreeIcon.IconColor.White)
1282: isOnlyWhite = false;
1283:
1284: if (sfi.iconColor == SourcesTreeIcon.IconColor.Green)
1285: hasGreen = true;
1286: if (sfi.iconColor == SourcesTreeIcon.IconColor.Red)
1287: hasRed = true;
1288: if (sfi.iconColor == SourcesTreeIcon.IconColor.RedGreen) {
1289: hasGreen = true;
1290: hasRed = true;
1291: }
1292:
1293: if (sfi.getIgnoredType() == SourcesTreeIcon.Ignored.Yes)
1294: hasIgnored = true;
1295: if (sfi.getIgnoredType() == SourcesTreeIcon.Ignored.No)
1296: hasIncluded = true;
1297: if (sfi.getIgnoredType() == SourcesTreeIcon.Ignored.Partially) {
1298: hasIgnored = true;
1299: hasIncluded = true;
1300: }
1301:
1302: if (sfi.isBeingEdited())
1303: editedNow = true;
1304:
1305: if (!sfi.isCompiled())
1306: isCompiled = false;
1307:
1308: }
1309:
1310: if (hasRed && hasGreen) {
1311: dir.iconColor = SourcesTreeIcon.IconColor.RedGreen;
1312: } else if (hasRed) {
1313: dir.iconColor = SourcesTreeIcon.IconColor.Red;
1314: } else {
1315: if (dir.getChildCount() == 0) {
1316: // when empty
1317: dir.iconColor = SourcesTreeIcon.IconColor.White;
1318: } else {
1319: if (isOnlyWhite) {
1320: dir.iconColor = SourcesTreeIcon.IconColor.White;
1321: } else {
1322: dir.iconColor = SourcesTreeIcon.IconColor.Green;
1323: }
1324: }
1325: }
1326:
1327: if (hasIgnored && hasIncluded) {
1328: dir.setIgnoredType(SourcesTreeIcon.Ignored.Partially);
1329: } else if (hasIgnored) {
1330: dir.setIgnoredType(SourcesTreeIcon.Ignored.Yes);
1331: } else {
1332: dir.setIgnoredType(SourcesTreeIcon.Ignored.No);
1333: }
1334:
1335: if (editedNow) {
1336: dir.setBeingEdited(true);
1337: }
1338:
1339: dir.setIsCompiled(isCompiled);
1340: }
1341: }
1342:
1343: /** Just for the view, reads the main class name from the project.
1344: * must be called when changes
1345: */
1346: public void markMainProjectSource() {
1347: // resets all
1348: List<SourceFile> srcs = getAllSourceFiles(true); // include the ignored ones of course
1349: for (SourceFile sf : srcs) {
1350: sf.isProjectMainClass = false;
1351: }
1352:
1353: String javaName = MainEditorFrame.instance.getActualProject()
1354: .getMainClassJavaName();
1355: if (javaName == null)
1356: return;
1357:
1358: SourceFile sf = this .getSourceFile(javaName, "");
1359: if (sf != null) {
1360: sf.isProjectMainClass = true;
1361: }
1362: }
1363:
1364: }
|