diff --git a/.idea/artifacts/jps_plugins.xml b/.idea/artifacts/jps_plugins.xml index fee03eee74f7..89f5927429ed 100644 --- a/.idea/artifacts/jps_plugins.xml +++ b/.idea/artifacts/jps_plugins.xml @@ -3,9 +3,6 @@ $PROJECT_DIR$/out/artifacts/jps - - - diff --git a/.idea/artifacts/jps_sources.xml b/.idea/artifacts/jps_sources.xml index 2cd42352db97..2b7c6fd1e0b7 100644 --- a/.idea/artifacts/jps_sources.xml +++ b/.idea/artifacts/jps_sources.xml @@ -6,7 +6,6 @@ - diff --git a/.idea/libraries/Mac.xml b/.idea/libraries/Mac.xml index dae0b732f5d2..256d4c9e54a9 100644 --- a/.idea/libraries/Mac.xml +++ b/.idea/libraries/Mac.xml @@ -1,12 +1,12 @@ - - - - - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Mocks.xml b/.idea/libraries/Mocks.xml index ab3be1d54be9..7e4ee7018f4e 100644 --- a/.idea/libraries/Mocks.xml +++ b/.idea/libraries/Mocks.xml @@ -6,7 +6,7 @@ - + diff --git a/.idea/libraries/tcServiceMessages.xml b/.idea/libraries/tcServiceMessages.xml index 2f8bf99242e5..e7fb38a05d50 100644 --- a/.idea/libraries/tcServiceMessages.xml +++ b/.idea/libraries/tcServiceMessages.xml @@ -1,11 +1,11 @@ - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index c95d45fbe908..ce8d7ca005f3 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -9,7 +9,8 @@ - + + @@ -59,9 +60,6 @@ - - - diff --git a/RegExpSupport/src/org/intellij/lang/regexp/psi/impl/RegExpElementImpl.java b/RegExpSupport/src/org/intellij/lang/regexp/psi/impl/RegExpElementImpl.java index 9b96b95d7b5f..f0befa3c0287 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/psi/impl/RegExpElementImpl.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/psi/impl/RegExpElementImpl.java @@ -49,7 +49,7 @@ public abstract class RegExpElementImpl extends ASTWrapperPsiElement implements } public String toString() { - return getClass().getSimpleName() + ": <" + getUnescapedText() + ">"; + return getClass().getSimpleName() + ": <" + getText() + ">"; } public void accept(@NotNull PsiElementVisitor visitor) { diff --git a/build/scripts/layouts.gant b/build/scripts/layouts.gant index c26409ec2350..6dc01096ba64 100644 --- a/build/scripts/layouts.gant +++ b/build/scripts/layouts.gant @@ -364,6 +364,8 @@ public def layoutCommunityPlugins(String home) { include(name: "**/*.jar") exclude(name: "**/ddmlib_1.jar") } + + jar("android_rt.jar") {module("android-rt")} } } } diff --git a/build/scripts/libLicenses.gant b/build/scripts/libLicenses.gant index e0fe9f0cfa10..b90f42d3b3b4 100644 --- a/build/scripts/libLicenses.gant +++ b/build/scripts/libLicenses.gant @@ -157,6 +157,7 @@ libraryLicense(name: "Axis", libraryName: "axis-1.4", version: "1.4", license: " libraryLicense(name: "CGLib", libraryName: "CGLIB", version: "2.2.2", license: "Apache", url: "http://cglib.sourceforge.net/", licenseUrl: "http://www.apache.org/foundation/licence-FAQ.html") libraryLicense(name: "classworlds", libraryName: "classworlds-1.1.jar", version: "1.1", license: "codehaus", url: "http://classworlds.codehaus.org/", licenseUrl: "http://classworlds.codehaus.org/license.html") libraryLicense(name: "Android SDK Tools", libraryName: "android-sdk-tools", license: "Apache 2.0", url: "http://source.android.com/") +libraryLicense(name: "Android SDK Tools JPS", libraryName: "android-sdk-tools-jps", license: "Apache 2.0", url: "http://source.android.com/") libraryLicense(name: "Apache Commons BeanUtils", libraryName: "commons-beanutils.jar", version: "1.6", license: "Apache 2.0", url: "http://commons.apache.org/beanutils/") libraryLicense(name: "Apache Commons Codec", libraryName: "commons-codec", version: "1.3", license: "Apache 2.0", url: "http://commons.apache.org/codec/", licenseUrl: "http://commons.apache.org/license.html") libraryLicense(name: "Apache Commons Collections", libraryName: "commons-collections", version: "3.1", license: "Apache 2.0", url: "http://commons.apache.org/collections/", licenseUrl: "http://commons.apache.org/license.html") @@ -190,9 +191,9 @@ libraryLicense(name: "JavaHelp", version: "2.0_02", license: "included as licens libraryLicense(name: "JCIP Annotations", libraryName: "jcip", license: "Creative Commons Attribution License", url: "http://www.jcip.net", licenseUrl: "http://creativecommons.org/licenses/by/2.5") libraryLicense(name: "JDOM", version: "1.1 (with patches by JetBrains)", license: "modified Apache", url: "http://www.jdom.org/", licenseUrl: "http://www.jdom.org/docs/faq.html#a0030") libraryLicense(name: "jgit-1.1.0", version: "1.1.0.201109151100", license: "EDL/BSD", url: "http://www.eclipse.org/jgit/", licenseUrl: "http://www.eclipse.org/org/documents/edl-v10.php", attachedTo: "git4idea") -libraryLicense(name: "JGoodies Forms", libraryName: "jgoodies-forms", version: "CVS snapshot as of 5 May 2006", license: "BSD ", url: "http://www.jgoodies.com/freeware/forms/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html") -libraryLicense(name: "JGoodies Looks", attachedTo: "platform-impl", version: "2.4.2", license: "BSD ", url: "http://www.jgoodies.com/freeware/looks/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html") -libraryLicense(name: "JGoodies Common", attachedTo: "platform-impl", version: "1.2.1", license: "BSD ", url: "http://www.jgoodies.com/freeware/looks/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html") +libraryLicense(name: "JGoodies Forms", libraryName: "jgoodies-forms", version: "1.1-preview 2006-05-04 11:55:37", license: "BSD ", url: "http://www.jgoodies.com/freeware/forms/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html") +libraryLicense(name: "JGoodies Looks", libraryName: "jgoodies-looks", version: "2.4.2", license: "BSD ", url: "http://www.jgoodies.com/freeware/looks/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html") +libraryLicense(name: "JGoodies Common", libraryName: "jgoodies-common", version: "1.2.1", license: "BSD ", url: "http://www.jgoodies.com/freeware/looks/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html") libraryLicense(name: "JNA", libraryName: "jna", version: "3.2.4", license: "LGPL 2.1", url: "https://jna.dev.java.net/", licenseUrl: "http://www.opensource.org/licenses/lgpl-2.1.php") libraryLicense(name: "JNA", libraryName: "jna.jar", version: "3.2.7", license: "LGPL 2.1", url: "https://jna.dev.java.net/", licenseUrl: "http://www.opensource.org/licenses/lgpl-2.1.php") libraryLicense(name: "JSch", libraryName: "JSch", version: "0.1.44", license: "BSD", url: "http://www.jcraft.com/jsch/", licenseUrl: "http://www.jcraft.com/jsch/LICENSE.txt") @@ -238,4 +239,4 @@ libraryLicense(name: "Kryo", libraryName: "Kryo", version: "1.04", license: "New jetbrainsLibrary("JPS") jetbrainsLibrary("Maven Embedder") jetbrainsLibrary("tcServiceMessages") -jetbrainsLibrary("optimizedFileManager.jar") \ No newline at end of file +jetbrainsLibrary("optimizedFileManager.jar") diff --git a/community-resources/src/idea/IdeaApplicationInfo.xml b/community-resources/src/idea/IdeaApplicationInfo.xml index 1e8dbaf004d0..6127d59b9959 100644 --- a/community-resources/src/idea/IdeaApplicationInfo.xml +++ b/community-resources/src/idea/IdeaApplicationInfo.xml @@ -1,5 +1,5 @@ - + diff --git a/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java b/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java index b207b8d4a5e2..ffbcdd9586d9 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java @@ -17,6 +17,7 @@ package com.intellij.compiler; import com.intellij.ProjectTopics; import com.intellij.application.options.PathMacrosImpl; +import com.intellij.compiler.server.impl.CompileServerClasspathManager; import com.intellij.execution.ExecutionException; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.execution.process.OSProcessHandler; @@ -35,9 +36,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.project.ProjectManagerAdapter; -import com.intellij.openapi.projectRoots.JavaSdkType; -import com.intellij.openapi.projectRoots.ProjectJdkTable; -import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.projectRoots.*; import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl; import com.intellij.openapi.roots.ModuleRootEvent; import com.intellij.openapi.roots.ModuleRootListener; @@ -45,6 +44,7 @@ import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar; import com.intellij.openapi.ui.MessageType; +import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.ShutDownTracker; @@ -61,6 +61,7 @@ import com.intellij.util.Alarm; import com.intellij.util.concurrency.Semaphore; import com.intellij.util.messages.MessageBusConnection; import com.intellij.util.net.NetUtils; +import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.api.*; @@ -99,6 +100,7 @@ public class CompileServerManager implements ApplicationComponent{ private final ProjectManager myProjectManager; private static final int MAKE_TRIGGER_DELAY = 5 * 1000 /*5 seconds*/; private final Map myAutomakeFutures = new HashMap(); + private final CompileServerClasspathManager myClasspathManager = new CompileServerClasspathManager(); public CompileServerManager(final ProjectManager projectManager) { myProjectManager = projectManager; @@ -271,9 +273,8 @@ public class CompileServerManager implements ApplicationComponent{ if (!config.useCompileServer() || !config.MAKE_PROJECT_ON_SAVE) { continue; } - final RequestFuture future = submitCompilationTask( - project, false, true, Collections.emptyList(), Collections.emptyList(), new AutoMakeResponseHandler(project) - ); + final RequestFuture future = submitCompilationTask(project, false, true, Collections.emptyList(), Collections.emptyList(), + Collections.emptyList(), new AutoMakeResponseHandler(project)); if (future != null) { futures.add(future); synchronized (myAutomakeFutures) { @@ -311,7 +312,9 @@ public class CompileServerManager implements ApplicationComponent{ } @Nullable - public RequestFuture submitCompilationTask(final Project project, final boolean isRebuild, final boolean isMake, final Collection modules, final Collection paths, final JpsServerResponseHandler handler) { + public RequestFuture submitCompilationTask(final Project project, final boolean isRebuild, final boolean isMake, + final Collection modules, final Collection artifacts, + final Collection paths, final JpsServerResponseHandler handler) { final String projectId = project.getLocation(); final Ref futureRef = new Ref(null); final RunnableFuture future = myTaskExecutor.submit(new Runnable() { @@ -321,7 +324,7 @@ public class CompileServerManager implements ApplicationComponent{ if (client != null) { final RequestFuture requestFuture = isRebuild ? client.sendRebuildRequest(projectId, handler) : - client.sendCompileRequest(isMake, projectId, modules, paths, handler); + client.sendCompileRequest(isMake, projectId, modules, artifacts, paths, handler); futureRef.set(requestFuture); } else { @@ -461,8 +464,9 @@ public class CompileServerManager implements ApplicationComponent{ private static RequestFuture sendSetupRequest(final @NotNull CompileServerClient client) throws Exception { final Map data = new HashMap(); - // need this for tests and when this macro is missing from PathMacros registry - data.put(PathMacrosImpl.APPLICATION_HOME_MACRO_NAME, FileUtil.toSystemIndependentName(PathManager.getHomePath())); + for (Map.Entry entry : PathMacrosImpl.getGlobalSystemMacros().entrySet()) { + data.put(entry.getKey(), FileUtil.toSystemIndependentName(entry.getValue())); + } final PathMacros pathVars = PathMacros.getInstance(); for (String name : pathVars.getAllMacroNames()) { @@ -487,8 +491,19 @@ public class CompileServerManager implements ApplicationComponent{ if (homePath == null) { continue; } + final SdkAdditionalData data = sdk.getSdkAdditionalData(); + final String additionalDataXml; + final SdkType sdkType = sdk.getSdkType(); + if (data == null) { + additionalDataXml = null; + } + else { + final Element element = new Element("additional"); + sdkType.saveAdditionalData(data, element); + additionalDataXml = JDOMUtil.writeElement(element, "\n"); + } final List paths = convertToLocalPaths(sdk.getRootProvider().getFiles(OrderRootType.CLASSES)); - globals.add(new SdkLibrary(name, homePath, paths)); + globals.add(new SdkLibrary(name, sdkType.getName(), homePath, paths, additionalDataXml)); } } @@ -582,6 +597,7 @@ public class CompileServerManager implements ApplicationComponent{ cmdLine.addParameter("-classpath"); final List cp = ClasspathBootstrap.getCompileServerApplicationClasspath(); + cp.addAll(myClasspathManager.getCompileServerPluginsClasspath()); cmdLine.addParameter(classpathToString(cp)); diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java index 87198ba9d5e7..857d42b0632b 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java @@ -144,8 +144,6 @@ public class CompileDriver { } }; - private OutputPathFinder myOutputFinder; // need this for updating zip archives (experimental feature) - private Set myAllOutputDirectories; private static final long ONE_MINUTE_MS = 60L /*sec*/ * 1000L /*millisec*/; @@ -414,19 +412,25 @@ public class CompileDriver { } @Nullable - private RequestFuture compileOnServer(final CompileContextImpl compileContext, Collection modules, final Collection paths, @Nullable final CompileStatusNotification callback) + private RequestFuture compileOnServer(final @NotNull CompileContextImpl compileContext, @NotNull Collection modules, @NotNull Collection artifacts, + final @NotNull Collection paths, @Nullable final CompileStatusNotification callback) throws Exception { Collection moduleNames = Collections.emptyList(); - if (modules != null && modules.size() > 0) { + if (modules.size() > 0) { moduleNames = new ArrayList(modules.size()); for (Module module : modules) { moduleNames.add(module.getName()); } } + List artifactNames = new ArrayList(); + for (Artifact artifact : artifacts) { + artifactNames.add(artifact.getName()); + } + final CompileServerManager csManager = CompileServerManager.getInstance(); final MessageBus messageBus = myProject.getMessageBus(); csManager.cancelAutoMakeTasks(myProject); - return csManager.submitCompilationTask(myProject, compileContext.isRebuild(), compileContext.isMake(), moduleNames, paths, new JpsServerResponseHandler() { + return csManager.submitCompilationTask(myProject, compileContext.isRebuild(), compileContext.isMake(), moduleNames, artifactNames, paths, new JpsServerResponseHandler() { @Override public void handleCompileMessage(JpsRemoteProto.Message.Response.CompileMessage compilerMessage) { @@ -584,7 +588,8 @@ public class CompileDriver { } final Collection paths = fetchFiles(compileContext); final List modules = paths.isEmpty()? Arrays.asList(compileContext.getCompileScope().getAffectedModules()) : Collections.emptyList(); - final RequestFuture future = compileOnServer(compileContext, modules, paths, callback); + final Set artifacts = ArtifactCompileScope.getArtifactsToBuild(myProject, compileContext.getCompileScope(), true); + final RequestFuture future = compileOnServer(compileContext, modules, artifacts, paths, callback); if (future != null) { try { startCancelWatcher(indicator, future); @@ -658,6 +663,7 @@ public class CompileDriver { finish - start ); CompilerCacheManager.getInstance(myProject).flushCaches(); + FileUtil.delete(CompilerPaths.getRebuildMarkerFile(myProject)); } } }; @@ -748,8 +754,6 @@ public class CompileDriver { } myAllOutputDirectories = getAllOutputDirectories(compileContext); - // need this for updating zip archives experiment, uncomment if the feature is turned on - //myOutputFinder = new OutputPathFinder(myAllOutputDirectories); status = doCompile(compileContext, isRebuild, forceCompile, false); } catch (Throwable ex) { @@ -820,6 +824,10 @@ public class CompileDriver { } private void checkCachesVersion(final CompileContextImpl compileContext, final long currentVFSTimestamp) { + if (CompilerPaths.getRebuildMarkerFile(compileContext.getProject()).exists()) { + compileContext.requestRebuildNextTime("Compiler caches are out of date, project rebuild is required"); + return; + } final CompileStatus compileStatus = readStatus(); if (compileStatus == null) { compileContext.requestRebuildNextTime(CompilerBundle.message("error.compiler.caches.corrupted")); diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java b/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java index 7f12839af0b4..f6c37ea4b2b9 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java @@ -19,6 +19,7 @@ import com.intellij.ProjectTopics; import com.intellij.compiler.CompileServerManager; import com.intellij.compiler.CompilerConfiguration; import com.intellij.compiler.CompilerIOUtil; +import com.intellij.compiler.CompilerWorkspaceConfiguration; import com.intellij.compiler.make.MakeUtil; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.Application; @@ -82,12 +83,16 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { public static boolean ourDebugMode = false; @NonNls private static final String PATHS_TO_DELETE_FILENAME = "paths_to_delete.dat"; + private static final String SUSPENDED_PROJECTS_FILENAME = "suspended.dat"; private static final String OUTPUT_ROOTS_FILENAME = "output_roots.dat"; private static final FileAttribute ourSourceFileAttribute = new FileAttribute("_make_source_file_info_", 3); private static final FileAttribute ourOutputFileAttribute = new FileAttribute("_make_output_file_info_", 3); private static final Key> SOURCE_FILES_CACHE = Key.create("_source_url_to_vfile_cache_"); private final Object myDataLock = new Object(); + + private final TIntHashSet mySuspendedProjects = new TIntHashSet(); // projectId for allprojects that should not be monitored + private final TIntObjectHashMap mySourcesToRecompile = new TIntObjectHashMap(); // ProjectId->set of source file paths private PersistentHashMap>> myOutputRootsStorage; // ProjectId->map[moduleId->Pair(outputDirId, testOutputDirId)] private final TIntObjectHashMap> myOutputsToDelete = new TIntObjectHashMap>(); // Map: projectId -> Map{output path -> [sourceUrl; classname]} @@ -126,7 +131,7 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { } }; private final ProjectManager myProjectManager; - private final TIntIntHashMap myInitInProgress = new TIntIntHashMap(); // projectId fior successfully initialized projects + private final TIntIntHashMap myInitInProgress = new TIntIntHashMap(); // projectId for successfully initialized projects private final Object myAsyncScanLock = new Object(); public TranslatingCompilerFilesMonitor(VirtualFileManager vfsManager, ProjectManager projectManager, Application application) { @@ -140,6 +145,46 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { return ApplicationManager.getApplication().getComponent(TranslatingCompilerFilesMonitor.class); } + public void suspendProject(Project project) { + final int projectId = getProjectId(project); + + synchronized (myDataLock) { + if (!mySuspendedProjects.add(projectId)) { + return; + } + FileUtil.createIfDoesntExist(CompilerPaths.getRebuildMarkerFile(project)); + // cleanup internal structures to free memory + mySourcesToRecompile.remove(projectId); + myOutputsToDelete.remove(projectId); + myGeneratedDataPaths.remove(project); + myProjectOutputRoots.remove(projectId); + } + + try { + myOutputRootsStorage.remove(projectId); + } + catch (IOException e) { + LOG.info(e); + } + + } + + public void watchProject(Project project) { + synchronized (myDataLock) { + mySuspendedProjects.remove(getProjectId(project)); + } + } + + public boolean isSuspended(Project project) { + return isSuspended(getProjectId(project)); + } + + public boolean isSuspended(int projectId) { + synchronized (myDataLock) { + return mySuspendedProjects.contains(projectId); + } + } + @Nullable public static VirtualFile getSourceFileByOutput(VirtualFile outputFile) { final OutputFileInfo outputFileInfo = loadOutputInfo(outputFile); @@ -420,6 +465,36 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { } public void initComponent() { + loadSuspendedProjects(); + loadPathsToDelete(); + ensureOutputStorageInitialized(); + } + + private void loadSuspendedProjects() { + final File file = new File(CompilerPaths.getCompilerSystemDirectory(), SUSPENDED_PROJECTS_FILENAME); + try { + final DataInputStream is = new DataInputStream(new BufferedInputStream(new FileInputStream(file))); + try { + final int projectsCount = is.readInt(); + synchronized (myDataLock) { + for (int idx = 0; idx < projectsCount; idx++) { + mySuspendedProjects.add(is.readInt()); + } + } + } + finally { + is.close(); + } + } + catch (FileNotFoundException ignored) { + } + catch (IOException e) { + LOG.info(e); + FileUtil.delete(file); + } + } + + private void loadPathsToDelete() { final File file = new File(CompilerPaths.getCompilerSystemDirectory(), PATHS_TO_DELETE_FILENAME); try { final DataInputStream is = new DataInputStream(new BufferedInputStream(new FileInputStream(file))); @@ -430,20 +505,29 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { final int projectId = is.readInt(); final int size = is.readInt(); if (size > 0) { - final Map map = new HashMap(); - myOutputsToDelete.put(projectId, map); + final Map map; + if (mySuspendedProjects.contains(projectId)) { + map = null; + } + else { + map = new HashMap(); + myOutputsToDelete.put(projectId, map); + } for (int i = 0; i < size; i++) { - final String outputPath = FileUtil.toSystemIndependentName(CompilerIOUtil.readString(is)); + final String _outputPath = CompilerIOUtil.readString(is); final String srcUrl = CompilerIOUtil.readString(is); final String className = CompilerIOUtil.readString(is); + if (map == null) { + continue; + } if (LOG.isDebugEnabled() || ourDebugMode) { - final String message = "INIT path to delete: " + outputPath; + final String message = "INIT path to delete: " + FileUtil.toSystemIndependentName(_outputPath); LOG.debug(message); if (ourDebugMode) { System.out.println(message); } } - map.put(outputPath, new SourceUrlClassNamePair(srcUrl, className)); + map.put(FileUtil.toSystemIndependentName(_outputPath), new SourceUrlClassNamePair(srcUrl, className)); } } } @@ -462,8 +546,6 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { } FileUtil.delete(file); } - - ensureOutputStorageInitialized(); } private void ensureOutputStorageInitialized() { @@ -528,12 +610,46 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { } public void disposeComponent() { + saveSuspendedProjects(); + savePathsToDelete(); + } + + private void saveSuspendedProjects() { + final File file = new File(CompilerPaths.getCompilerSystemDirectory(), SUSPENDED_PROJECTS_FILENAME); + try { + FileUtil.createParentDirs(file); + final DataOutputStream os = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))); + try { + synchronized (myDataLock) { + os.writeInt(mySuspendedProjects.size()); + for (int projectId : mySuspendedProjects.toArray()) { + os.writeInt(projectId); + } + } + } + finally { + os.close(); + } + } + catch (IOException e) { + LOG.error(e); + } + } + + private void savePathsToDelete() { final File file = new File(CompilerPaths.getCompilerSystemDirectory(), PATHS_TO_DELETE_FILENAME); try { FileUtil.createParentDirs(file); final DataOutputStream os = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))); try { synchronized (myDataLock) { + mySuspendedProjects.forEach(new TIntProcedure() { + @Override + public boolean execute(int projectId) { + myOutputsToDelete.remove(projectId); + return true; + } + }); final int[] keys = myOutputsToDelete.keys(); os.writeInt(keys.length); for (int projectId : keys) { @@ -839,10 +955,12 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { } } - public void clearPaths(final int projectId){ + public boolean clearPaths(final int projectId){ if (myProjectToOutputPathMap != null) { - myProjectToOutputPathMap.remove(projectId); + final Serializable removed = myProjectToOutputPathMap.remove(projectId); + return removed != null; } + return false; } long getTimestamp(final int projectId) { @@ -899,7 +1017,7 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { } public static List getCompiledClassNames(VirtualFile srcFile, Project project) { - SourceFileInfo info = loadSourceInfo(srcFile); + final SourceFileInfo info = loadSourceInfo(srcFile); if (info == null) { return Collections.emptyList(); } @@ -1083,6 +1201,9 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { public void scanSourcesForCompilableFiles(final Project project) { final int projectId = getProjectId(project); + if (isSuspended(projectId)) { + return; + } startAsyncScan(projectId); StartupManager.getInstance(project).runWhenProjectIsInitialized(new Runnable() { public void run() { @@ -1186,11 +1307,21 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { final ProjectRef projRef = new ProjectRef(project); final int projectId = getProjectId(project); + if (CompilerWorkspaceConfiguration.getInstance(project).useCompileServer()) { + suspendProject(project); + } + else { + watchProject(project); + } + conn.subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootListener() { private VirtualFile[] myRootsBefore; private Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, project); public void beforeRootsChange(final ModuleRootEvent event) { + if (isSuspended(projectId)) { + return; + } try { myRootsBefore = ProjectRootManager.getInstance(projRef.get()).getContentSourceRoots(); } @@ -1200,6 +1331,9 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { } public void rootsChanged(final ModuleRootEvent event) { + if (isSuspended(projectId)) { + return; + } try { final VirtualFile[] rootsBefore = myRootsBefore; myRootsBefore = null; @@ -1323,6 +1457,9 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { if (srcInfo != null) { final boolean srcWillBeDeleted = VfsUtil.isAncestor(eventFile, srcFile, false); for (int projectId : srcInfo.getProjectIds().toArray()) { + if (isSuspended(projectId)) { + continue; + } if (srcInfo.isAssociated(projectId, filePath)) { if (srcWillBeDeleted) { if (LOG.isDebugEnabled() || ourDebugMode) { @@ -1351,6 +1488,9 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { deletionProc.setRootBeingDeleted(eventFile); final int sourceFileId = Math.abs(getFileId(file)); for (int projectId : projects.toArray()) { + if (isSuspended(projectId)) { + continue; + } // mark associated outputs for deletion srcInfo.processOutputPaths(projectId, deletionProc); if (LOG.isDebugEnabled() || ourDebugMode) { @@ -1390,7 +1530,15 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { final SourceFileInfo srcInfo = file.isValid()? loadSourceInfo(file) : null; if (srcInfo != null) { for (int projectId : srcInfo.getProjectIds().toArray()) { - addSourceForRecompilation(projectId, file, srcInfo); + if (isSuspended(projectId)) { + if (srcInfo.clearPaths(projectId)) { + srcInfo.updateTimestamp(projectId, -1L); + saveSourceInfo(file, srcInfo); + } + } + else { + addSourceForRecompilation(projectId, file, srcInfo); + } } } else { @@ -1415,8 +1563,11 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { if (!project.isInitialized()) { continue; // the content of this project will be scanned during its post-startup activities } - final ProjectRootManager rootManager = ProjectRootManager.getInstance(project); final int projectId = getProjectId(project); + if (isSuspended(projectId)) { + continue; + } + final ProjectRootManager rootManager = ProjectRootManager.getInstance(project); if (rootManager.getFileIndex().isInSourceContent(file)) { final TranslatingCompiler[] translators = CompilerManager.getInstance(project).getCompilers(TranslatingCompiler.class); processRecursively(file, false, new FileProcessor() { diff --git a/java/compiler/impl/src/com/intellij/compiler/options/CompilerUIConfigurable.java b/java/compiler/impl/src/com/intellij/compiler/options/CompilerUIConfigurable.java index 783925920601..11a36baa4e36 100644 --- a/java/compiler/impl/src/com/intellij/compiler/options/CompilerUIConfigurable.java +++ b/java/compiler/impl/src/com/intellij/compiler/options/CompilerUIConfigurable.java @@ -110,11 +110,14 @@ public class CompilerUIConfigurable implements SearchableConfigurable, Configura applyResourcePatterns(extensionString, (CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject)); // this will schedule for compilation all files that might become compilable after resource patterns' changing - TranslatingCompilerFilesMonitor.getInstance().scanSourcesForCompilableFiles(myProject); + final TranslatingCompilerFilesMonitor monitor = TranslatingCompilerFilesMonitor.getInstance(); if (!workspaceConfiguration.USE_COMPILE_SERVER) { CompileServerManager.getInstance().shutdownServer(); + monitor.watchProject(myProject); + monitor.scanSourcesForCompilableFiles(myProject); } else { + monitor.suspendProject(myProject); SwingUtilities.invokeLater(new Runnable() { public void run() { CompileServerManager.getInstance().sendReloadRequest(myProject); diff --git a/java/compiler/impl/src/com/intellij/compiler/server/CompileServerPlugin.java b/java/compiler/impl/src/com/intellij/compiler/server/CompileServerPlugin.java new file mode 100644 index 000000000000..8a1775d27ab9 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/compiler/server/CompileServerPlugin.java @@ -0,0 +1,37 @@ +package com.intellij.compiler.server; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.extensions.PluginAware; +import com.intellij.openapi.extensions.PluginDescriptor; +import com.intellij.util.xmlb.annotations.Attribute; + +/** + * @author nik + */ +public class CompileServerPlugin implements PluginAware { + public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.compileServer.plugin"); + private PluginDescriptor myPluginDescriptor; + private String myJarPath; + + /** + * Specifies path to a jar file which should be added to the classpath of the compile server. The path is relative to the plugin 'lib' directory. + * In the development node the name of this file without extension is treated as a module name and the output directory of the module is added to the classpath. + */ + @Attribute("jar-path") + public String getJarPath() { + return myJarPath; + } + + public void setJarPath(String jarPath) { + myJarPath = jarPath; + } + + @Override + public final void setPluginDescriptor(PluginDescriptor pluginDescriptor) { + myPluginDescriptor = pluginDescriptor; + } + + public PluginDescriptor getPluginDescriptor() { + return myPluginDescriptor; + } +} diff --git a/java/compiler/impl/src/com/intellij/compiler/server/impl/CompileServerClasspathManager.java b/java/compiler/impl/src/com/intellij/compiler/server/impl/CompileServerClasspathManager.java new file mode 100644 index 000000000000..f1bd0abfc030 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/compiler/server/impl/CompileServerClasspathManager.java @@ -0,0 +1,74 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.compiler.server.impl; + +import com.intellij.compiler.server.CompileServerPlugin; +import com.intellij.ide.plugins.IdeaPluginDescriptor; +import com.intellij.ide.plugins.PluginManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.extensions.PluginId; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.util.PathUtil; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * @author nik + */ +public class CompileServerClasspathManager { + private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.server.impl.CompileServerClasspathManager"); + private List myCompileServerPluginsClasspath; + + public List getCompileServerPluginsClasspath() { + if (myCompileServerPluginsClasspath == null) { + myCompileServerPluginsClasspath = computeCompileServerPluginsClasspath(); + } + return myCompileServerPluginsClasspath; + } + + private static List computeCompileServerPluginsClasspath() { + final List classpath = new ArrayList(); + for (CompileServerPlugin serverPlugin : CompileServerPlugin.EP_NAME.getExtensions()) { + final PluginId pluginId = serverPlugin.getPluginDescriptor().getPluginId(); + final IdeaPluginDescriptor plugin = PluginManager.getPlugin(pluginId); + LOG.assertTrue(plugin != null, pluginId); + final File baseFile = plugin.getPath(); + if (baseFile.isFile()) { + classpath.add(baseFile); + } + else if (baseFile.isDirectory()) { + final String relativePath = serverPlugin.getJarPath(); + File jarFile = new File(new File(baseFile, "lib"), relativePath); + if (jarFile.exists()) { + classpath.add(jarFile); + } + else { + //development mode: add directory out/classes/production/ to classpath, assuming that jar-name is equal to module name + final String moduleName = FileUtil.getNameWithoutExtension(PathUtil.getFileName(relativePath)); + final File dir = new File(baseFile.getParentFile(), moduleName); + if (!dir.exists()) { + LOG.warn("Cannot add plugin " + pluginId + " to compile server classpath: " + jarFile.getAbsolutePath() + " and " + + dir.getAbsolutePath() + " don't exist"); + } + classpath.add(dir); + } + } + } + return classpath; + } +} diff --git a/java/compiler/openapi/src/com/intellij/openapi/compiler/CompilerPaths.java b/java/compiler/openapi/src/com/intellij/openapi/compiler/CompilerPaths.java index 798e2b1d9fa2..7f21c224225f 100644 --- a/java/compiler/openapi/src/com/intellij/openapi/compiler/CompilerPaths.java +++ b/java/compiler/openapi/src/com/intellij/openapi/compiler/CompilerPaths.java @@ -82,6 +82,10 @@ public class CompilerPaths { return new File(getCompilerSystemDirectory(project), ".caches"); } + public static File getRebuildMarkerFile(Project project) { + return new File(getCompilerSystemDirectory(project), "rebuild_required"); + } + /** * @param project * @return a directory under IDEA "system" directory where all files related to compiler subsystem are stored (such as compiler caches or generated files) diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/CompareValueWithClipboardAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/CompareValueWithClipboardAction.java index e415e08eacd4..4f9f6cbdf741 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/CompareValueWithClipboardAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/CompareValueWithClipboardAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,22 +16,20 @@ package com.intellij.debugger.actions; import com.intellij.debugger.DebuggerBundle; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diff.*; import com.intellij.openapi.ide.CopyPasteManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.SystemInfo; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; -/* - * Class SetValueAction +/** * @author Jeka */ public class CompareValueWithClipboardAction extends BaseValueAction { - private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.actions.CompareValueWithClipboardAction"); protected void processText(final Project project, final String text) { DiffManager.getInstance().getDiffTool().show(new ClipboardSelectionContents(text, project)); } @@ -57,10 +55,11 @@ public class CompareValueWithClipboardAction extends BaseValueAction { return !SystemInfo.isMac; } + @NotNull public DiffContent[] getContents() { if (myContents != null) return myContents; DiffContent clipboardContent = createClipboardContent(); - if (clipboardContent == null) return null; + if (clipboardContent == null) clipboardContent = new SimpleContent(""); myContents = new DiffContent[2]; myContents[0] = clipboardContent; diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/CodeFragmentFactoryContextWrapper.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/CodeFragmentFactoryContextWrapper.java index 2afe7c61bd74..4249138bdf29 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/CodeFragmentFactoryContextWrapper.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/CodeFragmentFactoryContextWrapper.java @@ -43,7 +43,7 @@ import java.util.Map; * @author Eugene Zhuravlev * Date: Aug 30, 2010 */ -public class CodeFragmentFactoryContextWrapper implements CodeFragmentFactory{ +public class CodeFragmentFactoryContextWrapper extends CodeFragmentFactory { public static final Key LABEL_VARIABLE_VALUE_KEY = Key.create("_label_variable_value_key_"); public static final String DEBUG_LABEL_SUFFIX = "_DebugLabel"; diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DefaultCodeFragmentFactory.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DefaultCodeFragmentFactory.java index ddefef449570..99a93876bf4e 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DefaultCodeFragmentFactory.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DefaultCodeFragmentFactory.java @@ -41,7 +41,7 @@ import java.util.concurrent.atomic.AtomicReference; * @author Eugene Zhuravlev * Date: Jun 7, 2005 */ -public class DefaultCodeFragmentFactory implements CodeFragmentFactory { +public class DefaultCodeFragmentFactory extends CodeFragmentFactory { private static final class SingletonHolder { public static final DefaultCodeFragmentFactory ourInstance = new DefaultCodeFragmentFactory(); } diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerDataViewsConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerDataViewsConfigurable.java index 0cb9987c79e7..6d5a9bd4b73a 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerDataViewsConfigurable.java +++ b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerDataViewsConfigurable.java @@ -53,6 +53,7 @@ public class DebuggerDataViewsConfigurable implements SearchableConfigurable { private StateRestoringCheckBox myCbShowStaticFinalFields; private final ArrayRendererConfigurable myArrayRendererConfigurable; + private JCheckBox myCbEnableAutoExpressions; private JCheckBox myCbEnableAlternateViews; private JCheckBox myCbEnableToString; @@ -92,6 +93,7 @@ public class DebuggerDataViewsConfigurable implements SearchableConfigurable { myCbShowStatic = new JCheckBox(DebuggerBundle.message("label.base.renderer.configurable.show.static.fields")); myCbShowStaticFinalFields = new StateRestoringCheckBox(DebuggerBundle.message("label.base.renderer.configurable.show.static.final.fields")); myCbEnableAlternateViews = new JCheckBox(DebuggerBundle.message("label.base.renderer.configurable.alternate.view")); + myCbEnableAutoExpressions = new JCheckBox(DebuggerBundle.message("label.base.renderer.configurable.auto.expressions")); myCbShowStatic.addChangeListener(new ChangeListener(){ public void stateChanged(ChangeEvent e) { if(myCbShowStatic.isSelected()) { @@ -163,7 +165,8 @@ public class DebuggerDataViewsConfigurable implements SearchableConfigurable { arraysPanel.setBorder(IdeBorderFactory.createTitledBorder("Arrays", false, true, true)); panel.add(arraysPanel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 3, 1, 1.0, 0.0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0)); - panel.add(myCbEnableAlternateViews, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 10), 0, 0)); + panel.add(myCbEnableAutoExpressions, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 10), 0, 0)); + panel.add(myCbEnableAlternateViews, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(4, 0, 0, 10), 0, 0)); // starting 4-th row panel.add(myCbEnableToString, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 3, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(4, 0, 0, 0), 0, 0)); panel.add(myRbAllThatOverride, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 3, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 12, 0, 0), 0, 0)); @@ -189,6 +192,7 @@ public class DebuggerDataViewsConfigurable implements SearchableConfigurable { generalSettings.AUTOSCROLL_TO_NEW_LOCALS = myCbAutoscroll.isSelected(); rendererSettings.setAlternateCollectionViewsEnabled(myCbEnableAlternateViews.isSelected()); generalSettings.HIDE_NULL_ARRAY_ELEMENTS = myCbHideNullArrayElements.isSelected(); + generalSettings.ENABLE_AUTO_EXPRESSIONS = myCbEnableAutoExpressions.isSelected(); final ClassRenderer classRenderer = rendererSettings.getClassRenderer(); classRenderer.SORT_ASCENDING = myCbSort.isSelected(); @@ -219,6 +223,7 @@ public class DebuggerDataViewsConfigurable implements SearchableConfigurable { myCbAutoscroll.setSelected(generalSettings.AUTOSCROLL_TO_NEW_LOCALS); myCbHideNullArrayElements.setSelected(generalSettings.HIDE_NULL_ARRAY_ELEMENTS); myCbEnableAlternateViews.setSelected(rendererSettings.areAlternateCollectionViewsEnabled()); + myCbEnableAutoExpressions.setSelected(generalSettings.ENABLE_AUTO_EXPRESSIONS); ClassRenderer classRenderer = rendererSettings.getClassRenderer(); @@ -264,6 +269,7 @@ public class DebuggerDataViewsConfigurable implements SearchableConfigurable { ViewsGeneralSettings generalSettings = ViewsGeneralSettings.getInstance(); return (generalSettings.AUTOSCROLL_TO_NEW_LOCALS != myCbAutoscroll.isSelected()) || + (generalSettings.ENABLE_AUTO_EXPRESSIONS != myCbEnableAutoExpressions.isSelected()) || (generalSettings.HIDE_NULL_ARRAY_ELEMENTS != myCbHideNullArrayElements.isSelected()) || myAutoTooltip.isChanged(); } diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/ViewsGeneralSettings.java b/java/debugger/impl/src/com/intellij/debugger/settings/ViewsGeneralSettings.java index 6558a3f97422..21d717b66c7b 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/ViewsGeneralSettings.java +++ b/java/debugger/impl/src/com/intellij/debugger/settings/ViewsGeneralSettings.java @@ -35,6 +35,7 @@ public class ViewsGeneralSettings implements PersistentStateComponent { public boolean SHOW_OBJECTID = true; public boolean HIDE_NULL_ARRAY_ELEMENTS = true; public boolean AUTOSCROLL_TO_NEW_LOCALS = true; + public boolean ENABLE_AUTO_EXPRESSIONS = true; public ViewsGeneralSettings() { } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/ExpressionEvaluationDialog.java b/java/debugger/impl/src/com/intellij/debugger/ui/ExpressionEvaluationDialog.java index eab6dd027d74..7ffde13a2e95 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/ExpressionEvaluationDialog.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/ExpressionEvaluationDialog.java @@ -28,10 +28,14 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CustomShortcutSet; import com.intellij.openapi.help.HelpManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.ui.IdeBorderFactory; +import com.intellij.util.ui.UIUtil; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; import java.awt.event.KeyEvent; public class ExpressionEvaluationDialog extends EvaluationDialog { @@ -77,15 +81,25 @@ public class ExpressionEvaluationDialog extends EvaluationDialog { } protected JComponent createCenterPanel() { - final JPanel panel = new JPanel(new GridBagLayout()); + final JPanel panel = new JPanel(new BorderLayout()); - final JLabel expressionLabel = new JLabel(DebuggerBundle.message("label.evaluate.dialog.expression")); - panel.add(expressionLabel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.BASELINE_LEADING, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0)); - panel.add(getExpressionCombo(), new GridBagConstraints(1, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.BASELINE_LEADING, GridBagConstraints.HORIZONTAL, new Insets(0, 10, 0, 0), 0, 0)); + final JPanel exprPanel = new JPanel(new BorderLayout()); + exprPanel.add(new JLabel(DebuggerBundle.message("label.evaluate.dialog.expression")), BorderLayout.WEST); + exprPanel.add(getExpressionCombo(), BorderLayout.CENTER); + final JLabel help = new JLabel( + String.format("Press Enter to Evaluate or %s+Enter to evaluate and add to the Watches", SystemInfo.isMac ? "Command" : "Control"), SwingConstants.RIGHT); + help.setBorder(IdeBorderFactory.createEmptyBorder(2,0,6,0)); + UIUtil.applyStyle(UIUtil.ComponentStyle.MINI, help); + help.setForeground(UIUtil.getInactiveTextColor()); + exprPanel.add(help, BorderLayout.SOUTH); - final JLabel resultLabel = new JLabel(DebuggerBundle.message("label.evaluate.dialog.result")); - panel.add(resultLabel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(5, 0, 0, 0), 0, 0)); - panel.add(getEvaluationPanel(), new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new Insets(5, 0, 0, 0), 0, 0)); + + final JPanel resultPanel = new JPanel(new BorderLayout()); + //resultPanel.add(new JLabel(DebuggerBundle.message("label.evaluate.dialog.result")), BorderLayout.NORTH); + resultPanel.add(getEvaluationPanel(), BorderLayout.CENTER); + + panel.add(exprPanel, BorderLayout.NORTH); + panel.add(resultPanel, BorderLayout.CENTER); return panel; } @@ -103,6 +117,31 @@ public class ExpressionEvaluationDialog extends EvaluationDialog { return new Action[] { getOKAction(), getCancelAction(), new SwitchAction(), getHelpAction() } ; } + @Override + protected void createDefaultActions() { + super.createDefaultActions(); + myOKAction = new OkAction(){ + @Override + public void actionPerformed(ActionEvent e) { + super.actionPerformed(e); + final int mask = SystemInfo.isMac ? InputEvent.META_MASK : InputEvent.CTRL_MASK; + if ((e.getModifiers() & mask) != 0) { + addCurrentExpressionToWatches(); + } + } + }; + } + + private void addCurrentExpressionToWatches() { + final DebuggerSessionTab tab = DebuggerPanelsManager.getInstance(getProject()).getSessionTab(); + if (tab != null) { + final TextWithImports evaluate = getCodeToEvaluate(); + if (evaluate != null) { + tab.getWatchPanel().getWatchTree().addWatch(evaluate); + } + } + } + protected void doHelpAction() { HelpManager.getInstance().invokeHelp(HelpID.EVALUATE); } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/FramesPanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/FramesPanel.java index bcde86b2c743..79a45ec2c7b1 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/FramesPanel.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/FramesPanel.java @@ -51,8 +51,10 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.ComboBoxWithWidePopup; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.IconLoader; +import com.intellij.ui.CaptionPanel; import com.intellij.ui.PopupHandler; import com.intellij.ui.ScrollPaneFactory; +import com.intellij.ui.border.CustomLineBorder; import com.intellij.ui.components.panels.Wrapper; import com.intellij.util.Alarm; import com.sun.jdi.ObjectCollectedException; @@ -114,6 +116,8 @@ public class FramesPanel extends UpdatableDebuggerView { final ActionToolbar toolbar = createToolbar(); Wrapper threads = new Wrapper(); + CustomLineBorder border = new CustomLineBorder(CaptionPanel.CNT_ACTIVE_COLOR, 0, 0, 1, 0); + threads.setBorder(border); threads.add(toolbar.getComponent(), BorderLayout.EAST); threads.add(myThreadsCombo, BorderLayout.CENTER); add(threads, BorderLayout.NORTH); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/FrameVariablesTree.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/FrameVariablesTree.java index 4cea2454b898..9afbfde4d121 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/FrameVariablesTree.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/FrameVariablesTree.java @@ -128,29 +128,35 @@ public class FrameVariablesTree extends DebuggerTree { return; } try { - final Map visibleVariables = getVisibleVariables(stackDescriptor); - final EvaluationContextImpl evalContext = debuggerContext.createEvaluationContext(); - final Pair, Set> usedVars = - ApplicationManager.getApplication().runReadAction(new Computable, Set>>() { - public Pair, Set> compute() { - return findReferencedVars(visibleVariables.keySet(), sourcePosition, evalContext); - } - }); - // add locals - if (myAutoWatchMode) { - for (String var : usedVars.first) { - final LocalVariableDescriptorImpl descriptor = myNodeManager.getLocalVariableDescriptor(stackDescriptor, visibleVariables.get(var)); - myChildren.add(myNodeManager.createNode(descriptor, evaluationContext)); - } - } - else { + if (!ViewsGeneralSettings.getInstance().ENABLE_AUTO_EXPRESSIONS && !myAutoWatchMode) { + // optimization super.buildVariables(stackDescriptor, evaluationContext); } - // add expressions - final EvaluationContextImpl evalContextCopy = evaluationContext.createEvaluationContext(evaluationContext.getThisObject()); - evalContextCopy.setAutoLoadClasses(false); - for (TextWithImports text : usedVars.second) { - myChildren.add(myNodeManager.createNode(myNodeManager.getWatchItemDescriptor(stackDescriptor, text, null), evalContextCopy)); + else { + final Map visibleVariables = getVisibleVariables(stackDescriptor); + final EvaluationContextImpl evalContext = debuggerContext.createEvaluationContext(); + final Pair, Set> usedVars = + ApplicationManager.getApplication().runReadAction(new Computable, Set>>() { + public Pair, Set> compute() { + return findReferencedVars(visibleVariables.keySet(), sourcePosition, evalContext); + } + }); + // add locals + if (myAutoWatchMode) { + for (String var : usedVars.first) { + final LocalVariableDescriptorImpl descriptor = myNodeManager.getLocalVariableDescriptor(stackDescriptor, visibleVariables.get(var)); + myChildren.add(myNodeManager.createNode(descriptor, evaluationContext)); + } + } + else { + super.buildVariables(stackDescriptor, evaluationContext); + } + // add expressions + final EvaluationContextImpl evalContextCopy = evaluationContext.createEvaluationContext(evaluationContext.getThisObject()); + evalContextCopy.setAutoLoadClasses(false); + for (TextWithImports text : usedVars.second) { + myChildren.add(myNodeManager.createNode(myNodeManager.getWatchItemDescriptor(stackDescriptor, text, null), evalContextCopy)); + } } } catch (EvaluateException e) { @@ -450,6 +456,7 @@ public class FrameVariablesTree extends DebuggerTree { private final Set myVars; private final SourcePosition myPosition; private final EvaluationContextImpl myEvalContext; + private final boolean myCollectExpressions; public VariablesCollector(final Set visibleLocals, final TextRange lineRange, @@ -462,6 +469,7 @@ public class FrameVariablesTree extends DebuggerTree { myVars = vars; myPosition = position; myEvalContext = evalContext; + myCollectExpressions = ViewsGeneralSettings.getInstance().ENABLE_AUTO_EXPRESSIONS; } @Override @@ -473,9 +481,11 @@ public class FrameVariablesTree extends DebuggerTree { @Override public void visitMethodCallExpression(final PsiMethodCallExpression expression) { - final PsiMethod psiMethod = expression.resolveMethod(); - if (psiMethod != null && !DebuggerUtils.hasSideEffectsOrReferencesMissingVars(expression, myVisibleLocals)) { - myExpressions.add(new TextWithImportsImpl(expression)); + if (myCollectExpressions) { + final PsiMethod psiMethod = expression.resolveMethod(); + if (psiMethod != null && !DebuggerUtils.hasSideEffectsOrReferencesMissingVars(expression, myVisibleLocals)) { + myExpressions.add(new TextWithImportsImpl(expression)); + } } super.visitMethodCallExpression(expression); } @@ -487,7 +497,7 @@ public class FrameVariablesTree extends DebuggerTree { if (psiElement instanceof PsiVariable) { final PsiVariable var = (PsiVariable)psiElement; if (var instanceof PsiField) { - if (!DebuggerUtils.hasSideEffectsOrReferencesMissingVars(reference, myVisibleLocals)) { + if (myCollectExpressions && !DebuggerUtils.hasSideEffectsOrReferencesMissingVars(reference, myVisibleLocals)) { /* if (var instanceof PsiEnumConstant && reference.getQualifier() == null) { final PsiClass enumClass = ((PsiEnumConstant)var).getContainingClass(); @@ -532,7 +542,7 @@ public class FrameVariablesTree extends DebuggerTree { @Override public void visitArrayAccessExpression(final PsiArrayAccessExpression expression) { - if (!DebuggerUtils.hasSideEffectsOrReferencesMissingVars(expression, myVisibleLocals)) { + if (myCollectExpressions && !DebuggerUtils.hasSideEffectsOrReferencesMissingVars(expression, myVisibleLocals)) { myExpressions.add(new TextWithImportsImpl(expression)); } super.visitArrayAccessExpression(expression); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/MainWatchPanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/MainWatchPanel.java index 314e360d2442..1674be4a3b11 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/MainWatchPanel.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/MainWatchPanel.java @@ -43,10 +43,10 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; -import com.intellij.ui.AnActionButton; -import com.intellij.ui.AnActionButtonRunnable; -import com.intellij.ui.ListenerUtil; -import com.intellij.ui.ToolbarDecorator; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.ui.*; +import com.intellij.ui.border.CustomLineBorder; +import com.intellij.xdebugger.impl.actions.XDebuggerActions; import javax.swing.*; import java.awt.*; @@ -218,13 +218,20 @@ public class MainWatchPanel extends WatchPanel implements DataProvider { executeAction(DebuggerActions.NEW_WATCH, tree); } }); - // TODO[den]: add "Add to watches action" + // TODO[den]: add "Add to watches action" on Mac + if (!SystemInfo.isMac) { + decorator.addExtraAction(AnActionButton.fromAction(ActionManager.getInstance().getAction(XDebuggerActions.ADD_TO_WATCH))); + } decorator.setRemoveAction(new AnActionButtonRunnable() { @Override public void run(AnActionButton button) { executeAction(DebuggerActions.REMOVE_WATCH, tree); } }); + CustomLineBorder border = new CustomLineBorder(CaptionPanel.CNT_ACTIVE_COLOR, + SystemInfo.isMac ? 1 : 0, 0, + SystemInfo.isMac ? 0 : 1, 0); + decorator.setToolbarBorder(border); final JPanel panel = decorator.createPanel(); panel.setBorder(null); return panel; diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/CodeFragmentFactory.java b/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/CodeFragmentFactory.java index e820d8748ed2..f7ceafc23355 100644 --- a/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/CodeFragmentFactory.java +++ b/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/CodeFragmentFactory.java @@ -22,21 +22,21 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.JavaCodeFragment; import com.intellij.psi.PsiElement; -public interface CodeFragmentFactory { - ExtensionPointName EXTENSION_POINT_NAME = ExtensionPointName.create("com.intellij.debugger.codeFragmentFactory"); +public abstract class CodeFragmentFactory { + public static final ExtensionPointName EXTENSION_POINT_NAME = ExtensionPointName.create("com.intellij.debugger.codeFragmentFactory"); - JavaCodeFragment createCodeFragment(TextWithImports item, PsiElement context, Project project); + public abstract JavaCodeFragment createCodeFragment(TextWithImports item, PsiElement context, Project project); - JavaCodeFragment createPresentationCodeFragment(TextWithImports item, PsiElement context, Project project); + public abstract JavaCodeFragment createPresentationCodeFragment(TextWithImports item, PsiElement context, Project project); - boolean isContextAccepted(PsiElement contextElement); + public abstract boolean isContextAccepted(PsiElement contextElement); - LanguageFileType getFileType(); + public abstract LanguageFileType getFileType(); /** * In case if createCodeFragment returns java code use * com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl#getInstance() * @return builder, which can evaluate expression for your code fragment */ - EvaluatorBuilder getEvaluatorBuilder(); + public abstract EvaluatorBuilder getEvaluatorBuilder(); } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/JavadocOrderRootTypeUIFactory.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/JavadocOrderRootTypeUIFactory.java index 728fd1617933..1ca685dd606b 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/JavadocOrderRootTypeUIFactory.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/JavadocOrderRootTypeUIFactory.java @@ -20,6 +20,8 @@ */ package com.intellij.openapi.roots.ui.configuration.libraryEditor; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CustomShortcutSet; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.projectRoots.JavaSdk; @@ -31,6 +33,10 @@ import com.intellij.openapi.roots.JavadocOrderRootType; import com.intellij.openapi.roots.ui.OrderRootTypeUIFactory; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.ui.AnActionButton; +import com.intellij.ui.AnActionButtonUpdater; +import com.intellij.ui.ToolbarDecorator; +import com.intellij.util.PlatformIcons; import javax.swing.*; @@ -62,12 +68,24 @@ public class JavadocOrderRootTypeUIFactory implements OrderRootTypeUIFactory { } @Override - protected boolean isShowUrlButton() { - return true; + protected void addToolbarButtons(ToolbarDecorator toolbarDecorator) { + AnActionButton specifyUrlButton = new AnActionButton(ProjectBundle.message("sdk.paths.specify.url.button"), PlatformIcons.TABLE_URL) { + @Override + public void actionPerformed(AnActionEvent e) { + onSpecifyUrlButtonClicked(); + } + }; + specifyUrlButton.setShortcut(CustomShortcutSet.fromString("alt S")); + specifyUrlButton.addCustomUpdater(new AnActionButtonUpdater() { + @Override + public boolean isEnabled(AnActionEvent e) { + return myEnabled && !isUrlInserted(); + } + }); + toolbarDecorator.addExtraAction(specifyUrlButton); } - @Override - protected void onSpecifyUrlButtonClicked() { + private void onSpecifyUrlButtonClicked() { VirtualFile virtualFile = Util.showSpecifyJavadocUrlDialog(myPanel, getInitialValue()); if(virtualFile != null){ addElement(virtualFile); diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ModuleProjectStructureElement.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ModuleProjectStructureElement.java index 6f3b39a5893c..bd4dd49ce2f9 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ModuleProjectStructureElement.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ModuleProjectStructureElement.java @@ -32,8 +32,7 @@ public class ModuleProjectStructureElement extends ProjectStructureElement { return myModule; } - @Override - public void check(ProjectStructureProblemsHolder problemsHolder) { + public void checkModulesNames(ProjectStructureProblemsHolder problemsHolder) { final ModifiableModuleModel moduleModel = myContext.getModulesConfigurator().getModuleModel(); final Module[] all = moduleModel.getModules(); if (!ArrayUtil.contains(myModule, all)) { @@ -42,11 +41,17 @@ public class ModuleProjectStructureElement extends ProjectStructureElement { for (Module each : all) { if (each != myModule && myContext.getRealName(each).equals(myContext.getRealName(myModule))) { - problemsHolder.registerProblem(ProjectBundle.message("project.roots.module.duplicate.name.message"), null, ProjectStructureProblemType.error("duplicate-module-name"), createPlace(), + problemsHolder.registerProblem(ProjectBundle.message("project.roots.module.duplicate.name.message"), null, + ProjectStructureProblemType.error("duplicate-module-name"), createPlace(), null); break; } } + } + + @Override + public void check(ProjectStructureProblemsHolder problemsHolder) { + checkModulesNames(problemsHolder); final ModuleRootModel rootModel = myContext.getModulesConfigurator().getRootModel(myModule); if (rootModel == null) return; //already disposed diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureDaemonAnalyzer.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureDaemonAnalyzer.java index 53e1f541d54a..a10dae160a8e 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureDaemonAnalyzer.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureDaemonAnalyzer.java @@ -59,7 +59,7 @@ public class ProjectStructureDaemonAnalyzer implements Disposable { if (LOG.isDebugEnabled()) { LOG.debug("checking " + element); } - element.check(problemsHolder); + ProjectStructureValidator.check(element, problemsHolder); } }.execute(); invokeLater(new Runnable() { diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureValidator.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureValidator.java new file mode 100644 index 000000000000..45505a8645d1 --- /dev/null +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureValidator.java @@ -0,0 +1,41 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.roots.ui.configuration.projectRoot.daemon; + +import com.intellij.openapi.extensions.ExtensionPointName; + +/** + * User: ksafonov + */ +public abstract class ProjectStructureValidator { + + private static final ExtensionPointName EP_NAME = + ExtensionPointName.create("com.intellij.projectStructureValidator"); + + public static void check(ProjectStructureElement element, ProjectStructureProblemsHolder problemsHolder) { + for (ProjectStructureValidator validator : EP_NAME.getExtensions()) { + if (validator.checkElement(element, problemsHolder)) { + return; + } + } + element.check(problemsHolder); + } + + protected boolean checkElement(ProjectStructureElement element, ProjectStructureProblemsHolder problemsHolder) { + return false; + } + +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaChainLookupElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaChainLookupElement.java index df36e2769cbf..83243e975e63 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaChainLookupElement.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaChainLookupElement.java @@ -19,11 +19,13 @@ import com.intellij.codeInsight.lookup.*; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.openapi.editor.Document; import com.intellij.openapi.util.ClassConditionKey; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.util.PsiTreeUtil; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Set; @@ -65,7 +67,16 @@ public class JavaChainLookupElement extends LookupElementDecorator() { + addAllClasses(parameters, parameters.getInvocationCount() <= 1, + JavaCompletionSorting.addJavaSorting(parameters, result).getPrefixMatcher(), new Consumer() { @Override public void consume(LookupElement element) { _result.addElement(element); @@ -68,8 +69,8 @@ public class JavaClassNameCompletionContributor extends CompletionContributor { } public static void addAllClasses(CompletionParameters parameters, - final CompletionResultSet result, final boolean filterByScope, + @NotNull final PrefixMatcher matcher, @NotNull final Consumer consumer) { final PsiElement insertedElement = parameters.getPosition(); @@ -110,7 +111,7 @@ public class JavaClassNameCompletionContributor extends CompletionContributor { } final boolean lookingForAnnotations = PsiJavaPatterns.psiElement().afterLeaf("@").accepts(insertedElement); - AllClassesGetter.processJavaClasses(parameters, result.getPrefixMatcher(), filterByScope, new Consumer() { + AllClassesGetter.processJavaClasses(parameters, matcher, filterByScope, new Consumer() { @Override public void consume(PsiClass psiClass) { if (lookingForAnnotations && !psiClass.isAnnotationType()) return; diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java index 30f5c20fbef8..499040da4f31 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java @@ -106,7 +106,7 @@ public class JavaCompletionContributor extends CompletionContributor { withParent(or(psiElement(PsiResourceVariable.class), psiElement(PsiResourceList.class))))); @Nullable - private static ElementFilter getReferenceFilter(PsiElement position) { + public static ElementFilter getReferenceFilter(PsiElement position) { // Completion after extends in interface, type parameter and implements in class final PsiClass containingClass = PsiTreeUtil.getParentOfType(position, PsiClass.class, false, PsiCodeBlock.class, PsiMethod.class, PsiExpressionList.class, PsiVariable.class); if (containingClass != null && psiElement().afterLeaf(PsiKeyword.EXTENDS, PsiKeyword.IMPLEMENTS, ",", "&").accepts(position)) { @@ -239,7 +239,7 @@ public class JavaCompletionContributor extends CompletionContributor { if (!isClassNamePossible(parameters.getPosition()) || !mayStartClassName(result, parameters.isRelaxedMatching())) return; if (mayShowAllClasses(parameters)) { - JavaClassNameCompletionContributor.addAllClasses(parameters, result, parameters.getInvocationCount() <= 2, new Consumer() { + JavaClassNameCompletionContributor.addAllClasses(parameters, parameters.getInvocationCount() <= 2, result.getPrefixMatcher(), new Consumer() { @Override public void consume(LookupElement element) { if (!inheritors.alreadyProcessed(element)) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java index b803bc1d126d..14fe9f277dd1 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java @@ -346,6 +346,9 @@ public class JavaCompletionUtil { @Nullable private static PsiType getPsiType(final Object o) { + if (o instanceof ResolveResult) { + return getPsiType(((ResolveResult)o).getElement()); + } if (o instanceof PsiVariable) { return ((PsiVariable)o).getType(); } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java index 9dcfb4a9f016..a70318059c7c 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java @@ -15,10 +15,21 @@ */ package com.intellij.codeInsight.completion; +import com.intellij.codeInsight.completion.impl.CamelHumpMatcher; import com.intellij.codeInsight.lookup.AutoCompletionPolicy; import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiJavaCodeReferenceElement; +import com.intellij.psi.PsiReferenceExpression; +import com.intellij.psi.PsiType; +import com.intellij.psi.filters.ElementFilter; +import com.intellij.util.CollectConsumer; import com.intellij.util.Consumer; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Set; + /** * @author peter */ @@ -26,29 +37,87 @@ public class JavaNoVariantsDelegator extends NoVariantsDelegator { @Override protected void delegate(CompletionParameters parameters, CompletionResultSet result, Consumer passResult) { - if (parameters.getCompletionType() == CompletionType.BASIC && - parameters.getInvocationCount() <= 1 && - JavaCompletionContributor.mayStartClassName(result, false) && - JavaCompletionContributor.isClassNamePossible(parameters.getPosition())) { - final ClassByNameMerger merger = new ClassByNameMerger(parameters.getInvocationCount() == 0, result); + if (parameters.getCompletionType() == CompletionType.BASIC) { + PsiElement position = parameters.getPosition(); + if (parameters.getInvocationCount() <= 1 && + JavaCompletionContributor.mayStartClassName(result, false) && + JavaCompletionContributor.isClassNamePossible(position)) { + suggestNonImportedClasses(parameters, result); + return; + } - JavaClassNameCompletionContributor.addAllClasses(parameters, JavaCompletionSorting.addJavaSorting(parameters, result), - true, new Consumer() { - @Override - public void consume(LookupElement element) { - JavaPsiClassReferenceElement classElement = element.as(JavaPsiClassReferenceElement.CLASS_CONDITION_KEY); - if (classElement != null) { - classElement.setAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE); - } + suggestChainedCalls(parameters, result, position); + } - merger.consume(classElement); - } - }); - - merger.finishedClassProcessing(); - - } else if (parameters.getCompletionType() == CompletionType.SMART && parameters.getInvocationCount() == 2) { + if (parameters.getCompletionType() == CompletionType.SMART && parameters.getInvocationCount() == 2) { result.runRemainingContributors(parameters.withInvocationCount(3), passResult); } } + + private static void suggestChainedCalls(CompletionParameters parameters, CompletionResultSet result, PsiElement position) { + PsiElement parent = position.getParent(); + if (!(parent instanceof PsiJavaCodeReferenceElement)) { + return; + } + PsiElement qualifier = ((PsiJavaCodeReferenceElement)parent).getQualifier(); + if (!(qualifier instanceof PsiJavaCodeReferenceElement) || + ((PsiJavaCodeReferenceElement)qualifier).isQualified() || + ((PsiJavaCodeReferenceElement)qualifier).resolve() != null) { + return; + } + + String fullPrefix = position.getContainingFile().getText().substring(parent.getTextRange().getStartOffset(), parameters.getOffset()); + CompletionResultSet qualifiedCollector = result.withPrefixMatcher(fullPrefix); + ElementFilter filter = JavaCompletionContributor.getReferenceFilter(position); + for (LookupElement base : suggestQualifierItems(parameters, (PsiJavaCodeReferenceElement)qualifier, filter)) { + PsiType type = JavaCompletionUtil.getLookupElementType(base); + if (type != null && !PsiType.VOID.equals(type)) { + PsiReferenceExpression ref = ReferenceExpressionCompletionContributor.createMockReference(position, type, base); + for (final LookupElement item : JavaSmartCompletionContributor.completeReference(position, ref, filter, true, true, parameters, + result.getPrefixMatcher())) { + qualifiedCollector.addElement(new JavaChainLookupElement(base, item)); + } + } + } + } + + private static Set suggestQualifierItems(CompletionParameters parameters, + PsiJavaCodeReferenceElement qualifier, + ElementFilter filter) { + String referenceName = qualifier.getReferenceName(); + if (referenceName == null) { + return Collections.emptySet(); + } + + PrefixMatcher qMatcher = new CamelHumpMatcher(referenceName); + Set plainVariants = + JavaSmartCompletionContributor.completeReference(qualifier, qualifier, filter, true, true, parameters, qMatcher); + if (!plainVariants.isEmpty()) { + return plainVariants; + } + + final Set allClasses = new LinkedHashSet(); + JavaClassNameCompletionContributor.addAllClasses(parameters.withPosition(qualifier.getReferenceNameElement(), qualifier.getTextRange().getEndOffset()), + true, qMatcher, new CollectConsumer(allClasses)); + return allClasses; + } + + private static void suggestNonImportedClasses(CompletionParameters parameters, CompletionResultSet result) { + final ClassByNameMerger merger = new ClassByNameMerger(parameters.getInvocationCount() == 0, result); + + JavaClassNameCompletionContributor.addAllClasses(parameters, + true, JavaCompletionSorting.addJavaSorting(parameters, result).getPrefixMatcher(), new Consumer() { + @Override + public void consume(LookupElement element) { + JavaPsiClassReferenceElement classElement = element.as(JavaPsiClassReferenceElement.CLASS_CONDITION_KEY); + if (classElement != null) { + classElement.setAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE); + } + + merger.consume(classElement); + } + }); + + merger.finishedClassProcessing(); + } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java index 649a4ed6e7ff..e4825f5781f2 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java @@ -155,14 +155,15 @@ public class JavaSmartCompletionContributor extends CompletionContributor { final ElementFilter filter = getReferenceFilter(element); if (filter != null) { final List infos = Arrays.asList(getExpectedTypes(parameters)); - for (final LookupElement item : completeReference(element, reference, filter, true, parameters)) { + for (final LookupElement item : completeReference(element, reference, filter, true, false, parameters, result.getPrefixMatcher())) { if (item.getObject() instanceof PsiClass) { result.addElement(decorate(LookupElementDecorator.withInsertHandler((LookupItem)item, ConstructorInsertHandler.SMART_INSTANCE), infos)); } } } else if (INSIDE_TYPECAST_EXPRESSION.accepts(element)) { - for (final LookupElement item : completeReference(element, reference, new GeneratorFilter(AssignableToFilter.class, new CastTypeGetter()), false, parameters)) { + for (final LookupElement item : completeReference(element, reference, new GeneratorFilter(AssignableToFilter.class, new CastTypeGetter()), false, true, parameters, + result.getPrefixMatcher())) { result.addElement(item); } } @@ -182,7 +183,7 @@ public class JavaSmartCompletionContributor extends CompletionContributor { final PsiElement element = parameters.getPosition(); final PsiReference reference = element.getContainingFile().findReferenceAt(parameters.getOffset()); assert reference != null; - for (final LookupElement item : completeReference(element, reference, THROWABLES_FILTER, true, parameters)) { + for (final LookupElement item : completeReference(element, reference, THROWABLES_FILTER, true, false, parameters, result.getPrefixMatcher())) { result.addElement(item); } } @@ -456,7 +457,12 @@ public class JavaSmartCompletionContributor extends CompletionContributor { return ExpectedTypesProvider.getExpectedTypes(expression, true, parameters.getCompletionType() == CompletionType.SMART, false); } - static Set completeReference(final PsiElement element, PsiReference reference, final ElementFilter filter, final boolean acceptClasses, CompletionParameters parameters) { + static Set completeReference(final PsiElement element, + PsiReference reference, + final ElementFilter filter, + final boolean acceptClasses, + final boolean acceptMembers, + CompletionParameters parameters, @Nullable final PrefixMatcher matcher) { if (reference instanceof PsiMultiReference) { reference = ContainerUtil.findInstance(((PsiMultiReference) reference).getReferences(), PsiJavaReference.class); } @@ -470,15 +476,18 @@ public class JavaSmartCompletionContributor extends CompletionContributor { } public boolean isClassAcceptable(Class hintClass) { - if (acceptClasses) { - return ReflectionCache.isAssignable(PsiClass.class, hintClass); + if (ReflectionCache.isAssignable(PsiClass.class, hintClass)) { + return acceptClasses; } - return ReflectionCache.isAssignable(PsiVariable.class, hintClass) || - ReflectionCache.isAssignable(PsiMethod.class, hintClass) || - ReflectionCache.isAssignable(CandidateInfo.class, hintClass); + if (ReflectionCache.isAssignable(PsiVariable.class, hintClass) || + ReflectionCache.isAssignable(PsiMethod.class, hintClass) || + ReflectionCache.isAssignable(CandidateInfo.class, hintClass)) { + return acceptMembers; + } + return false; } - }, true, parameters.getInvocationCount() <= 1, null, parameters); + }, true, parameters.getInvocationCount() <= 1, matcher, parameters); } return Collections.emptySet(); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java index 277188306be0..24aa41aafa2e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java @@ -33,8 +33,11 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.filters.*; import com.intellij.psi.filters.element.ModifierFilter; import com.intellij.psi.filters.types.AssignableFromFilter; +import com.intellij.psi.impl.FakePsiElement; +import com.intellij.psi.impl.light.LightVariableBuilder; import com.intellij.psi.impl.source.PostprocessReformattingAspect; import com.intellij.psi.infos.CandidateInfo; +import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; @@ -122,7 +125,7 @@ public class ReferenceExpressionCompletionContributor { final boolean secondTime = parameters.getParameters().getInvocationCount() >= 2; final Set base = - JavaSmartCompletionContributor.completeReference(element, reference, filter, false, parameters.getParameters()); + JavaSmartCompletionContributor.completeReference(element, reference, filter, false, true, parameters.getParameters(), null); for (final LookupElement item : base) { addSingleArrayElementAccess(element, item, parameters, result); } @@ -177,7 +180,7 @@ public class ReferenceExpressionCompletionContributor { public boolean isClassAcceptable(Class hintClass) { return true; } - }), false, parameters.getParameters()); + }), false, true, parameters.getParameters(), null); for (LookupElement lookupElement : elements) { if (lookupElement.getObject() instanceof PsiMethod) { final JavaMethodCallElement item = lookupElement.as(JavaMethodCallElement.CLASS_CONDITION_KEY); @@ -419,32 +422,43 @@ public class ReferenceExpressionCompletionContributor { final Consumer result, PsiType qualifierType, final PsiType expectedType, JavaSmartCompletionParameters parameters) throws IncorrectOperationException { - final JavaCodeFragmentFactory factory = JavaCodeFragmentFactory.getInstance(place.getProject()); - PsiType varType = qualifierType; - if (varType instanceof PsiEllipsisType) { - varType = ((PsiEllipsisType)varType).getComponentType(); - } - if (varType instanceof PsiWildcardType || varType instanceof PsiCapturedWildcardType) { - varType = TypeConversionUtil.erasure(expectedType); - } - - final String typeText = varType.getCanonicalText(); - final JavaCodeFragment block = factory.createCodeBlockCodeFragment(typeText + " xxx;xxx.xxx;", place, false); - final PsiElement secondChild = block.getChildren()[1]; - if (!(secondChild instanceof PsiExpressionStatement)) { - LOG.error(typeText + " of " + varType.getClass()); - } - final PsiExpressionStatement expressionStatement = (PsiExpressionStatement)secondChild; - final PsiReferenceExpression mockRef = (PsiReferenceExpression) expressionStatement.getExpression(); + final PsiReferenceExpression mockRef = createMockReference(place, qualifierType, qualifierItem); final ElementFilter filter = getReferenceFilter(place, true); for (final LookupElement item : completeFinalReference(place, mockRef, filter, parameters)) { - if (shoudChain(place, varType, expectedType, item)) { + if (shoudChain(place, qualifierType, expectedType, item)) { result.consume(new JavaChainLookupElement(qualifierItem, item)); } } } + public static PsiReferenceExpression createMockReference(final PsiElement place, @NotNull PsiType qualifierType, LookupElement qualifierItem) { + PsiElementFactory factory = JavaPsiFacade.getElementFactory(place.getProject()); + if (qualifierItem.getObject() instanceof PsiClass) { + return (PsiReferenceExpression)factory + .createExpressionFromText(((PsiClass)qualifierItem.getObject()).getQualifiedName() + ".xxx", place); + } + + return (PsiReferenceExpression) factory.createExpressionFromText("xxx.xxx", createContextWithXxxVariable(place, qualifierType)); + } + + public static FakePsiElement createContextWithXxxVariable(final PsiElement place, final PsiType varType) { + return new FakePsiElement() { + @Override + public boolean processDeclarations(@NotNull PsiScopeProcessor processor, + @NotNull ResolveState state, + PsiElement lastParent, + @NotNull PsiElement place) { + return processor.execute(new LightVariableBuilder("xxx", varType, place), ResolveState.initial()); + } + + @Override + public PsiElement getParent() { + return place; + } + }; + } + private static boolean shoudChain(PsiElement element, PsiType qualifierType, PsiType expectedType, LookupElement item) { if (item.getObject() instanceof PsiMethod) { final PsiMethod method = (PsiMethod)item.getObject(); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/PostHighlightingPass.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/PostHighlightingPass.java index 815715a494fa..94249f82e089 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/PostHighlightingPass.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/PostHighlightingPass.java @@ -640,9 +640,9 @@ public class PostHighlightingPass extends TextEditorHighlightingPass { } private static boolean isEnumValuesMethodUsed(PsiMember member, ProgressIndicator progress, GlobalUsageHelper helper) { - final PsiClassImpl containingClass = (PsiClassImpl)member.getContainingClass(); - if (containingClass == null) return true; - final PsiMethod valuesMethod = containingClass.getValuesMethod(); + final PsiClass containingClass = member.getContainingClass(); + if (containingClass == null || !(containingClass instanceof PsiClassImpl)) return true; + final PsiMethod valuesMethod = ((PsiClassImpl)containingClass).getValuesMethod(); if (valuesMethod == null) return true; return isMethodReferenced(valuesMethod, progress, helper); } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateClassFromNewFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateClassFromNewFix.java index 3165e7e01aad..49b37d9b9b2a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateClassFromNewFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateClassFromNewFix.java @@ -89,7 +89,7 @@ public class CreateClassFromNewFix extends CreateFromUsageBaseFix { setupInheritance(newExpression, aClass); PsiExpressionList argList = newExpression.getArgumentList(); - Project project = aClass.getProject(); + final Project project = aClass.getProject(); if (argList != null && argList.getExpressions().length > 0) { PsiMethod constructor = elementFactory.createConstructor(); constructor = (PsiMethod) aClass.add(constructor); @@ -101,14 +101,27 @@ public class CreateClassFromNewFix extends CreateFromUsageBaseFix { getReferenceElement(newExpression).bindToElement(aClass); aClass = CodeInsightUtilBase.forcePsiPostprocessAndRestoreElement(aClass); - Template template = templateBuilder.buildTemplate(); + final Template template = templateBuilder.buildTemplate(); template.setToReformat(true); - Editor editor = positionCursor(project, aClass.getContainingFile(), aClass); - TextRange textRange = aClass.getTextRange(); - editor.getDocument().deleteString(textRange.getStartOffset(), textRange.getEndOffset()); - - startTemplate(editor, template, project, null, getText()); + final Editor editor = positionCursor(project, aClass.getContainingFile(), aClass); + final TextRange textRange = aClass.getTextRange(); + final Runnable runnable = new Runnable() { + public void run() { + new WriteCommandAction(project, getText(), getText()) { + @Override + protected void run(Result result) throws Throwable { + editor.getDocument().deleteString(textRange.getStartOffset(), textRange.getEndOffset()); + } + }.execute(); + startTemplate(editor, template, project, null, getText()); + } + }; + if (ApplicationManager.getApplication().isUnitTestMode()) { + runnable.run(); + } else { + ApplicationManager.getApplication().invokeLater(runnable); + } } else { positionCursor(project, aClass.getContainingFile(), aClass); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFieldFromUsageFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFieldFromUsageFix.java index 59b5b6cd290a..2d4a27faa3c6 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFieldFromUsageFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFieldFromUsageFix.java @@ -52,6 +52,11 @@ public class CreateFieldFromUsageFix extends CreateVarFromUsageFix { return false; } + @Override + protected boolean canBeTargetClass(PsiClass psiClass) { + return super.canBeTargetClass(psiClass) && !psiClass.isInterface() && !psiClass.isAnnotationType(); + } + @Override protected void invokeImpl(final PsiClass targetClass) { final Project project = myReferenceExpression.getProject(); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageBaseFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageBaseFix.java index b8743cc13044..027a045545ca 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageBaseFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageBaseFix.java @@ -130,7 +130,12 @@ public abstract class CreateFromUsageBaseFix extends BaseIntentionAction { int index = list.getSelectedIndex(); if (index < 0) return; final PsiClass aClass = (PsiClass) list.getSelectedValue(); - doInvoke(project, aClass); + CommandProcessor.getInstance().executeCommand(project, new Runnable() { + @Override + public void run() { + doInvoke(project, aClass); + } + }, getText(), null); } }; @@ -321,10 +326,15 @@ public abstract class CreateFromUsageBaseFix extends BaseIntentionAction { return Collections.emptyList(); } - if (!allowOuterClasses || - !isAllowOuterTargetClass() || - ApplicationManager.getApplication().isUnitTestMode()) + if (ApplicationManager.getApplication().isUnitTestMode()) { return Collections.singletonList(psiClass); + } + + if (!allowOuterClasses || !isAllowOuterTargetClass()) { + final ArrayList classes = new ArrayList(); + collectSupers(psiClass, classes); + return classes; + } List result = new ArrayList(); @@ -337,6 +347,21 @@ public abstract class CreateFromUsageBaseFix extends BaseIntentionAction { } } + private void collectSupers(PsiClass psiClass, ArrayList classes) { + classes.add(psiClass); + + final PsiClass[] supers = psiClass.getSupers(); + for (PsiClass aSuper : supers) { + if (canBeTargetClass(aSuper)) { + collectSupers(aSuper, classes); + } + } + } + + protected boolean canBeTargetClass(PsiClass psiClass) { + return psiClass.getManager().isInProject(psiClass); + } + protected static void startTemplate (@NotNull Editor editor, final Template template, @NotNull final Project project) { startTemplate(editor, template, project, null); } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/PullAsAbstractUpFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/PullAsAbstractUpFix.java index 92134363acbf..883c17f21592 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/PullAsAbstractUpFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/PullAsAbstractUpFix.java @@ -122,6 +122,7 @@ public class PullAsAbstractUpFix extends LocalQuickFixAndIntentionActionOnPsiEle } private static void pullUp(PsiMethod method, PsiClass containingClass, PsiClass baseClass) { + if (!CodeInsightUtilBase.prepareFileForWrite(baseClass.getContainingFile())) return; final MemberInfo memberInfo = new MemberInfo(method); memberInfo.setChecked(true); memberInfo.setToAbstract(true); diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java index 21c23437de84..d684041bc68b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java @@ -30,6 +30,7 @@ import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.filters.ClassFilter; import com.intellij.psi.filters.position.SuperParentFilter; import com.intellij.psi.javadoc.PsiDocComment; @@ -146,6 +147,11 @@ public class JavaTypedHandler extends TypedHandlerDelegate { handleAfterJavaLT(editor, JavaTokenType.LT, JavaTokenType.GT, INVALID_INSIDE_REFERENCE); return Result.STOP; } + else if (c == ':') { + if (autoIndentCase(editor, project, file)) { + return Result.STOP; + } + } return Result.CONTINUE; } @@ -283,4 +289,18 @@ public class JavaTypedHandler extends TypedHandlerDelegate { return false; } + + private static boolean autoIndentCase(Editor editor, Project project, PsiFile file) { + int offset = editor.getCaretModel().getOffset(); + PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument()); + PsiElement currElement = file.findElementAt(offset - 1); + if (currElement != null) { + PsiElement parent = currElement.getParent(); + if (parent != null && parent instanceof PsiSwitchLabelStatement) { + CodeStyleManager.getInstance(project).adjustLineIndent(file, parent.getTextOffset()); + return true; + } + } + return false; + } } diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddOnDemandStaticImportAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddOnDemandStaticImportAction.java index 1810ff8cef1b..517f21e8def5 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddOnDemandStaticImportAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddOnDemandStaticImportAction.java @@ -34,6 +34,8 @@ import gnu.trove.TIntProcedure; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.List; + /** * @author ven */ @@ -104,7 +106,7 @@ public class AddOnDemandStaticImportAction extends PsiElementBaseIntentionAction } importList.add(importStaticStatement); - PsiFile[] roots = file.getPsiRoots(); + List roots = file.getViewProvider().getAllFiles(); for (final PsiFile root : roots) { PsiElement copy = root.copy(); final PsiManager manager = root.getManager(); diff --git a/java/java-impl/src/com/intellij/codeInspection/RedundantSuppressInspection.java b/java/java-impl/src/com/intellij/codeInspection/RedundantSuppressInspection.java index f2e52e81a203..e8cecdcef73c 100644 --- a/java/java-impl/src/com/intellij/codeInspection/RedundantSuppressInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/RedundantSuppressInspection.java @@ -40,10 +40,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; +import java.util.*; /** * @author cdr @@ -162,11 +159,25 @@ public class RedundantSuppressInspection extends GlobalInspectionTool{ Collection suppressedTools = new THashSet(); InspectionTool[] tools = getInspectionTools(psiElement, manager); for (Collection ids : suppressedScopes.values()) { - for (String id : ids) { - String shortName = id.trim(); + for (Iterator iterator = ids.iterator(); iterator.hasNext(); ) { + final String shortName = iterator.next().trim(); for (InspectionTool tool : tools) { - if (tool instanceof LocalInspectionToolWrapper && ((LocalInspectionToolWrapper)tool).getTool().getID().equals(shortName) || tool.getShortName().equals(shortName)) { - suppressedTools.add(tool); + if (tool instanceof LocalInspectionToolWrapper && ((LocalInspectionToolWrapper)tool).getTool().getID().equals(shortName)) { + if (!((LocalInspectionToolWrapper)tool).isUnfair()) { + suppressedTools.add(tool); + } else { + iterator.remove(); + break; + } + } + else if (tool.getShortName().equals(shortName)) { + //ignore global unused as it won't be checked anyway + if (!(tool instanceof LocalInspectionToolWrapper) && !(tool instanceof GlobalInspectionToolWrapper)) { + iterator.remove(); + break; + } else { + suppressedTools.add(tool); + } } } } diff --git a/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java b/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java index c1d316ff0914..0b0c60e7395d 100644 --- a/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java +++ b/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java @@ -432,7 +432,7 @@ public class EntryPointsManagerImpl implements PersistentStateComponent myAddNonJavaEntries = addNonJavaEntries; } - public boolean isEntryPoint(PsiModifierListOwner element) { + public boolean isEntryPoint(@NotNull PsiModifierListOwner element) { return AnnotationUtil.isAnnotated(element, ADDITIONAL_ANNOTATIONS) || AnnotationUtil.isAnnotated(element, getAdditionalAnnotations()); } diff --git a/java/java-impl/src/com/intellij/codeInspection/unusedParameters/UnusedParametersInspection.java b/java/java-impl/src/com/intellij/codeInspection/unusedParameters/UnusedParametersInspection.java index aed39b1e7802..2e32ea1a744d 100644 --- a/java/java-impl/src/com/intellij/codeInspection/unusedParameters/UnusedParametersInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/unusedParameters/UnusedParametersInspection.java @@ -74,7 +74,9 @@ public class UnusedParametersInspection extends GlobalJavaInspectionTool { if ((refMethod.isAbstract() || refMethod.getOwnerClass().isInterface()) && refMethod.getDerivedMethods().isEmpty()) return null; if (RefUtil.isEntryPoint(refMethod)) return null; - if (EntryPointsManagerImpl.getInstance(manager.getProject()).isEntryPoint(refMethod.getElement())) return null; + + final PsiModifierListOwner element = refMethod.getElement(); + if (element != null && EntryPointsManagerImpl.getInstance(manager.getProject()).isEntryPoint(element)) return null; if (refMethod.isAppMain()) return null; diff --git a/java/java-impl/src/com/intellij/psi/impl/cache/impl/idCache/JavaFilterLexer.java b/java/java-impl/src/com/intellij/psi/impl/cache/impl/idCache/JavaFilterLexer.java index d803bdaec1c9..4ecc16fc6986 100644 --- a/java/java-impl/src/com/intellij/psi/impl/cache/impl/idCache/JavaFilterLexer.java +++ b/java/java-impl/src/com/intellij/psi/impl/cache/impl/idCache/JavaFilterLexer.java @@ -22,18 +22,37 @@ import com.intellij.psi.impl.cache.impl.OccurrenceConsumer; import com.intellij.psi.impl.source.tree.ElementType; import com.intellij.psi.search.UsageSearchContext; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; /** * @author ven */ public class JavaFilterLexer extends BaseFilterLexer { + private static final TokenSet ourSkipWordsScanSet = TokenSet.orSet( + TokenSet.create( + JavaTokenType.WHITE_SPACE, + JavaTokenType.LPARENTH, + JavaTokenType.RPARENTH, + JavaTokenType.LBRACE, + JavaTokenType.RBRACE, + JavaTokenType.LBRACKET, + JavaTokenType.RBRACKET, + JavaTokenType.SEMICOLON, + JavaTokenType.COMMA, + JavaTokenType.DOT, + JavaTokenType.ELLIPSIS, + JavaTokenType.AT + ), + JavaTokenType.OPERATION_BIT_SET + ); + public JavaFilterLexer(final Lexer originalLexer, final OccurrenceConsumer table) { super(originalLexer, table); } @Override public void advance() { - final IElementType tokenType = getDelegate().getTokenType(); + final IElementType tokenType = myDelegate.getTokenType(); if (tokenType == JavaTokenType.IDENTIFIER || tokenType == JavaTokenType.LONG_LITERAL @@ -48,10 +67,10 @@ public class JavaFilterLexer extends BaseFilterLexer { scanWordsInToken(UsageSearchContext.IN_COMMENTS, false, false); advanceTodoItemCountsInToken(); } - else { + else if (!ourSkipWordsScanSet.contains(tokenType)) { scanWordsInToken(UsageSearchContext.IN_PLAIN_TEXT, false, false); } - getDelegate().advance(); + myDelegate.advance(); } } diff --git a/java/java-impl/src/com/intellij/psi/impl/cache/impl/idCache/JavaIdIndexer.java b/java/java-impl/src/com/intellij/psi/impl/cache/impl/idCache/JavaIdIndexer.java index 8522ed2d8105..1b0898a48e52 100644 --- a/java/java-impl/src/com/intellij/psi/impl/cache/impl/idCache/JavaIdIndexer.java +++ b/java/java-impl/src/com/intellij/psi/impl/cache/impl/idCache/JavaIdIndexer.java @@ -15,13 +15,11 @@ */ package com.intellij.psi.impl.cache.impl.idCache; -import com.intellij.lexer.FilterLexer; import com.intellij.lexer.JavaLexer; import com.intellij.lexer.Lexer; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.impl.cache.impl.OccurrenceConsumer; import com.intellij.psi.impl.cache.impl.id.LexerBasedIdIndexer; -import com.intellij.psi.impl.source.tree.StdTokenSets; public class JavaIdIndexer extends LexerBasedIdIndexer { @Override @@ -31,7 +29,6 @@ public class JavaIdIndexer extends LexerBasedIdIndexer { public static Lexer createIndexingLexer(OccurrenceConsumer consumer) { final JavaLexer javaLexer = new JavaLexer(LanguageLevel.JDK_1_3); - final JavaFilterLexer filterLexer = new JavaFilterLexer(javaLexer, consumer); - return new FilterLexer(filterLexer, new FilterLexer.SetFilter(StdTokenSets.WHITE_SPACE_OR_COMMENT_BIT_SET)); + return new JavaFilterLexer(javaLexer, consumer); } } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/ImportHelper.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/ImportHelper.java index 840947dedf8e..c85b542a0d13 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/ImportHelper.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/ImportHelper.java @@ -696,7 +696,7 @@ public class ImportHelper{ PsiFile context) { String packageName = file.getPackageName(); - final PsiElement[] roots = file.getPsiRoots(); + final List roots = file.getViewProvider().getAllFiles(); for (PsiElement root : roots) { addNamesToImport(names, comments, root, packageName, context); } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java index 1da1f5915186..8e6d81444213 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java @@ -153,7 +153,7 @@ public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager { } else { redundants = allImports; - final PsiElement[] roots = file.getPsiRoots(); + final List roots = file.getViewProvider().getAllFiles(); for (PsiElement root : roots) { root.accept(new JavaRecursiveElementWalkingVisitor() { @Override public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { diff --git a/java/java-impl/src/com/intellij/refactoring/copy/CopyClassesHandler.java b/java/java-impl/src/com/intellij/refactoring/copy/CopyClassesHandler.java index 16768174d072..c0c8328a9820 100644 --- a/java/java-impl/src/com/intellij/refactoring/copy/CopyClassesHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/copy/CopyClassesHandler.java @@ -41,6 +41,7 @@ import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.IOException; import java.util.*; public class CopyClassesHandler extends CopyHandlerDelegateBase { @@ -310,13 +311,14 @@ public class CopyClassesHandler extends CopyHandlerDelegateBase { } } } - final PsiFile[] createdFiles = new PsiFile[fileToClasses.size()]; + final List createdFiles = new ArrayList(fileToClasses.size()); int foIdx = 0; + List files = new ArrayList(); for (final Map.Entry entry : fileToClasses.entrySet()) { - final PsiFile createdFile = copy(entry.getKey(), targetDirectory, copyClassName, map == null ? null : map.get(entry.getKey())); - final PsiClass[] sources = entry.getValue(); - - if (createdFile instanceof PsiClassOwner) { + final PsiFile psiFile = entry.getKey(); + if (psiFile instanceof PsiClassOwner) { + final PsiFile createdFile = copy(psiFile, targetDirectory, copyClassName, map == null ? null : map.get(psiFile)); + final PsiClass[] sources = entry.getValue(); for (final PsiClass destination : ((PsiClassOwner)createdFile).getClasses()) { if (destination instanceof SyntheticElement) { continue; @@ -331,9 +333,24 @@ public class CopyClassesHandler extends CopyHandlerDelegateBase { destination.delete(); } } + createdFiles.add(createdFile); + } else { + files.add(psiFile); } + } - createdFiles[foIdx++] = createdFile; + int[] choice = files.size() > 1 ? new int[]{-1} : null; + for (PsiFile file : files) { + try { + final PsiFile fileCopy = + CopyFilesOrDirectoriesHandler.copyToDirectory(file, getNewFileName(file, copyClassName), targetDirectory, choice); + if (fileCopy != null) { + createdFiles.add(fileCopy); + } + } + catch (IOException e) { + throw new IncorrectOperationException(e.getMessage()); + } } final Set rebindExpressions = new HashSet(); @@ -354,8 +371,8 @@ public class CopyClassesHandler extends CopyHandlerDelegateBase { for (PsiElement expression : rebindExpressions) { codeStyleManager.shortenClassReferences(expression); } - new OptimizeImportsProcessor(project, createdFiles, null).run(); - return newElement != null ? newElement : createdFiles.length > 0 ? createdFiles[0] : null; + new OptimizeImportsProcessor(project, createdFiles.toArray(new PsiFile[createdFiles.size()]), null).run(); + return newElement != null ? newElement : createdFiles.size() > 0 ? createdFiles.get(0) : null; } private static PsiFile copy(@NotNull PsiFile file, PsiDirectory directory, String name, String relativePath) { diff --git a/java/java-impl/src/com/intellij/refactoring/extractInterface/ExtractClassUtil.java b/java/java-impl/src/com/intellij/refactoring/extractInterface/ExtractClassUtil.java index cac66668c83c..30f6d3491c6b 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractInterface/ExtractClassUtil.java +++ b/java/java-impl/src/com/intellij/refactoring/extractInterface/ExtractClassUtil.java @@ -15,15 +15,14 @@ */ package com.intellij.refactoring.extractInterface; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ApplicationNamesInfo; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.SmartPointerManager; import com.intellij.psi.SmartPsiElementPointer; -import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.JavaRefactoringSettings; +import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.turnRefsToSuper.TurnRefsToSuperProcessor; import com.intellij.refactoring.ui.YesNoPreviewUsagesDialog; @@ -36,7 +35,7 @@ public class ExtractClassUtil { final SmartPsiElementPointer interfacePointer = SmartPointerManager.getInstance(project).createSmartPsiElementPointer(aSuperClass); final PsiElement classElement = classPointer.getElement(); final PsiElement interfaceElement = interfacePointer.getElement(); - if (classElement instanceof PsiClass && interfaceElement instanceof PsiClass) { + if (classElement instanceof PsiClass && classElement.isValid() && interfaceElement instanceof PsiClass && interfaceElement.isValid()) { final PsiClass superClass = (PsiClass) interfaceElement; String superClassName = superClass.getName(); String className = ((PsiClass) classElement).getName(); @@ -56,7 +55,7 @@ public class ExtractClassUtil { final boolean isPreviewUsages = dialog.isPreviewUsages(); JavaRefactoringSettings.getInstance().EXTRACT_INTERFACE_PREVIEW_USAGES = isPreviewUsages; TurnRefsToSuperProcessor processor = - new TurnRefsToSuperProcessor(project, (PsiClass) classElement, (PsiClass) interfaceElement, true); + new TurnRefsToSuperProcessor(project, (PsiClass) classElement, superClass, true); processor.setPreviewUsages(isPreviewUsages); processor.run(); } diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java index f1a0966c1dc6..123463734811 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java @@ -509,6 +509,11 @@ public class ExtractMethodProcessor implements MatchProvider { myVariableDatum[i] = myInputVariables.getInputVariables().get(i); } } + + @TestOnly + public void doNotPassParameter(int i) { + myVariableDatum[i].passAsParameter = false; + } /** * Invoked in command and in atomic action @@ -760,6 +765,7 @@ public class ExtractMethodProcessor implements MatchProvider { for (int i = 0, length = myVariableDatum.length; i < length; i++) { ParameterTablePanel.VariableData data = myVariableDatum[i]; + if (!data.passAsParameter) continue; final PsiVariable variable = data.variable; final PsiParameter psiParameter = newMethod.getParameterList().getParameters()[i]; if (!TypeConversionUtil.isAssignable(variable.getType(), psiParameter.getType())) { diff --git a/java/java-impl/src/com/intellij/refactoring/extractSuperclass/JavaExtractSuperBaseDialog.java b/java/java-impl/src/com/intellij/refactoring/extractSuperclass/JavaExtractSuperBaseDialog.java index 2e9b83218969..674b6b16fe65 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractSuperclass/JavaExtractSuperBaseDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/extractSuperclass/JavaExtractSuperBaseDialog.java @@ -125,7 +125,7 @@ public abstract class JavaExtractSuperBaseDialog extends ExtractSuperBaseDialog< protected void preparePackage() throws OperationFailedException { final String targetPackageName = getTargetPackageName(); final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(myProject); - if (!psiFacade.getNameHelper().isIdentifier(targetPackageName)) { + if (!psiFacade.getNameHelper().isQualifiedName(targetPackageName)) { throw new OperationFailedException("Invalid package name: " + targetPackageName); } final PsiPackage aPackage = psiFacade.findPackage(targetPackageName); diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/BaseExpressionToFieldHandler.java b/java/java-impl/src/com/intellij/refactoring/introduceField/BaseExpressionToFieldHandler.java index c628f9454cc5..56a465861857 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/BaseExpressionToFieldHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/BaseExpressionToFieldHandler.java @@ -689,11 +689,11 @@ public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase InitializationPlace initializerPlace = mySettings.getInitializerPlace(); final PsiLocalVariable localVariable = mySettings.getLocalVariable(); final boolean deleteLocalVariable = mySettings.isDeleteLocalVariable(); - @Nullable PsiExpression initializer; + @Nullable PsiExpression initializer = null; if (localVariable != null) { initializer = localVariable.getInitializer(); } - else { + else if (!(mySelectedExpr instanceof PsiReferenceExpression && ((PsiReferenceExpression)mySelectedExpr).resolve() == null)){ initializer = mySelectedExpr; } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/JavaVariableInplaceIntroducer.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/JavaVariableInplaceIntroducer.java index 0ff43fa7f042..400611d56e47 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/JavaVariableInplaceIntroducer.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/JavaVariableInplaceIntroducer.java @@ -45,6 +45,7 @@ import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.util.ArrayList; import java.util.List; /** @@ -85,8 +86,10 @@ public class JavaVariableInplaceIntroducer extends InplaceVariableIntroducer rangeMarkers = new ArrayList(occurrenceMarkers); + rangeMarkers.add(exprMarker); editor.putUserData(ReassignVariableUtil.OCCURRENCES_KEY, - occurrenceMarkers.toArray(new RangeMarker[occurrenceMarkers.size()])); + rangeMarkers.toArray(new RangeMarker[rangeMarkers.size()])); } myExpression = expression; final PsiType defaultType = elementToRename.getType(); diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MultipleRootsMoveDestination.java b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MultipleRootsMoveDestination.java index b24013958510..c27309dd11c1 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MultipleRootsMoveDestination.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MultipleRootsMoveDestination.java @@ -45,7 +45,7 @@ public class MultipleRootsMoveDestination extends AutocreatingMoveDestination { public PsiDirectory getTargetDirectory(PsiDirectory source) throws IncorrectOperationException { - if (JavaDirectoryService.getInstance().isSourceRoot(source)) return null; + //if (JavaDirectoryService.getInstance().isSourceRoot(source)) return null; return getOrCreateDirectoryForSource(source.getVirtualFile()); } diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/JavaMoveFilesOrDirectoriesHandler.java b/java/java-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/JavaMoveFilesOrDirectoriesHandler.java index 370d0e4f271b..c67b7b7b0967 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/JavaMoveFilesOrDirectoriesHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/JavaMoveFilesOrDirectoriesHandler.java @@ -24,6 +24,7 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.impl.file.JavaDirectoryServiceImpl; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.PsiUtilBase; import com.intellij.refactoring.move.MoveCallback; import com.intellij.util.ArrayUtil; @@ -76,9 +77,12 @@ public class JavaMoveFilesOrDirectoriesHandler extends MoveFilesOrDirectoriesHan @Override protected void run(Result result) throws Throwable { final List adjustedElements = new ArrayList(); - for (PsiElement element : elements) { + for (int i = 0, length = elements.length; i < length; i++) { + PsiElement element = elements[i]; if (element instanceof PsiClass) { - final PsiFile containingFile = obtainContainingFile(element, elements); + final PsiClass topLevelClass = PsiUtil.getTopLevelClass(element); + elements[i] = topLevelClass; + final PsiFile containingFile = obtainContainingFile(topLevelClass, elements); if (containingFile != null && !adjustedElements.contains(containingFile)) { adjustedElements.add(containingFile); } diff --git a/java/java-psi-impl/src/com/intellij/core/CoreJavaFileManager.java b/java/java-psi-impl/src/com/intellij/core/CoreJavaFileManager.java index 845339e66d7a..a4a26f9f3f5e 100644 --- a/java/java-psi-impl/src/com/intellij/core/CoreJavaFileManager.java +++ b/java/java-psi-impl/src/com/intellij/core/CoreJavaFileManager.java @@ -31,10 +31,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; +import java.util.*; /** * @author yole @@ -45,6 +42,8 @@ public class CoreJavaFileManager extends PackageIndex implements JavaFileManager private final CoreLocalFileSystem myLocalFileSystem; private final CoreJarFileSystem myJarFileSystem; private final List myClasspath = new ArrayList(); + private VirtualFile[] myClasspathRoots = null; + private final PsiManager myPsiManager; public CoreJavaFileManager(PsiManager psiManager, CoreLocalFileSystem localFileSystem, CoreJarFileSystem jarFileSystem) { @@ -53,6 +52,35 @@ public class CoreJavaFileManager extends PackageIndex implements JavaFileManager myJarFileSystem = jarFileSystem; } + private VirtualFile[] roots() { + VirtualFile[] answer = myClasspathRoots; + + if (answer == null) { + ArrayList answerList = new ArrayList(myClasspath.size()); + for (File root : myClasspath) { + VirtualFile rootVfs = calcRoot(root); + if (rootVfs != null) { + answerList.add(rootVfs); + } + } + + answer = answerList.toArray(new VirtualFile[answerList.size()]); + myClasspathRoots = answer; + } + + return answer; + } + + @Nullable + private VirtualFile calcRoot(File root) { + if (root.isFile()) { + return myJarFileSystem.findFileByPath(root.getPath() + "!/"); + } + else { + return myLocalFileSystem.findFileByPath(root.getPath()); + } + } + @Override public PsiPackage findPackage(@NotNull String packageName) { final List files = findDirectoriesByPackageName(packageName); @@ -65,8 +93,8 @@ public class CoreJavaFileManager extends PackageIndex implements JavaFileManager private List findDirectoriesByPackageName(String packageName) { List result = new ArrayList(); String dirName = packageName.replace(".", "/"); - for (File file : myClasspath) { - VirtualFile classDir = findUnderClasspathEntry(file, dirName); + for (VirtualFile root : roots()) { + VirtualFile classDir = root.findFileByRelativePath(dirName); if (classDir != null) { result.add(classDir); } @@ -85,22 +113,6 @@ public class CoreJavaFileManager extends PackageIndex implements JavaFileManager } return null; } - - @Nullable - private VirtualFile findUnderClasspathEntry(File classpathEntry, String relativeName) { - VirtualFile root = findRootInClassPathEntry(classpathEntry); - return root != null ? root.findFileByRelativePath(relativeName) : null; - } - - @Nullable - private VirtualFile findRootInClassPathEntry(File classpathEntry) { - if (classpathEntry.isFile()) { - return myJarFileSystem.findFileByPath(classpathEntry.getPath() + "!/"); - } - else { - return myLocalFileSystem.findFileByPath(classpathEntry.getPath()); - } - } @Override public VirtualFile[] getDirectoriesByPackageName(@NotNull String packageName, boolean includeLibrarySources) { @@ -114,8 +126,8 @@ public class CoreJavaFileManager extends PackageIndex implements JavaFileManager @Override public PsiClass findClass(@NotNull String qName, @NotNull GlobalSearchScope scope) { - for (File file : myClasspath) { - final PsiClass psiClass = findClassInClasspathEntry(qName, file); + for (VirtualFile root : roots()) { + final PsiClass psiClass = findClassInClasspathRoot(qName, root, myPsiManager); if (psiClass != null) { return psiClass; } @@ -123,14 +135,6 @@ public class CoreJavaFileManager extends PackageIndex implements JavaFileManager return null; } - @Nullable - private PsiClass findClassInClasspathEntry(String qName, File rootEntry) { - VirtualFile root = findRootInClassPathEntry(rootEntry); - if (root == null) return null; - - return findClassInClasspathRoot(qName, root, myPsiManager); - } - @Nullable public static PsiClass findClassInClasspathRoot(String qName, VirtualFile root, PsiManager psiManager) { String pathRest = qName; @@ -201,8 +205,8 @@ public class CoreJavaFileManager extends PackageIndex implements JavaFileManager @Override public PsiClass[] findClasses(@NotNull String qName, @NotNull GlobalSearchScope scope) { List result = new ArrayList(); - for (File file : myClasspath) { - final PsiClass psiClass = findClassInClasspathEntry(qName, file); + for (VirtualFile file : roots()) { + final PsiClass psiClass = findClassInClasspathRoot(qName, file, myPsiManager); if (psiClass != null) { result.add(psiClass); } @@ -221,5 +225,6 @@ public class CoreJavaFileManager extends PackageIndex implements JavaFileManager public void addToClasspath(File path) { myClasspath.add(path); + myClasspathRoots = null; } } diff --git a/java/java-psi-impl/src/com/intellij/lexer/JavaLexer.java b/java/java-psi-impl/src/com/intellij/lexer/JavaLexer.java index e4f4b3d83899..cee9feac4a2d 100644 --- a/java/java-psi-impl/src/com/intellij/lexer/JavaLexer.java +++ b/java/java-psi-impl/src/com/intellij/lexer/JavaLexer.java @@ -196,7 +196,7 @@ public class JavaLexer extends LexerBase { @Override public final IElementType getTokenType() { - locateToken(); + if (myTokenType == null) _locateToken(); return myTokenType; } @@ -208,22 +208,17 @@ public class JavaLexer extends LexerBase { @Override public final int getTokenEnd() { - locateToken(); + if (myTokenType == null) _locateToken(); return myTokenEndOffset; } @Override public final void advance() { - locateToken(); + if (myTokenType == null) _locateToken(); myTokenType = null; } - protected final void locateToken() { - if (myTokenType != null) return; - _locateToken(); - } - private void _locateToken() { if (myTokenEndOffset == myBufferEndOffset) { myTokenType = null; diff --git a/java/java-psi-impl/src/com/intellij/psi/ClassFileViewProviderFactory.java b/java/java-psi-impl/src/com/intellij/psi/ClassFileViewProviderFactory.java index bb7fd8e6d9de..213468b0669f 100644 --- a/java/java-psi-impl/src/com/intellij/psi/ClassFileViewProviderFactory.java +++ b/java/java-psi-impl/src/com/intellij/psi/ClassFileViewProviderFactory.java @@ -23,10 +23,11 @@ import com.intellij.lang.Language; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.fileTypes.ContentBasedFileSubstitutor; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; public class ClassFileViewProviderFactory implements FileViewProviderFactory{ @Override - public FileViewProvider createFileViewProvider(final VirtualFile file, final Language language, final PsiManager manager, final boolean physical) { + public FileViewProvider createFileViewProvider(@NotNull final VirtualFile file, final Language language, @NotNull final PsiManager manager, final boolean physical) { // Define language for compiled file final ContentBasedFileSubstitutor[] processors = Extensions.getExtensions(ContentBasedFileSubstitutor.EP_NAME); for (ContentBasedFileSubstitutor processor : processors) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java index 72de4e653c72..b071cc0053bc 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java @@ -350,8 +350,13 @@ public class StubBuildingVisitor implements ClassVisitor { final String desc, final String signature, final String[] exceptions) { - if ((access & Opcodes.ACC_SYNTHETIC) != 0) return null; - if ((access & Opcodes.ACC_BRIDGE) != 0) return null; + boolean isSynthetic = (access & Opcodes.ACC_SYNTHETIC) != 0; + + // JLS 13.1 says: Any constructs introduced by the compiler that do not have a corresponding construct in the source code + // must be marked as synthetic, except for default constructors and the class initialization method. + // However Scala compiler erroneously generates ACC_BRIDGE instead of ACC_SYNTHETIC flag for in-trait implementation delegation. See IDEA-78649 + if (isSynthetic) return null; + if (SYNTHETIC_CLINIT_METHOD.equals(name)) return null; boolean isDeprecated = (access & Opcodes.ACC_DEPRECATED) != 0; diff --git a/java/java-runtime/src/com/intellij/rt/execution/CommandLineWrapper.java b/java/java-runtime/src/com/intellij/rt/execution/CommandLineWrapper.java index e0b8236b9c72..57567b0a6d84 100644 --- a/java/java-runtime/src/com/intellij/rt/execution/CommandLineWrapper.java +++ b/java/java-runtime/src/com/intellij/rt/execution/CommandLineWrapper.java @@ -32,6 +32,7 @@ import java.util.ArrayList; import java.util.List; public class CommandLineWrapper { + private static final String PREFIX = "-D"; public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException, InstantiationException { @@ -54,9 +55,41 @@ public class CommandLineWrapper { reader.close(); } file.delete(); - String progClass = args[1]; - String[] progArgs = new String[args.length - 2]; - System.arraycopy(args, 2, progArgs, 0, progArgs.length); + + int startArgsIdx = 2; + if (args[1].equals("@vm_params")) { + startArgsIdx = 4; + final File vmParamsFile = new File(args[2]); + final BufferedReader vmParamsReader = new BufferedReader(new FileReader(vmParamsFile)); + try { + while (vmParamsReader.ready()) { + final String vmParam = vmParamsReader.readLine().trim(); + final int eqIdx = vmParam.indexOf("="); + String vmParamName; + String vmParamValue; + + if (eqIdx > -1 && eqIdx < vmParam.length() - 1) { + vmParamName = vmParam.substring(0, eqIdx); + vmParamValue = vmParam.substring(eqIdx + 1); + } else { + vmParamName = vmParam; + vmParamValue = ""; + } + vmParamName = vmParamName.trim(); + if (vmParamName.startsWith(PREFIX)) { + vmParamName = vmParamName.substring(PREFIX.length()); + System.setProperty(vmParamName, vmParamValue); + } + } + } + finally { + vmParamsReader.close(); + } + vmParamsFile.delete(); + } + String progClass = args[startArgsIdx - 1]; + String[] progArgs = new String[args.length - startArgsIdx]; + System.arraycopy(args, startArgsIdx, progArgs, 0, progArgs.length); ClassLoader loader = new URLClassLoader((URL[])urls.toArray(new URL[urls.size()]), null); final String classloader = System.getProperty("java.system.class.loader"); if (classloader != null) { diff --git a/java/java-tests/testData/refactoring/extractMethod/DisabledParam.java b/java/java-tests/testData/refactoring/extractMethod/DisabledParam.java new file mode 100644 index 000000000000..64406a7febeb --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/DisabledParam.java @@ -0,0 +1,6 @@ +class Fest { + public static void main(String[] args) { + String f = ""; + System.out.println(f); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/DisabledParam_after.java b/java/java-tests/testData/refactoring/extractMethod/DisabledParam_after.java new file mode 100644 index 000000000000..c25ade46e4d5 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/DisabledParam_after.java @@ -0,0 +1,11 @@ +class Fest { + public static void main(String[] args) { + String f = ""; + newMethod(); + } + + private static void newMethod() { + String f = ; + System.out.println(f); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/introduceField/afterUnresolvedReferenceToLocalVar.java b/java/java-tests/testData/refactoring/introduceField/afterUnresolvedReferenceToLocalVar.java new file mode 100644 index 000000000000..5dc141e72462 --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceField/afterUnresolvedReferenceToLocalVar.java @@ -0,0 +1,12 @@ +import java.util.ArrayList; + +public class Test +{ + public final ArrayList arrayList; + + public Test() + { + arrayList = new ArrayList(); + } + +} diff --git a/java/java-tests/testData/refactoring/introduceField/beforeUnresolvedReferenceToLocalVar.java b/java/java-tests/testData/refactoring/introduceField/beforeUnresolvedReferenceToLocalVar.java new file mode 100644 index 000000000000..bd34a5d54bd2 --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceField/beforeUnresolvedReferenceToLocalVar.java @@ -0,0 +1,10 @@ +import java.util.ArrayList; + +public class Test +{ + public Test() + { + arrayList = new ArrayList(); + } + +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy index e8b463fa0575..47542b0b1266 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy @@ -750,7 +750,6 @@ class Foo { joinCommit() myFixture.type 'a.' myFixture.checkResult(" class Foo { { int iteraaa; iteraaa. } } ") - assert !lookup } public void testRestartWithInvisibleLookup() { @@ -1216,4 +1215,22 @@ class Foo {{ } } + public void testReturnLParen() { + myFixture.configureByText 'a.java', 'class Foo { int foo() { }}' + type 're(' + myFixture.checkResult 'class Foo { int foo() { re() }}' + } + + public void testAmbiguousClassQualifier() { + myFixture.addClass("package foo; public class Util { public static void foo() {} }") + myFixture.addClass("package bar; public class Util { public static void bar() {} }") + myFixture.configureByText 'a.java', 'class Foo {{ }}' + type 'Util.' + assert myFixture.lookupElementStrings == ['Util.bar', 'Util.foo'] + type 'fo\n' + myFixture.checkResult '''import foo.Util; + +class Foo {{ Util.foo(); }}''' + } + } diff --git a/java/java-tests/testSrc/com/intellij/lang/java/parser/JavaParsingTestCase.java b/java/java-tests/testSrc/com/intellij/lang/java/parser/JavaParsingTestCase.java index bd5c08833ab1..79915cc67295 100644 --- a/java/java-tests/testSrc/com/intellij/lang/java/parser/JavaParsingTestCase.java +++ b/java/java-tests/testSrc/com/intellij/lang/java/parser/JavaParsingTestCase.java @@ -108,7 +108,7 @@ public abstract class JavaParsingTestCase extends ParsingTestCase { myFile = createPsiFile(name, text, parser); myFile.putUserData(PsiUtil.FILE_LANGUAGE_LEVEL_KEY, myLanguageLevel); try { - checkResult(name + ".txt", myFile); + checkResult(name, myFile); } catch (IOException e) { throw new RuntimeException(e); diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/FoldingProcessingOnDocumentModificationTest.java b/java/java-tests/testSrc/com/intellij/openapi/editor/impl/FoldingProcessingOnDocumentModificationTest.java similarity index 97% rename from platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/FoldingProcessingOnDocumentModificationTest.java rename to java/java-tests/testSrc/com/intellij/openapi/editor/impl/FoldingProcessingOnDocumentModificationTest.java index 20c7ccdb4afa..6764d070b20d 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/FoldingProcessingOnDocumentModificationTest.java +++ b/java/java-tests/testSrc/com/intellij/openapi/editor/impl/FoldingProcessingOnDocumentModificationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java index cf4e75003a50..dd534625c829 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java @@ -9,6 +9,7 @@ import com.intellij.psi.PsiExpression; import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; +import com.intellij.refactoring.extractMethod.ExtractMethodHandler; import com.intellij.refactoring.extractMethod.ExtractMethodProcessor; import com.intellij.refactoring.extractMethod.PrepareFailedException; import com.intellij.refactoring.introduceVariable.IntroduceVariableBase; @@ -500,6 +501,16 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { public void testRedundantCast() throws Exception { doTest(); } + + public void testDisabledParam() throws Exception { + final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); + settings.ELSE_ON_NEW_LINE = true; + settings.CATCH_ON_NEW_LINE = myCatchOnNewLine; + configureByFile(BASE_PATH + getTestName(false) + ".java"); + boolean success = performExtractMethod(true, true, getEditor(), getFile(), getProject(), false, 0); + assertTrue(success); + checkResultByFile(BASE_PATH + getTestName(false) + "_after.java"); + } private void doPrepareErrorTest(final String expectedMessage) throws Exception { String expectedError = null; @@ -545,6 +556,17 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { public static boolean performExtractMethod(boolean doRefactor, boolean replaceAllDuplicates, Editor editor, PsiFile file, Project project, final boolean extractChainedConstructor) throws PrepareFailedException, IncorrectOperationException { + return performExtractMethod(doRefactor, replaceAllDuplicates, editor, file, project, extractChainedConstructor, null); + } + + public static boolean performExtractMethod(boolean doRefactor, + boolean replaceAllDuplicates, + Editor editor, + PsiFile file, + Project project, + final boolean extractChainedConstructor, + int... disabledParams) + throws PrepareFailedException, IncorrectOperationException { int startOffset = editor.getSelectionModel().getSelectionStart(); int endOffset = editor.getSelectionModel().getSelectionEnd(); @@ -574,7 +596,13 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { } if (doRefactor) { - processor.testRun(); + processor.testPrepare(); + if (disabledParams != null) { + for (int param : disabledParams) { + processor.doNotPassParameter(param); + } + } + ExtractMethodHandler.run(project, editor, processor); } if (replaceAllDuplicates) { diff --git a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceFieldInSameClassTest.java b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceFieldInSameClassTest.java index dd6e9734be1c..28a6c6ce2c83 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceFieldInSameClassTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceFieldInSameClassTest.java @@ -71,6 +71,12 @@ public class IntroduceFieldInSameClassTest extends LightCodeInsightTestCase { } //------------------------------------------------------------------------------------------------- + public void testUnresolvedReferenceToLocalVar() throws Exception { + configureByFile("/refactoring/introduceField/beforeUnresolvedReferenceToLocalVar.java"); + performRefactoring(BaseExpressionToFieldHandler.InitializationPlace.IN_CURRENT_METHOD, false); + checkResultByFile("/refactoring/introduceField/afterUnresolvedReferenceToLocalVar.java"); + } + private static void performRefactoring(final BaseExpressionToFieldHandler.InitializationPlace initializationPlace, final boolean declareStatic) { new MockIntroduceFieldHandler(initializationPlace, declareStatic).invoke(getProject(), myEditor, myFile, null); } diff --git a/java/testFramework/src/com/intellij/codeInsight/daemon/DaemonAnalyzerTestCase.java b/java/testFramework/src/com/intellij/codeInsight/daemon/DaemonAnalyzerTestCase.java index 968bc4192614..53f1c6b6583e 100644 --- a/java/testFramework/src/com/intellij/codeInsight/daemon/DaemonAnalyzerTestCase.java +++ b/java/testFramework/src/com/intellij/codeInsight/daemon/DaemonAnalyzerTestCase.java @@ -147,6 +147,11 @@ public abstract class DaemonAnalyzerTestCase extends CodeInsightTestCase { @Override public boolean isToolEnabled(HighlightDisplayKey key, PsiElement element) { + return isToolEnabled(key); + } + + @Override + public boolean isToolEnabled(HighlightDisplayKey key) { return key != null && myAvailableTools.containsKey(key.toString()); } diff --git a/jps/.idea/artifacts/jps_gwt.xml b/jps/.idea/artifacts/jps_gwt.xml deleted file mode 100644 index bdd54326be60..000000000000 --- a/jps/.idea/artifacts/jps_gwt.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - $PROJECT_DIR$/out/artifacts - - - - - \ No newline at end of file diff --git a/jps/.idea/artifacts/jps_javaee.xml b/jps/.idea/artifacts/jps_javaee.xml deleted file mode 100644 index 687d1ac5c3c5..000000000000 --- a/jps/.idea/artifacts/jps_javaee.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - $PROJECT_DIR$/out/artifacts - - - - - \ No newline at end of file diff --git a/jps/.idea/artifacts/jps_jpa.xml b/jps/.idea/artifacts/jps_jpa.xml deleted file mode 100644 index 95ed475bb3ce..000000000000 --- a/jps/.idea/artifacts/jps_jpa.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - $PROJECT_DIR$/out/artifacts - - - - - \ No newline at end of file diff --git a/jps/.idea/artifacts/jps_sources.xml b/jps/.idea/artifacts/jps_sources.xml index b9c9e404bca3..2f527656df83 100644 --- a/jps/.idea/artifacts/jps_sources.xml +++ b/jps/.idea/artifacts/jps_sources.xml @@ -3,9 +3,6 @@ $PROJECT_DIR$/out/artifacts - - - diff --git a/jps/jps-builders/proto/gen_proto.sh b/jps/jps-builders/proto/gen_proto.sh new file mode 100755 index 000000000000..0a2ba92d332e --- /dev/null +++ b/jps/jps-builders/proto/gen_proto.sh @@ -0,0 +1,2 @@ +protoc -I=. --java_out=../src javac_remote_proto.proto +protoc -I=. --java_out=../src jps_remote_proto.proto \ No newline at end of file diff --git a/jps/jps-builders/proto/jps_remote_proto.proto b/jps/jps-builders/proto/jps_remote_proto.proto index 4f9cbb27b579..03eabce9567f 100644 --- a/jps/jps-builders/proto/jps_remote_proto.proto +++ b/jps/jps-builders/proto/jps_remote_proto.proto @@ -43,6 +43,7 @@ message Message { optional string project_id = 2; repeated string module_name = 3; repeated string file_path = 4; + repeated string artifact_name = 5; } message ShutdownCommand { @@ -63,7 +64,9 @@ message Message { message GlobalLibrary { required string name = 1; optional string homePath = 2; - repeated string path = 3; + optional string type_name = 3; + optional string additional_data_xml = 4; + repeated string path = 5; } repeated PathVariable path_variable = 1; diff --git a/jps/jps-builders/src/META-INF/services/org.jetbrains.jps.incremental.BuilderService b/jps/jps-builders/src/META-INF/services/org.jetbrains.jps.incremental.BuilderService new file mode 100644 index 000000000000..128f95ade09d --- /dev/null +++ b/jps/jps-builders/src/META-INF/services/org.jetbrains.jps.incremental.BuilderService @@ -0,0 +1 @@ +org.jetbrains.jps.incremental.JavaBuilderService diff --git a/jps/jps-builders/src/org/jetbrains/jps/api/JpsRemoteProto.java b/jps/jps-builders/src/org/jetbrains/jps/api/JpsRemoteProto.java index 42191910cc47..cf6dd424fbba 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/api/JpsRemoteProto.java +++ b/jps/jps-builders/src/org/jetbrains/jps/api/JpsRemoteProto.java @@ -857,6 +857,18 @@ public final class JpsRemoteProto { return filePath_.get(index); } + // repeated string artifact_name = 5; + public static final int ARTIFACT_NAME_FIELD_NUMBER = 5; + private java.util.List artifactName_ = + java.util.Collections.emptyList(); + public java.util.List getArtifactNameList() { + return artifactName_; + } + public int getArtifactNameCount() { return artifactName_.size(); } + public java.lang.String getArtifactName(int index) { + return artifactName_.get(index); + } + private void initFields() { commandType_ = org.jetbrains.jps.api.JpsRemoteProto.Message.Request.CompilationRequest.Type.REBUILD; } @@ -880,6 +892,9 @@ public final class JpsRemoteProto { for (java.lang.String element : getFilePathList()) { output.writeString(4, element); } + for (java.lang.String element : getArtifactNameList()) { + output.writeString(5, element); + } } private int memoizedSerializedSize = -1; @@ -914,6 +929,15 @@ public final class JpsRemoteProto { size += dataSize; size += 1 * getFilePathList().size(); } + { + int dataSize = 0; + for (java.lang.String element : getArtifactNameList()) { + dataSize += com.google.protobuf.CodedOutputStream + .computeStringSizeNoTag(element); + } + size += dataSize; + size += 1 * getArtifactNameList().size(); + } memoizedSerializedSize = size; return size; } @@ -1059,6 +1083,10 @@ public final class JpsRemoteProto { result.filePath_ = java.util.Collections.unmodifiableList(result.filePath_); } + if (result.artifactName_ != java.util.Collections.EMPTY_LIST) { + result.artifactName_ = + java.util.Collections.unmodifiableList(result.artifactName_); + } org.jetbrains.jps.api.JpsRemoteProto.Message.Request.CompilationRequest returnMe = result; result = null; return returnMe; @@ -1084,6 +1112,12 @@ public final class JpsRemoteProto { } result.filePath_.addAll(other.filePath_); } + if (!other.artifactName_.isEmpty()) { + if (result.artifactName_.isEmpty()) { + result.artifactName_ = new java.util.ArrayList(); + } + result.artifactName_.addAll(other.artifactName_); + } return this; } @@ -1122,6 +1156,10 @@ public final class JpsRemoteProto { addFilePath(input.readString()); break; } + case 42: { + addArtifactName(input.readString()); + break; + } } } } @@ -1249,6 +1287,46 @@ public final class JpsRemoteProto { return this; } + // repeated string artifact_name = 5; + public java.util.List getArtifactNameList() { + return java.util.Collections.unmodifiableList(result.artifactName_); + } + public int getArtifactNameCount() { + return result.getArtifactNameCount(); + } + public java.lang.String getArtifactName(int index) { + return result.getArtifactName(index); + } + public Builder setArtifactName(int index, java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + result.artifactName_.set(index, value); + return this; + } + public Builder addArtifactName(java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + if (result.artifactName_.isEmpty()) { + result.artifactName_ = new java.util.ArrayList(); + } + result.artifactName_.add(value); + return this; + } + public Builder addAllArtifactName( + java.lang.Iterable values) { + if (result.artifactName_.isEmpty()) { + result.artifactName_ = new java.util.ArrayList(); + } + super.addAll(values, result.artifactName_); + return this; + } + public Builder clearArtifactName() { + result.artifactName_ = java.util.Collections.emptyList(); + return this; + } + // @@protoc_insertion_point(builder_scope:org.jetbrains.jpsservice.Message.Request.CompilationRequest) } @@ -1908,8 +1986,22 @@ public final class JpsRemoteProto { public boolean hasHomePath() { return hasHomePath; } public java.lang.String getHomePath() { return homePath_; } - // repeated string path = 3; - public static final int PATH_FIELD_NUMBER = 3; + // optional string type_name = 3; + public static final int TYPE_NAME_FIELD_NUMBER = 3; + private boolean hasTypeName; + private java.lang.String typeName_ = ""; + public boolean hasTypeName() { return hasTypeName; } + public java.lang.String getTypeName() { return typeName_; } + + // optional string additional_data_xml = 4; + public static final int ADDITIONAL_DATA_XML_FIELD_NUMBER = 4; + private boolean hasAdditionalDataXml; + private java.lang.String additionalDataXml_ = ""; + public boolean hasAdditionalDataXml() { return hasAdditionalDataXml; } + public java.lang.String getAdditionalDataXml() { return additionalDataXml_; } + + // repeated string path = 5; + public static final int PATH_FIELD_NUMBER = 5; private java.util.List path_ = java.util.Collections.emptyList(); public java.util.List getPathList() { @@ -1936,8 +2028,14 @@ public final class JpsRemoteProto { if (hasHomePath()) { output.writeString(2, getHomePath()); } + if (hasTypeName()) { + output.writeString(3, getTypeName()); + } + if (hasAdditionalDataXml()) { + output.writeString(4, getAdditionalDataXml()); + } for (java.lang.String element : getPathList()) { - output.writeString(3, element); + output.writeString(5, element); } } @@ -1955,6 +2053,14 @@ public final class JpsRemoteProto { size += com.google.protobuf.CodedOutputStream .computeStringSize(2, getHomePath()); } + if (hasTypeName()) { + size += com.google.protobuf.CodedOutputStream + .computeStringSize(3, getTypeName()); + } + if (hasAdditionalDataXml()) { + size += com.google.protobuf.CodedOutputStream + .computeStringSize(4, getAdditionalDataXml()); + } { int dataSize = 0; for (java.lang.String element : getPathList()) { @@ -2118,6 +2224,12 @@ public final class JpsRemoteProto { if (other.hasHomePath()) { setHomePath(other.getHomePath()); } + if (other.hasTypeName()) { + setTypeName(other.getTypeName()); + } + if (other.hasAdditionalDataXml()) { + setAdditionalDataXml(other.getAdditionalDataXml()); + } if (!other.path_.isEmpty()) { if (result.path_.isEmpty()) { result.path_ = new java.util.ArrayList(); @@ -2151,6 +2263,14 @@ public final class JpsRemoteProto { break; } case 26: { + setTypeName(input.readString()); + break; + } + case 34: { + setAdditionalDataXml(input.readString()); + break; + } + case 42: { addPath(input.readString()); break; } @@ -2201,7 +2321,49 @@ public final class JpsRemoteProto { return this; } - // repeated string path = 3; + // optional string type_name = 3; + public boolean hasTypeName() { + return result.hasTypeName(); + } + public java.lang.String getTypeName() { + return result.getTypeName(); + } + public Builder setTypeName(java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + result.hasTypeName = true; + result.typeName_ = value; + return this; + } + public Builder clearTypeName() { + result.hasTypeName = false; + result.typeName_ = getDefaultInstance().getTypeName(); + return this; + } + + // optional string additional_data_xml = 4; + public boolean hasAdditionalDataXml() { + return result.hasAdditionalDataXml(); + } + public java.lang.String getAdditionalDataXml() { + return result.getAdditionalDataXml(); + } + public Builder setAdditionalDataXml(java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + result.hasAdditionalDataXml = true; + result.additionalDataXml_ = value; + return this; + } + public Builder clearAdditionalDataXml() { + result.hasAdditionalDataXml = false; + result.additionalDataXml_ = getDefaultInstance().getAdditionalDataXml(); + return this; + } + + // repeated string path = 5; public java.util.List getPathList() { return java.util.Collections.unmodifiableList(result.path_); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/api/ProtoUtil.java b/jps/jps-builders/src/org/jetbrains/jps/api/ProtoUtil.java index 681baf46a0d8..5df797fd4519 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/api/ProtoUtil.java +++ b/jps/jps-builders/src/org/jetbrains/jps/api/ProtoUtil.java @@ -28,20 +28,23 @@ public class ProtoUtil { return builder.build(); } - public static JpsRemoteProto.Message.Request createMakeRequest(String project, Collection modules) { - return createCompileRequest(JpsRemoteProto.Message.Request.CompilationRequest.Type.MAKE, project, modules, Collections.emptyList()); + public static JpsRemoteProto.Message.Request createMakeRequest(String project, Collection modules, Collection artifacts) { + return createCompileRequest(JpsRemoteProto.Message.Request.CompilationRequest.Type.MAKE, project, modules, artifacts, Collections.emptyList()); } - public static JpsRemoteProto.Message.Request createForceCompileRequest(String project, Collection modules, Collection paths) { - return createCompileRequest(JpsRemoteProto.Message.Request.CompilationRequest.Type.FORCED_COMPILATION, project, modules, paths); + public static JpsRemoteProto.Message.Request createForceCompileRequest(String project, + Collection modules, + Collection artifacts, Collection paths) { + return createCompileRequest(JpsRemoteProto.Message.Request.CompilationRequest.Type.FORCED_COMPILATION, project, modules, artifacts, paths); } public static JpsRemoteProto.Message.Request createRebuildRequest(String project) { - return createCompileRequest(JpsRemoteProto.Message.Request.CompilationRequest.Type.REBUILD, project, Collections.emptyList(), Collections.emptyList()); + return createCompileRequest(JpsRemoteProto.Message.Request.CompilationRequest.Type.REBUILD, project, Collections.emptyList(), + Collections.emptyList(), Collections.emptyList()); } - public static JpsRemoteProto.Message.Request createCleanRequest(String project, Collection modules) { - return createCompileRequest(JpsRemoteProto.Message.Request.CompilationRequest.Type.CLEAN, project, modules, Collections.emptyList()); + public static JpsRemoteProto.Message.Request createCleanRequest(String project, Collection modules, Collection artifacts) { + return createCompileRequest(JpsRemoteProto.Message.Request.CompilationRequest.Type.CLEAN, project, modules, artifacts, Collections.emptyList()); } public static JpsRemoteProto.Message.Request createCancelRequest(UUID compileSessionId) { @@ -50,13 +53,17 @@ public class ProtoUtil { return JpsRemoteProto.Message.Request.newBuilder().setRequestType(JpsRemoteProto.Message.Request.Type.CANCEL_BUILD_COMMAND).setCancelBuildCommand(builder.build()).build(); } - public static JpsRemoteProto.Message.Request createCompileRequest(final JpsRemoteProto.Message.Request.CompilationRequest.Type command, String project, Collection modules, Collection paths) { + public static JpsRemoteProto.Message.Request createCompileRequest(final JpsRemoteProto.Message.Request.CompilationRequest.Type command, String project, Collection modules, + Collection artifacts, Collection paths) { final JpsRemoteProto.Message.Request.CompilationRequest.Builder builder = JpsRemoteProto.Message.Request.CompilationRequest.newBuilder().setCommandType( command); builder.setProjectId(project); if (modules.size() > 0) { builder.addAllModuleName(modules); } + if (artifacts.size() > 0) { + builder.addAllArtifactName(artifacts); + } if (paths.size() > 0) { builder.addAllFilePath(paths); } @@ -107,7 +114,13 @@ public class ProtoUtil { JpsRemoteProto.Message.Request.SetupCommand.GlobalLibrary.newBuilder(); libBuilder.setName(lib.getName()).addAllPath(lib.getPaths()); if (lib instanceof SdkLibrary) { - libBuilder.setHomePath(((SdkLibrary)lib).getHomePath()); + final SdkLibrary sdk = (SdkLibrary)lib; + libBuilder.setHomePath(sdk.getHomePath()); + libBuilder.setTypeName(sdk.getTypeName()); + final String additional = sdk.getAdditionalDataXml(); + if (additional != null) { + libBuilder.setAdditionalDataXml(additional); + } } cmdBuilder.addGlobalLibrary(libBuilder.build()); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/api/SdkLibrary.java b/jps/jps-builders/src/org/jetbrains/jps/api/SdkLibrary.java index 891d87d490d9..8fc12ba8cd10 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/api/SdkLibrary.java +++ b/jps/jps-builders/src/org/jetbrains/jps/api/SdkLibrary.java @@ -1,5 +1,7 @@ package org.jetbrains.jps.api; +import org.jetbrains.annotations.Nullable; + import java.util.List; /** @@ -8,14 +10,32 @@ import java.util.List; */ public class SdkLibrary extends GlobalLibrary { + private final String myTypeName; private final String myHomePath; + @Nullable + private final String myAdditionalDataXml; - public SdkLibrary(String name, String homePath, List paths) { + public SdkLibrary(String name, final String typeName, String homePath, List paths) { + this(name, typeName, homePath, paths, null); + } + + public SdkLibrary(String name, String typeName, String homePath, List paths, @Nullable String additionalDataXml) { super(name, paths); + myTypeName = typeName; myHomePath = homePath; + myAdditionalDataXml = additionalDataXml; + } + + public String getTypeName() { + return myTypeName; } public String getHomePath() { return myHomePath; } + + @Nullable + public String getAdditionalDataXml() { + return myAdditionalDataXml; + } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/client/CompileServerClient.java b/jps/jps-builders/src/org/jetbrains/jps/client/CompileServerClient.java index 474227367a40..139eaa703e74 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/client/CompileServerClient.java +++ b/jps/jps-builders/src/org/jetbrains/jps/client/CompileServerClient.java @@ -27,11 +27,12 @@ public class CompileServerClient extends SimpleProtobufClient modules, Collection paths, JpsServerResponseHandler handler) throws Exception{ + public RequestFuture sendCompileRequest(boolean isMake, String projectId, Collection modules, final Collection artifacts, + Collection paths, JpsServerResponseHandler handler) throws Exception{ checkConnected(); final JpsRemoteProto.Message.Request request = isMake? - ProtoUtil.createMakeRequest(projectId, modules) : - ProtoUtil.createForceCompileRequest(projectId, modules, paths); + ProtoUtil.createMakeRequest(projectId, modules, artifacts) : + ProtoUtil.createForceCompileRequest(projectId, modules, artifacts, paths); return sendRequest(request, handler); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/Builder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/Builder.java index bf1265d0ca4a..aa154c937595 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/Builder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/Builder.java @@ -1,14 +1,13 @@ package org.jetbrains.jps.incremental; /** + * @see ModuleLevelBuilder + * @see ProjectLevelBuilder + * * @author nik */ public abstract class Builder { public abstract String getName(); public abstract String getDescription(); - - public static enum ExitCode { - OK, ABORT, ADDITIONAL_PASS_REQUIRED - } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/BuilderRegistry.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/BuilderRegistry.java index 7956d9210086..62b2c1fd2cb4 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/BuilderRegistry.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/BuilderRegistry.java @@ -1,9 +1,6 @@ package org.jetbrains.jps.incremental; import org.jetbrains.jps.idea.OwnServiceLoader; -import org.jetbrains.jps.incremental.groovy.GroovyBuilder; -import org.jetbrains.jps.incremental.java.JavaBuilder; -import org.jetbrains.jps.incremental.resources.ResourcesBuilder; import java.util.*; import java.util.concurrent.ExecutorService; @@ -37,18 +34,15 @@ public class BuilderRegistry { } }); - final OwnServiceLoader loader = OwnServiceLoader.load(ProjectLevelBuilderService.class); + final OwnServiceLoader loader = OwnServiceLoader.load(BuilderService.class); - for (ProjectLevelBuilderService service : loader) { - myProjectLevelBuilders.add(service.createBuilder()); + for (BuilderService service : loader) { + myProjectLevelBuilders.addAll(service.createProjectLevelBuilders()); + final List moduleLevelBuilders = service.createModuleLevelBuilders(myTasksExecutor); + for (ModuleLevelBuilder builder : moduleLevelBuilders) { + myModuleLevelBuilders.get(builder.getCategory()).add(builder); + } } - // todo: some builder registration mechanism for plugins needed - - myModuleLevelBuilders.get(BuilderCategory.TRANSLATOR).add(new GroovyBuilder(true)); - myModuleLevelBuilders.get(BuilderCategory.TRANSLATOR).add(new JavaBuilder(myTasksExecutor)); - myModuleLevelBuilders.get(BuilderCategory.TRANSLATOR).add(new ResourcesBuilder()); - myModuleLevelBuilders.get(BuilderCategory.TRANSLATOR).add(new GroovyBuilder(false)); - } public int getModuleLevelBuilderCount() { diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/BuilderService.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/BuilderService.java new file mode 100644 index 000000000000..e4df2b9d7a8a --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/BuilderService.java @@ -0,0 +1,22 @@ +package org.jetbrains.jps.incremental; + +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutorService; + +/** + * @author nik + */ +public abstract class BuilderService { + @NotNull + public List createModuleLevelBuilders(ExecutorService executorService) { + return Collections.emptyList(); + } + + @NotNull + public List createProjectLevelBuilders() { + return Collections.emptyList(); + } +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java index baf4d2552cb1..6b1ac2a438ea 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java @@ -15,6 +15,7 @@ import org.jetbrains.jps.incremental.storage.SourceToOutputMapping; import org.jetbrains.jps.incremental.storage.TimestampStorage; import java.io.File; +import java.io.IOException; import java.util.*; /** @@ -80,14 +81,14 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler return myIsProjectRebuild; } - public void markDirty(final File file) throws Exception { + public void markDirty(final File file) throws IOException { final RootDescriptor descriptor = getModuleAndRoot(file); if (descriptor != null) { myFsState.markDirty(file, descriptor, myTsStorage); } } - public void markDirty(final ModuleChunk chunk) throws Exception { + public void markDirty(final ModuleChunk chunk) throws IOException { myFsState.clearContextRoundData(); final Set modules = chunk.getModules(); for (Module module : modules) { @@ -95,7 +96,7 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler } } - public void markDirtyRecursively(ModuleChunk chunk) throws Exception { + public void markDirtyRecursively(ModuleChunk chunk) throws IOException { final Set modules = chunk.getModules(); final Set dirtyModules = new HashSet(modules); @@ -170,7 +171,7 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler myFsState.beforeNextRoundStart(); } - void onChunkBuildComplete(@NotNull ModuleChunk chunk) throws Exception { + void onChunkBuildComplete(@NotNull ModuleChunk chunk) throws IOException { myDataManager.flush(true); try { @@ -225,13 +226,13 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler myDelegateMessageHandler.processMessage(msg); } - public void processFilesToRecompile(ModuleChunk chunk, FileProcessor processor) throws Exception { + public void processFilesToRecompile(ModuleChunk chunk, FileProcessor processor) throws IOException { for (Module module : chunk.getModules()) { myFsState.processFilesToRecompile(this, module, processor); } } - final void ensureFSStateInitialized(ModuleChunk chunk) throws Exception { + final void ensureFSStateInitialized(ModuleChunk chunk) throws IOException { for (Module module : chunk.getModules()) { if (isProjectRebuild()) { markDirtyFiles(module, myTsStorage, true, isCompilingTests() ? DirtyMarkScope.TESTS : DirtyMarkScope.PRODUCTION, null); @@ -252,7 +253,7 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler } } - private void initModuleFSState(Module module) throws Exception { + private void initModuleFSState(Module module) throws IOException { final HashSet currentFiles = new HashSet(); markDirtyFiles(module, myTsStorage, false, isCompilingTests() ? DirtyMarkScope.TESTS : DirtyMarkScope.PRODUCTION, currentFiles); @@ -296,7 +297,7 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler PRODUCTION, TESTS, BOTH } - private void markDirtyFiles(Module module, final TimestampStorage tsStorage, final boolean forceMarkDirty, @NotNull final DirtyMarkScope scope, @Nullable final Set currentFiles) throws Exception { + private void markDirtyFiles(Module module, final TimestampStorage tsStorage, final boolean forceMarkDirty, @NotNull final DirtyMarkScope scope, @Nullable final Set currentFiles) throws IOException { final Set excludes = new HashSet(); for (String excludePath : module.getExcludes()) { excludes.add(new File(excludePath)); @@ -323,7 +324,7 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler } } - private void traverseRecursively(final RootDescriptor rd, final File file, Set excludes, @NotNull final TimestampStorage tsStorage, final boolean forceDirty, @Nullable Set currentFiles) throws Exception { + private void traverseRecursively(final RootDescriptor rd, final File file, Set excludes, @NotNull final TimestampStorage tsStorage, final boolean forceDirty, @Nullable Set currentFiles) throws IOException { if (file.isDirectory()) { if (!PathUtil.isUnder(excludes, file)) { final File[] children = file.listFiles(); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/FSState.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/FSState.java index a2ec11bd1ba7..1c2874f47004 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/FSState.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/FSState.java @@ -9,6 +9,7 @@ import org.jetbrains.jps.ModuleChunk; import org.jetbrains.jps.incremental.storage.TimestampStorage; import java.io.File; +import java.io.IOException; import java.util.*; /** @@ -66,7 +67,7 @@ public class FSState { getDelta(rd.module).clearRecompile(rd.root, rd.isTestRoot); } - public void markDirty(final File file, final RootDescriptor rd, final @Nullable TimestampStorage tsStorage) throws Exception { + public void markDirty(final File file, final RootDescriptor rd, final @Nullable TimestampStorage tsStorage) throws IOException { final FilesDelta roundDelta = myCurrentRoundDelta; if (roundDelta != null) { if (myContextModules.contains(rd.module)) { @@ -83,7 +84,7 @@ public class FSState { /** * @return true if marked something, false otherwise */ - public boolean markAllUpToDate(CompileScope scope, final RootDescriptor rd, final TimestampStorage tsStorage, final long compilationStartStamp) throws Exception { + public boolean markAllUpToDate(CompileScope scope, final RootDescriptor rd, final TimestampStorage tsStorage, final long compilationStartStamp) throws IOException { boolean marked = false; final FilesDelta delta = getDelta(rd.module); final Set files = delta.clearRecompile(rd.root, rd.isTestRoot); @@ -115,7 +116,7 @@ public class FSState { return marked; } - public boolean processFilesToRecompile(CompileContext context, final Module module, final FileProcessor processor) throws Exception { + public boolean processFilesToRecompile(CompileContext context, final Module module, final FileProcessor processor) throws IOException { final FilesDelta lastRoundDelta = myLastRoundDelta; final FilesDelta delta = lastRoundDelta != null? lastRoundDelta : getDelta(module); final Map> data = delta.getSourcesToRecompile(context.isCompilingTests()); @@ -140,7 +141,7 @@ public class FSState { return true; } - public void registerDeleted(final Module module, final File file, final boolean isTest, @Nullable TimestampStorage tsStorage) throws Exception { + public void registerDeleted(final Module module, final File file, final boolean isTest, @Nullable TimestampStorage tsStorage) throws IOException { getDelta(module).addDeleted(file, isTest); if (tsStorage != null) { tsStorage.remove(file); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/FileProcessor.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/FileProcessor.java index b021673496cf..aa2b800c6633 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/FileProcessor.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/FileProcessor.java @@ -3,6 +3,7 @@ package org.jetbrains.jps.incremental; import org.jetbrains.jps.Module; import java.io.File; +import java.io.IOException; /** * @author Eugene Zhuravlev @@ -12,5 +13,5 @@ public interface FileProcessor { /** * @return true if processing should continue, false if should stop */ - boolean apply(Module module, File file, String sourceRoot) throws Exception; + boolean apply(Module module, File file, String sourceRoot) throws IOException; } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/FilesCollector.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/FilesCollector.java index ad0c324e33a1..620bcaf846e0 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/FilesCollector.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/FilesCollector.java @@ -4,6 +4,7 @@ import org.jetbrains.jps.Module; import java.io.File; import java.io.FileFilter; +import java.io.IOException; import java.util.ArrayList; import java.util.Collection; @@ -37,7 +38,7 @@ public class FilesCollector implements FileProcessor{ return myContainer; } - public boolean apply(Module module, File file, String sourceRoot) throws Exception { + public boolean apply(Module module, File file, String sourceRoot) throws IOException { if (myFilter.accept(file)) { myContainer.add(file); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java index 1396d301ac03..1399c69ed651 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java @@ -77,11 +77,13 @@ public class IncProjectBuilder { } catch (ProjectBuildException e) { final Throwable cause = e.getCause(); - if (cause instanceof PersistentEnumerator.CorruptedException || cause instanceof MappingFailedException) { + if (cause instanceof PersistentEnumerator.CorruptedException || cause instanceof MappingFailedException || cause instanceof IOException) { // force rebuild - myMessageDispatcher.processMessage(new CompilerMessage(COMPILE_SERVER_NAME, BuildMessage.Kind.INFO, - "Internal caches are corrupted or have outdated format, forcing project rebuild: " + - e.getMessage())); + myMessageDispatcher.processMessage(new CompilerMessage( + COMPILE_SERVER_NAME, BuildMessage.Kind.INFO, + "Internal caches are corrupted or have outdated format, forcing project rebuild: " + + e.getMessage()) + ); flushContext(context); context = createContext(new AllProjectScope(scope.getProject(), Collections.emptySet(), true), false, true); runBuild(context); @@ -460,7 +462,7 @@ public class IncProjectBuilder { private final Map storageMap = new HashMap(); @Override - public boolean apply(Module module, File file, String sourceRoot) throws Exception { + public boolean apply(Module module, File file, String sourceRoot) throws IOException { SourceToOutputMapping srcToOut = storageMap.get(module); if (srcToOut == null) { srcToOut = dataManager.getSourceToOutputMap(module.getName().toLowerCase(Locale.US), compilingTests); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/JavaBuilderService.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/JavaBuilderService.java new file mode 100644 index 000000000000..9f8bff5fac8c --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/JavaBuilderService.java @@ -0,0 +1,24 @@ +package org.jetbrains.jps.incremental; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.incremental.groovy.GroovyBuilder; +import org.jetbrains.jps.incremental.java.JavaBuilder; +import org.jetbrains.jps.incremental.resources.ResourcesBuilder; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ExecutorService; + +/** + * @author nik + */ +public class JavaBuilderService extends BuilderService { + @NotNull + @Override + public List createModuleLevelBuilders(ExecutorService executorService) { + return Arrays.asList(new GroovyBuilder(true), + new JavaBuilder(executorService), + new ResourcesBuilder(), + new GroovyBuilder(false)); + } +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleLevelBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleLevelBuilder.java index 8fb35f7c1a9a..56c67f167d7f 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleLevelBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleLevelBuilder.java @@ -14,6 +14,8 @@ import java.util.HashSet; import java.util.Set; /** + * Use {@link BuilderService} to register implementations of this class + * * @author Eugene Zhuravlev * Date: 9/17/11 */ @@ -23,12 +25,22 @@ public abstract class ModuleLevelBuilder extends Builder { private static final Key> ALL_AFFECTED_FILES_KEY = Key.create("_all_affected_files_"); private static final Key> ALL_COMPILED_FILES_KEY = Key.create("_all_compiled_files_"); + private final BuilderCategory myCategory; + + protected ModuleLevelBuilder(BuilderCategory category) { + myCategory = category; + } + public static enum ExitCode { OK, ABORT, ADDITIONAL_PASS_REQUIRED, CHUNK_REBUILD_REQUIRED } public abstract ExitCode build(CompileContext context, ModuleChunk chunk) throws ProjectBuildException; + public final BuilderCategory getCategory() { + return myCategory; + } + public void cleanupResources(CompileContext context, ModuleChunk chunk) { ALL_AFFECTED_FILES_KEY.set(context, null); ALL_COMPILED_FILES_KEY.set(context, null); @@ -43,7 +55,7 @@ public abstract class ModuleLevelBuilder extends Builder { * @return true if additional compilation pass is required, false otherwise * @throws Exception */ - public final boolean updateMappings(CompileContext context, final Mappings delta, ModuleChunk chunk, Collection filesToCompile, Collection successfullyCompiled) throws Exception { + public final boolean updateMappings(CompileContext context, final Mappings delta, ModuleChunk chunk, Collection filesToCompile, Collection successfullyCompiled) throws IOException { try { boolean additionalPassRequired = false; @@ -115,7 +127,7 @@ public abstract class ModuleLevelBuilder extends Builder { } } - private static boolean chunkContainsAffectedFiles(CompileContext context, ModuleChunk chunk, final Set affected) throws Exception { + private static boolean chunkContainsAffectedFiles(CompileContext context, ModuleChunk chunk, final Set affected) throws IOException { final Set chunkModules = new HashSet(chunk.getModules()); if (!chunkModules.isEmpty()) { for (File file : affected) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/ProjectLevelBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/ProjectLevelBuilder.java index dadd38cc9928..a3e95a39c409 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/ProjectLevelBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/ProjectLevelBuilder.java @@ -1,6 +1,7 @@ package org.jetbrains.jps.incremental; /** + * Use {@link BuilderService} to register implementations of this class * @author nik */ public abstract class ProjectLevelBuilder extends Builder { diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/ProjectLevelBuilderService.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/ProjectLevelBuilderService.java deleted file mode 100644 index fb6dc5eeda14..000000000000 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/ProjectLevelBuilderService.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.jetbrains.jps.incremental; - -import org.jetbrains.annotations.NotNull; - -/** - * @author nik - */ -public abstract class ProjectLevelBuilderService { - @NotNull - public abstract ProjectLevelBuilder createBuilder(); -} diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderService.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderService.java index 6c4b8b19cd95..9d0622b67b18 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderService.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderService.java @@ -1,16 +1,19 @@ package org.jetbrains.jps.incremental.artifacts; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.incremental.BuilderService; import org.jetbrains.jps.incremental.ProjectLevelBuilder; -import org.jetbrains.jps.incremental.ProjectLevelBuilderService; + +import java.util.Collections; +import java.util.List; /** * @author nik */ -public class ArtifactBuilderService extends ProjectLevelBuilderService { +public class ArtifactBuilderService extends BuilderService { @NotNull @Override - public ProjectLevelBuilder createBuilder() { - return new IncArtifactBuilder(); + public List createProjectLevelBuilders() { + return Collections.singletonList(new IncArtifactBuilder()); } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/ArtifactSourceFilesState.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/ArtifactSourceFilesState.java index 5adc718077ec..c8831e095f5c 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/ArtifactSourceFilesState.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/ArtifactSourceFilesState.java @@ -2,6 +2,7 @@ package org.jetbrains.jps.incremental.artifacts; import com.intellij.openapi.util.io.FileUtil; import com.intellij.util.ArrayUtil; +import org.jetbrains.annotations.NotNull; import org.jetbrains.jps.Project; import org.jetbrains.jps.ProjectPaths; import org.jetbrains.jps.artifacts.Artifact; @@ -37,16 +38,16 @@ public class ArtifactSourceFilesState { public ArtifactSourceFilesState(Artifact artifact, int artifactId, Project project, ModuleRootsIndex rootsIndex, ArtifactSourceTimestampStorage timestampStorage, - File artifactsDataDir) { + File mappingsDir) { myProject = project; myArtifact = artifact; myRootsIndex = rootsIndex; myTimestampStorage = timestampStorage; myArtifactId = artifactId; - myMappingsFile = new File(artifactsDataDir, "mappings" + File.separator + artifactId); + myMappingsFile = new File(mappingsDir, String.valueOf(artifactId)); } - public ArtifactSourceToOutputMapping getOrCreateMapping() throws Exception { + public ArtifactSourceToOutputMapping getOrCreateMapping() throws IOException { if (myMapping == null) { myMapping = new ArtifactSourceToOutputMapping(myMappingsFile); } @@ -67,7 +68,7 @@ public class ArtifactSourceFilesState { return myDeletedFiles; } - public void initState() throws Exception { + public void initState() throws IOException { /* if (!myInitialized.compareAndSet(false, true)) { return; @@ -79,7 +80,7 @@ public class ArtifactSourceFilesState { myDeletedFiles.clear(); getOrCreateInstructions().processRoots(new ArtifactRootProcessor() { @Override - public void process(ArtifactSourceRoot root, Collection destinations) throws Exception { + public void process(ArtifactSourceRoot root, Collection destinations) throws IOException { final File rootFile = root.getRootFile(); if (rootFile.exists()) { processRecursively(rootFile, root.getFilter(), currentPaths); @@ -100,7 +101,7 @@ public class ArtifactSourceFilesState { return myTimestampStorage; } - private void processRecursively(File file, SourceFileFilter filter, Set currentPaths) throws Exception { + private void processRecursively(File file, SourceFileFilter filter, Set currentPaths) throws IOException { final String filePath = FileUtil.toSystemIndependentName(FileUtil.toCanonicalPath(file.getPath())); if (!filter.accept(filePath)) return; @@ -147,7 +148,7 @@ public class ArtifactSourceFilesState { return instructionsBuilder; } - public void updateTimestamps(Set deletedFiles, Set changedFiles) throws Exception { + public void updateTimestamps(Set deletedFiles, Set changedFiles) throws IOException { for (String filePath : deletedFiles) { final ArtifactSourceTimestampStorage.PerArtifactTimestamp[] state = myTimestampStorage.getState(filePath); if (state == null) continue; @@ -161,20 +162,29 @@ public class ArtifactSourceFilesState { } for (String filePath : changedFiles) { final ArtifactSourceTimestampStorage.PerArtifactTimestamp[] state = myTimestampStorage.getState(filePath); - if (state == null) continue; - for (int i = 0, length = state.length; i < length; i++) { - if (state[i].myArtifactId == myArtifactId) { - File file = new File(FileUtil.toSystemDependentName(filePath)); - state[i] = new ArtifactSourceTimestampStorage.PerArtifactTimestamp(myArtifactId, file.lastModified()); - myTimestampStorage.update(filePath, state); - break; - } - } + File file = new File(FileUtil.toSystemDependentName(filePath)); + final long timestamp = file.lastModified(); + myTimestampStorage.update(filePath, updateTimestamp(state, timestamp)); } myDeletedFiles.clear(); myChangedFiles.clear(); } + @NotNull + private ArtifactSourceTimestampStorage.PerArtifactTimestamp[] updateTimestamp(ArtifactSourceTimestampStorage.PerArtifactTimestamp[] oldState, long timestamp) { + final ArtifactSourceTimestampStorage.PerArtifactTimestamp newItem = new ArtifactSourceTimestampStorage.PerArtifactTimestamp(myArtifactId, timestamp); + if (oldState == null) { + return new ArtifactSourceTimestampStorage.PerArtifactTimestamp[]{newItem}; + } + for (int i = 0, length = oldState.length; i < length; i++) { + if (oldState[i].myArtifactId == myArtifactId) { + oldState[i] = newItem; + return oldState; + } + } + return ArrayUtil.append(oldState, newItem); + } + public void close() throws IOException { if (myMapping != null) { myMapping.close(); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/ArtifactSourceTimestampStorage.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/ArtifactSourceTimestampStorage.java index 8f5bab766b6c..e0e903c0f5f9 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/ArtifactSourceTimestampStorage.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/ArtifactSourceTimestampStorage.java @@ -37,11 +37,11 @@ public class ArtifactSourceTimestampStorage extends AbstractStateStorage(); myPersistentData = new ArtifactCompilerPersistentData(artifactsDataDir); + myMappingsDir = new File(myArtifactsDataDir, "mappings"); } public ArtifactSourceFilesState getOrCreateState(Artifact artifact, Project project, ModuleRootsIndex index) { ArtifactSourceFilesState state = myArtifactState.get(artifact); if (state == null) { final int artifactId = myPersistentData.getId(artifact.getName()); - state = new ArtifactSourceFilesState(artifact, artifactId, project, index, myTimestampStorage, myArtifactsDataDir); + state = new ArtifactSourceFilesState(artifact, artifactId, project, index, myTimestampStorage, myMappingsDir); myArtifactState.put(artifact, state); } return state; @@ -42,7 +44,8 @@ public class ArtifactsBuildData { for (ArtifactSourceFilesState state : myArtifactState.values()) { state.clean(); } - FileUtil.delete(myArtifactsDataDir); + myArtifactState.clear(); + FileUtil.delete(myMappingsDir); } public void close() throws IOException { diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/IncArtifactBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/IncArtifactBuilder.java index 6ca0a195981d..83a60f1cda2b 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/IncArtifactBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/IncArtifactBuilder.java @@ -6,7 +6,6 @@ import com.intellij.util.ArrayUtil; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashSet; -import org.jetbrains.jps.PathUtil; import org.jetbrains.jps.artifacts.Artifact; import org.jetbrains.jps.incremental.CompileContext; import org.jetbrains.jps.incremental.ProjectBuildException; @@ -94,10 +93,10 @@ public class IncArtifactBuilder extends ProjectLevelBuilder { final List outputs = new SmartList(); instructions.processContainingRoots(filePath, new ArtifactRootProcessor() { @Override - public void process(ArtifactSourceRoot root, Collection destinations) throws Exception { + public void process(ArtifactSourceRoot root, Collection destinations) throws IOException { for (DestinationInfo destination : destinations) { if (destination instanceof ExplodedDestinationInfo) { - copyFromRoot(root, filePath, destination.getOutputPath(), outputs); + root.copyFromRoot(filePath, destination.getOutputPath(), outputs); } else { outputs.add(destination.getOutputFilePath()); @@ -121,33 +120,13 @@ public class IncArtifactBuilder extends ProjectLevelBuilder { } context.processMessage(UptoDateFilesSavedEvent.INSTANCE); } - catch (Exception e) { + catch (IOException e) { throw new ProjectBuildException(e); } } - private static void copyFromRoot(ArtifactSourceRoot root, String path, String outputPath, List outputs) throws IOException { - if (root instanceof FileBasedArtifactSourceRoot) { - final File file = new File(FileUtil.toSystemDependentName(path)); - String targetPath; - if (!file.equals(root.getRootFile())) { - final String relativePath = FileUtil.getRelativePath(FileUtil.toSystemIndependentName(root.getRootFile().getPath()), path, '/'); - targetPath = PathUtil.appendToPath(outputPath, relativePath); - } - else { - targetPath = outputPath; - } - final File targetFile = new File(FileUtil.toSystemDependentName(targetPath)); - FileUtil.copyContent(file, targetFile); - outputs.add(outputPath); - } - else { - //todo[nik] - } - } - private static Set deleteOutdatedFiles(Set deletedFiles, CompileContext context, - ArtifactSourceToOutputMapping mapping) throws Exception { + ArtifactSourceToOutputMapping mapping) throws IOException { if (deletedFiles.isEmpty()) return Collections.emptySet(); context.processMessage(new ProgressMessage("Deleting outdated files...")); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/impl/JarsBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/impl/JarsBuilder.java index 4b570e9717c6..1aa7c878c77c 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/impl/JarsBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/impl/JarsBuilder.java @@ -29,6 +29,7 @@ import gnu.trove.THashSet; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.PathUtil; import org.jetbrains.jps.incremental.CompileContext; import org.jetbrains.jps.incremental.artifacts.IncArtifactBuilder; import org.jetbrains.jps.incremental.artifacts.instructions.*; @@ -182,22 +183,29 @@ public class JarsBuilder { } } - private void extractFileAndAddToJar(JarOutputStream jarOutputStream, JarBasedArtifactSourceRoot root, String relativePath, THashSet writtenPaths) + private static void extractFileAndAddToJar(final JarOutputStream jarOutputStream, final JarBasedArtifactSourceRoot root, + final String relativeOutputPath, final THashSet writtenPaths) throws IOException { - //todo[nik] - /* - relativePath = addParentDirectories(jarOutputStream, writtenPaths, relativePath); - if (!writtenPaths.add(relativePath)) return; + final long timestamp = root.getRootFile().lastModified(); + root.processEntries(new JarBasedArtifactSourceRoot.EntryProcessor() { + @Override + public void process(@Nullable InputStream inputStream, @NotNull String relativePath) throws IOException { + String pathInJar = addParentDirectories(jarOutputStream, writtenPaths, PathUtil.appendToPath(relativeOutputPath, relativePath)); + if (!writtenPaths.add(pathInJar)) return; - final BufferedInputStream input = ArtifactCompilerUtil.getJarEntryInputStream(root, myContext); - if (input == null) return; + if (inputStream != null) { + ZipEntry entry = new ZipEntry(pathInJar); + entry.setTime(timestamp); + jarOutputStream.putNextEntry(entry); + FileUtil.copy(inputStream, jarOutputStream); + jarOutputStream.closeEntry(); + } + else { + addDirectoryEntry(jarOutputStream, pathInJar + "/"); + } + } + }); - ZipEntry entry = new ZipEntry(relativePath); - entry.setTime(root.getRootFile().lastModified()); - jarOutputStream.putNextEntry(entry); - FileUtil.copy(input, jarOutputStream); - jarOutputStream.closeEntry(); - */ } private void addFileToJar(final @NotNull JarOutputStream jarOutputStream, final @NotNull File jarFile, @NotNull File file, @@ -218,7 +226,7 @@ public class JarsBuilder { while (i != -1) { String prefix = relativePath.substring(0, i+1); if (!writtenPaths.contains(prefix) && prefix.length() > 1) { - addEntry(jarOutputStream, prefix); + addDirectoryEntry(jarOutputStream, prefix); writtenPaths.add(prefix); } i = relativePath.indexOf('/', i + 1); @@ -226,7 +234,7 @@ public class JarsBuilder { return relativePath; } - private static void addEntry(final ZipOutputStream output, @NonNls final String relativePath) throws IOException { + private static void addDirectoryEntry(final ZipOutputStream output, @NonNls final String relativePath) throws IOException { ZipEntry e = new ZipEntry(relativePath); e.setMethod(ZipEntry.STORED); e.setSize(0); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/instructions/ArtifactInstructionsBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/instructions/ArtifactInstructionsBuilder.java index 990c62f9d043..4f2a935ecbc0 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/instructions/ArtifactInstructionsBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/instructions/ArtifactInstructionsBuilder.java @@ -2,13 +2,15 @@ package org.jetbrains.jps.incremental.artifacts.instructions; import org.jetbrains.annotations.Nullable; +import java.io.IOException; + /** * @author nik */ public interface ArtifactInstructionsBuilder { - void processRoots(ArtifactRootProcessor processor) throws Exception; + void processRoots(ArtifactRootProcessor processor) throws IOException; - void processContainingRoots(String filePath, ArtifactRootProcessor processor) throws Exception; + void processContainingRoots(String filePath, ArtifactRootProcessor processor) throws IOException; @Nullable JarInfo getJarInfo(String outputPath); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/instructions/ArtifactInstructionsBuilderImpl.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/instructions/ArtifactInstructionsBuilderImpl.java index 32aa1ffe4568..affd9f3a097f 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/instructions/ArtifactInstructionsBuilderImpl.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/instructions/ArtifactInstructionsBuilderImpl.java @@ -7,6 +7,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.incremental.ModuleRootsIndex; import java.io.File; +import java.io.IOException; import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -46,17 +47,17 @@ public class ArtifactInstructionsBuilderImpl implements ArtifactInstructionsBuil public boolean checkOutputPath(final String outputPath, final ArtifactSourceRoot sourceFile) { //todo[nik] combine intersecting roots - ArtifactSourceRoot old = mySourceByOutput.get(outputPath); - if (old == null) { - mySourceByOutput.put(outputPath, sourceFile); - return true; - } + //ArtifactSourceRoot old = mySourceByOutput.get(outputPath); + //if (old == null) { + // mySourceByOutput.put(outputPath, sourceFile); + // return true; + //} //todo[nik] show warning? - return false; + return true; } public boolean registerJarFile(@NotNull JarInfo jarInfo, @NotNull String outputPath) { - if (mySourceByOutput.containsKey(outputPath) || myJarByPath.containsKey(outputPath)) { + if (myJarByPath.containsKey(outputPath)) { return false; } myJarByPath.put(outputPath, jarInfo); @@ -70,14 +71,14 @@ public class ArtifactInstructionsBuilderImpl implements ArtifactInstructionsBuil } @Override - public void processRoots(ArtifactRootProcessor processor) throws Exception { + public void processRoots(ArtifactRootProcessor processor) throws IOException { for (Map.Entry> entry : myInstructions.entrySet()) { processor.process(entry.getKey(), entry.getValue()); } } @Override - public void processContainingRoots(String filePath, ArtifactRootProcessor processor) throws Exception { + public void processContainingRoots(String filePath, ArtifactRootProcessor processor) throws IOException { //todo[nik] improve? for (Map.Entry> entry : myInstructions.entrySet()) { final ArtifactSourceRoot root = entry.getKey(); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/instructions/ArtifactRootProcessor.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/instructions/ArtifactRootProcessor.java index c90152dff468..2d048dfbfeeb 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/instructions/ArtifactRootProcessor.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/instructions/ArtifactRootProcessor.java @@ -1,10 +1,11 @@ package org.jetbrains.jps.incremental.artifacts.instructions; +import java.io.IOException; import java.util.Collection; /** * @author nik */ public interface ArtifactRootProcessor { - void process(ArtifactSourceRoot root, Collection destinations) throws Exception; + void process(ArtifactSourceRoot root, Collection destinations) throws IOException; } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/instructions/ArtifactSourceRoot.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/instructions/ArtifactSourceRoot.java index b0bbf9e79d51..5f57da302b7d 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/instructions/ArtifactSourceRoot.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/instructions/ArtifactSourceRoot.java @@ -3,6 +3,8 @@ package org.jetbrains.jps.incremental.artifacts.instructions; import org.jetbrains.annotations.NotNull; import java.io.File; +import java.io.IOException; +import java.util.List; /** * @author nik @@ -19,6 +21,8 @@ public abstract class ArtifactSourceRoot { public abstract boolean containsFile(String filePath); + public abstract void copyFromRoot(String filePath, String outputPath, List outputs) throws IOException; + public SourceFileFilter getFilter() { return myFilter; } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/instructions/FileBasedArtifactSourceRoot.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/instructions/FileBasedArtifactSourceRoot.java index 51df48f08dd8..e07e0305c3e9 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/instructions/FileBasedArtifactSourceRoot.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/instructions/FileBasedArtifactSourceRoot.java @@ -2,8 +2,11 @@ package org.jetbrains.jps.incremental.artifacts.instructions; import com.intellij.openapi.util.io.FileUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.PathUtil; import java.io.File; +import java.io.IOException; +import java.util.List; /** * @author nik @@ -36,8 +39,28 @@ public class FileBasedArtifactSourceRoot extends ArtifactSourceRoot { return myFile.equals(((FileBasedArtifactSourceRoot)o).myFile); } + @Override + public String toString() { + return myFile.getPath(); + } + @Override public int hashCode() { return 31 * super.hashCode() + myFile.hashCode(); } + + public void copyFromRoot(String filePath, String outputPath, List outputs) throws IOException { + final File file = new File(FileUtil.toSystemDependentName(filePath)); + String targetPath; + if (!file.equals(getRootFile())) { + final String relativePath = FileUtil.getRelativePath(FileUtil.toSystemIndependentName(getRootFile().getPath()), filePath, '/'); + targetPath = PathUtil.appendToPath(outputPath, relativePath); + } + else { + targetPath = outputPath; + } + final File targetFile = new File(FileUtil.toSystemDependentName(targetPath)); + FileUtil.copyContent(file, targetFile); + outputs.add(outputPath); + } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/instructions/JarBasedArtifactSourceRoot.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/instructions/JarBasedArtifactSourceRoot.java index 7e8784b1774f..5505f62c7758 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/instructions/JarBasedArtifactSourceRoot.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/instructions/JarBasedArtifactSourceRoot.java @@ -1,9 +1,17 @@ package org.jetbrains.jps.incremental.artifacts.instructions; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.PathUtil; +import org.jetbrains.jps.incremental.artifacts.JarPathUtil; -import java.io.File; +import java.io.*; +import java.util.Enumeration; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; /** * @author nik @@ -43,4 +51,65 @@ public class JarBasedArtifactSourceRoot extends ArtifactSourceRoot { public int hashCode() { return 31 * (31 * super.hashCode() + myJarFile.hashCode()) + myPathInJar.hashCode(); } + + @Override + public String toString() { + return myJarFile.getPath() + JarPathUtil.JAR_SEPARATOR + myPathInJar; + } + + public void processEntries(EntryProcessor processor) throws IOException { + String prefix = StringUtil.trimStart(myPathInJar, "/"); + if (!StringUtil.endsWithChar(prefix, '/')) prefix += "/"; + if (prefix.equals("/")) { + prefix = ""; + } + + ZipFile zipFile = new ZipFile(myJarFile); + try { + final Enumeration entries = zipFile.entries(); + + while (entries.hasMoreElements()) { + ZipEntry entry = entries.nextElement(); + final String name = entry.getName(); + if (name.startsWith(prefix)) { + String relativePath = name.substring(prefix.length()); + processor.process(entry.isDirectory() ? null : zipFile.getInputStream(entry), relativePath); + } + } + } + finally { + zipFile.close(); + } + } + + public void copyFromRoot(String filePath, final String outputPath, final List outputs) throws IOException { + processEntries(new EntryProcessor() { + @Override + public void process(@Nullable InputStream inputStream, @NotNull String relativePath) throws IOException { + final String fullOutputPath = FileUtil.toSystemDependentName(PathUtil.appendToPath(outputPath, relativePath)); + final File outputFile = new File(fullOutputPath); + + FileUtil.createParentDirs(outputFile); + if (inputStream == null) { + outputFile.mkdir(); + } + else { + final BufferedInputStream from = new BufferedInputStream(inputStream); + final BufferedOutputStream to = new BufferedOutputStream(new FileOutputStream(outputFile)); + try { + FileUtil.copy(from, to); + } + finally { + from.close(); + to.close(); + } + } + outputs.add(fullOutputPath); + } + }); + } + + public interface EntryProcessor { + void process(@Nullable InputStream inputStream, @NotNull String relativePath) throws IOException; + } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java index 2a156ddbb253..0fbd21881c8d 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java @@ -38,6 +38,7 @@ public class GroovyBuilder extends ModuleLevelBuilder { private final String myBuilderName; public GroovyBuilder(boolean forStubs) { + super(BuilderCategory.TRANSLATOR); myForStubs = forStubs; myBuilderName = BUILDER_NAME + (forStubs ? "-stubs" : "-classes"); } @@ -140,11 +141,11 @@ public class GroovyBuilder extends ModuleLevelBuilder { return FileUtil.toCanonicalPath(dir.getPath()); } - private static List collectChangedFiles(CompileContext context, ModuleChunk chunk) throws Exception { + private static List collectChangedFiles(CompileContext context, ModuleChunk chunk) throws IOException { final List toCompile = new ArrayList(); context.processFilesToRecompile(chunk, new FileProcessor() { @Override - public boolean apply(Module module, File file, String sourceRoot) throws Exception { + public boolean apply(Module module, File file, String sourceRoot) throws IOException { final String path = file.getPath(); if (isGroovyFile(path)) { //todo file type check toCompile.add(file); @@ -159,7 +160,7 @@ public class GroovyBuilder extends ModuleLevelBuilder { ModuleChunk chunk, List toCompile, String moduleOutputPath, - List successfullyCompiled) throws Exception { + List successfullyCompiled) throws IOException { final Mappings delta = context.createDelta(); final List successfullyCompiledFiles = new ArrayList(); if (!successfullyCompiled.isEmpty()) { @@ -207,7 +208,7 @@ public class GroovyBuilder extends ModuleLevelBuilder { return path.endsWith(".groovy") || path.endsWith(".gpp"); } - private static Map buildClassToSourceMap(ModuleChunk chunk, CompileContext context, Set toCompilePaths, String moduleOutputPath) throws Exception { + private static Map buildClassToSourceMap(ModuleChunk chunk, CompileContext context, Set toCompilePaths, String moduleOutputPath) throws IOException { final Map class2Src = new HashMap(); for (Module module : chunk.getModules()) { final String moduleName = module.getName().toLowerCase(Locale.US); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java index cda2b4094bbb..ac1d7e09b598 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java @@ -73,6 +73,7 @@ public class JavaBuilder extends ModuleLevelBuilder { private final List myClassProcessors = new ArrayList(); public JavaBuilder(ExecutorService tasksExecutor) { + super(BuilderCategory.TRANSLATOR); myTaskRunner = tasksExecutor; //add here class processors in the sequence they should be executed myClassProcessors.add(new ClassPostProcessor() { @@ -132,7 +133,7 @@ public class JavaBuilder extends ModuleLevelBuilder { final Set formsToCompile = new HashSet(); context.processFilesToRecompile(chunk, new FileProcessor() { - public boolean apply(Module module, File file, String sourceRoot) throws Exception { + public boolean apply(Module module, File file, String sourceRoot) throws IOException { if (JAVA_SOURCES_FILTER.accept(file)) { filesToCompile.add(file); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/resources/ResourcesBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/resources/ResourcesBuilder.java index a318f8ef4dd7..e964a0284036 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/resources/ResourcesBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/resources/ResourcesBuilder.java @@ -2,7 +2,6 @@ package org.jetbrains.jps.incremental.resources; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.io.FileUtil; -import org.jetbrains.jps.CompilerConfiguration; import org.jetbrains.jps.Module; import org.jetbrains.jps.ModuleChunk; import org.jetbrains.jps.incremental.*; @@ -24,6 +23,7 @@ public class ResourcesBuilder extends ModuleLevelBuilder { public static final String BUILDER_NAME = "resources"; public ResourcesBuilder() { + super(BuilderCategory.TRANSLATOR); } @Override @@ -32,16 +32,6 @@ public class ResourcesBuilder extends ModuleLevelBuilder { } public ExitCode build(final CompileContext context, ModuleChunk chunk) throws ProjectBuildException { - CompilerConfiguration config = null; - for (Module module : chunk.getModules()) { - config = module.getProject().getCompilerConfiguration(); - break; - } - - if (config == null) { - return ExitCode.OK; - } - ResourcePatterns patterns = ResourcePatterns.KEY.get(context); if (patterns == null) { ResourcePatterns.KEY.set(context, patterns = new ResourcePatterns(context.getProject())); @@ -51,7 +41,7 @@ public class ResourcesBuilder extends ModuleLevelBuilder { // todo: process all files in case of rebuild or wholeModuleDirty // todo: otherwise avoid traverwing the whole module and use dirty file list taken from params context.processFilesToRecompile(chunk, new FileProcessor() { - public boolean apply(final Module module, final File file, final String sourceRoot) throws Exception { + public boolean apply(final Module module, final File file, final String sourceRoot) throws IOException { if (finalPatterns.isResourceFile(file, sourceRoot)) { try { context.processMessage(new ProgressMessage("Copying " + file.getPath())); @@ -79,7 +69,7 @@ public class ResourcesBuilder extends ModuleLevelBuilder { Module module, File file, String sourceRoot, - final SourceToOutputMapping outputToSourceMapping) throws Exception { + final SourceToOutputMapping outputToSourceMapping) throws IOException { final String outputRoot = context.isCompilingTests() ? module.getTestOutputPath() : module.getOutputPath(); final String relativePath = FileUtil.getRelativePath(sourceRoot, FileUtil.toSystemIndependentName(file.getPath()), '/'); final String prefix = module.getSourceRootPrefixes().get(sourceRoot); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/AbstractStateStorage.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/AbstractStateStorage.java index 4ab0d58eb54a..cefe772c13c5 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/AbstractStateStorage.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/AbstractStateStorage.java @@ -20,7 +20,7 @@ public abstract class AbstractStateStorage { private final DataExternalizer myStateExternalizer; protected final Object myDataLock = new Object(); - public AbstractStateStorage(@NonNls File storePath, KeyDescriptor keyDescriptor, DataExternalizer stateExternalizer) throws Exception { + public AbstractStateStorage(@NonNls File storePath, KeyDescriptor keyDescriptor, DataExternalizer stateExternalizer) throws IOException { myBaseFile = storePath; myKeyDescriptor = keyDescriptor; myStateExternalizer = stateExternalizer; @@ -58,14 +58,14 @@ public abstract class AbstractStateStorage { try { myMap = createMap(myBaseFile); } - catch (Exception ignored) { + catch (IOException ignored) { return false; } return true; } } - public void update(Key key, @Nullable T state) throws Exception { + public void update(Key key, @Nullable T state) throws IOException { if (state != null) { synchronized (myDataLock) { myMap.put(key, state); @@ -76,7 +76,7 @@ public abstract class AbstractStateStorage { } } - public void appendData(final Key key, final T data) throws Exception { + public void appendData(final Key key, final T data) throws IOException { synchronized (myDataLock) { myMap.appendData(key, new PersistentHashMap.ValueDataAppender() { public void append(DataOutput out) throws IOException { @@ -86,32 +86,32 @@ public abstract class AbstractStateStorage { } } - public void remove(Key key) throws Exception { + public void remove(Key key) throws IOException { synchronized (myDataLock) { myMap.remove(key); } } - public T getState(Key key) throws Exception { + public T getState(Key key) throws IOException { synchronized (myDataLock) { return myMap.get(key); } } - public Collection getKeys() throws Exception { + public Collection getKeys() throws IOException { synchronized (myDataLock) { return myMap.getAllKeysWithExistingMapping(); } } - public Iterator getKeysIterator() throws Exception { + public Iterator getKeysIterator() throws IOException { synchronized (myDataLock) { return myMap.getAllKeysWithExistingMapping().iterator(); } } - private PersistentHashMap createMap(final File file) throws Exception { + private PersistentHashMap createMap(final File file) throws IOException { FileUtil.createIfDoesntExist(file); return new PersistentHashMap(file, myKeyDescriptor, myStateExternalizer); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/BuildDataManager.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/BuildDataManager.java index a6935dbcd70f..2d8c0516570f 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/BuildDataManager.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/BuildDataManager.java @@ -31,7 +31,7 @@ public class BuildDataManager { private final ArtifactsBuildData myArtifactsBuildData; private final Mappings myMappings; - public BuildDataManager(String projectName, final boolean useMemoryTempCaches) throws Exception { + public BuildDataManager(String projectName, final boolean useMemoryTempCaches) throws IOException { myProjectName = projectName; mySrcToFormMap = new SourceToFormMapping(new File(getSourceToFormsRoot(), "data")); myMappings = new Mappings(getMappingsRoot(), useMemoryTempCaches); @@ -39,7 +39,7 @@ public class BuildDataManager { myArtifactsBuildData = new ArtifactsBuildData(artifactsDataDir); } - public SourceToOutputMapping getSourceToOutputMap(String moduleName, boolean testSources) throws Exception { + public SourceToOutputMapping getSourceToOutputMap(String moduleName, boolean testSources) throws IOException { final Map storageMap = testSources? myTestSourceToOutputs : myProductionSourceToOutputs; SourceToOutputMapping mapping; synchronized (mySourceToOutputLock) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/ProjectTimestamps.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/ProjectTimestamps.java index f4c362460ac9..702992bcef16 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/ProjectTimestamps.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/ProjectTimestamps.java @@ -17,7 +17,7 @@ public class ProjectTimestamps { private final String myProjectName; private final TimestampStorage myTimestamps; - public ProjectTimestamps(String projectName) throws Exception { + public ProjectTimestamps(String projectName) throws IOException { myProjectName = projectName; myTimestamps = new TimestampStorage(new File(getTimestampsRoot(projectName), "data")); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/SourceToFormMapping.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/SourceToFormMapping.java index 4cefda66eff1..03381e5ae836 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/SourceToFormMapping.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/SourceToFormMapping.java @@ -4,6 +4,7 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.util.io.EnumeratorStringDescriptor; import java.io.File; +import java.io.IOException; /** * @author Eugene Zhuravlev @@ -11,23 +12,23 @@ import java.io.File; */ public class SourceToFormMapping extends AbstractStateStorage{ - public SourceToFormMapping(File storePath) throws Exception { + public SourceToFormMapping(File storePath) throws IOException { super(storePath, new EnumeratorStringDescriptor(), new EnumeratorStringDescriptor()); } - public void update(String srcPath, String formPath) throws Exception { + public void update(String srcPath, String formPath) throws IOException { super.update(FileUtil.toSystemIndependentName(srcPath), FileUtil.toSystemIndependentName(formPath)); } - public final void appendData(String srcPath, String formPath) throws Exception { + public final void appendData(String srcPath, String formPath) throws IOException { update(srcPath, formPath); } - public void remove(String srcPath) throws Exception { + public void remove(String srcPath) throws IOException { super.remove(FileUtil.toSystemIndependentName(srcPath)); } - public String getState(String srcPath) throws Exception { + public String getState(String srcPath) throws IOException { return super.getState(FileUtil.toSystemIndependentName(srcPath)); } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/SourceToOutputMapping.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/SourceToOutputMapping.java index 7812fcf9fcad..af699e81ed42 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/SourceToOutputMapping.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/SourceToOutputMapping.java @@ -20,34 +20,34 @@ import java.util.List; */ public final class SourceToOutputMapping extends AbstractStateStorage> { - public SourceToOutputMapping(File storePath) throws Exception { + public SourceToOutputMapping(File storePath) throws IOException { super(storePath, new EnumeratorStringDescriptor(), new StringCollectionExternalizer()); } @Override - public void update(@NotNull String srcPath, @NotNull Collection outputs) throws Exception { + public void update(@NotNull String srcPath, @NotNull Collection outputs) throws IOException { super.update(FileUtil.toSystemIndependentName(srcPath), normalizePaths(outputs)); } - public void update(@NotNull String srcPath, @NotNull String outputPath) throws Exception { + public void update(@NotNull String srcPath, @NotNull String outputPath) throws IOException { super.update(FileUtil.toSystemIndependentName(srcPath), Collections.singleton(FileUtil.toSystemIndependentName(outputPath))); } - public void appendData(String srcPath, String outputPath) throws Exception { + public void appendData(String srcPath, String outputPath) throws IOException { super.appendData(FileUtil.toSystemIndependentName(srcPath), Collections.singleton(FileUtil.toSystemIndependentName(outputPath))); } - public void appendData(String srcPath, Collection data) throws Exception { + public void appendData(String srcPath, Collection data) throws IOException { super.appendData(FileUtil.toSystemIndependentName(srcPath), normalizePaths(data)); } @Override - public void remove(@NotNull String srcPath) throws Exception { + public void remove(@NotNull String srcPath) throws IOException { super.remove(FileUtil.toSystemIndependentName(srcPath)); } @Override - public Collection getState(@NotNull String srcPath) throws Exception { + public Collection getState(@NotNull String srcPath) throws IOException { return super.getState(FileUtil.toSystemIndependentName(srcPath)); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/TimestampStorage.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/TimestampStorage.java index c02947082364..5e8b8fa89afc 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/TimestampStorage.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/TimestampStorage.java @@ -15,20 +15,20 @@ import java.io.IOException; */ public class TimestampStorage extends AbstractStateStorage { - public TimestampStorage(File storePath) throws Exception { + public TimestampStorage(File storePath) throws IOException { super(storePath, new FileKeyDescriptor(), new StateExternalizer()); } - public long getStamp(File file) throws Exception { + public long getStamp(File file) throws IOException { final TimestampValidityState state = getState(file); return state != null? state.getTimestamp() : -1L; } - public void saveStamp(File file, long timestamp) throws Exception { + public void saveStamp(File file, long timestamp) throws IOException { update(file, new TimestampValidityState(timestamp)); } - public void markDirty(File file) throws Exception { + public void markDirty(File file) throws IOException { update(file, null); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/server/ClasspathBootstrap.java b/jps/jps-builders/src/org/jetbrains/jps/server/ClasspathBootstrap.java index d95a41544503..f520c8128d28 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/server/ClasspathBootstrap.java +++ b/jps/jps-builders/src/org/jetbrains/jps/server/ClasspathBootstrap.java @@ -82,11 +82,7 @@ public class ClasspathBootstrap { cp.add(getResourcePath(FileMonitor.class)); // jna-utils.jar cp.add(getResourcePath(ClassWriter.class)); // asm cp.add(getResourcePath(org.objectweb.asm.commons.EmptyVisitor.class)); // asm-commons - final File jpsModel = getResourcePath(MacroExpander.class); - cp.add(jpsModel); // jps-model - cp.add(new File(jpsModel.getParentFile(), "jps-javaee")); - cp.add(new File(jpsModel.getParentFile(), "jps-gwt")); - cp.add(new File(jpsModel.getParentFile(), "jps-jpa")); + cp.add(getResourcePath(MacroExpander.class)); // jps-model cp.add(getResourcePath(AlienFormFileException.class)); // forms-compiler cp.add(getResourcePath(GroovyException.class)); // groovy cp.add(getResourcePath(org.jdom.input.SAXBuilder.class)); // jdom diff --git a/jps/jps-builders/src/org/jetbrains/jps/server/ServerMessageHandler.java b/jps/jps-builders/src/org/jetbrains/jps/server/ServerMessageHandler.java index cf00e51af4b0..2dc966b51c51 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/server/ServerMessageHandler.java +++ b/jps/jps-builders/src/org/jetbrains/jps/server/ServerMessageHandler.java @@ -76,7 +76,7 @@ class ServerMessageHandler extends SimpleChannelHandler { for (JpsRemoteProto.Message.Request.SetupCommand.GlobalLibrary library : setupCommand.getGlobalLibraryList()) { libs.add( library.hasHomePath()? - new SdkLibrary(library.getName(), library.getHomePath(), library.getPathList()) : + new SdkLibrary(library.getName(), library.getTypeName(), library.getHomePath(), library.getPathList(), library.hasAdditionalDataXml()? library.getAdditionalDataXml() : null) : new GlobalLibrary(library.getName(), library.getPathList()) ); } @@ -187,8 +187,8 @@ class ServerMessageHandler extends SimpleChannelHandler { case REBUILD: { channelContext.setAttachment(sessionId); final BuildType buildType = convertCompileType(compileType); - final CompilationTask task = new CompilationTask( - sessionId, channelContext, projectId, buildType, compileRequest.getModuleNameList(), Collections.emptySet(), compileRequest.getFilePathList()); + final CompilationTask task = new CompilationTask(sessionId, channelContext, projectId, buildType, compileRequest.getModuleNameList(), + compileRequest.getArtifactNameList(), compileRequest.getFilePathList()); final RunnableFuture future = getCompileTaskExecutor(projectId).submit(task); myBuildsInProgress.add(new Pair(future, task)); return null; diff --git a/jps/jps-builders/src/org/jetbrains/jps/server/ServerState.java b/jps/jps-builders/src/org/jetbrains/jps/server/ServerState.java index ba7bd3963f74..444918206990 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/server/ServerState.java +++ b/jps/jps-builders/src/org/jetbrains/jps/server/ServerState.java @@ -3,6 +3,8 @@ package org.jetbrains.jps.server; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; +import groovy.util.Node; +import groovy.util.XmlParser; import org.codehaus.groovy.runtime.MethodClosure; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.Library; @@ -295,12 +297,32 @@ class ServerState { for (GlobalLibrary library : myGlobalLibraries) { if (library instanceof SdkLibrary) { final SdkLibrary sdk = (SdkLibrary)library; - final Sdk jdk = project.createSdk("JavaSDK", sdk.getName(), sdk.getHomePath(), null); - jdk.setClasspath(sdk.getPaths()); + Node additionalData = null; + final String additionalXml = sdk.getAdditionalDataXml(); + if (additionalXml != null) { + try { + additionalData = new XmlParser(false, false).parseText(additionalXml); + } + catch (Exception e) { + LOG.info(e); + } + } + final Sdk jdk = project.createSdk(/*"JavaSDK"*/sdk.getTypeName(), sdk.getName(), sdk.getHomePath(), additionalData); + if (jdk != null) { + jdk.setClasspath(sdk.getPaths()); + } + else { + LOG.info("Failed to load SDK " + sdk.getName() + ", type: " + sdk.getTypeName()); + } } else { final Library lib = project.createGlobalLibrary(library.getName(), fakeClosure); - lib.setClasspath(library.getPaths()); + if (lib != null) { + lib.setClasspath(library.getPaths()); + } + else { + LOG.info("Failed to load global library " + lib.getName()); + } } } diff --git a/jps/jps-builders/testSrc/org/jetbrains/ether/FieldPropertyTest.java b/jps/jps-builders/testSrc/org/jetbrains/ether/FieldPropertyTest.java index 9355a4a554d1..8af0a272f344 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/ether/FieldPropertyTest.java +++ b/jps/jps-builders/testSrc/org/jetbrains/ether/FieldPropertyTest.java @@ -77,10 +77,10 @@ public class FieldPropertyTest extends IncrementalTestCase { } public void testNonIncremental1() throws Exception { - doTest(); + doTest(); } public void testNonIncremental2() throws Exception { - doTest(); + doTest(); } } diff --git a/jps/jps-builders/testSrc/org/jetbrains/ether/IncrementalTestCase.java b/jps/jps-builders/testSrc/org/jetbrains/ether/IncrementalTestCase.java index 31e596cef0b7..48ed13b9920e 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/ether/IncrementalTestCase.java +++ b/jps/jps-builders/testSrc/org/jetbrains/ether/IncrementalTestCase.java @@ -19,8 +19,8 @@ import com.intellij.openapi.application.ex.PathManagerEx; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; import junit.framework.TestCase; -import junitx.framework.FileAssert; import org.apache.log4j.Level; import org.apache.log4j.PropertyConfigurator; import org.jetbrains.annotations.NonNls; @@ -342,7 +342,9 @@ public abstract class IncrementalTestCase extends TestCase { new AllProjectScope(project, Collections.emptySet(), false), true, false ); - FileAssert.assertEquals(new File(getBaseDir() + ".log"), new File(getWorkDir() + ".log")); + final String expected = StringUtil.convertLineSeparators(FileUtil.loadFile(new File(getBaseDir() + ".log"))); + final String actual = StringUtil.convertLineSeparators(FileUtil.loadFile(new File(getWorkDir() + ".log"))); + assertEquals(expected, actual); } finally { projectDescriptor.release(); diff --git a/jps/model/src/org/jetbrains/ether/dependencyView/Callbacks.java b/jps/model/src/org/jetbrains/ether/dependencyView/Callbacks.java index a98010808e86..51d644f2ec40 100644 --- a/jps/model/src/org/jetbrains/ether/dependencyView/Callbacks.java +++ b/jps/model/src/org/jetbrains/ether/dependencyView/Callbacks.java @@ -28,5 +28,6 @@ public class Callbacks { void associate(String classFileName, SourceFileNameLookup sourceLookup, ClassReader cr); void markOverride(String className, String methodName, String methodSignature); void registerConstantUsage(String className, String fieldName, String fieldOwner); + void registerImports(Collection imports, String rootClass); } } diff --git a/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java b/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java index 2d0141c4cb2d..d5d3bd1957c0 100644 --- a/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java +++ b/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java @@ -32,6 +32,35 @@ public class Mappings { private final boolean myIsDelta; private final boolean myDeltaIsTransient; + private boolean myIsDifferentiated = false; + + private final Set myChangedClasses; + private final Set myChangedFiles; + + private void addChangedClass(final DependencyContext.S it) { + assert (myChangedClasses != null && myChangedFiles != null); + myChangedClasses.add(it); + + final DependencyContext.S file = myClassToSourceFile.get(it); + + if (file != null) { + myChangedFiles.add(it); + } + + myIsDifferentiated = true; + } + + private Collection getChangedClasses() { + return myChangedClasses; + } + + private Collection getChangedFiles() { + return myChangedFiles; + } + + private boolean isDifferentiated() { + return myIsDifferentiated; + } private final File myRootDir; private DependencyContext myContext; @@ -92,6 +121,8 @@ public class Mappings { private Mappings(final Mappings base) throws IOException { myIsDelta = true; + myChangedClasses = new HashSet(); + myChangedFiles = new HashSet(); myDeltaIsTransient = base.myDeltaIsTransient; myRootDir = new File(FileUtil.toSystemIndependentName(base.myRootDir.getAbsolutePath()) + File.separatorChar + "delta"); myContext = base.myContext; @@ -102,6 +133,8 @@ public class Mappings { public Mappings(final File rootDir, final boolean transientDelta) throws IOException { myIsDelta = false; + myChangedClasses = null; + myChangedFiles = null; myDeltaIsTransient = transientDelta; myRootDir = rootDir; createImplementation(); @@ -820,6 +853,8 @@ public class Mappings { self.appendDependents(it, dependants); + delta.addChangedClass(it.name); + debug("Changed: ", it.name); final int addedModifiers = diff.addedModifiers(); @@ -1382,6 +1417,7 @@ public class Mappings { debug("Processing removed classes:"); for (ClassRepr c : classDiff.removed()) { + delta.addChangedClass(c.name); self.appendDependents(c, dependants); debug("Adding usages of class ", c.name); affectedUsages.add(c.createUsage()); @@ -1390,6 +1426,8 @@ public class Mappings { debug("Processing added classes:"); for (ClassRepr c : classDiff.added()) { + delta.addChangedClass(c.name); + final Collection depClasses = myClassToClassDependency.get(c.name); if (depClasses != null) { @@ -1531,11 +1569,56 @@ public class Mappings { } } - myClassToSubclasses.putAll(delta.myClassToSubclasses); - mySourceFileToClasses.putAll(delta.mySourceFileToClasses); - mySourceFileToUsages.putAll(delta.mySourceFileToUsages); - mySourceFileToAnnotationUsages.putAll(delta.mySourceFileToAnnotationUsages); - myClassToSourceFile.putAll(delta.myClassToSourceFile); + if (delta.isDifferentiated()) { + for (DependencyContext.S c : delta.getChangedClasses()) { + myClassToSubclasses.remove(c); + + final Collection subClasses = delta.myClassToSubclasses.get(c); + + if (subClasses != null) { + myClassToSubclasses.put(c, subClasses); + } + + myClassToSourceFile.remove(c); + + final DependencyContext.S sourceFile = delta.myClassToSourceFile.get(c); + + if (sourceFile != null) { + myClassToSourceFile.put(c, sourceFile); + } + } + } + else { + myClassToSubclasses.putAll(delta.myClassToSubclasses); + myClassToSourceFile.putAll(delta.myClassToSourceFile); + } + + if (delta.isDifferentiated() && false) { + for (DependencyContext.S f : delta.getChangedFiles()) { + mySourceFileToClasses.remove(f); + final Collection classes = delta.mySourceFileToClasses.get(f); + if (classes != null){ + mySourceFileToClasses.put(f, classes); + } + + mySourceFileToUsages.remove(f); + final Collection clusters = delta.mySourceFileToUsages.get(f); + if (clusters != null){ + mySourceFileToUsages.put(f, clusters); + } + + mySourceFileToAnnotationUsages.remove(f); + final Collection usages = delta.mySourceFileToAnnotationUsages.get(f); + if (usages != null){ + mySourceFileToAnnotationUsages.put(f, usages); + } + } + } + else { + mySourceFileToClasses.putAll(delta.mySourceFileToClasses); + mySourceFileToUsages.putAll(delta.mySourceFileToUsages); + mySourceFileToAnnotationUsages.putAll(delta.mySourceFileToAnnotationUsages); + } final Collection compiledSet = new HashSet(compiled.size()); @@ -1543,20 +1626,34 @@ public class Mappings { compiledSet.add(myContext.get(FileUtil.toSystemIndependentName(c.getAbsolutePath()))); } - for (DependencyContext.S file : delta.myClassToClassDependency.keyCollection()) { - final Collection now = delta.myClassToClassDependency.get(file); - final Collection past = myClassToClassDependency.get(file); + final Collection changedClasses = delta.getChangedClasses(); + + for (DependencyContext.S aClass : delta.myClassToClassDependency.keyCollection()) { + final Collection now = delta.myClassToClassDependency.get(aClass); + + if (delta.isDifferentiated()) { + final boolean classChanged = changedClasses.contains(aClass); + final HashSet depClasses = new HashSet(now); + + depClasses.retainAll(changedClasses); + + if (! classChanged && depClasses.isEmpty()) { + continue; + } + } + + final Collection past = myClassToClassDependency.get(aClass); if (past == null) { - myClassToClassDependency.put(file, now); + myClassToClassDependency.put(aClass, now); } else { boolean changed = past.removeAll(compiledSet); changed |= past.addAll(now); if (changed) { - myClassToClassDependency.remove(file); - myClassToClassDependency.put(file, past); + myClassToClassDependency.remove(aClass); + myClassToClassDependency.put(aClass, past); } } } @@ -1636,6 +1733,24 @@ public class Mappings { public void registerConstantUsage(final String className, final String fieldName, final String fieldOwner) { //To change body of implemented methods use File | Settings | File Templates. } + + @Override + public void registerImports(final Collection imports, final String rootClass) { + final DependencyContext.S rootClassName = myContext.get(rootClass); + final DependencyContext.S fileName = myClassToSourceFile.get(rootClassName); + + for (final String i : imports) { + final DependencyContext.S iname = myContext.get(i); + + myClassToClassDependency.put(rootClassName, iname); + + if (fileName != null) { + final UsageRepr.Cluster cluster = new UsageRepr.Cluster(); + cluster.addUsage(rootClassName, UsageRepr.createClassUsage(myContext, iname)); + mySourceFileToUsages.put(fileName, cluster); + } + } + } }; } diff --git a/jps/plugins/gwt/jps-gwt.iml b/jps/plugins/gwt/jps-gwt.iml deleted file mode 100644 index 621daa2f0ea8..000000000000 --- a/jps/plugins/gwt/jps-gwt.iml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/jps/plugins/gwt/src/META-INF/services/org.jetbrains.jps.artifacts.LayoutElementTypeService b/jps/plugins/gwt/src/META-INF/services/org.jetbrains.jps.artifacts.LayoutElementTypeService deleted file mode 100644 index e6e827eede86..000000000000 --- a/jps/plugins/gwt/src/META-INF/services/org.jetbrains.jps.artifacts.LayoutElementTypeService +++ /dev/null @@ -1 +0,0 @@ -org.jetbrains.jps.gwt.GwtCompilerOutputElementType \ No newline at end of file diff --git a/jps/plugins/gwt/src/META-INF/services/org.jetbrains.jps.builders.ModuleBuilderService b/jps/plugins/gwt/src/META-INF/services/org.jetbrains.jps.builders.ModuleBuilderService deleted file mode 100644 index 0a91a2e156a1..000000000000 --- a/jps/plugins/gwt/src/META-INF/services/org.jetbrains.jps.builders.ModuleBuilderService +++ /dev/null @@ -1 +0,0 @@ -org.jetbrains.jps.gwt.GwtModuleBuilderService \ No newline at end of file diff --git a/jps/plugins/gwt/src/META-INF/services/org.jetbrains.jps.idea.FacetTypeService b/jps/plugins/gwt/src/META-INF/services/org.jetbrains.jps.idea.FacetTypeService deleted file mode 100644 index ca9265f096a7..000000000000 --- a/jps/plugins/gwt/src/META-INF/services/org.jetbrains.jps.idea.FacetTypeService +++ /dev/null @@ -1 +0,0 @@ -org.jetbrains.jps.gwt.GwtFacetType \ No newline at end of file diff --git a/jps/plugins/gwt/src/org/jetbrains/jps/gwt/GwtCompilerOutputElement.groovy b/jps/plugins/gwt/src/org/jetbrains/jps/gwt/GwtCompilerOutputElement.groovy deleted file mode 100644 index 845cebc23b18..000000000000 --- a/jps/plugins/gwt/src/org/jetbrains/jps/gwt/GwtCompilerOutputElement.groovy +++ /dev/null @@ -1,32 +0,0 @@ -package org.jetbrains.jps.gwt - -import org.jetbrains.jps.artifacts.ComplexLayoutElement -import org.jetbrains.jps.artifacts.LayoutElement -import org.jetbrains.jps.Project -import org.jetbrains.jps.idea.IdeaProjectLoadingUtil -import org.jetbrains.jps.idea.Facet -import org.jetbrains.jps.artifacts.DirectoryCopyElement -import org.jetbrains.jps.idea.ProjectLoadingErrorReporter - -/** - * @author nik - */ -class GwtCompilerOutputElement extends ComplexLayoutElement { - String facetId - ProjectLoadingErrorReporter errorReporter - - @Override - List getSubstitution(Project project) { - Facet facet = IdeaProjectLoadingUtil.findFacetByIdWithAssertion(project, facetId, errorReporter) - if (!(facet instanceof GwtFacet)) { - errorReporter.error("'$facetId' is not GWT facet!") - } - - GwtFacet gwtFacet = (GwtFacet)facet - return [new DirectoryCopyElement(dirPath: gwtFacet.tempOutputDir)] - } - - Facet findFacet(Project project) { - return IdeaProjectLoadingUtil.findFacetById(project, facetId) - } -} diff --git a/jps/plugins/gwt/src/org/jetbrains/jps/gwt/GwtCompilerOutputElementType.groovy b/jps/plugins/gwt/src/org/jetbrains/jps/gwt/GwtCompilerOutputElementType.groovy deleted file mode 100644 index 752ded36d090..000000000000 --- a/jps/plugins/gwt/src/org/jetbrains/jps/gwt/GwtCompilerOutputElementType.groovy +++ /dev/null @@ -1,21 +0,0 @@ -package org.jetbrains.jps.gwt - -import org.jetbrains.jps.MacroExpander -import org.jetbrains.jps.Project -import org.jetbrains.jps.artifacts.LayoutElement -import org.jetbrains.jps.artifacts.LayoutElementTypeService -import org.jetbrains.jps.idea.ProjectLoadingErrorReporter - -/** - * @author nik - */ -public class GwtCompilerOutputElementType extends LayoutElementTypeService { - public GwtCompilerOutputElementType() { - super("gwt-compiler-output") - } - - @Override - public LayoutElement createElement(Project project, Node tag, MacroExpander macroExpander, ProjectLoadingErrorReporter errorReporter) { - return new GwtCompilerOutputElement(facetId: tag."@facet", errorReporter: errorReporter) - } -} diff --git a/jps/plugins/gwt/src/org/jetbrains/jps/gwt/GwtFacet.groovy b/jps/plugins/gwt/src/org/jetbrains/jps/gwt/GwtFacet.groovy deleted file mode 100644 index 8da8527439b8..000000000000 --- a/jps/plugins/gwt/src/org/jetbrains/jps/gwt/GwtFacet.groovy +++ /dev/null @@ -1,16 +0,0 @@ -package org.jetbrains.jps.gwt - -import org.jetbrains.jps.Module -import org.jetbrains.jps.idea.Facet - -/** - * @author nik - */ -class GwtFacet extends Facet { - Module module - String compilerMaxHeapSize = "128" - String scriptOutputStyle = "DETAILED" - String additionalCompilerParameters = "" - String sdkPath - String tempOutputDir -} diff --git a/jps/plugins/gwt/src/org/jetbrains/jps/gwt/GwtFacetType.groovy b/jps/plugins/gwt/src/org/jetbrains/jps/gwt/GwtFacetType.groovy deleted file mode 100644 index 8ddf201eb5b9..000000000000 --- a/jps/plugins/gwt/src/org/jetbrains/jps/gwt/GwtFacetType.groovy +++ /dev/null @@ -1,42 +0,0 @@ -package org.jetbrains.jps.gwt - -import org.jetbrains.jps.MacroExpander -import org.jetbrains.jps.Module -import org.jetbrains.jps.idea.Facet -import org.jetbrains.jps.idea.FacetTypeService - -import org.jetbrains.jps.idea.IdeaProjectLoadingUtil - -/** - * @author nik - */ -class GwtFacetType extends FacetTypeService { - GwtFacetType() { - super("gwt") - } - - @Override - Facet createFacet(Module module, String name, Node facetConfiguration, MacroExpander macroExpander) { - def facet = new GwtFacet(module: module, name: name) - facetConfiguration.setting.each {Node child -> - String value = child."@value" - switch (child."@name") { - case "compilerMaxHeapSize": - facet.compilerMaxHeapSize = Integer.parseInt(value) - break - case "gwtScriptOutputStyle": - facet.scriptOutputStyle = value - break - case "additionalCompilerParameters": - facet.additionalCompilerParameters = value - break - case "gwtSdkUrl": - facet.sdkPath = macroExpander.expandMacros(IdeaProjectLoadingUtil.pathFromUrl(value)) - break - } - } - - return facet - } - -} diff --git a/jps/plugins/gwt/src/org/jetbrains/jps/gwt/GwtModuleBuilder.groovy b/jps/plugins/gwt/src/org/jetbrains/jps/gwt/GwtModuleBuilder.groovy deleted file mode 100644 index 90d7368f3cc4..000000000000 --- a/jps/plugins/gwt/src/org/jetbrains/jps/gwt/GwtModuleBuilder.groovy +++ /dev/null @@ -1,94 +0,0 @@ -package org.jetbrains.jps.gwt - -import org.jetbrains.jps.ModuleBuildState -import org.jetbrains.jps.ModuleBuilder -import org.jetbrains.jps.ModuleChunk -import org.jetbrains.jps.Project -import org.jetbrains.jps.artifacts.LayoutElement -import org.jetbrains.jps.artifacts.ArtifactLayoutElement -import org.jetbrains.jps.builders.BuildUtil -import org.jetbrains.jps.ProjectBuilder - -/** - * @author nik - */ -class GwtModuleBuilder implements ModuleBuilder { - def processModule(ModuleBuildState state, ModuleChunk moduleChunk, ProjectBuilder projectBuilder) { - List facets = [] - moduleChunk.modules.each { - it.facets.values().each { - if (it instanceof GwtFacet) { - facets << it - } - } - } - - if (facets.isEmpty()) return - - facets.each {GwtFacet facet -> - compileGwtFacet(facet, projectBuilder, state) - } - } - - def compileGwtFacet(GwtFacet facet, ProjectBuilder projectBuilder, ModuleBuildState state) { - if (!isIncludedInArtifact(facet, projectBuilder.project)) { - projectBuilder.info("GWT Facet in module '${facet.module.name}' isn't included in artifacts so GWT compiler won't be called") - return - } - - if (facet.tempOutputDir != null) return - - if (!new File(facet.sdkPath).exists()) { - projectBuilder.error("GWT SDK directory $facet.sdkPath not found") - } - - List gwtModules = GwtModulesSearcher.findGwtModules(facet.module.sourceRoots) - if (gwtModules.isEmpty()) { - projectBuilder.info("No GWT modules found in GWT facet in ${facet.module} module") - return - } - - String outputDir = projectBuilder.getTempDirectoryPath("GWT_Output_$facet.module.name") - facet.tempOutputDir = outputDir - - def ant = projectBuilder.binding.ant - BuildUtil.deleteDir(projectBuilder, outputDir) - ant.mkdir(dir: outputDir) - - gwtModules.each {String moduleName -> - projectBuilder.stage("Compiling GWT Module") - ant.java(fork: "true", classname: "com.google.gwt.dev.Compiler", failonerror: "true") { - jvmarg(line: "-Xmx${facet.compilerMaxHeapSize}m") - if (!facet.additionalCompilerParameters.isEmpty()) { - jvmarg(line: facet.additionalCompilerParameters) - } - classpath { - pathelement(location: "${facet.sdkPath}/gwt-dev.jar") - state.sourceRootsFromModuleWithDependencies.each { - pathelement(location: it) - } - state.classpath.each { - pathelement(location: it) - } - } - arg(value: "-war") - arg(value: outputDir) - arg(value: "-style") - arg(value: facet.scriptOutputStyle) - arg(value: moduleName) - } - } - } - - private boolean isIncludedInArtifact(GwtFacet gwtFacet, Project project) { - boolean included = false - project.artifacts.values()*.rootElement*.process(project) {LayoutElement element -> - if (element instanceof GwtCompilerOutputElement - && ((GwtCompilerOutputElement)element).findFacet(project) == gwtFacet) { - included = true - } - return !(element instanceof ArtifactLayoutElement) - } - return included - } -} diff --git a/jps/plugins/gwt/src/org/jetbrains/jps/gwt/GwtModuleBuilderService.groovy b/jps/plugins/gwt/src/org/jetbrains/jps/gwt/GwtModuleBuilderService.groovy deleted file mode 100644 index ee58cfeb3385..000000000000 --- a/jps/plugins/gwt/src/org/jetbrains/jps/gwt/GwtModuleBuilderService.groovy +++ /dev/null @@ -1,15 +0,0 @@ -package org.jetbrains.jps.gwt - -import org.jetbrains.jps.builders.ModuleBuilderService -import org.jetbrains.jps.ProjectBuilder - -/** - * @author nik - */ -class GwtModuleBuilderService extends ModuleBuilderService { - @Override - registerBuilders(ProjectBuilder builder) { - builder.weavingBuilders << new GwtModuleBuilder() - } - -} diff --git a/jps/plugins/gwt/src/org/jetbrains/jps/gwt/GwtModuleUtil.groovy b/jps/plugins/gwt/src/org/jetbrains/jps/gwt/GwtModuleUtil.groovy deleted file mode 100644 index cd744b880ac6..000000000000 --- a/jps/plugins/gwt/src/org/jetbrains/jps/gwt/GwtModuleUtil.groovy +++ /dev/null @@ -1,21 +0,0 @@ -package org.jetbrains.jps.gwt - -import org.xml.sax.SAXParseException; - -/** - * @author nik - */ -class GwtModuleUtil { - public static boolean hasEntryPoints(File child) { - try { - def root = new XmlParser(false, false).parse(child) - return !root."entry-point".isEmpty() - } - catch (IOException e) { - return true; - } - catch (SAXParseException e) { - return true; - } - } -} diff --git a/jps/plugins/gwt/src/org/jetbrains/jps/gwt/GwtModulesSearcher.java b/jps/plugins/gwt/src/org/jetbrains/jps/gwt/GwtModulesSearcher.java deleted file mode 100644 index b1e7658e06df..000000000000 --- a/jps/plugins/gwt/src/org/jetbrains/jps/gwt/GwtModulesSearcher.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.jetbrains.jps.gwt; - -import groovy.util.XmlParser; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; - -/** - * @author nik - */ -public class GwtModulesSearcher { - private static final String GWT_XML_SUFFIX = ".gwt.xml"; - - public static List findGwtModules(List sourcePaths) { - final List result = new ArrayList(); - for (CharSequence sourcePath : sourcePaths) { - collectGwtModules(new File(sourcePath.toString()), "", result); - } - return result; - } - - private static void collectGwtModules(File dir, String packageName, List result) { - if (!dir.isDirectory()) { - return; - } - - final File[] files = dir.listFiles(); - if (files != null) { - for (File child : files) { - final String name = child.getName(); - if (child.isFile() && name.endsWith(GWT_XML_SUFFIX)) { - if (GwtModuleUtil.hasEntryPoints(child)) { - result.add(packageName + name.substring(0, name.length() - GWT_XML_SUFFIX.length())); - } - } - else { - collectGwtModules(child, packageName + name + ".", result); - } - } - } - } -} diff --git a/jps/plugins/gwt/testData/modules/com/app/App.gwt.xml b/jps/plugins/gwt/testData/modules/com/app/App.gwt.xml deleted file mode 100644 index d31f3637779f..000000000000 --- a/jps/plugins/gwt/testData/modules/com/app/App.gwt.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/jps/plugins/gwt/testData/modules/com/app/InvalidXml.gwt.xml b/jps/plugins/gwt/testData/modules/com/app/InvalidXml.gwt.xml deleted file mode 100644 index 4e87e20e57f4..000000000000 --- a/jps/plugins/gwt/testData/modules/com/app/InvalidXml.gwt.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - diff --git a/jps/plugins/gwt/testData/modules/com/app/NoEntryPoints.gwt.xml b/jps/plugins/gwt/testData/modules/com/app/NoEntryPoints.gwt.xml deleted file mode 100644 index 86a82eb089d4..000000000000 --- a/jps/plugins/gwt/testData/modules/com/app/NoEntryPoints.gwt.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - diff --git a/jps/plugins/gwt/testSrc/org/jetbrains/jps/gwt/GwtModulesSearcherTest.java b/jps/plugins/gwt/testSrc/org/jetbrains/jps/gwt/GwtModulesSearcherTest.java deleted file mode 100644 index 0375f1105c49..000000000000 --- a/jps/plugins/gwt/testSrc/org/jetbrains/jps/gwt/GwtModulesSearcherTest.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.jetbrains.jps.gwt; - -import junit.framework.TestCase; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; - -/** - * @author nik - */ -public class GwtModulesSearcherTest extends TestCase { - public void test() { - List modules = GwtModulesSearcher.findGwtModules(Arrays.asList("plugins/gwt/testData/modules")); - assertEquals(new HashSet(Arrays.asList("com.app.App", "com.app.InvalidXml")), - new HashSet(modules)); - } -} diff --git a/jps/plugins/javaee/jps-javaee.iml b/jps/plugins/javaee/jps-javaee.iml deleted file mode 100644 index d67aceeddab5..000000000000 --- a/jps/plugins/javaee/jps-javaee.iml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/jps/plugins/javaee/src/META-INF/services/org.jetbrains.jps.artifacts.LayoutElementTypeService b/jps/plugins/javaee/src/META-INF/services/org.jetbrains.jps.artifacts.LayoutElementTypeService deleted file mode 100644 index 45b2dc247bd9..000000000000 --- a/jps/plugins/javaee/src/META-INF/services/org.jetbrains.jps.artifacts.LayoutElementTypeService +++ /dev/null @@ -1,2 +0,0 @@ -org.jetbrains.jps.javaee.JavaeeFacetResourcesElementType -org.jetbrains.jps.javaee.JavaeeFacetClassesElementType \ No newline at end of file diff --git a/jps/plugins/javaee/src/META-INF/services/org.jetbrains.jps.idea.FacetTypeService b/jps/plugins/javaee/src/META-INF/services/org.jetbrains.jps.idea.FacetTypeService deleted file mode 100644 index 4b60ca861db8..000000000000 --- a/jps/plugins/javaee/src/META-INF/services/org.jetbrains.jps.idea.FacetTypeService +++ /dev/null @@ -1,3 +0,0 @@ -org.jetbrains.jps.javaee.WebFacetType -org.jetbrains.jps.javaee.EjbFacetType -org.jetbrains.jps.javaee.JavaeeAppFacetType \ No newline at end of file diff --git a/jps/plugins/javaee/src/org/jetbrains/jps/javaee/EjbFacetType.groovy b/jps/plugins/javaee/src/org/jetbrains/jps/javaee/EjbFacetType.groovy deleted file mode 100644 index 96fa9b90232e..000000000000 --- a/jps/plugins/javaee/src/org/jetbrains/jps/javaee/EjbFacetType.groovy +++ /dev/null @@ -1,10 +0,0 @@ -package org.jetbrains.jps.javaee - -/** - * @author nik - */ -class EjbFacetType extends JavaeeFacetTypeBase { - EjbFacetType() { - super("ejb") - } -} diff --git a/jps/plugins/javaee/src/org/jetbrains/jps/javaee/JavaeeAppFacetType.groovy b/jps/plugins/javaee/src/org/jetbrains/jps/javaee/JavaeeAppFacetType.groovy deleted file mode 100644 index 20dff7d7e44d..000000000000 --- a/jps/plugins/javaee/src/org/jetbrains/jps/javaee/JavaeeAppFacetType.groovy +++ /dev/null @@ -1,10 +0,0 @@ -package org.jetbrains.jps.javaee - -/** - * @author nik - */ -public class JavaeeAppFacetType extends JavaeeFacetTypeBase { - JavaeeAppFacetType() { - super("javaeeApplication") - } -} diff --git a/jps/plugins/javaee/src/org/jetbrains/jps/javaee/JavaeeFacet.groovy b/jps/plugins/javaee/src/org/jetbrains/jps/javaee/JavaeeFacet.groovy deleted file mode 100644 index 844d2108deda..000000000000 --- a/jps/plugins/javaee/src/org/jetbrains/jps/javaee/JavaeeFacet.groovy +++ /dev/null @@ -1,11 +0,0 @@ -package org.jetbrains.jps.javaee - -import org.jetbrains.jps.idea.Facet - -/** - * @author nik - */ -class JavaeeFacet extends Facet { - final List> descriptors = [] - final List> webRoots = [] -} diff --git a/jps/plugins/javaee/src/org/jetbrains/jps/javaee/JavaeeFacetClassesElementType.groovy b/jps/plugins/javaee/src/org/jetbrains/jps/javaee/JavaeeFacetClassesElementType.groovy deleted file mode 100644 index c63ff6f18e4d..000000000000 --- a/jps/plugins/javaee/src/org/jetbrains/jps/javaee/JavaeeFacetClassesElementType.groovy +++ /dev/null @@ -1,24 +0,0 @@ -package org.jetbrains.jps.javaee; - - -import org.jetbrains.jps.MacroExpander -import org.jetbrains.jps.Project -import org.jetbrains.jps.artifacts.LayoutElement -import org.jetbrains.jps.artifacts.LayoutElementTypeService -import org.jetbrains.jps.artifacts.ModuleOutputElement -import org.jetbrains.jps.idea.ProjectLoadingErrorReporter - -/** - * @author nik - */ -class JavaeeFacetClassesElementType extends LayoutElementTypeService { - JavaeeFacetClassesElementType() { - super("javaee-facet-classes") - } - - @Override - LayoutElement createElement(Project project, Node tag, MacroExpander macroExpander, ProjectLoadingErrorReporter errorReporter) { - String facetId = tag."@facet" - return new ModuleOutputElement(moduleName: facetId.substring(0, facetId.indexOf('/'))) - } -} diff --git a/jps/plugins/javaee/src/org/jetbrains/jps/javaee/JavaeeFacetResourcesElement.groovy b/jps/plugins/javaee/src/org/jetbrains/jps/javaee/JavaeeFacetResourcesElement.groovy deleted file mode 100644 index 7298d28c8ac1..000000000000 --- a/jps/plugins/javaee/src/org/jetbrains/jps/javaee/JavaeeFacetResourcesElement.groovy +++ /dev/null @@ -1,32 +0,0 @@ -package org.jetbrains.jps.javaee - -import org.jetbrains.jps.Project -import org.jetbrains.jps.idea.Facet -import org.jetbrains.jps.idea.IdeaProjectLoadingUtil -import org.jetbrains.jps.idea.ProjectLoadingErrorReporter -import org.jetbrains.jps.artifacts.* - -/** - * @author nik - */ -class JavaeeFacetResourcesElement extends ComplexLayoutElement { - String facetId - ProjectLoadingErrorReporter errorReporter - - List getSubstitution(Project project) { - Facet facet = IdeaProjectLoadingUtil.findFacetByIdWithAssertion(project, facetId, errorReporter) - - if (!(facet instanceof JavaeeFacet)) { - errorReporter.error("$facetId facet is not JavaEE facet") - } - - List result = [] - facet.descriptors.each {Map descriptor -> - result << LayoutElementFactory.createParentDirectories(descriptor.outputPath, new FileCopyElement(filePath: descriptor.path)) - } - facet.webRoots.each {Map webRoot -> - result << LayoutElementFactory.createParentDirectories(webRoot.outputPath, new DirectoryCopyElement(dirPath: webRoot.path)) - } - return result - } -} diff --git a/jps/plugins/javaee/src/org/jetbrains/jps/javaee/JavaeeFacetResourcesElementType.groovy b/jps/plugins/javaee/src/org/jetbrains/jps/javaee/JavaeeFacetResourcesElementType.groovy deleted file mode 100644 index 527c536a21f2..000000000000 --- a/jps/plugins/javaee/src/org/jetbrains/jps/javaee/JavaeeFacetResourcesElementType.groovy +++ /dev/null @@ -1,22 +0,0 @@ -package org.jetbrains.jps.javaee - -import org.jetbrains.jps.MacroExpander -import org.jetbrains.jps.Project -import org.jetbrains.jps.artifacts.LayoutElement -import org.jetbrains.jps.artifacts.LayoutElementTypeService -import org.jetbrains.jps.idea.ProjectLoadingErrorReporter - -/** - * @author nik - */ -class JavaeeFacetResourcesElementType extends LayoutElementTypeService { - JavaeeFacetResourcesElementType() { - super("javaee-facet-resources") - } - - @Override - LayoutElement createElement(Project project, Node tag, MacroExpander macroExpander, ProjectLoadingErrorReporter errorReporter) { - return new JavaeeFacetResourcesElement(facetId: tag."@facet", errorReporter: errorReporter) - } - -} diff --git a/jps/plugins/javaee/src/org/jetbrains/jps/javaee/JavaeeFacetTypeBase.groovy b/jps/plugins/javaee/src/org/jetbrains/jps/javaee/JavaeeFacetTypeBase.groovy deleted file mode 100644 index 657a6ed2b9f7..000000000000 --- a/jps/plugins/javaee/src/org/jetbrains/jps/javaee/JavaeeFacetTypeBase.groovy +++ /dev/null @@ -1,40 +0,0 @@ -package org.jetbrains.jps.javaee - -import org.jetbrains.jps.MacroExpander -import org.jetbrains.jps.Module -import org.jetbrains.jps.idea.Facet -import org.jetbrains.jps.idea.FacetTypeService - -import org.jetbrains.jps.idea.IdeaProjectLoadingUtil - -/** - * @author nik - */ -public abstract class JavaeeFacetTypeBase extends FacetTypeService { - protected JavaeeFacetTypeBase(String typeId) { - super(typeId) - } - - protected String getDescriptorOutputPath(String descriptorId) { - return "META-INF" - } - - @Override - public Facet createFacet(Module module, String name, Node facetConfiguration, MacroExpander macroExpander) { - def facet = new JavaeeFacet(name: name) - facetConfiguration?.descriptors?.deploymentDescriptor?.each {Node tag -> - def outputPath = getDescriptorOutputPath(tag."@name") - String path = urlToPath(tag."@url", macroExpander) - facet.descriptors << [path: path, outputPath: outputPath] - } - facetConfiguration?.webroots?.root?.each {Node tag -> - String path = urlToPath(tag."@url", macroExpander) - facet.webRoots << [path: path, outputPath: tag."@relative"] - } - return facet - } - - def urlToPath(String url, MacroExpander macroExpander) { - return macroExpander.expandMacros(IdeaProjectLoadingUtil.pathFromUrl(url)) - } -} diff --git a/jps/plugins/javaee/src/org/jetbrains/jps/javaee/WebFacetType.groovy b/jps/plugins/javaee/src/org/jetbrains/jps/javaee/WebFacetType.groovy deleted file mode 100644 index d6e7f972eb5a..000000000000 --- a/jps/plugins/javaee/src/org/jetbrains/jps/javaee/WebFacetType.groovy +++ /dev/null @@ -1,18 +0,0 @@ -package org.jetbrains.jps.javaee - -/** - * @author nik - */ -public class WebFacetType extends JavaeeFacetTypeBase { - public WebFacetType() { - super("web"); - } - - @Override - protected String getDescriptorOutputPath(String descriptorId) { - if (descriptorId == "context.xml") return "META-INF" - return "WEB-INF" - } - - -} diff --git a/jps/plugins/jpa/jps-jpa.iml b/jps/plugins/jpa/jps-jpa.iml deleted file mode 100644 index 9d7005eff21a..000000000000 --- a/jps/plugins/jpa/jps-jpa.iml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/jps/plugins/jpa/src/META-INF/services/org.jetbrains.jps.artifacts.LayoutElementTypeService b/jps/plugins/jpa/src/META-INF/services/org.jetbrains.jps.artifacts.LayoutElementTypeService deleted file mode 100644 index 93c232491864..000000000000 --- a/jps/plugins/jpa/src/META-INF/services/org.jetbrains.jps.artifacts.LayoutElementTypeService +++ /dev/null @@ -1 +0,0 @@ -org.jetbrains.jps.jpa.JpaFacetDescriptorsElementType \ No newline at end of file diff --git a/jps/plugins/jpa/src/META-INF/services/org.jetbrains.jps.idea.FacetTypeService b/jps/plugins/jpa/src/META-INF/services/org.jetbrains.jps.idea.FacetTypeService deleted file mode 100644 index 3617f029eafb..000000000000 --- a/jps/plugins/jpa/src/META-INF/services/org.jetbrains.jps.idea.FacetTypeService +++ /dev/null @@ -1 +0,0 @@ -org.jetbrains.jps.jpa.JpaFacetType \ No newline at end of file diff --git a/jps/plugins/jpa/src/org/jetbrains/jps/jpa/JpaFacet.groovy b/jps/plugins/jpa/src/org/jetbrains/jps/jpa/JpaFacet.groovy deleted file mode 100644 index 0ff329b873d5..000000000000 --- a/jps/plugins/jpa/src/org/jetbrains/jps/jpa/JpaFacet.groovy +++ /dev/null @@ -1,10 +0,0 @@ -package org.jetbrains.jps.jpa - -import org.jetbrains.jps.idea.Facet - -/** - * @author nik - */ -class JpaFacet extends Facet { - final List descriptors = [] -} diff --git a/jps/plugins/jpa/src/org/jetbrains/jps/jpa/JpaFacetDescriptorsElement.groovy b/jps/plugins/jpa/src/org/jetbrains/jps/jpa/JpaFacetDescriptorsElement.groovy deleted file mode 100644 index 55ef512d28cc..000000000000 --- a/jps/plugins/jpa/src/org/jetbrains/jps/jpa/JpaFacetDescriptorsElement.groovy +++ /dev/null @@ -1,34 +0,0 @@ -package org.jetbrains.jps.jpa - -import org.jetbrains.jps.Project -import org.jetbrains.jps.artifacts.ComplexLayoutElement -import org.jetbrains.jps.artifacts.FileCopyElement -import org.jetbrains.jps.artifacts.LayoutElement -import org.jetbrains.jps.artifacts.LayoutElementFactory -import org.jetbrains.jps.idea.ProjectLoadingErrorReporter - -/** - * @author nik - */ -class JpaFacetDescriptorsElement extends ComplexLayoutElement { - String facetId - ProjectLoadingErrorReporter errorReporter - - List getSubstitution(Project project) { - def moduleName = facetId.substring(0, facetId.indexOf('/')) - def facet = project.modules[moduleName]?.facets[facetId] - if (facet == null) { - errorReporter.error("Unknown facet id: $facetId") - } - - if (!(facet instanceof JpaFacet)) { - errorReporter.error("$facetId facet is not JPA facet") - } - - List result = [] - facet.descriptors.each {String path -> - result << LayoutElementFactory.createParentDirectories("META-INF", new FileCopyElement(filePath: path)) - } - return result - } -} diff --git a/jps/plugins/jpa/src/org/jetbrains/jps/jpa/JpaFacetDescriptorsElementType.groovy b/jps/plugins/jpa/src/org/jetbrains/jps/jpa/JpaFacetDescriptorsElementType.groovy deleted file mode 100644 index 78d5de1d5440..000000000000 --- a/jps/plugins/jpa/src/org/jetbrains/jps/jpa/JpaFacetDescriptorsElementType.groovy +++ /dev/null @@ -1,21 +0,0 @@ -package org.jetbrains.jps.jpa - -import org.jetbrains.jps.MacroExpander -import org.jetbrains.jps.Project -import org.jetbrains.jps.artifacts.LayoutElement -import org.jetbrains.jps.artifacts.LayoutElementTypeService -import org.jetbrains.jps.idea.ProjectLoadingErrorReporter - -/** - * @author nik - */ -class JpaFacetDescriptorsElementType extends LayoutElementTypeService { - JpaFacetDescriptorsElementType() { - super("jpa-descriptors") - } - - @Override - LayoutElement createElement(Project project, Node tag, MacroExpander macroExpander, ProjectLoadingErrorReporter errorReporter) { - return new JpaFacetDescriptorsElement(facetId: tag."@facet", errorReporter: errorReporter) - } -} diff --git a/jps/plugins/jpa/src/org/jetbrains/jps/jpa/JpaFacetType.groovy b/jps/plugins/jpa/src/org/jetbrains/jps/jpa/JpaFacetType.groovy deleted file mode 100644 index 50886e42cbef..000000000000 --- a/jps/plugins/jpa/src/org/jetbrains/jps/jpa/JpaFacetType.groovy +++ /dev/null @@ -1,29 +0,0 @@ -package org.jetbrains.jps.jpa - -import org.jetbrains.jps.idea.FacetTypeService -import org.jetbrains.jps.idea.Facet -import org.jetbrains.jps.Module -import org.jetbrains.jps.MacroExpander - -import org.jetbrains.jps.idea.IdeaProjectLoadingUtil - -/** - * @author nik - */ -class JpaFacetType extends FacetTypeService { - JpaFacetType() { - super("jpa") - } - - @Override - Facet createFacet(Module module, String name, Node facetConfiguration, MacroExpander macroExpander) { - JpaFacet facet = new JpaFacet(name: name) - facetConfiguration?.deploymentDescriptor?.each {Node tag -> - String path = macroExpander.expandMacros(IdeaProjectLoadingUtil.pathFromUrl(tag."@url")) - facet.descriptors << path - } - return facet - } - - -} diff --git a/jps/plugins/jpa/testData/jpaTest/jpaTest.iml b/jps/plugins/jpa/testData/jpaTest/jpaTest.iml deleted file mode 100644 index c44032a334dc..000000000000 --- a/jps/plugins/jpa/testData/jpaTest/jpaTest.iml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/jps/plugins/jpa/testData/jpaTest/jpaTest.ipr b/jps/plugins/jpa/testData/jpaTest/jpaTest.ipr deleted file mode 100644 index 3b17b74a3a30..000000000000 --- a/jps/plugins/jpa/testData/jpaTest/jpaTest.ipr +++ /dev/null @@ -1,24 +0,0 @@ - - - - - $PROJECT_DIR$/out/artifacts/jpaTest - - - - - - - - - - - - - - - - - - - diff --git a/jps/plugins/jpa/testData/jpaTest/src/META-INF/persistence.xml b/jps/plugins/jpa/testData/jpaTest/src/META-INF/persistence.xml deleted file mode 100644 index ec93f1cad212..000000000000 --- a/jps/plugins/jpa/testData/jpaTest/src/META-INF/persistence.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/jps/plugins/jpa/testSrc/org/jetbrains/jps/JpaTest.groovy b/jps/plugins/jpa/testSrc/org/jetbrains/jps/JpaTest.groovy deleted file mode 100644 index 11255f751ab0..000000000000 --- a/jps/plugins/jpa/testSrc/org/jetbrains/jps/JpaTest.groovy +++ /dev/null @@ -1,29 +0,0 @@ -package org.jetbrains.jps - -/** - * @author nik - */ -class JpaTest extends JpsBuildTestCase { - public void testOverwriteArtifacts() throws Exception { - doTest("plugins/jpa/testData/jpaTest/jpaTest.ipr", null, { - dir("artifacts") { - dir("jpaTest") { - dir("WEB-INF") { - dir("classes") { - dir("META-INF") { - file("persistence.xml") - } - } - } - } - } - dir("production") { - dir("jpaTest") { - dir("META-INF") { - file("persistence.xml") - } - } - } - }) - } -} diff --git a/platform/core-api/src/com/intellij/lexer/DelegateLexer.java b/platform/core-api/src/com/intellij/lexer/DelegateLexer.java index e2ca198886fb..4b95562b6189 100644 --- a/platform/core-api/src/com/intellij/lexer/DelegateLexer.java +++ b/platform/core-api/src/com/intellij/lexer/DelegateLexer.java @@ -23,7 +23,7 @@ import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.Nullable; public class DelegateLexer extends LexerBase { - private final Lexer myDelegate; + protected final Lexer myDelegate; public DelegateLexer(Lexer delegate) { myDelegate = delegate; diff --git a/platform/core-api/src/com/intellij/openapi/editor/event/DocumentEvent.java b/platform/core-api/src/com/intellij/openapi/editor/event/DocumentEvent.java index 181072e30c89..10f2b7ee9126 100644 --- a/platform/core-api/src/com/intellij/openapi/editor/event/DocumentEvent.java +++ b/platform/core-api/src/com/intellij/openapi/editor/event/DocumentEvent.java @@ -21,22 +21,27 @@ import org.jetbrains.annotations.NotNull; import java.util.EventObject; public abstract class DocumentEvent extends EventObject { - protected DocumentEvent(Document document) { + protected DocumentEvent(@NotNull Document document) { super(document); } - @NotNull public abstract Document getDocument(); + @NotNull + public abstract Document getDocument(); public abstract int getOffset(); public abstract int getOldLength(); + public abstract int getNewLength(); + @NotNull public abstract CharSequence getOldFragment(); + + @NotNull public abstract CharSequence getNewFragment(); public abstract long getOldTimeStamp(); - + public boolean isWholeTextReplaced() { return getOffset() == 0 && getNewLength() == getDocument().getTextLength(); } diff --git a/platform/core-api/src/com/intellij/psi/FileViewProviderFactory.java b/platform/core-api/src/com/intellij/psi/FileViewProviderFactory.java index a59327bf1409..66e25e3f9ca7 100644 --- a/platform/core-api/src/com/intellij/psi/FileViewProviderFactory.java +++ b/platform/core-api/src/com/intellij/psi/FileViewProviderFactory.java @@ -18,6 +18,7 @@ package com.intellij.psi; import com.intellij.lang.Language; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; /** * Register in extension point {@code com.intellij.fileType.fileViewProviderFactory} @@ -26,5 +27,5 @@ import com.intellij.openapi.vfs.VirtualFile; * @author yole */ public interface FileViewProviderFactory { - FileViewProvider createFileViewProvider(final VirtualFile file, final Language language, final PsiManager manager, final boolean physical); + FileViewProvider createFileViewProvider(@NotNull VirtualFile file, Language language, @NotNull PsiManager manager, final boolean physical); } \ No newline at end of file diff --git a/platform/core-api/src/com/intellij/psi/search/LocalSearchScope.java b/platform/core-api/src/com/intellij/psi/search/LocalSearchScope.java index 562c2b617f85..c092c70e2d10 100644 --- a/platform/core-api/src/com/intellij/psi/search/LocalSearchScope.java +++ b/platform/core-api/src/com/intellij/psi/search/LocalSearchScope.java @@ -66,7 +66,8 @@ public class LocalSearchScope extends SearchScope { for (final PsiElement element : scope) { LOG.assertTrue(element.getContainingFile() != null, element.getClass().getName()); if (element instanceof PsiFile) { - ContainerUtil.addAll(localScope, ((PsiFile)element).getPsiRoots()); + List files = ((PsiFile)element).getViewProvider().getAllFiles(); + ContainerUtil.addAll(localScope, files); } else { localScope.add(element); diff --git a/platform/core-api/src/com/intellij/psi/util/PsiTreeUtil.java b/platform/core-api/src/com/intellij/psi/util/PsiTreeUtil.java index 9aac4bf4323d..c43925dde0ff 100644 --- a/platform/core-api/src/com/intellij/psi/util/PsiTreeUtil.java +++ b/platform/core-api/src/com/intellij/psi/util/PsiTreeUtil.java @@ -713,7 +713,7 @@ public class PsiTreeUtil { int offset, @NotNull Class clazz, boolean strictStart) { - final PsiElement[] psiRoots = file.getPsiRoots(); + final List psiRoots = file.getViewProvider().getAllFiles(); T result = null; for (PsiElement root : psiRoots) { final PsiElement elementAt = root.findElementAt(offset); @@ -739,7 +739,7 @@ public class PsiTreeUtil { @NotNull Class clazz, boolean strictStart, @NotNull Class... stopAt) { - final PsiElement[] psiRoots = file.getPsiRoots(); + final List psiRoots = file.getViewProvider().getAllFiles(); T result = null; for (PsiElement root : psiRoots) { final PsiElement elementAt = root.findElementAt(offset); diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarker.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarker.java index e09639f0aded..e1b34cc49ad7 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarker.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarker.java @@ -25,8 +25,8 @@ import com.intellij.util.diff.FilesTooBigForDiffException; * is replaced. *

* Example: consider that the user selects all text at editor (Ctrl+A), copies it to the buffer (Ctrl+C) and performs paste (Ctrl+V). - * All document text is replaced then but in essence it's the same, hence, we may want particular range markers to be still valid. - * + * All document text is replaced then but in essence it's the same, hence, we may want particular range markers to be still valid. + * * @author max */ class PersistentRangeMarker extends RangeMarkerImpl { @@ -69,22 +69,23 @@ class PersistentRangeMarker extends RangeMarkerImpl { private boolean translateViaDiff(final DocumentEventImpl event) { try { myStartLine = event.translateLineViaDiffStrict(myStartLine); - if (myStartLine < 0 || myStartLine >= getDocument().getLineCount()){ + if (myStartLine < 0 || myStartLine >= getDocument().getLineCount()) { invalidate(event); } - else{ + else { setIntervalStart(getDocument().getLineStartOffset(myStartLine) + myStartColumn); } myEndLine = event.translateLineViaDiffStrict(myEndLine); - if (myEndLine < 0 || myEndLine >= getDocument().getLineCount()){ + if (myEndLine < 0 || myEndLine >= getDocument().getLineCount()) { invalidate(event); } - else{ + else { setIntervalEnd(getDocument().getLineStartOffset(myEndLine) + myEndColumn); } return true; - } catch (FilesTooBigForDiffException e) { + } + catch (FilesTooBigForDiffException e) { return false; } } @@ -94,12 +95,12 @@ class PersistentRangeMarker extends RangeMarkerImpl { DocumentEventImpl event = (DocumentEventImpl)e; final boolean shouldTranslateViaDiff = PersistentRangeMarkerUtil.shouldTranslateViaDiff(event, this); boolean wasTranslated = shouldTranslateViaDiff; - if (shouldTranslateViaDiff){ + if (shouldTranslateViaDiff) { wasTranslated = translateViaDiff(event); } - if (! wasTranslated) { + if (!wasTranslated) { super.changedUpdateImpl(e); - if (isValid()){ + if (isValid()) { storeLinesAndCols(e); } } diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/event/DocumentEventImpl.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/event/DocumentEventImpl.java index 1bd95fca7b5c..993dda9c0535 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/event/DocumentEventImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/event/DocumentEventImpl.java @@ -38,6 +38,8 @@ public class DocumentEventImpl extends DocumentEvent { private final long myOldTimeStamp; private final boolean myIsWholeDocReplaced; private Diff.Change myChange; + private static final Diff.Change TOO_BIG_FILE = new Diff.Change(0, 0, 0, 0, null) { + }; private int myOptimizedLineShift = -1; private boolean myOptimizedLineShiftCalculated; @@ -45,7 +47,11 @@ public class DocumentEventImpl extends DocumentEvent { private int myOptimizedOldLineShift = -1; private boolean myOptimizedOldLineShiftCalculated; - public DocumentEventImpl(Document document, int offset, CharSequence oldString, CharSequence newString, long oldTimeStamp, + public DocumentEventImpl(@NotNull Document document, + int offset, + CharSequence oldString, + CharSequence newString, + long oldTimeStamp, boolean wholeTextReplaced) { super(document); myOffset = offset; @@ -83,11 +89,13 @@ public class DocumentEventImpl extends DocumentEvent { return myNewLength; } + @NotNull @Override public CharSequence getOldFragment() { return myOldString; } + @NotNull @Override public CharSequence getNewFragment() { return myNewString; @@ -96,11 +104,11 @@ public class DocumentEventImpl extends DocumentEvent { @Override @NotNull public Document getDocument() { - return (Document) getSource(); + return (Document)getSource(); } public int getStartOldIndex() { - if(isStartOldIndexCalculated) return myStartOldIndex; + if (isStartOldIndexCalculated) return myStartOldIndex; isStartOldIndexCalculated = true; myStartOldIndex = getDocument().getLineNumber(myOffset); @@ -108,21 +116,21 @@ public class DocumentEventImpl extends DocumentEvent { } public boolean isOnlyOneLineChanged() { - if(isOnlyOneLineChangedCalculated) return isOnlyOneLineChanged; + if (isOnlyOneLineChangedCalculated) return isOnlyOneLineChanged; isOnlyOneLineChangedCalculated = true; isOnlyOneLineChanged = true; - for(int i=0; i= change.line0 + change.deleted) { newLine += change.inserted - change.deleted; - } else { + } + else { int delta = Math.min(change.inserted, line - change.line0); newLine = change.line1 + delta; break; @@ -172,16 +179,23 @@ public class DocumentEventImpl extends DocumentEvent { } public int translateLineViaDiffStrict(int line) throws FilesTooBigForDiffException { - if (myChange == null) buildDiff(); - Diff.Change change = myChange; + Diff.Change change = reBuildDiffIfNeeded(); if (change == null) return line; return Diff.translateLine(change, line); } - private void buildDiff() throws FilesTooBigForDiffException { - //Diff diff = new Diff(strings1, strings2); - //myChange = diff.diff_2(false); - myChange = Diff.buildChanges(myOldString, myNewString); + private Diff.Change reBuildDiffIfNeeded() throws FilesTooBigForDiffException { + if (myChange == TOO_BIG_FILE) throw new FilesTooBigForDiffException(0); + if (myChange == null) { + try { + myChange = Diff.buildChanges(myOldString, myNewString); + } + catch (FilesTooBigForDiffException e) { + myChange = TOO_BIG_FILE; + throw e; + } + } + return myChange; } public int getOptimizedLineShift() { diff --git a/platform/core-impl/src/com/intellij/openapi/vfs/local/CoreLocalVirtualFile.java b/platform/core-impl/src/com/intellij/openapi/vfs/local/CoreLocalVirtualFile.java index 067fe61a8266..f7c8749da965 100644 --- a/platform/core-impl/src/com/intellij/openapi/vfs/local/CoreLocalVirtualFile.java +++ b/platform/core-impl/src/com/intellij/openapi/vfs/local/CoreLocalVirtualFile.java @@ -31,10 +31,13 @@ import java.util.List; public class CoreLocalVirtualFile extends VirtualFile { private final CoreLocalFileSystem myFileSystem; private final File myIoFile; + private VirtualFile[] myChildren; + private final boolean isDirectory; public CoreLocalVirtualFile(CoreLocalFileSystem fileSystem, File ioFile) { myFileSystem = fileSystem; myIoFile = ioFile; + isDirectory = ioFile == null || ioFile.isDirectory(); } @NotNull @@ -56,17 +59,17 @@ public class CoreLocalVirtualFile extends VirtualFile { @Override public boolean isWritable() { - return myIoFile.canWrite(); + return false; // Core VFS isn't writable. } @Override public boolean isDirectory() { - return myIoFile.isDirectory(); + return isDirectory; } @Override public boolean isValid() { - return myIoFile.exists(); + return true; // Core VFS cannot change, doesn't refresh so once found, any file is writable } @Override @@ -77,12 +80,18 @@ public class CoreLocalVirtualFile extends VirtualFile { @Override public VirtualFile[] getChildren() { - List result = new ArrayList(); - final File[] files = myIoFile.listFiles(); - for (File file : files) { - result.add(new CoreLocalVirtualFile(myFileSystem, file)); + VirtualFile[] answer = myChildren; + if (answer == null) { + List result = new ArrayList(); + final File[] files = myIoFile.listFiles(); + for (File file : files) { + result.add(new CoreLocalVirtualFile(myFileSystem, file)); + } + answer = result.toArray(new VirtualFile[result.size()]); + + myChildren = answer; } - return result.toArray(new VirtualFile[result.size()]); + return answer; } @NotNull diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java b/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java index 553de3e50cb9..dd202dd57883 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java @@ -519,18 +519,17 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF } roots[i++] = psi; } - // getPsiRoots() returns languages in the same order - //if (roots.length > 1) { - // Arrays.sort(roots, FILE_BY_LANGUAGE_ID); - //} + if (roots.length > 1) { + Arrays.sort(roots, FILE_BY_LANGUAGE_ID); + } return roots; } - //private static final Comparator FILE_BY_LANGUAGE_ID = new Comparator() { - // @Override - // public int compare(PsiFile o1, PsiFile o2) { - // return o1.getLanguage().getID().compareTo(o2.getLanguage().getID()); - // } - //}; + private static final Comparator FILE_BY_LANGUAGE_ID = new Comparator() { + @Override + public int compare(PsiFile o1, PsiFile o2) { + return o1.getLanguage().getID().compareTo(o2.getLanguage().getID()); + } + }; @Override public boolean isPhysical() { diff --git a/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionParameters.java b/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionParameters.java index b7ac712d6767..56eb0c10af62 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionParameters.java +++ b/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionParameters.java @@ -100,4 +100,8 @@ public class CompletionParameters { public boolean isRelaxedMatching() { return myRelaxedMatching; } + + public CompletionParameters withPosition(PsiElement element, int offset) { + return new CompletionParameters(element, myOriginalFile, myCompletionType, offset, myInvocationCount, myLookup, myRelaxedMatching); + } } diff --git a/platform/lang-api/src/com/intellij/codeInsight/lookup/LookupElementPresentation.java b/platform/lang-api/src/com/intellij/codeInsight/lookup/LookupElementPresentation.java index 08f0eb90752e..e8552d0191e2 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/lookup/LookupElementPresentation.java +++ b/platform/lang-api/src/com/intellij/codeInsight/lookup/LookupElementPresentation.java @@ -167,4 +167,10 @@ public class LookupElementPresentation { public void setTypeGrayed(boolean typeGrayed) { myTypeGrayed = typeGrayed; } + + public static LookupElementPresentation renderElement(LookupElement element) { + LookupElementPresentation presentation = new LookupElementPresentation(); + element.renderElement(presentation); + return presentation; + } } diff --git a/platform/lang-api/src/com/intellij/codeInspection/ProblemsHolder.java b/platform/lang-api/src/com/intellij/codeInspection/ProblemsHolder.java index d768bc49e2fe..8933cb6006b8 100644 --- a/platform/lang-api/src/com/intellij/codeInspection/ProblemsHolder.java +++ b/platform/lang-api/src/com/intellij/codeInspection/ProblemsHolder.java @@ -28,7 +28,6 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiReference; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -91,7 +90,7 @@ public class ProblemsHolder { private boolean isInPsiFile(@NotNull PsiElement element) { PsiFile file = element.getContainingFile(); - return ArrayUtil.indexOf(myFile.getPsiRoots(), file) != -1; + return myFile.getViewProvider() == file.getViewProvider(); } private void redirectProblem(@NotNull final ProblemDescriptor problem, @NotNull final PsiElement target) { @@ -136,6 +135,10 @@ public class ProblemsHolder { } public void registerProblem(@NotNull PsiReference reference) { + registerProblem(reference, inresolvedReferenceMessage(reference), ProblemHighlightType.LIKE_UNKNOWN_SYMBOL); + } + + public static String inresolvedReferenceMessage(PsiReference reference) { String message; if (reference instanceof EmptyResolveMessageProvider) { String pattern = ((EmptyResolveMessageProvider)reference).getUnresolvedMessagePattern(); @@ -144,7 +147,7 @@ public class ProblemsHolder { else { message = CodeInsightBundle.message("error.cannot.resolve.default.message", reference.getCanonicalText()); } - registerProblem(reference, message, ProblemHighlightType.LIKE_UNKNOWN_SYMBOL); + return message; } /** diff --git a/platform/lang-api/src/com/intellij/execution/filters/CompositeFilter.java b/platform/lang-api/src/com/intellij/execution/filters/CompositeFilter.java index 335b039546b4..4c77cbbf99ee 100644 --- a/platform/lang-api/src/com/intellij/execution/filters/CompositeFilter.java +++ b/platform/lang-api/src/com/intellij/execution/filters/CompositeFilter.java @@ -70,7 +70,7 @@ public class CompositeFilter implements Filter, FilterMixin { //noinspection ForLoopReplaceableByForEach for (int i = 0; i < count; i++) { Filter filter = filters.get(i); - if (! (filter instanceof FilterMixin)) continue; + if (! (filter instanceof FilterMixin) || !((FilterMixin)filter).shouldRunHeavy()) continue; if (!dumb || DumbService.isDumbAware(filter)) { ((FilterMixin) filter).applyHeavyFilter(copiedFragment, startOffset, startLineNumber, consumer); } diff --git a/platform/lang-api/src/com/intellij/lang/cacheBuilder/DefaultWordsScanner.java b/platform/lang-api/src/com/intellij/lang/cacheBuilder/DefaultWordsScanner.java index 8f777e4864c9..3661f0524d16 100644 --- a/platform/lang-api/src/com/intellij/lang/cacheBuilder/DefaultWordsScanner.java +++ b/platform/lang-api/src/com/intellij/lang/cacheBuilder/DefaultWordsScanner.java @@ -19,6 +19,7 @@ import com.intellij.lexer.Lexer; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; import com.intellij.util.Processor; +import org.jetbrains.annotations.NotNull; /** * The default implementation of a words scanner based on a custom language lexer. @@ -31,6 +32,7 @@ public class DefaultWordsScanner implements WordsScanner { private final TokenSet myIdentifierTokenSet; private final TokenSet myCommentTokenSet; private final TokenSet myLiteralTokenSet; + private final TokenSet mySkipCodeContextTokenSet; private boolean myMayHaveFileRefsInLiterals; /** @@ -43,18 +45,33 @@ public class DefaultWordsScanner implements WordsScanner { */ public DefaultWordsScanner(final Lexer lexer, final TokenSet identifierTokenSet, final TokenSet commentTokenSet, final TokenSet literalTokenSet) { + this(lexer, identifierTokenSet, commentTokenSet, literalTokenSet, TokenSet.EMPTY); + } + + /** + * Creates a new instance of the words scanner. + * + * @param lexer the lexer used for breaking the text into tokens. + * @param identifierTokenSet the set of token types which represent identifiers. + * @param commentTokenSet the set of token types which represent comments. + * @param literalTokenSet the set of token types which represent literals. + * @param SkipCodeContextTokenSet the set of token types which should not be considered as code context. + */ + public DefaultWordsScanner(final Lexer lexer, final TokenSet identifierTokenSet, final TokenSet commentTokenSet, + final TokenSet literalTokenSet, @NotNull TokenSet skipCodeContextTokenSet) { myLexer = lexer; myIdentifierTokenSet = identifierTokenSet; myCommentTokenSet = commentTokenSet; myLiteralTokenSet = literalTokenSet; + mySkipCodeContextTokenSet = skipCodeContextTokenSet; } public void processWords(CharSequence fileText, Processor processor) { myLexer.start(fileText); WordOccurrence occurrence = null; // shared occurrence - while (myLexer.getTokenType() != null) { - final IElementType type = myLexer.getTokenType(); + IElementType type; + while ((type = myLexer.getTokenType()) != null) { if (myIdentifierTokenSet.contains(type)) { if (occurrence == null) { occurrence = new WordOccurrence(fileText, myLexer.getTokenStart(), myLexer.getTokenEnd(), WordOccurrence.Kind.CODE); @@ -70,9 +87,7 @@ public class DefaultWordsScanner implements WordsScanner { else if (myLiteralTokenSet.contains(type)) { if (!stripWords(processor, fileText, myLexer.getTokenStart(),myLexer.getTokenEnd(),WordOccurrence.Kind.LITERALS,occurrence, myMayHaveFileRefsInLiterals)) return; } - else { - // process all word-like characters as words - // Plugin writers may have (Maximka in JavaScript especially) some keyword token types omitted from the identifierTokenSet + else if (!mySkipCodeContextTokenSet.contains(type)) { if (!stripWords(processor, fileText, myLexer.getTokenStart(), myLexer.getTokenEnd(), WordOccurrence.Kind.CODE, occurrence, false)) return; } myLexer.advance(); diff --git a/platform/lang-api/src/com/intellij/openapi/projectRoots/JdkUtil.java b/platform/lang-api/src/com/intellij/openapi/projectRoots/JdkUtil.java index 23076fc95046..62ea6513fb23 100644 --- a/platform/lang-api/src/com/intellij/openapi/projectRoots/JdkUtil.java +++ b/platform/lang-api/src/com/intellij/openapi/projectRoots/JdkUtil.java @@ -40,6 +40,7 @@ import org.jetbrains.annotations.Nullable; import java.io.*; import java.nio.charset.Charset; import java.nio.charset.UnsupportedCharsetException; +import java.util.List; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.jar.Manifest; @@ -147,32 +148,13 @@ public class JdkUtil { commandLine.setExePath(exePath); ParametersList parametersList = javaParameters.getVMParametersList(); - commandLine.addParameters(parametersList.getList()); - - // Value of -Dfile.encoding and charset of GeneralCommandLine should be in sync in order process's input and output be correctly handled. - String encoding = parametersList.getPropertyValue("file.encoding"); - if (encoding == null) { - Charset charset = javaParameters.getCharset(); - if (charset == null) charset = EncodingManager.getInstance().getDefaultCharset(); - if (charset == null) charset = CharsetToolkit.getDefaultSystemCharset(); - commandLine.addParameter("-Dfile.encoding=" + charset.name()); - commandLine.setCharset(charset); - } - else { - try { - Charset charset = Charset.forName(encoding); - commandLine.setCharset(charset); - } - catch (UnsupportedCharsetException ignore) { - } - } - commandLine.setEnvParams(javaParameters.getEnv()); commandLine.setPassParentEnvs(javaParameters.isPassParentEnvs()); final Class commandLineWrapper; if (forceDynamicClasspath && (commandLineWrapper = getCommandLineWrapperClass()) != null) { File classpathFile = null; + File vmParamsFile = null; if(!parametersList.hasParameter("-classpath") && !parametersList.hasParameter("-cp")){ try { classpathFile = FileUtil.createTempFile("classpath", null); @@ -199,16 +181,55 @@ public class JdkUtil { catch (IOException e) { LOG.error(e); } + + try { + vmParamsFile = FileUtil.createTempFile("vm_params", null); + final PrintWriter writer = new PrintWriter(vmParamsFile); + try { + for (String param : parametersList.getList()) { + if (param.startsWith("-D")) { + writer.println(param); + } + } + } + finally { + writer.close(); + } + } + catch (IOException e) { + LOG.error(e); + } } + final List list = parametersList.getList(); + if (vmParamsFile == null) { + commandLine.addParameters(list); + } else { + for (String param : list) { + if (!param.trim().startsWith("-D")) { + commandLine.addParameter(param); + } + } + } + appendEncoding(javaParameters, commandLine, parametersList); if (classpathFile != null) { commandLine.addParameter(commandLineWrapper.getName()); commandLine.addParameter(classpathFile.getAbsolutePath()); } + if (vmParamsFile != null) { + commandLine.addParameter("@vm_params"); + commandLine.addParameter(vmParamsFile.getAbsolutePath()); + } } - else if(!parametersList.hasParameter("-classpath") && !parametersList.hasParameter("-cp")){ + else if (!parametersList.hasParameter("-classpath") && !parametersList.hasParameter("-cp")){ + commandLine.addParameters(parametersList.getList()); + appendEncoding(javaParameters, commandLine, parametersList); + commandLine.addParameter("-classpath"); commandLine.addParameter(javaParameters.getClassPath().getPathsString()); + } else { + commandLine.addParameters(parametersList.getList()); + appendEncoding(javaParameters, commandLine, parametersList); } final String mainClass = javaParameters.getMainClass(); @@ -220,6 +241,26 @@ public class JdkUtil { return commandLine; } + private static void appendEncoding(SimpleJavaParameters javaParameters, GeneralCommandLine commandLine, ParametersList parametersList) { + // Value of -Dfile.encoding and charset of GeneralCommandLine should be in sync in order process's input and output be correctly handled. + String encoding = parametersList.getPropertyValue("file.encoding"); + if (encoding == null) { + Charset charset = javaParameters.getCharset(); + if (charset == null) charset = EncodingManager.getInstance().getDefaultCharset(); + if (charset == null) charset = CharsetToolkit.getDefaultSystemCharset(); + commandLine.addParameter("-Dfile.encoding=" + charset.name()); + commandLine.setCharset(charset); + } + else { + try { + Charset charset = Charset.forName(encoding); + commandLine.setCharset(charset); + } + catch (UnsupportedCharsetException ignore) { + } + } + } + @Nullable private static Class getCommandLineWrapperClass() { try { diff --git a/platform/lang-api/src/com/intellij/openapi/projectRoots/ui/PathEditor.java b/platform/lang-api/src/com/intellij/openapi/projectRoots/ui/PathEditor.java index bf285be9c8a4..26732a0f1817 100644 --- a/platform/lang-api/src/com/intellij/openapi/projectRoots/ui/PathEditor.java +++ b/platform/lang-api/src/com/intellij/openapi/projectRoots/ui/PathEditor.java @@ -17,7 +17,6 @@ package com.intellij.openapi.projectRoots.ui; import com.intellij.ide.DataManager; import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CustomShortcutSet; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; @@ -26,7 +25,6 @@ import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileChooser.FileChooserDialog; import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.vfs.JarFileSystem; @@ -61,7 +59,7 @@ public class PathEditor { private DefaultListModel myModel; private final Set myAllFiles = new HashSet(); private boolean myModified = false; - private boolean myEnabled = false; + protected boolean myEnabled = false; private static final Icon ICON_INVALID = IconLoader.getIcon("/nodes/ppInvalid.png"); private static final Icon ICON_EMPTY = IconLoader.getIcon("/nodes/emptyNode.png"); private final FileChooserDescriptor myDescriptor; @@ -81,13 +79,6 @@ public class PathEditor { myEnabled = enabled; } - protected boolean isShowUrlButton() { - return false; - } - - protected void onSpecifyUrlButtonClicked() { - } - protected void setModified(boolean modified) { myModified = modified; } @@ -143,22 +134,7 @@ public class PathEditor { } }); - if (isShowUrlButton()) { - AnActionButton specifyUrlButton = new AnActionButton(ProjectBundle.message("sdk.paths.specify.url.button"), PlatformIcons.TABLE_URL) { - @Override - public void actionPerformed(AnActionEvent e) { - onSpecifyUrlButtonClicked(); - } - }; - specifyUrlButton.setShortcut(CustomShortcutSet.fromString("alt S")); - specifyUrlButton.addCustomUpdater(new AnActionButtonUpdater() { - @Override - public boolean isEnabled(AnActionEvent e) { - return myEnabled && !isUrlInserted(); - } - }); - toolbarDecorator.addExtraAction(specifyUrlButton); - } + addToolbarButtons(toolbarDecorator); myPanel = toolbarDecorator.createPanel(); myPanel.setBorder(null); @@ -180,6 +156,9 @@ public class PathEditor { return myPanel; } + protected void addToolbarButtons(ToolbarDecorator toolbarDecorator) { + } + protected void doRemoveItems(int[] idxs, JList list) { List removedItems = ListUtil.removeIndices(list, idxs); itemsRemoved(removedItems); @@ -234,7 +213,7 @@ public class PathEditor { return files; } - private boolean isUrlInserted() { + protected boolean isUrlInserted() { if (getRowCount() > 0) { return ((VirtualFile)getListModel().lastElement()).getFileSystem() instanceof HttpFileSystem; } diff --git a/platform/lang-api/src/com/intellij/psi/util/PsiUtilBase.java b/platform/lang-api/src/com/intellij/psi/util/PsiUtilBase.java index 283c09222413..56a9c1960525 100644 --- a/platform/lang-api/src/com/intellij/psi/util/PsiUtilBase.java +++ b/platform/lang-api/src/com/intellij/psi/util/PsiUtilBase.java @@ -42,6 +42,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.util.*; public class PsiUtilBase extends PsiUtilCore { @@ -51,6 +52,12 @@ public class PsiUtilBase extends PsiUtilCore { throw new IllegalAccessError(); } }; + public static final Comparator LANGUAGE_COMPARATOR = new Comparator() { + @Override + public int compare(Language o1, Language o2) { + return o1.getID().compareTo(o2.getID()); + } + }; public static int getRootIndex(PsiElement root) { ASTNode node = root.getNode(); @@ -59,11 +66,18 @@ public class PsiUtilBase extends PsiUtilCore { } if(node != null) root = node.getPsi(); final PsiFile containingFile = root.getContainingFile(); - final PsiFile[] psiRoots = containingFile.getPsiRoots(); - for (int i = 0; i < psiRoots.length; i++) { - if(root == psiRoots[i]) return i; + FileViewProvider provider = containingFile.getViewProvider(); + Set languages = provider.getLanguages(); + if (languages.size() == 1) { + return 0; } - throw new RuntimeException("invalid element"); + List array = new ArrayList(languages); + Collections.sort(array, LANGUAGE_COMPARATOR); + for (int i = 0; i < array.size(); i++) { + Language language = array.get(i); + if (provider.getPsi(language) == containingFile) return i; + } + throw new RuntimeException("Cannot find root for: "+root); } @NotNull diff --git a/platform/lang-api/src/com/intellij/refactoring/rename/PreferrableNameSuggestionProvider.java b/platform/lang-api/src/com/intellij/refactoring/rename/PreferrableNameSuggestionProvider.java new file mode 100644 index 000000000000..a99ce5ede9a9 --- /dev/null +++ b/platform/lang-api/src/com/intellij/refactoring/rename/PreferrableNameSuggestionProvider.java @@ -0,0 +1,26 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.refactoring.rename; + +/** + * User: anna + * Date: 2/8/12 + */ +public abstract class PreferrableNameSuggestionProvider implements NameSuggestionProvider { + public boolean shouldCheckOthers() { + return true; + } +} diff --git a/platform/lang-impl/src/com/intellij/application/options/CodeStyleAbstractPanel.java b/platform/lang-impl/src/com/intellij/application/options/CodeStyleAbstractPanel.java index cb467e646318..2ba65b47b927 100644 --- a/platform/lang-impl/src/com/intellij/application/options/CodeStyleAbstractPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/CodeStyleAbstractPanel.java @@ -615,10 +615,8 @@ public abstract class CodeStyleAbstractPanel implements Disposable { return myCurrentSettings; } - public void setupCopyFromMenu(Menu copyMenu) { - if (copyMenu.getItemCount() > 0) { - copyMenu.removeAll(); - } + public void setupCopyFromMenu(JPopupMenu copyMenu) { + copyMenu.removeAll(); } public boolean isCopyFromMenuAvailable() { diff --git a/platform/lang-impl/src/com/intellij/application/options/TabbedLanguageCodeStylePanel.java b/platform/lang-impl/src/com/intellij/application/options/TabbedLanguageCodeStylePanel.java index d0732dd73fab..8de3532808a5 100644 --- a/platform/lang-impl/src/com/intellij/application/options/TabbedLanguageCodeStylePanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/TabbedLanguageCodeStylePanel.java @@ -28,7 +28,6 @@ import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectUtil; import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.IconLoader; import com.intellij.psi.codeStyle.*; import com.intellij.ui.components.JBTabbedPane; import org.jetbrains.annotations.NotNull; @@ -36,7 +35,8 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; -import java.awt.event.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -47,15 +47,12 @@ import java.util.List; */ public abstract class TabbedLanguageCodeStylePanel extends CodeStyleAbstractPanel { - - private final static Icon COPY_ICON = IconLoader.getIcon("/actions/import.png"); - private CodeStyleAbstractPanel myActiveTab; private List myTabs; private JPanel myPanel; private JTabbedPane myTabbedPane; private PredefinedCodeStyle[] myPredefinedCodeStyles; - private PopupMenu myCopyFromMenu; + private JPopupMenu myCopyFromMenu; protected TabbedLanguageCodeStylePanel(@Nullable Language language, CodeStyleSettings currentSettings, CodeStyleSettings settings) { super(language, currentSettings, settings); @@ -120,37 +117,22 @@ public abstract class TabbedLanguageCodeStylePanel extends CodeStyleAbstractPane myTabs = new ArrayList(); myPanel.add(myTabbedPane); initTabs(getSettings()); - addSetFrom(); } assert !myTabs.isEmpty(); } - private void addSetFrom() { - myPredefinedCodeStyles = getPredefinedStyles(); - JLabel dummyLabel = new JLabel(""); - myTabbedPane.addTab("Set From...", dummyLabel); - int dummyIndex = myTabbedPane.indexOfComponent(dummyLabel); - myTabbedPane.setEnabledAt(dummyIndex, false); - JPanel setFromPanel = new JPanel(); - setFromPanel.setBorder(BorderFactory.createEtchedBorder()); - setFromPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 0)); - final JLabel setFromLabel = new JLabel("Set from..."); - setFromPanel.add(setFromLabel); - setFromLabel.setIcon(COPY_ICON); - setFromLabel.addMouseListener(new MouseAdapter() { - @Override - public void mousePressed(MouseEvent e) { - initCopyFromMenu(setFromLabel); - myCopyFromMenu.show(e.getComponent(), e.getX(), e.getY()); - } - }); - myTabbedPane.setTabComponentAt(dummyIndex, setFromPanel); + public void showSetFrom(Object e) { + final Container component = (Container)e; + final Component[] components = component.getComponents(); + final Component last = components[components.length - 1]; + initCopyFromMenu(last); + myCopyFromMenu.show(last, 0, last.getHeight() + 3); } - - private void initCopyFromMenu(JComponent parent) { + + private void initCopyFromMenu(Component component) { if (myCopyFromMenu == null) { - myCopyFromMenu = new PopupMenu(); - parent.add(myCopyFromMenu); + myCopyFromMenu = new JPopupMenu(); + //component.add(myCopyFromMenu); setupCopyFromMenu(myCopyFromMenu); } } @@ -283,13 +265,13 @@ public abstract class TabbedLanguageCodeStylePanel extends CodeStyleAbstractPane @Override - public void setupCopyFromMenu(Menu copyMenu) { + public void setupCopyFromMenu(JPopupMenu copyMenu) { super.setupCopyFromMenu(copyMenu); if (myPredefinedCodeStyles.length > 0) { - Menu langs = new Menu("Language"); //TODO: Move to resource bundle + JMenuItem langs = new JMenuItem("Language"); //TODO: Move to resource bundle copyMenu.add(langs); fillLanguages(langs); - Menu predefined = new Menu("Predefined Style"); //TODO: Move to resource bundle + JMenuItem predefined = new JMenuItem("Predefined Style"); //TODO: Move to resource bundle copyMenu.add(predefined); fillPredefined(predefined); } @@ -299,14 +281,14 @@ public abstract class TabbedLanguageCodeStylePanel extends CodeStyleAbstractPane } - private void fillLanguages(Menu parentMenu) { + private void fillLanguages(JComponent parentMenu) { Language[] languages = LanguageCodeStyleSettingsProvider.getLanguagesWithCodeStyleSettings(); @SuppressWarnings("UnnecessaryFullyQualifiedName") - java.util.List langItems = new ArrayList(); + java.util.List langItems = new ArrayList(); for (final Language lang : languages) { if (!lang.equals(getDefaultLanguage())) { final String langName = LanguageCodeStyleSettingsProvider.getLanguageName(lang); - MenuItem langItem = new MenuItem(langName); + JMenuItem langItem = new JMenuItem(langName); langItem.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent e) { @@ -316,20 +298,20 @@ public abstract class TabbedLanguageCodeStylePanel extends CodeStyleAbstractPane langItems.add(langItem); } } - Collections.sort(langItems, new Comparator() { + Collections.sort(langItems, new Comparator() { @Override - public int compare(MenuItem item1, MenuItem item2) { - return item1.getLabel().compareToIgnoreCase(item2.getLabel()); + public int compare(JMenuItem item1, JMenuItem item2) { + return item1.getText().compareToIgnoreCase(item2.getText()); } }); - for (MenuItem langItem : langItems) { + for (JMenuItem langItem : langItems) { parentMenu.add(langItem); } } - private void fillPredefined(Menu parentMenu) { + private void fillPredefined(JMenuItem parentMenu) { for (final PredefinedCodeStyle predefinedCodeStyle : myPredefinedCodeStyles) { - MenuItem predefinedItem = new MenuItem(predefinedCodeStyle.getName()); + JMenuItem predefinedItem = new JMenuItem(predefinedCodeStyle.getName()); parentMenu.add(predefinedItem); predefinedItem.addActionListener(new ActionListener() { @Override diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleMainPanel.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleMainPanel.java index 3ac71f3f27d8..f998dfb410c7 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleMainPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleMainPanel.java @@ -16,18 +16,20 @@ package com.intellij.application.options.codeStyle; +import com.intellij.application.options.CodeStyleAbstractPanel; +import com.intellij.application.options.TabbedLanguageCodeStylePanel; import com.intellij.lang.Language; import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.ui.DetailsComponent; import com.intellij.psi.codeStyle.CodeStyleScheme; import com.intellij.psi.codeStyle.CodeStyleSchemes; -import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider; import com.intellij.util.Alarm; import org.jetbrains.annotations.NonNls; import javax.swing.*; import java.awt.*; +import java.awt.event.ActionEvent; import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -93,6 +95,7 @@ public class CodeStyleMainPanel extends JPanel implements LanguageSelectorListen myDetailsComponent.setPaintBorder(false); myDetailsComponent.setContent(mySettingsPanel); myDetailsComponent.setText(getDisplayName()); + myDetailsComponent.setBannerMinHeight(24); add(myDetailsComponent.getComponent(), BorderLayout.CENTER); @@ -120,6 +123,7 @@ public class CodeStyleMainPanel extends JPanel implements LanguageSelectorListen ensureCurrentPanel().onSomethingChanged(); String schemeName = myModel.getSelectedScheme().getName(); myDetailsComponent.setText(schemeName); + updateSetFrom(); myLayout.show(mySettingsPanel, schemeName); } } @@ -137,6 +141,21 @@ public class CodeStyleMainPanel extends JPanel implements LanguageSelectorListen } } + private void updateSetFrom() { + final CodeStyleAbstractPanel selectedPanel = ensureCurrentPanel().getSelectedPanel(); + if (selectedPanel instanceof TabbedLanguageCodeStylePanel) { + myDetailsComponent.setBannerActions(new Action[]{new AbstractAction("Set from...") { + @Override + public void actionPerformed(ActionEvent e) { + final CodeStyleAbstractPanel selectedPanel = ensureCurrentPanel().getSelectedPanel(); + if (selectedPanel instanceof TabbedLanguageCodeStylePanel) { + ((TabbedLanguageCodeStylePanel)selectedPanel).showSetFrom(e.getSource()); + } + } + }}); + } + } + public NewCodeStyleSettingsPanel[] getPanels() { final Collection panels = mySettingsPanels.values(); return panels.toArray(new NewCodeStyleSettingsPanel[panels.size()]); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/HectorComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/HectorComponent.java index f43f4e7ad6ce..d8d1cea46466 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/HectorComponent.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/HectorComponent.java @@ -39,11 +39,13 @@ import com.intellij.profile.codeInspection.ui.ErrorsConfigurable; import com.intellij.psi.FileViewProvider; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import com.intellij.psi.util.PsiUtilBase; import com.intellij.ui.Gray; import com.intellij.ui.HyperlinkLabel; import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.awt.RelativePoint; import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -55,6 +57,7 @@ import javax.swing.plaf.basic.BasicSliderUI; import java.awt.*; import java.lang.ref.WeakReference; import java.util.*; +import java.util.List; /** * User: anna @@ -70,7 +73,7 @@ public class HectorComponent extends JPanel { private final String myTitle = EditorBundle.message("hector.highlighting.level.title"); - public HectorComponent(PsiFile file) { + public HectorComponent(@NotNull PsiFile file) { super(new GridBagLayout()); setBorder(BorderFactory.createEmptyBorder(0, 0, 7, 0)); myFile = file; @@ -83,15 +86,8 @@ public class HectorComponent extends JPanel { final boolean notInLibrary = !fileIndex.isInLibrarySource(virtualFile) && !fileIndex.isInLibraryClasses(virtualFile) || fileIndex.isInContent(virtualFile); final FileViewProvider viewProvider = myFile.getViewProvider(); - //List languages = new ArrayList(viewProvider.getLanguages()); - //Collections.sort(languages, new Comparator() { - // @Override - // public int compare(Language o1, Language o2) { - // return o1.getID().compareTo(o2.getID()); - // } - //}); - Collection languages = viewProvider.getLanguages(); - + List languages = new ArrayList(viewProvider.getLanguages()); + Collections.sort(languages, PsiUtilBase.LANGUAGE_COMPARATOR); for (Language language : languages) { @SuppressWarnings("UseOfObsoleteCollectionType") final Hashtable sliderLabels = new Hashtable(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficLightRenderer.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficLightRenderer.java index 592797f8b32e..dd89cd16c6e2 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficLightRenderer.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficLightRenderer.java @@ -20,6 +20,7 @@ import com.intellij.codeHighlighting.HighlightDisplayLevel; import com.intellij.codeHighlighting.TextEditorHighlightingPass; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.codeInsight.daemon.impl.analysis.HighlightLevelUtil; +import com.intellij.lang.Language; import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; @@ -36,6 +37,7 @@ import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.IconLoader; +import com.intellij.psi.FileViewProvider; import com.intellij.psi.PsiFile; import com.intellij.ui.LayeredIcon; import com.intellij.util.ArrayUtil; @@ -50,6 +52,7 @@ import java.awt.*; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Set; public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable { private static final Icon IN_PROGRESS_ICON = IconLoader.getIcon("/general/errorsInProgress.png"); @@ -166,13 +169,15 @@ public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable { List noInspectionRoots = new ArrayList(); List noHighlightingRoots = new ArrayList(); - final PsiFile[] roots = myFile.getPsiRoots(); - for (PsiFile file : roots) { - if (!HighlightLevelUtil.shouldHighlight(file)) { - noHighlightingRoots.add(file.getLanguage().getID()); + FileViewProvider provider = myFile.getViewProvider(); + Set languages = provider.getLanguages(); + for (Language language : languages) { + PsiFile root = provider.getPsi(language); + if (!HighlightLevelUtil.shouldHighlight(root)) { + noHighlightingRoots.add(language.getID()); } - else if (!HighlightLevelUtil.shouldInspect(file)) { - noInspectionRoots.add(file.getLanguage().getID()); + else if (!HighlightLevelUtil.shouldInspect(root)) { + noInspectionRoots.add(language.getID()); } } DaemonCodeAnalyzerStatus status = new DaemonCodeAnalyzerStatus(); @@ -180,7 +185,7 @@ public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable { status.noHighlightingRoots = noHighlightingRoots.isEmpty() ? null : ArrayUtil.toStringArray(noHighlightingRoots); status.errorCount = errorCount.clone(); - status.rootsNumber = roots.length; + status.rootsNumber = languages.size(); fillDaemonCodeAnalyzerErrorsStatus(status, fillErrorsCount, severityRegistrar); List passes = myDaemonCodeAnalyzer.getPassesToShowProgressFor(myDocument); status.passStati = passes.isEmpty() ? Collections.emptyList() : diff --git a/platform/lang-impl/src/com/intellij/codeInspection/LossyEncodingInspection.java b/platform/lang-impl/src/com/intellij/codeInspection/LossyEncodingInspection.java index 0da4475a2058..38747fe3759f 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/LossyEncodingInspection.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/LossyEncodingInspection.java @@ -78,8 +78,8 @@ public class LossyEncodingInspection extends LocalInspectionTool { @Nullable public ProblemDescriptor[] checkFile(@NotNull PsiFile file, @NotNull InspectionManager manager, boolean isOnTheFly) { if (InjectedLanguageManager.getInstance(file.getProject()).isInjectedFragment(file)) return null; - if (ArrayUtil.find(file.getPsiRoots(), file) != 0) return null; if (!file.isPhysical()) return null; + if (file.getViewProvider().getBaseLanguage() != file.getLanguage()) return null; VirtualFile virtualFile = file.getVirtualFile(); if (virtualFile == null) return null; if (virtualFile.getFileSystem() != LocalFileSystem.getInstance() diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/DescriptorProviderInspection.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/DescriptorProviderInspection.java index 2d8d5ec100a3..6503e871fc90 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/DescriptorProviderInspection.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/DescriptorProviderInspection.java @@ -187,6 +187,14 @@ public abstract class DescriptorProviderInspection extends InspectionTool implem getIgnoredElements().put(refEntity, problemDescriptors); } + public void ignoreCurrentElementProblem(RefEntity refEntity, CommonProblemDescriptor descriptor) { + CommonProblemDescriptor[] descriptors = getIgnoredElements().get(refEntity); + if (descriptors == null) { + descriptors = new CommonProblemDescriptor[0]; + } + getIgnoredElements().put(refEntity, ArrayUtil.append(descriptors, descriptor)); + } + private static boolean isIgnoreProblem(QuickFix[] problemFixes, Set fixes, int idx){ if (problemFixes == null || fixes == null) { return true; @@ -451,6 +459,17 @@ public abstract class DescriptorProviderInspection extends InspectionTool implem return false; } + public boolean isProblemResolved(RefEntity refEntity, CommonProblemDescriptor descriptor) { + if (getIgnoredElements() == null) return false; + for (RefEntity entity : getIgnoredElements().keySet()) { + if (Comparing.equal(entity, refEntity)) { + final CommonProblemDescriptor[] descriptors = getIgnoredElements().get(refEntity); + return ArrayUtil.contains(descriptor, descriptors); + } + } + return false; + } + public FileStatus getProblemStatus(final CommonProblemDescriptor descriptor) { final GlobalInspectionContextImpl context = getContext(); if (context != null && context.getUIOptions().SHOW_DIFF_WITH_PREVIOUS_RUN){ diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/ProblemDescriptionNode.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/ProblemDescriptionNode.java index 2610ab6d0fb5..b92dab9a6384 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/ProblemDescriptionNode.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/ProblemDescriptionNode.java @@ -95,11 +95,11 @@ public class ProblemDescriptionNode extends InspectionTreeNode { public boolean isResolved() { - return myElement instanceof RefElement && myTool.isElementIgnored(myElement); + return myElement instanceof RefElement && myTool.isProblemResolved(myElement, getDescriptor()); } public void ignoreElement() { - myTool.ignoreCurrentElement(getElement()); + myTool.ignoreCurrentElementProblem(getElement(), getDescriptor()); } public void amnesty() { diff --git a/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleBase.java b/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleBase.java index 6b6fd6351e66..452f22b6a61b 100644 --- a/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleBase.java +++ b/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleBase.java @@ -617,6 +617,7 @@ public abstract class LogConsoleBase extends AdditionalTabComponent implements L myAlarm.addRequest(this, 100); } }; + if (myAlarm.isDisposed()) return; myAlarm.addRequest(runnable, 10); } diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java index 39e3f980d4df..e9c60bb92039 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java @@ -985,7 +985,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo public static class ClearAllAction extends DumbAwareAction { public ClearAllAction() { - super(ExecutionBundle.message("clear.all.from.console.action.name")); + super(ExecutionBundle.message("clear.all.from.console.action.name"), "Clear the contents of the console", IconLoader.findIcon("/actions/gc.png")); } @Override @@ -1356,21 +1356,20 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo final AnAction autoScrollToTheEndAction = new ScrollToTheEndToolbarAction(myEditor); //Initializing custom actions - final AnAction[] consoleActions = new AnAction[4 + customActions.size()]; + final AnAction[] consoleActions = new AnAction[5 + customActions.size()]; consoleActions[0] = prevAction; consoleActions[1] = nextAction; consoleActions[2] = switchSoftWrapsAction; consoleActions[3] = autoScrollToTheEndAction; + consoleActions[4] = new ClearAllAction(); //consoleActions[4] = new ShowRecentlyChanged(); for (int i = 0; i < customActions.size(); ++i) { - consoleActions[i + 4] = customActions.get(i); + consoleActions[i + 5] = customActions.get(i); } ConsoleActionsPostProcessor[] postProcessors = Extensions.getExtensions(ConsoleActionsPostProcessor.EP_NAME); AnAction[] result = consoleActions; - if (postProcessors != null) { - for (ConsoleActionsPostProcessor postProcessor : postProcessors) { - result = postProcessor.postProcess(this, result); - } + for (ConsoleActionsPostProcessor postProcessor : postProcessors) { + result = postProcessor.postProcess(this, result); } return result; } diff --git a/platform/lang-impl/src/com/intellij/execution/ui/RunContentManagerImpl.java b/platform/lang-impl/src/com/intellij/execution/ui/RunContentManagerImpl.java index 0a6f6b508feb..a9db26f1d957 100644 --- a/platform/lang-impl/src/com/intellij/execution/ui/RunContentManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/ui/RunContentManagerImpl.java @@ -48,6 +48,7 @@ import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.openapi.wm.ex.ToolWindowManagerAdapter; import com.intellij.openapi.wm.ex.ToolWindowManagerEx; import com.intellij.ui.content.*; +import com.intellij.ui.content.impl.ContentImpl; import com.intellij.ui.docking.DockManager; import com.intellij.util.concurrency.Semaphore; import com.intellij.util.containers.ContainerUtil; @@ -279,7 +280,7 @@ public class RunContentManagerImpl implements RunContentManager, Disposable { getSyncPublisher().contentRemoved(oldDescriptor, executor); oldDescriptor.dispose(); // is of the same category, can be reused } - else if (descriptor.getAttachedContent() == null) { + else if (descriptor.getAttachedContent() == null || !descriptor.getAttachedContent().isValid() ) { content = createNewContent(contentManager, descriptor, executor); final Icon icon = descriptor.getIcon(); content.setIcon(icon == null ? executor.getToolWindowIcon() : icon); diff --git a/platform/lang-impl/src/com/intellij/execution/ui/layout/impl/RunnerContentUi.java b/platform/lang-impl/src/com/intellij/execution/ui/layout/impl/RunnerContentUi.java index d7cdcf4eb107..59c1dfd29bc9 100644 --- a/platform/lang-impl/src/com/intellij/execution/ui/layout/impl/RunnerContentUi.java +++ b/platform/lang-impl/src/com/intellij/execution/ui/layout/impl/RunnerContentUi.java @@ -811,9 +811,10 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac private void updateTabsUI(final boolean validateNow) { boolean hasToolbarContent = rebuildToolbar(); + Set usedNames = new HashSet(); List tabs = myTabs.getTabs(); for (TabInfo each : tabs) { - hasToolbarContent |= updateTabUI(each); + hasToolbarContent |= updateTabUI(each, usedNames); } int tabsCount = tabs.size(); for (RunnerContentUi child : myChildren) { @@ -827,7 +828,7 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac } } - private boolean updateTabUI(TabInfo tab) { + private boolean updateTabUI(TabInfo tab, Set usedNames) { TabImpl t = getTabFor(tab); if (t == null) { return false; @@ -842,7 +843,7 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac String title = contents.size() > 1 ? t.getDisplayName() : null; if (title == null) { final String name = myLayoutSettings.getDefaultDisplayName(t.getDefaultIndex()); - if (name != null && contents.size() > 1) { + if (name != null && contents.size() > 1 && !usedNames.contains(name)) { title = name; } else { title = StringUtil.join(contents, new NotNullFunction() { @@ -854,14 +855,16 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac }, " | "); } } + usedNames.add(title); - tab.setHidden(true); + boolean hidden = true; for (Content content : contents) { if (!grid.isMinimized(content)) { - tab.setHidden(false); + hidden = false; break; } } + tab.setHidden(hidden); if (icon == null && contents.size() == 1) { icon = contents.get(0).getIcon(); } @@ -1609,6 +1612,7 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac @Override public void dragOutCancelled(TabInfo source) { + source.setHidden(false); mySession.cancel(); mySession = null; } diff --git a/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java b/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java index fa52ac698e9b..80ead536ae99 100644 --- a/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java +++ b/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java @@ -20,11 +20,9 @@ import com.intellij.codeInsight.hint.HintManager; import com.intellij.codeInsight.hint.HintUtil; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.find.FindManager; -import com.intellij.find.findUsages.AbstractFindUsagesDialog; -import com.intellij.find.findUsages.FindUsagesHandler; -import com.intellij.find.findUsages.FindUsagesManager; -import com.intellij.find.findUsages.PsiElement2UsageTargetAdapter; +import com.intellij.find.findUsages.*; import com.intellij.find.impl.FindManagerImpl; +import com.intellij.ide.DataManager; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ActionManagerEx; @@ -225,14 +223,15 @@ public class ShowUsagesAction extends AnAction implements PopupAction { } }; FindUsagesManager findUsagesManager = ((FindManagerImpl)FindManager.getInstance(handler.getProject())).getFindUsagesManager(); - presentation = findUsagesManager.processUsages(handler, collect); + FindUsagesOptions options = handler.getFindUsagesOptions(DataManager.getInstance().getDataContext()); + presentation = findUsagesManager.processUsages(handler, collect, options); if (presentation == null) { Disposer.dispose(usageView); return; } final String title = presentation.getTabText(); - JBPopup popup = createUsagePopup(usages, visibleNodes, title, handler, editor, popupPosition, maxUsages, usageView); + JBPopup popup = createUsagePopup(usages, visibleNodes, title, handler, editor, popupPosition, maxUsages, usageView, options); if (popup == null) { Disposer.dispose(usageView); } @@ -301,9 +300,9 @@ public class ShowUsagesAction extends AnAction implements PopupAction { } } - private static String searchScopePresentableName(final FindUsagesHandler handler) { - SearchScope searchScope = FindUsagesManager.getCurrentSearchScope(handler); - if (searchScope == null) searchScope = ProjectScope.getAllScope(handler.getProject()); + private static String searchScopePresentableName(FindUsagesOptions options, Project project) { + SearchScope searchScope = options.searchScope; + if (searchScope == null) searchScope = ProjectScope.getAllScope(project); return searchScope.getDisplayName(); } @@ -314,14 +313,15 @@ public class ShowUsagesAction extends AnAction implements PopupAction { final Editor editor, final RelativePoint popupPosition, final int maxUsages, - final UsageViewImpl usageView) { + final UsageViewImpl usageView, FindUsagesOptions options) { boolean hasMore = visibleNodes.remove(UsageViewImpl.NULL_NODE); final Project project = handler.getProject(); if (visibleNodes.isEmpty()) { if (usages.isEmpty()) { - String text = UsageViewBundle.message("no.usages.found.in", searchScopePresentableName(handler)); + String text = UsageViewBundle.message("no.usages.found.in", searchScopePresentableName(options, + project)); showHint(text, editor, popupPosition, handler, maxUsages); return null; } @@ -332,7 +332,8 @@ public class ShowUsagesAction extends AnAction implements PopupAction { if (visibleNodes.size() == 1 && usages.size() == 1) { //the only usage Usage usage = visibleNodes.iterator().next().getUsage(); - navigateAndHint(usage, UsageViewBundle.message("show.usages.only.usage", searchScopePresentableName(handler)), handler, popupPosition, + navigateAndHint(usage, UsageViewBundle.message("show.usages.only.usage", + searchScopePresentableName(options, project)), handler, popupPosition, maxUsages); return null; } @@ -340,7 +341,8 @@ public class ShowUsagesAction extends AnAction implements PopupAction { // usage view can filter usages down to one Usage usage = visibleNodes.iterator().next().getUsage(); if (areAllUsagesInThisLine(usage, usages)) { - String hint = UsageViewBundle.message("all.usages.are.in.this.line", usages.size(), searchScopePresentableName(handler)); + String hint = UsageViewBundle.message("all.usages.are.in.this.line", usages.size(), + searchScopePresentableName(options, project)); navigateAndHint(usage, hint, handler, popupPosition, maxUsages); return null; } diff --git a/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesManager.java b/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesManager.java index 2103f229738b..1682455dfe00 100644 --- a/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesManager.java +++ b/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesManager.java @@ -20,7 +20,6 @@ import com.intellij.codeInsight.hint.HintManager; import com.intellij.codeInsight.hint.HintManagerImpl; import com.intellij.codeInsight.hint.HintUtil; import com.intellij.find.FindBundle; -import com.intellij.ide.DataManager; import com.intellij.lang.findUsages.LanguageFindUsages; import com.intellij.navigation.NavigationItem; import com.intellij.openapi.actionSystem.ActionManager; @@ -273,13 +272,6 @@ public class FindUsagesManager implements JDOMExternalizable { } } - @Nullable - public static SearchScope getCurrentSearchScope(FindUsagesHandler handler) { - if (handler == null) return null; - FindUsagesOptions findUsagesOptions = handler.getFindUsagesOptions(); - return findUsagesOptions.searchScope; - } - public boolean isUsed(@NotNull PsiElement element, @NotNull FindUsagesOptions findUsagesOptions) { FindUsagesHandler handler = getFindUsagesHandler(element, true); if (handler == null) return false; @@ -298,11 +290,10 @@ public class FindUsagesManager implements JDOMExternalizable { // return null on failure or cancel @Nullable - public UsageViewPresentation processUsages(FindUsagesHandler handler, @NotNull final Processor processor) { + public UsageViewPresentation processUsages(FindUsagesHandler handler, + @NotNull final Processor processor, FindUsagesOptions findUsagesOptions) { if (handler == null) return null; - FindUsagesOptions findUsagesOptions = handler.getFindUsagesOptions(DataManager.getInstance().getDataContext()); - PsiElement element = handler.getPsiElement(); LOG.assertTrue(element.isValid()); final UsageInfoToUsageConverter.TargetElementsDescriptor descriptor = diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java index 14d7b9b9c5e5..1e5bdc1ddfd6 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java @@ -386,7 +386,7 @@ public class FindInProjectUtil { public boolean processFile(VirtualFile virtualFile) { if (!virtualFile.isDirectory() && (fileMaskRegExp == null || fileMaskRegExp.matcher(virtualFile.getName()).matches()) && - (customScope == null || customScope.contains(virtualFile))) { + customScope.contains(virtualFile)) { final PsiFile psiFile = psiManager.findFile(virtualFile); if (psiFile != null && !filesForFastWordSearch.contains(psiFile)) { myFiles.add(psiFile); @@ -403,10 +403,10 @@ public class FindInProjectUtil { if (psiDirectory == null) { boolean success = fileIndex.iterateContent(iterator); - if (success && customScope instanceof GlobalSearchScope && ((GlobalSearchScope)customScope).isSearchInLibraries()) { + if (success && customScope.isSearchInLibraries()) { OrderEnumerator enumerator = module == null ? OrderEnumerator.orderEntries(project) : OrderEnumerator.orderEntries(module); final VirtualFile[] librarySources = enumerator.withoutModuleSourceEntries().withoutDepModules().getSourceRoots(); - iterateAll(librarySources, (GlobalSearchScope)customScope, iterator); + iterateAll(librarySources, customScope, iterator); } } else { @@ -440,11 +440,14 @@ public class FindInProjectUtil { return true; } - @Nullable + @NotNull private static GlobalSearchScope toGlobal(Project project, @Nullable SearchScope scope) { - if (scope instanceof GlobalSearchScope || scope == null) { + if (scope instanceof GlobalSearchScope) { return (GlobalSearchScope)scope; } + if (scope == null) { + return GlobalSearchScope.projectScope(project); + } Set files = new HashSet(); for (PsiElement element : ((LocalSearchScope)scope).getScope()) { PsiFile file = element.getContainingFile(); @@ -472,7 +475,7 @@ public class FindInProjectUtil { ? moduleContentScope(module) : customScope instanceof GlobalSearchScope ? (GlobalSearchScope)customScope - : GlobalSearchScope.projectScope(project); + : toGlobal(project, customScope); Set keys = new THashSet(30); Set resultFiles = new THashSet(); diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java b/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java index 8b4ef8400f58..4047bd1c4e07 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java @@ -316,6 +316,7 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo private static boolean isWholeWord(CharSequence text, int startOffset, int endOffset) { boolean isWordStart = startOffset == 0 || !Character.isJavaIdentifierPart(text.charAt(startOffset - 1)) || + !Character.isJavaIdentifierPart(text.charAt(startOffset)) || startOffset > 1 && text.charAt(startOffset - 2) == '\\'; boolean isWordEnd = endOffset == text.length() || diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/CustomFileTypeLexer.java b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/CustomFileTypeLexer.java index 79731c9373cf..0163a24f0cab 100644 --- a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/CustomFileTypeLexer.java +++ b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/CustomFileTypeLexer.java @@ -17,6 +17,7 @@ package com.intellij.ide.highlighter.custom; import com.intellij.ide.highlighter.custom.tokens.*; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.CustomHighlighterTokenType; import java.util.ArrayList; @@ -36,7 +37,7 @@ public final class CustomFileTypeLexer extends AbstractCustomLexer { } private static List buildTokenParsers(SyntaxTable table, boolean forHighlighting) { - final LineCommentParser lineCommentParser = LineCommentParser.create(table.getLineComment()); + final LineCommentParser lineCommentParser = StringUtil.isEmpty(table.getLineComment()) ? null : new LineCommentParser(table.getLineComment(), table.lineCommentOnlyAtStart); final MultilineCommentParser multilineCommentParser = MultilineCommentParser.create(table.getStartComment(), table.getEndComment()); final NumberParser numberParser = new NumberParser(table.getNumPostfixChars(), table.isIgnoreCase()); diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/LineCommentParser.java b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/LineCommentParser.java index 0dd023de50be..0f358da64732 100644 --- a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/LineCommentParser.java +++ b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/LineCommentParser.java @@ -23,8 +23,20 @@ import com.intellij.psi.CustomHighlighterTokenType; * @author dsl */ public class LineCommentParser extends PrefixedTokenParser { - private LineCommentParser(String prefix) { + private final boolean myAtStartOnly; + + public LineCommentParser(String prefix, boolean atStartOnly) { super(prefix, CustomHighlighterTokenType.LINE_COMMENT); + myAtStartOnly = atStartOnly; + } + + @Override + public boolean hasToken(int position) { + if (myAtStartOnly && position > 0 && myBuffer.charAt(position - 1) != '\n') { + return false; + } + + return super.hasToken(position); } protected int getTokenEnd(int position) { @@ -34,12 +46,4 @@ public class LineCommentParser extends PrefixedTokenParser { return position; } - public static LineCommentParser create(String prefix) { - final String trimmedPrefix = prefix.trim(); - if (!"".equals(trimmedPrefix)) { - return new LineCommentParser(prefix); - } else { - return null; - } - } } diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/PrefixedTokenParser.java b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/PrefixedTokenParser.java index 2bdc1972a3c2..c80015baa874 100644 --- a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/PrefixedTokenParser.java +++ b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/PrefixedTokenParser.java @@ -30,7 +30,7 @@ public abstract class PrefixedTokenParser extends TokenParser { myPrefix = prefix.toCharArray(); } - public final boolean hasToken(int position) { + public boolean hasToken(int position) { final int start = position; int i; for (i = 0; i < myPrefix.length && position < myEndOffset; i++, position++) { diff --git a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarItem.java b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarItem.java index e8385b9da65a..47cdf243c920 100644 --- a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarItem.java +++ b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarItem.java @@ -59,7 +59,7 @@ public class NavBarItem extends SimpleColoredComponent implements Disposable { openIcon = closedIcon = EmptyIcon.create(5); } final NavBarPresentation presentation = myPanel.getPresentation(); - myText = NavBarPresentation.getPresentableText(object, myPanel.getWindow()); + myText = NavBarPresentation.getPresentableText(object); myIcon = wrapIcon(openIcon, closedIcon, idx); myAttributes = presentation.getTextAttributes(object, false); } else { diff --git a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarListCellRenderer.java b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarListCellRenderer.java index 3f6c87c8fc45..6bb72e0a405f 100644 --- a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarListCellRenderer.java +++ b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarListCellRenderer.java @@ -47,7 +47,7 @@ public class NavBarListCellRenderer extends ColoredListCellRenderer { protected void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus) { setFocusBorderAroundIcon(false); - final String name = NavBarPresentation.getPresentableText(value, myPanel.getWindow()); + final String name = NavBarPresentation.getPresentableText(value); Color color = list.getForeground(); boolean isProblemFile = false; diff --git a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarModel.java b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarModel.java index a356f92abcf9..8bb0189b8481 100644 --- a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarModel.java +++ b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarModel.java @@ -159,6 +159,22 @@ public class NavBarModel { setModel(updatedModel); } + void revalidate() { + final List objects = new ArrayList(); + boolean update = false; + for (Object o : myModel) { + if (isValid(o)) { + objects.add(o); + } else { + update = true; + break; + } + } + if (update) { + setModel(objects); + } + } + private void setModel(List model) { if (!model.equals(myModel)) { myModel = model; diff --git a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarPanel.java b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarPanel.java index a6d8f607482a..abfa5435a815 100644 --- a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarPanel.java +++ b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarPanel.java @@ -336,6 +336,7 @@ public class NavBarPanel extends JPanel implements DataProvider, PopupOwner, Dis } boolean isRebuildUiNeeded() { + myModel.revalidate(); if (myList.size() == myModel.size()) { int index = 0; for (NavBarItem eachLabel : myList) { @@ -344,7 +345,7 @@ public class NavBarPanel extends JPanel implements DataProvider, PopupOwner, Dis return true; } - if (!StringUtil.equals(eachLabel.getText(), NavBarPresentation.getPresentableText(eachElement, null))) { + if (!StringUtil.equals(eachLabel.getText(), NavBarPresentation.getPresentableText(eachElement))) { return true; } diff --git a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarPopup.java b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarPopup.java index f131e966b4fc..c592df43b92b 100644 --- a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarPopup.java +++ b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarPopup.java @@ -160,7 +160,7 @@ public class NavBarPopup extends LightweightHint implements Disposable{ final JComponent component = ListWithFilter.wrap(list, new NavBarListWrapper(list), new Function() { @Override public String fun(Object o) { - return NavBarPresentation.getPresentableText(o, panel.getWindow()); + return NavBarPresentation.getPresentableText(o); } }); component.putClientProperty(JBLIST_KEY, list); diff --git a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarPresentation.java b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarPresentation.java index 7726804491ae..50526eba63e9 100644 --- a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarPresentation.java +++ b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarPresentation.java @@ -91,8 +91,10 @@ public class NavBarPresentation { } @NotNull - protected static String getPresentableText(final Object object, @Nullable Window window) { - if (!NavBarModel.isValid(object)) return IdeBundle.message("node.structureview.invalid"); + protected static String getPresentableText(final Object object) { + if (!NavBarModel.isValid(object)) { + return IdeBundle.message("node.structureview.invalid"); + } for (NavBarModelExtension modelExtension : Extensions.getExtensions(NavBarModelExtension.EP_NAME)) { String text = modelExtension.getPresentableText(object); if (text != null) { diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java index daa29aefff5c..d04635ae967b 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java @@ -450,7 +450,7 @@ public abstract class AbstractProjectViewPane implements DataProvider, Disposabl } } - void saveExpandedPaths() { + protected void saveExpandedPaths() { if (myTree != null) { TreeState treeState = TreeState.createOn(myTree); myReadTreeState.put(getSubId(), treeState); diff --git a/platform/lang-impl/src/com/intellij/ide/scopeView/ScopeViewPane.java b/platform/lang-impl/src/com/intellij/ide/scopeView/ScopeViewPane.java index f4af769a5f14..0ac0f595d497 100644 --- a/platform/lang-impl/src/com/intellij/ide/scopeView/ScopeViewPane.java +++ b/platform/lang-impl/src/com/intellij/ide/scopeView/ScopeViewPane.java @@ -108,8 +108,7 @@ public class ScopeViewPane extends AbstractProjectViewPane { myViewPanel = new ScopeTreeViewPanel(myProject); Disposer.register(this, myViewPanel); myViewPanel.initListeners(); - updateFromRoot(true); - + myViewPanel.selectScope(NamedScopesHolder.getScope(myProject, getSubId())); myTree = myViewPanel.getTree(); PopupHandler.installPopupHandler(myTree, IdeActions.GROUP_SCOPE_VIEW_POPUP, ActionPlaces.SCOPE_VIEW_POPUP); enableDnD(); @@ -152,7 +151,9 @@ public class ScopeViewPane extends AbstractProjectViewPane { } public ActionCallback updateFromRoot(boolean restoreExpandedPaths) { + saveExpandedPaths(); myViewPanel.selectScope(NamedScopesHolder.getScope(myProject, getSubId())); + restoreExpandedPaths(); return new ActionCallback.Done(); } diff --git a/platform/lang-impl/src/com/intellij/internal/psiView/ViewerTreeStructure.java b/platform/lang-impl/src/com/intellij/internal/psiView/ViewerTreeStructure.java index b6e1235c8ab3..77fff7a7c9db 100644 --- a/platform/lang-impl/src/com/intellij/internal/psiView/ViewerTreeStructure.java +++ b/platform/lang-impl/src/com/intellij/internal/psiView/ViewerTreeStructure.java @@ -67,7 +67,11 @@ public class ViewerTreeStructure extends AbstractTreeStructure { if (myRootPsiElement == null) { return ArrayUtil.EMPTY_OBJECT_ARRAY; } - return myRootPsiElement instanceof PsiFile ? ((PsiFile)myRootPsiElement).getPsiRoots() : new Object[]{myRootPsiElement}; + if (!(myRootPsiElement instanceof PsiFile)) { + return new Object[]{myRootPsiElement}; + } + List files = ((PsiFile)myRootPsiElement).getViewProvider().getAllFiles(); + return PsiUtilCore.toPsiFileArray(files); } final Object[][] children = new Object[1][]; children[0] = ArrayUtil.EMPTY_OBJECT_ARRAY; @@ -79,10 +83,8 @@ public class ViewerTreeStructure extends AbstractTreeStructure { final ArrayList list = new ArrayList(); ASTNode root = element instanceof PsiElement? SourceTreeToPsiMap.psiElementToTree((PsiElement)element) : element instanceof ASTNode? (ASTNode)element : null; - boolean injected = false; if (element instanceof Inject) { root = SourceTreeToPsiMap.psiElementToTree(((Inject)element).getPsi()); - injected = true; } if (root != null) { diff --git a/platform/lang-impl/src/com/intellij/openapi/components/impl/ModulePathMacroManager.java b/platform/lang-impl/src/com/intellij/openapi/components/impl/ModulePathMacroManager.java index ebb4c9358668..8136ae66517c 100644 --- a/platform/lang-impl/src/com/intellij/openapi/components/impl/ModulePathMacroManager.java +++ b/platform/lang-impl/src/com/intellij/openapi/components/impl/ModulePathMacroManager.java @@ -18,6 +18,7 @@ package com.intellij.openapi.components.impl; import com.intellij.application.options.PathMacrosImpl; import com.intellij.application.options.ReplacePathToMacroMap; +import com.intellij.openapi.application.PathMacros; import com.intellij.openapi.components.ExpandMacroToPathMap; import com.intellij.openapi.components.PathMacroMap; import com.intellij.openapi.module.Module; @@ -29,7 +30,8 @@ import java.io.File; public class ModulePathMacroManager extends BasePathMacroManager { private final Module myModule; - public ModulePathMacroManager(final Module module) { + public ModulePathMacroManager(PathMacros pathMacros, Module module) { + super(pathMacros); myModule = module; } @@ -43,7 +45,8 @@ public class ModulePathMacroManager extends BasePathMacroManager { public ReplacePathToMacroMap getReplacePathMap() { ReplacePathToMacroMap result = super.getReplacePathMap(); if (!myModule.isDisposed()) { - addFileHierarchyReplacements(result, PathMacrosImpl.MODULE_DIR_MACRO_NAME, getModuleDir(myModule.getModuleFilePath()), getUserHome()); + addFileHierarchyReplacements(result, PathMacrosImpl.MODULE_DIR_MACRO_NAME, getModuleDir(myModule.getModuleFilePath()), PathMacrosImpl + .getUserHome()); } return result; } diff --git a/platform/lang-impl/src/com/intellij/openapi/diff/impl/settings/DiffPreviewPanel.java b/platform/lang-impl/src/com/intellij/openapi/diff/impl/settings/DiffPreviewPanel.java index e274135f8133..76a3f35cd3b6 100644 --- a/platform/lang-impl/src/com/intellij/openapi/diff/impl/settings/DiffPreviewPanel.java +++ b/platform/lang-impl/src/com/intellij/openapi/diff/impl/settings/DiffPreviewPanel.java @@ -123,6 +123,7 @@ public class DiffPreviewPanel implements PreviewPanel { super(project); } + @NotNull public DiffContent[] getContents() { return DiffPreviewProvider.getContents(); } diff --git a/platform/lang-impl/src/com/intellij/openapi/options/colors/pages/GeneralColorsPage.java b/platform/lang-impl/src/com/intellij/openapi/options/colors/pages/GeneralColorsPage.java index 9c00557dfbc4..755d819d6627 100644 --- a/platform/lang-impl/src/com/intellij/openapi/options/colors/pages/GeneralColorsPage.java +++ b/platform/lang-impl/src/com/intellij/openapi/options/colors/pages/GeneralColorsPage.java @@ -58,7 +58,7 @@ public class GeneralColorsPage implements ColorSettingsPage, InspectionColorSett "Code Inspections:\n" + " Error\n" + " Warning\n" + - " Info\n" + + " Weak warning\n" + " Deprecated symbol\n" + " Unused symbol\n"+ " Unknown symbol\n" + diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkImpl.java b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkImpl.java index 97fe325586f1..876484fa60bc 100644 --- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkImpl.java +++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkImpl.java @@ -103,6 +103,11 @@ public class ProjectJdkImpl extends UserDataHolderBase implements JDOMExternaliz return myVersionString; } + public final void resetVersionString() { + myVersionDefined = false; + myVersionString = null; + } + public String getHomePath() { return myHomePath; } @@ -228,13 +233,16 @@ public class ProjectJdkImpl extends UserDataHolderBase implements JDOMExternaliz return myRootProvider; } - public void copyTo(ProjectJdkImpl dest){ + public void copyTo(ProjectJdkImpl dest) { final String name = getName(); dest.setName(name); dest.setHomePath(getHomePath()); if (myVersionDefined) { dest.setVersionString(getVersionString()); } + else { + dest.resetVersionString(); + } dest.setSdkAdditionalData(getSdkAdditionalData()); dest.myRootContainer.startChange(); dest.myRootContainer.removeAllRoots(); diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/SdkConfigurationUtil.java b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/SdkConfigurationUtil.java index 30db6d35e0e9..2d612d830f29 100644 --- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/SdkConfigurationUtil.java +++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/SdkConfigurationUtil.java @@ -354,7 +354,7 @@ public class SdkConfigurationUtil { popup.showUnderneathOf(popupOwner); } - private static List filterExistingPaths(SdkType sdkType, Collection sdkHomes, final Sdk[] sdks) { + public static List filterExistingPaths(SdkType sdkType, Collection sdkHomes, final Sdk[] sdks) { List result = new ArrayList(); for (String sdkHome : sdkHomes) { if (findByPath(sdkType, sdks, sdkHome) == null) { diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexImpl.java b/platform/lang-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexImpl.java index 78a20effa8ad..6ce8a7e99644 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexImpl.java @@ -44,6 +44,7 @@ import com.intellij.util.containers.MultiMap; import com.intellij.util.messages.MessageBusConnection; import gnu.trove.THashMap; import gnu.trove.THashSet; +import gnu.trove.TObjectObjectProcedure; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; @@ -409,10 +410,10 @@ public class DirectoryIndexImpl extends DirectoryIndex implements ProjectCompone } private class IndexState { - final Map> myExcludeRootsMap = new THashMap>(); + final THashMap> myExcludeRootsMap = new THashMap>(); final Set myProjectExcludeRoots = new THashSet(); final Map myDirToInfoMap = new THashMap(); - final Map> myPackageNameToDirsMap = new THashMap>(); + final THashMap> myPackageNameToDirsMap = new THashMap>(); final Map myDirToPackageName = new THashMap(); public IndexState() { @@ -864,7 +865,7 @@ public class DirectoryIndexImpl extends DirectoryIndex implements ProjectCompone while (true) { Set set = map.get(file); if (set == null) { - set = new HashSet(); + set = new THashSet(); map.put(file, set); } set.add(value); @@ -887,18 +888,26 @@ public class DirectoryIndexImpl extends DirectoryIndex implements ProjectCompone } public IndexState copy() { - IndexState copy = new IndexState(); + final IndexState copy = new IndexState(); - for (Map.Entry> entry : myExcludeRootsMap.entrySet()) { - copy.myExcludeRootsMap.put(entry.getKey(), new HashSet(entry.getValue())); - } + myExcludeRootsMap.forEachEntry(new TObjectObjectProcedure>() { + @Override + public boolean execute(VirtualFile key, Set value) { + copy.myExcludeRootsMap.put(key, new THashSet(value)); + return true; + } + }); copy.myProjectExcludeRoots.addAll(myProjectExcludeRoots); copy.myDirToInfoMap.putAll(myDirToInfoMap); - for (Map.Entry> entry : myPackageNameToDirsMap.entrySet()) { - copy.myPackageNameToDirsMap.put(entry.getKey(), new SmartList(entry.getValue())); - } + myPackageNameToDirsMap.forEachEntry(new TObjectObjectProcedure>() { + @Override + public boolean execute(String key, List value) { + copy.myPackageNameToDirsMap.put(key, new SmartList(value)); + return true; + } + }); copy.myDirToPackageName.putAll(myDirToPackageName); diff --git a/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java index d264b1b5807b..addd3ad3365d 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java @@ -298,8 +298,8 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { public void run() { try { if (myManager.getProject().isDisposed()) throw new ProcessCanceledException(); - PsiElement[] psiRoots = file.getPsiRoots(); - Set processed = new HashSet(psiRoots.length * 2, (float)0.5); + List psiRoots = file.getViewProvider().getAllFiles(); + Set processed = new HashSet(psiRoots.size() * 2, (float)0.5); for (PsiElement psiRoot : psiRoots) { if (progress != null) progress.checkCanceled(); if (!processed.add(psiRoot)) continue; diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultiHostRegistrarImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultiHostRegistrarImpl.java index 0c5d2887a08c..600282b97fe6 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultiHostRegistrarImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultiHostRegistrarImpl.java @@ -472,22 +472,23 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT while (range != null && !range.isEmpty()) { if (range.getStartOffset() >= shredEndOffset) { hostNum++; - shredEndOffset = shreds.get(hostNum).range.getEndOffset(); + PsiLanguageInjectionHost.Shred shred = shreds.get(hostNum); + shredEndOffset = shred.range.getEndOffset(); prevHostEndOffset = range.getStartOffset(); - host = shreds.get(hostNum).host; + host = shred.host; escaper = escapers.get(hostNum); - rangeInsideHost = shreds.get(hostNum).getRangeInsideHost(); - prefixLength = shreds.get(hostNum).prefix.length(); - suffixLength = shreds.get(hostNum).suffix.length(); + rangeInsideHost = shred.getRangeInsideHost(); + prefixLength = shred.prefix.length(); + suffixLength = shred.suffix.length(); } //in prefix/suffix or spills over to next fragment if (range.getStartOffset() < prevHostEndOffset + prefixLength) { range = new TextRange(prevHostEndOffset + prefixLength, range.getEndOffset()); } TextRange spilled = null; - if (range.getEndOffset() >= shredEndOffset - suffixLength) { + if (range.getEndOffset() > shredEndOffset - suffixLength) { spilled = new TextRange(shredEndOffset, range.getEndOffset()); - range = new TextRange(range.getStartOffset(), shredEndOffset); + range = new TextRange(range.getStartOffset(), shredEndOffset-suffixLength); } if (!range.isEmpty()) { int start = escaper.getOffsetInHost(range.getStartOffset() - prevHostEndOffset - prefixLength, rangeInsideHost); diff --git a/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/FilePackageSetParserExtension.java b/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/FilePackageSetParserExtension.java index 76a8887d309a..0ac74be01590 100644 --- a/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/FilePackageSetParserExtension.java +++ b/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/FilePackageSetParserExtension.java @@ -85,6 +85,10 @@ public class FilePackageSetParserExtension implements PackageSetParserExtension wasIdentifier = false; pattern.append("-"); } + else if (lexer.getTokenType() == ScopeTokenTypes.TILDE) { + wasIdentifier = false; + pattern.append("~"); + } else { break; } diff --git a/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/PackageSetFactoryImpl.java b/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/PackageSetFactoryImpl.java index 8f52b76f7ad3..19293742a3e5 100644 --- a/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/PackageSetFactoryImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/PackageSetFactoryImpl.java @@ -128,7 +128,10 @@ public class PackageSetFactoryImpl extends PackageSetFactory { pattern.append("."); } else if (myLexer.getTokenType() == ScopeTokenTypes.MINUS) { pattern.append("-"); - } else if (myLexer.getTokenType() == ScopeTokenTypes.COLON) { + } else if (myLexer.getTokenType() == ScopeTokenTypes.TILDE) { + pattern.append("~"); + } + else if (myLexer.getTokenType() == ScopeTokenTypes.COLON) { pattern.append(":"); } else { error(AnalysisScopeBundle.message("error.packageset.token.expectations", getTokenText())); diff --git a/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/lexer/ScopeTokenTypes.java b/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/lexer/ScopeTokenTypes.java index 199f29de8553..d9e4d8f0219f 100644 --- a/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/lexer/ScopeTokenTypes.java +++ b/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/lexer/ScopeTokenTypes.java @@ -33,6 +33,7 @@ public interface ScopeTokenTypes extends TokenType { IElementType RBRACKET = new ScopeTokenType("Scope.RBRACKET"); IElementType LPARENTH = new ScopeTokenType("Scope.LPARENTH"); IElementType RPARENTH = new ScopeTokenType("Scope.RPARENTH"); + IElementType TILDE = new ScopeTokenType("TILDE"); IElementType DOT = new ScopeTokenType("Scope.DOT"); IElementType COLON = new ScopeTokenType("Scope.COLON"); IElementType ASTERISK = new ScopeTokenType("Scope.ASTERISK"); diff --git a/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/lexer/_ScopesLexer.flex b/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/lexer/_ScopesLexer.flex index 7c850c380607..b1400fda1f9f 100644 --- a/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/lexer/_ScopesLexer.flex +++ b/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/lexer/_ScopesLexer.flex @@ -34,6 +34,7 @@ DIGIT=[0-9]+ "!" { return ScopeTokenTypes.EXCL; } "$" { return ScopeTokenTypes.IDENTIFIER;} "-" { return ScopeTokenTypes.MINUS;} + "~" { return ScopeTokenTypes.TILDE;} "[" { return ScopeTokenTypes.LBRACKET; } "]" { return ScopeTokenTypes.RBRACKET; } diff --git a/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/lexer/_ScopesLexer.java b/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/lexer/_ScopesLexer.java index 92a2ec839142..4fcd0e7c424c 100644 --- a/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/lexer/_ScopesLexer.java +++ b/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/lexer/_ScopesLexer.java @@ -1,33 +1,16 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* The following code was generated by JFlex 1.4.1 on 2/13/08 6:36 PM */ +/* The following code was generated by JFlex 1.4.3 on 2/8/12 9:29 PM */ /* It's an automatically generated code. Do not modify it. */ package com.intellij.psi.search.scope.packageSet.lexer; - -import com.intellij.lexer.FlexLexer; import com.intellij.psi.tree.IElementType; +import com.intellij.lexer.FlexLexer; /** * This class is a scanner generated by - * JFlex 1.4.1 - * on 2/13/08 6:36 PM from the specification file - * /Users/max/Depot/Trunk/tools/lexer/_ScopesLexer.flex + * JFlex 1.4.3 + * on 2/8/12 9:29 PM from the specification file + * C:/work/IDEA/tools/lexer/../../community/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/lexer/_ScopesLexer.flex */ class _ScopesLexer implements FlexLexer { /** initial size of the lookahead buffer */ @@ -36,95 +19,105 @@ class _ScopesLexer implements FlexLexer { /** lexical states */ public static final int YYINITIAL = 0; + /** + * ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l + * ZZ_LEXSTATE[l+1] is the state in the DFA for the lexical state l + * at the beginning of a line + * l is of the form l = 2*k, k a non negative integer + */ + private static final int ZZ_LEXSTATE[] = { + 0, 0 + }; + /** * Translates characters to character classes */ private static final String ZZ_CMAP_PACKED = "\11\2\1\3\1\3\1\0\2\3\16\2\4\0\1\3\1\7\2\0"+ - "\1\1\1\0\1\6\1\0\1\13\1\14\1\17\2\0\1\10\1\15"+ - "\1\20\12\4\1\16\6\0\32\1\1\11\1\0\1\12\1\0\1\1"+ - "\1\0\32\1\1\0\1\5\2\0\41\2\2\0\4\1\4\0\1\1"+ - "\2\0\1\2\7\0\1\1\4\0\1\1\5\0\27\1\1\0\37\1"+ - "\1\0\u013f\1\31\0\162\1\4\0\14\1\16\0\5\1\11\0\1\1"+ - "\21\0\130\2\5\0\23\2\12\0\1\1\13\0\1\1\1\0\3\1"+ - "\1\0\1\1\1\0\24\1\1\0\54\1\1\0\46\1\1\0\5\1"+ - "\4\0\202\1\1\0\4\2\3\0\105\1\1\0\46\1\2\0\2\1"+ - "\6\0\20\1\41\0\46\1\2\0\1\1\7\0\47\1\11\0\21\2"+ - "\1\0\27\2\1\0\3\2\1\0\1\2\1\0\2\2\1\0\1\2"+ - "\13\0\33\1\5\0\3\1\15\0\4\2\14\0\6\2\13\0\32\1"+ - "\5\0\13\1\16\2\7\0\12\2\4\0\2\1\1\2\143\1\1\0"+ - "\1\1\10\2\1\0\6\2\2\1\2\2\1\0\4\2\2\1\12\2"+ - "\3\1\2\0\1\1\17\0\1\2\1\1\1\2\36\1\33\2\2\0"+ - "\3\1\60\0\46\1\13\2\1\1\u014f\0\3\2\66\1\2\0\1\2"+ - "\1\1\20\2\2\0\1\1\4\2\3\0\12\1\2\2\2\0\12\2"+ - "\21\0\3\2\1\0\10\1\2\0\2\1\2\0\26\1\1\0\7\1"+ - "\1\0\1\1\3\0\4\1\2\0\1\2\1\1\7\2\2\0\2\2"+ - "\2\0\3\2\11\0\1\2\4\0\2\1\1\0\3\1\2\2\2\0"+ - "\12\2\4\1\15\0\3\2\1\0\6\1\4\0\2\1\2\0\26\1"+ - "\1\0\7\1\1\0\2\1\1\0\2\1\1\0\2\1\2\0\1\2"+ - "\1\0\5\2\4\0\2\2\2\0\3\2\13\0\4\1\1\0\1\1"+ - "\7\0\14\2\3\1\14\0\3\2\1\0\11\1\1\0\3\1\1\0"+ - "\26\1\1\0\7\1\1\0\2\1\1\0\5\1\2\0\1\2\1\1"+ - "\10\2\1\0\3\2\1\0\3\2\2\0\1\1\17\0\2\1\2\2"+ - "\2\0\12\2\1\0\1\1\17\0\3\2\1\0\10\1\2\0\2\1"+ - "\2\0\26\1\1\0\7\1\1\0\2\1\1\0\5\1\2\0\1\2"+ - "\1\1\6\2\3\0\2\2\2\0\3\2\10\0\2\2\4\0\2\1"+ - "\1\0\3\1\4\0\12\2\1\0\1\1\20\0\1\2\1\1\1\0"+ - "\6\1\3\0\3\1\1\0\4\1\3\0\2\1\1\0\1\1\1\0"+ - "\2\1\3\0\2\1\3\0\3\1\3\0\10\1\1\0\3\1\4\0"+ - "\5\2\3\0\3\2\1\0\4\2\11\0\1\2\17\0\11\2\11\0"+ - "\1\1\7\0\3\2\1\0\10\1\1\0\3\1\1\0\27\1\1\0"+ - "\12\1\1\0\5\1\4\0\7\2\1\0\3\2\1\0\4\2\7\0"+ - "\2\2\11\0\2\1\4\0\12\2\22\0\2\2\1\0\10\1\1\0"+ - "\3\1\1\0\27\1\1\0\12\1\1\0\5\1\2\0\1\2\1\1"+ - "\7\2\1\0\3\2\1\0\4\2\7\0\2\2\7\0\1\1\1\0"+ - "\2\1\4\0\12\2\22\0\2\2\1\0\10\1\1\0\3\1\1\0"+ - "\27\1\1\0\20\1\4\0\6\2\2\0\3\2\1\0\4\2\11\0"+ - "\1\2\10\0\2\1\4\0\12\2\22\0\2\2\1\0\22\1\3\0"+ - "\30\1\1\0\11\1\1\0\1\1\2\0\7\1\3\0\1\2\4\0"+ - "\6\2\1\0\1\2\1\0\10\2\22\0\2\2\15\0\60\1\1\2"+ - "\2\1\7\2\4\0\10\1\10\2\1\0\12\2\47\0\2\1\1\0"+ - "\1\1\2\0\2\1\1\0\1\1\2\0\1\1\6\0\4\1\1\0"+ - "\7\1\1\0\3\1\1\0\1\1\1\0\1\1\2\0\2\1\1\0"+ - "\4\1\1\2\2\1\6\2\1\0\2\2\1\1\2\0\5\1\1\0"+ - "\1\1\1\0\6\2\2\0\12\2\2\0\2\1\42\0\1\1\27\0"+ - "\2\2\6\0\12\2\13\0\1\2\1\0\1\2\1\0\1\2\4\0"+ - "\2\2\10\1\1\0\42\1\6\0\24\2\1\0\2\2\4\1\4\0"+ - "\10\2\1\0\44\2\11\0\1\2\71\0\42\1\1\0\5\1\1\0"+ - "\2\1\1\0\7\2\3\0\4\2\6\0\12\2\6\0\6\1\4\2"+ - "\106\0\46\1\12\0\51\1\7\0\132\1\5\0\104\1\5\0\122\1"+ - "\6\0\7\1\1\0\77\1\1\0\1\1\1\0\4\1\2\0\7\1"+ - "\1\0\1\1\1\0\4\1\2\0\47\1\1\0\1\1\1\0\4\1"+ - "\2\0\37\1\1\0\1\1\1\0\4\1\2\0\7\1\1\0\1\1"+ - "\1\0\4\1\2\0\7\1\1\0\7\1\1\0\27\1\1\0\37\1"+ - "\1\0\1\1\1\0\4\1\2\0\7\1\1\0\47\1\1\0\23\1"+ - "\16\0\11\2\56\0\125\1\14\0\u026c\1\2\0\10\1\12\0\32\1"+ - "\5\0\113\1\3\0\3\1\17\0\15\1\1\0\4\1\3\2\13\0"+ - "\22\1\3\2\13\0\22\1\2\2\14\0\15\1\1\0\3\1\1\0"+ - "\2\2\14\0\64\1\40\2\3\0\1\1\3\0\2\1\1\2\2\0"+ - "\12\2\41\0\3\2\2\0\12\2\6\0\130\1\10\0\51\1\1\2"+ - "\126\0\35\1\3\0\14\2\4\0\14\2\12\0\12\2\36\1\2\0"+ - "\5\1\u038b\0\154\1\224\0\234\1\4\0\132\1\6\0\26\1\2\0"+ - "\6\1\2\0\46\1\2\0\6\1\2\0\10\1\1\0\1\1\1\0"+ - "\1\1\1\0\1\1\1\0\37\1\2\0\65\1\1\0\7\1\1\0"+ - "\1\1\3\0\3\1\1\0\7\1\3\0\4\1\2\0\6\1\4\0"+ - "\15\1\5\0\3\1\1\0\7\1\17\0\4\2\32\0\5\2\20\0"+ - "\2\1\23\0\1\1\13\0\4\2\6\0\6\2\1\0\1\1\15\0"+ - "\1\1\40\0\22\1\36\0\15\2\4\0\1\2\3\0\6\2\27\0"+ - "\1\1\4\0\1\1\2\0\12\1\1\0\1\1\3\0\5\1\6\0"+ - "\1\1\1\0\1\1\1\0\1\1\1\0\4\1\1\0\3\1\1\0"+ - "\7\1\3\0\3\1\5\0\5\1\26\0\44\1\u0e81\0\3\1\31\0"+ - "\11\1\6\2\1\0\5\1\2\0\5\1\4\0\126\1\2\0\2\2"+ - "\2\0\3\1\1\0\137\1\5\0\50\1\4\0\136\1\21\0\30\1"+ - "\70\0\20\1\u0200\0\u19b6\1\112\0\u51a6\1\132\0\u048d\1\u0773\0\u2ba4\1"+ - "\u215c\0\u012e\1\2\0\73\1\225\0\7\1\14\0\5\1\5\0\1\1"+ - "\1\2\12\1\1\0\15\1\1\0\5\1\1\0\1\1\1\0\2\1"+ - "\1\0\2\1\1\0\154\1\41\0\u016b\1\22\0\100\1\2\0\66\1"+ - "\50\0\15\1\3\0\20\2\20\0\4\2\17\0\2\1\30\0\3\1"+ - "\31\0\1\1\6\0\5\1\1\0\207\1\2\0\1\2\4\0\1\1"+ - "\13\0\12\2\7\0\32\1\4\0\1\1\1\0\32\1\12\0\132\1"+ - "\3\0\6\1\2\0\6\1\2\0\6\1\2\0\3\1\3\0\2\1"+ - "\3\0\2\1\22\0\3\2\4\0"; + "\1\1\1\0\1\6\1\0\1\14\1\15\1\20\2\0\1\10\1\16"+ + "\1\21\12\4\1\17\6\0\32\1\1\12\1\0\1\13\1\0\1\1"+ + "\1\0\32\1\1\0\1\5\1\0\1\11\41\2\2\0\4\1\4\0"+ + "\1\1\2\0\1\2\7\0\1\1\4\0\1\1\5\0\27\1\1\0"+ + "\37\1\1\0\u013f\1\31\0\162\1\4\0\14\1\16\0\5\1\11\0"+ + "\1\1\21\0\130\2\5\0\23\2\12\0\1\1\13\0\1\1\1\0"+ + "\3\1\1\0\1\1\1\0\24\1\1\0\54\1\1\0\46\1\1\0"+ + "\5\1\4\0\202\1\1\0\4\2\3\0\105\1\1\0\46\1\2\0"+ + "\2\1\6\0\20\1\41\0\46\1\2\0\1\1\7\0\47\1\11\0"+ + "\21\2\1\0\27\2\1\0\3\2\1\0\1\2\1\0\2\2\1\0"+ + "\1\2\13\0\33\1\5\0\3\1\15\0\4\2\14\0\6\2\13\0"+ + "\32\1\5\0\13\1\16\2\7\0\12\2\4\0\2\1\1\2\143\1"+ + "\1\0\1\1\10\2\1\0\6\2\2\1\2\2\1\0\4\2\2\1"+ + "\12\2\3\1\2\0\1\1\17\0\1\2\1\1\1\2\36\1\33\2"+ + "\2\0\3\1\60\0\46\1\13\2\1\1\u014f\0\3\2\66\1\2\0"+ + "\1\2\1\1\20\2\2\0\1\1\4\2\3\0\12\1\2\2\2\0"+ + "\12\2\21\0\3\2\1\0\10\1\2\0\2\1\2\0\26\1\1\0"+ + "\7\1\1\0\1\1\3\0\4\1\2\0\1\2\1\1\7\2\2\0"+ + "\2\2\2\0\3\2\11\0\1\2\4\0\2\1\1\0\3\1\2\2"+ + "\2\0\12\2\4\1\15\0\3\2\1\0\6\1\4\0\2\1\2\0"+ + "\26\1\1\0\7\1\1\0\2\1\1\0\2\1\1\0\2\1\2\0"+ + "\1\2\1\0\5\2\4\0\2\2\2\0\3\2\13\0\4\1\1\0"+ + "\1\1\7\0\14\2\3\1\14\0\3\2\1\0\11\1\1\0\3\1"+ + "\1\0\26\1\1\0\7\1\1\0\2\1\1\0\5\1\2\0\1\2"+ + "\1\1\10\2\1\0\3\2\1\0\3\2\2\0\1\1\17\0\2\1"+ + "\2\2\2\0\12\2\1\0\1\1\17\0\3\2\1\0\10\1\2\0"+ + "\2\1\2\0\26\1\1\0\7\1\1\0\2\1\1\0\5\1\2\0"+ + "\1\2\1\1\6\2\3\0\2\2\2\0\3\2\10\0\2\2\4\0"+ + "\2\1\1\0\3\1\4\0\12\2\1\0\1\1\20\0\1\2\1\1"+ + "\1\0\6\1\3\0\3\1\1\0\4\1\3\0\2\1\1\0\1\1"+ + "\1\0\2\1\3\0\2\1\3\0\3\1\3\0\10\1\1\0\3\1"+ + "\4\0\5\2\3\0\3\2\1\0\4\2\11\0\1\2\17\0\11\2"+ + "\11\0\1\1\7\0\3\2\1\0\10\1\1\0\3\1\1\0\27\1"+ + "\1\0\12\1\1\0\5\1\4\0\7\2\1\0\3\2\1\0\4\2"+ + "\7\0\2\2\11\0\2\1\4\0\12\2\22\0\2\2\1\0\10\1"+ + "\1\0\3\1\1\0\27\1\1\0\12\1\1\0\5\1\2\0\1\2"+ + "\1\1\7\2\1\0\3\2\1\0\4\2\7\0\2\2\7\0\1\1"+ + "\1\0\2\1\4\0\12\2\22\0\2\2\1\0\10\1\1\0\3\1"+ + "\1\0\27\1\1\0\20\1\4\0\6\2\2\0\3\2\1\0\4\2"+ + "\11\0\1\2\10\0\2\1\4\0\12\2\22\0\2\2\1\0\22\1"+ + "\3\0\30\1\1\0\11\1\1\0\1\1\2\0\7\1\3\0\1\2"+ + "\4\0\6\2\1\0\1\2\1\0\10\2\22\0\2\2\15\0\60\1"+ + "\1\2\2\1\7\2\4\0\10\1\10\2\1\0\12\2\47\0\2\1"+ + "\1\0\1\1\2\0\2\1\1\0\1\1\2\0\1\1\6\0\4\1"+ + "\1\0\7\1\1\0\3\1\1\0\1\1\1\0\1\1\2\0\2\1"+ + "\1\0\4\1\1\2\2\1\6\2\1\0\2\2\1\1\2\0\5\1"+ + "\1\0\1\1\1\0\6\2\2\0\12\2\2\0\2\1\42\0\1\1"+ + "\27\0\2\2\6\0\12\2\13\0\1\2\1\0\1\2\1\0\1\2"+ + "\4\0\2\2\10\1\1\0\42\1\6\0\24\2\1\0\2\2\4\1"+ + "\4\0\10\2\1\0\44\2\11\0\1\2\71\0\42\1\1\0\5\1"+ + "\1\0\2\1\1\0\7\2\3\0\4\2\6\0\12\2\6\0\6\1"+ + "\4\2\106\0\46\1\12\0\51\1\7\0\132\1\5\0\104\1\5\0"+ + "\122\1\6\0\7\1\1\0\77\1\1\0\1\1\1\0\4\1\2\0"+ + "\7\1\1\0\1\1\1\0\4\1\2\0\47\1\1\0\1\1\1\0"+ + "\4\1\2\0\37\1\1\0\1\1\1\0\4\1\2\0\7\1\1\0"+ + "\1\1\1\0\4\1\2\0\7\1\1\0\7\1\1\0\27\1\1\0"+ + "\37\1\1\0\1\1\1\0\4\1\2\0\7\1\1\0\47\1\1\0"+ + "\23\1\16\0\11\2\56\0\125\1\14\0\u026c\1\2\0\10\1\12\0"+ + "\32\1\5\0\113\1\3\0\3\1\17\0\15\1\1\0\4\1\3\2"+ + "\13\0\22\1\3\2\13\0\22\1\2\2\14\0\15\1\1\0\3\1"+ + "\1\0\2\2\14\0\64\1\40\2\3\0\1\1\3\0\2\1\1\2"+ + "\2\0\12\2\41\0\3\2\2\0\12\2\6\0\130\1\10\0\51\1"+ + "\1\2\126\0\35\1\3\0\14\2\4\0\14\2\12\0\12\2\36\1"+ + "\2\0\5\1\u038b\0\154\1\224\0\234\1\4\0\132\1\6\0\26\1"+ + "\2\0\6\1\2\0\46\1\2\0\6\1\2\0\10\1\1\0\1\1"+ + "\1\0\1\1\1\0\1\1\1\0\37\1\2\0\65\1\1\0\7\1"+ + "\1\0\1\1\3\0\3\1\1\0\7\1\3\0\4\1\2\0\6\1"+ + "\4\0\15\1\5\0\3\1\1\0\7\1\17\0\4\2\32\0\5\2"+ + "\20\0\2\1\23\0\1\1\13\0\4\2\6\0\6\2\1\0\1\1"+ + "\15\0\1\1\40\0\22\1\36\0\15\2\4\0\1\2\3\0\6\2"+ + "\27\0\1\1\4\0\1\1\2\0\12\1\1\0\1\1\3\0\5\1"+ + "\6\0\1\1\1\0\1\1\1\0\1\1\1\0\4\1\1\0\3\1"+ + "\1\0\7\1\3\0\3\1\5\0\5\1\26\0\44\1\u0e81\0\3\1"+ + "\31\0\11\1\6\2\1\0\5\1\2\0\5\1\4\0\126\1\2\0"+ + "\2\2\2\0\3\1\1\0\137\1\5\0\50\1\4\0\136\1\21\0"+ + "\30\1\70\0\20\1\u0200\0\u19b6\1\112\0\u51a6\1\132\0\u048d\1\u0773\0"+ + "\u2ba4\1\u215c\0\u012e\1\2\0\73\1\225\0\7\1\14\0\5\1\5\0"+ + "\1\1\1\2\12\1\1\0\15\1\1\0\5\1\1\0\1\1\1\0"+ + "\2\1\1\0\2\1\1\0\154\1\41\0\u016b\1\22\0\100\1\2\0"+ + "\66\1\50\0\15\1\3\0\20\2\20\0\4\2\17\0\2\1\30\0"+ + "\3\1\31\0\1\1\6\0\5\1\1\0\207\1\2\0\1\2\4\0"+ + "\1\1\13\0\12\2\7\0\32\1\4\0\1\1\1\0\32\1\12\0"+ + "\132\1\3\0\6\1\2\0\6\1\2\0\6\1\2\0\3\1\3\0"+ + "\2\1\3\0\2\1\22\0\3\2\4\0"; /** * Translates characters to character classes @@ -139,10 +132,10 @@ class _ScopesLexer implements FlexLexer { private static final String ZZ_ACTION_PACKED_0 = "\1\0\1\1\1\2\1\3\1\4\2\1\1\5\1\6"+ "\1\7\1\10\1\11\1\12\1\13\1\14\1\15\1\16"+ - "\1\17\1\20"; + "\1\17\1\20\1\21"; private static int [] zzUnpackAction() { - int [] result = new int[19]; + int [] result = new int[20]; int offset = 0; offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); return result; @@ -167,12 +160,12 @@ class _ScopesLexer implements FlexLexer { private static final int [] ZZ_ROWMAP = zzUnpackRowMap(); private static final String ZZ_ROWMAP_PACKED_0 = - "\0\0\0\21\0\42\0\63\0\104\0\125\0\146\0\21"+ - "\0\21\0\21\0\21\0\21\0\21\0\21\0\21\0\21"+ - "\0\21\0\21\0\21"; + "\0\0\0\22\0\44\0\66\0\110\0\132\0\154\0\22"+ + "\0\22\0\22\0\22\0\22\0\22\0\22\0\22\0\22"+ + "\0\22\0\22\0\22\0\22"; private static int [] zzUnpackRowMap() { - int [] result = new int[19]; + int [] result = new int[20]; int offset = 0; offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); return result; @@ -197,11 +190,11 @@ class _ScopesLexer implements FlexLexer { private static final String ZZ_TRANS_PACKED_0 = "\1\2\1\3\1\2\1\4\1\5\1\6\1\7\1\10"+ "\1\11\1\12\1\13\1\14\1\15\1\16\1\17\1\20"+ - "\1\21\22\0\2\3\1\0\1\3\17\0\1\4\21\0"+ - "\1\5\21\0\1\22\21\0\1\23\12\0"; + "\1\21\1\22\23\0\2\3\1\0\1\3\20\0\1\4"+ + "\22\0\1\5\22\0\1\23\22\0\1\24\13\0"; private static int [] zzUnpackTrans() { - int [] result = new int[119]; + int [] result = new int[126]; int offset = 0; offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); return result; @@ -242,10 +235,10 @@ class _ScopesLexer implements FlexLexer { private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); private static final String ZZ_ATTRIBUTE_PACKED_0 = - "\1\0\1\11\5\1\14\11"; + "\1\0\1\11\5\1\15\11"; private static int [] zzUnpackAttribute() { - int [] result = new int[19]; + int [] result = new int[20]; int offset = 0; offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); return result; @@ -338,7 +331,7 @@ class _ScopesLexer implements FlexLexer { char [] map = new char[0x10000]; int i = 0; /* index in packed string */ int j = 0; /* index in unpacked array */ - while (i < 1690) { + while (i < 1692) { int count = packed.charAt(i++); char value = packed.charAt(i++); do map[j++] = value; while (--count > 0); @@ -346,17 +339,14 @@ class _ScopesLexer implements FlexLexer { return map; } - @Override public final int getTokenStart(){ return zzStartRead; } - @Override public final int getTokenEnd(){ return getTokenStart() + yylength(); } - @Override public void reset(CharSequence buffer, int start, int end,int initialState){ zzBuffer = buffer; zzBufferArray = com.intellij.util.text.CharArrayUtil.fromSequenceWithoutCopying(buffer); @@ -383,7 +373,6 @@ class _ScopesLexer implements FlexLexer { /** * Returns the current lexical state. */ - @Override public final int yystate() { return zzLexicalState; } @@ -394,7 +383,6 @@ class _ScopesLexer implements FlexLexer { * * @param newState the new lexical state */ - @Override public final void yybegin(int newState) { zzLexicalState = newState; } @@ -494,7 +482,6 @@ class _ScopesLexer implements FlexLexer { * @return the next token * @exception java.io.IOException if any I/O-Error occurs */ - @Override public IElementType advance() throws java.io.IOException { int zzInput; int zzAction; @@ -518,7 +505,7 @@ class _ScopesLexer implements FlexLexer { zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL; - zzState = zzLexicalState; + zzState = ZZ_LEXSTATE[zzLexicalState]; zzForAction: { @@ -569,67 +556,71 @@ class _ScopesLexer implements FlexLexer { case 5: { return ScopeTokenTypes.EXCL; } - case 17: break; - case 16: - { return ScopeTokenTypes.ANDAND; - } case 18: break; - case 9: - { return ScopeTokenTypes.LPARENTH; + case 7: + { return ScopeTokenTypes.TILDE; } case 19: break; - case 13: - { return ScopeTokenTypes.ASTERISK; + case 17: + { return ScopeTokenTypes.ANDAND; } case 20: break; - case 15: - { return ScopeTokenTypes.OROR; + case 10: + { return ScopeTokenTypes.LPARENTH; } case 21: break; - case 7: - { return ScopeTokenTypes.LBRACKET; + case 14: + { return ScopeTokenTypes.ASTERISK; } case 22: break; + case 16: + { return ScopeTokenTypes.OROR; + } + case 23: break; + case 8: + { return ScopeTokenTypes.LBRACKET; + } + case 24: break; case 4: { return ScopeTokenTypes.INTEGER_LITERAL; } - case 23: break; - case 12: + case 25: break; + case 13: { return ScopeTokenTypes.COLON; } - case 24: break; + case 26: break; case 3: { return ScopeTokenTypes.WHITE_SPACE; } - case 25: break; + case 27: break; case 2: { return ScopeTokenTypes.IDENTIFIER; } - case 26: break; - case 14: + case 28: break; + case 15: { return ScopeTokenTypes.DIV; } - case 27: break; - case 11: + case 29: break; + case 12: { return ScopeTokenTypes.DOT; } - case 28: break; - case 10: + case 30: break; + case 11: { return ScopeTokenTypes.RPARENTH; } - case 29: break; + case 31: break; case 1: { return ScopeTokenTypes.BAD_CHARACTER; } - case 30: break; - case 8: + case 32: break; + case 9: { return ScopeTokenTypes.RBRACKET; } - case 31: break; + case 33: break; case 6: { return ScopeTokenTypes.MINUS; } - case 32: break; + case 34: break; default: if (zzInput == YYEOF && zzStartRead == zzCurrentPos) { zzAtEOF = true; diff --git a/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java b/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java index 8d7d0c769521..21f0e587b203 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java +++ b/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java @@ -33,7 +33,9 @@ import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.*; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiNamedElement; +import com.intellij.psi.codeStyle.SuggestedNameInfo; import com.intellij.refactoring.rename.NameSuggestionProvider; +import com.intellij.refactoring.rename.PreferrableNameSuggestionProvider; import com.intellij.refactoring.rename.inplace.InplaceRefactoring; import com.intellij.ui.awt.RelativePoint; import com.intellij.util.ui.PositionTracker; @@ -240,7 +242,8 @@ public abstract class InplaceVariableIntroducer extends In final LinkedHashSet names = new LinkedHashSet(); names.add(text); for (NameSuggestionProvider provider : Extensions.getExtensions(NameSuggestionProvider.EP_NAME)) { - provider.getSuggestedNames(psiVariable, psiVariable, names); + final SuggestedNameInfo suggestedNameInfo = provider.getSuggestedNames(psiVariable, psiVariable, names); + if (suggestedNameInfo != null && provider instanceof PreferrableNameSuggestionProvider && !((PreferrableNameSuggestionProvider)provider).shouldCheckOthers()) break; } final LookupElement[] items = new LookupElement[names.size()]; final Iterator iterator = names.iterator(); diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/RenameDialog.java b/platform/lang-impl/src/com/intellij/refactoring/rename/RenameDialog.java index 7ab5099e12a9..e3d2983c6b0f 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/RenameDialog.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/RenameDialog.java @@ -138,7 +138,10 @@ public class RenameDialog extends RefactoringDialog { final NameSuggestionProvider[] providers = Extensions.getExtensions(NameSuggestionProvider.EP_NAME); for(NameSuggestionProvider provider: providers) { SuggestedNameInfo info = provider.getSuggestedNames(myPsiElement, myNameSuggestionContext, result); - if (info != null) mySuggestedNameInfo = info; + if (info != null) { + mySuggestedNameInfo = info; + if (provider instanceof PreferrableNameSuggestionProvider && !((PreferrableNameSuggestionProvider)provider).shouldCheckOthers()) break; + } } if (result.size() == 0) { result.add(UsageViewUtil.getShortName(myPsiElement)); diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java index 71ac83cf8e95..9164e640fa5c 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java @@ -60,6 +60,7 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; +import com.intellij.psi.codeStyle.SuggestedNameInfo; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.ProjectScope; @@ -68,6 +69,7 @@ import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.rename.NameSuggestionProvider; +import com.intellij.refactoring.rename.PreferrableNameSuggestionProvider; import com.intellij.refactoring.util.CommonRefactoringUtil; import com.intellij.util.containers.Stack; import org.jetbrains.annotations.NonNls; @@ -616,7 +618,8 @@ public abstract class InplaceRefactoring { if (names == null) { names = new LinkedHashSet(); for (NameSuggestionProvider provider : Extensions.getExtensions(NameSuggestionProvider.EP_NAME)) { - provider.getSuggestedNames(myElementToRename, myElementToRename, names); + final SuggestedNameInfo suggestedNameInfo = provider.getSuggestedNames(myElementToRename, myElementToRename, names); + if (suggestedNameInfo != null && provider instanceof PreferrableNameSuggestionProvider && !((PreferrableNameSuggestionProvider)provider).shouldCheckOthers()) break; } } myLookupItems = new LookupElement[names.size()]; diff --git a/platform/platform-api/src/com/intellij/ide/BrowserUtil.java b/platform/platform-api/src/com/intellij/ide/BrowserUtil.java index 1fae47755094..3ab271d75bc3 100644 --- a/platform/platform-api/src/com/intellij/ide/BrowserUtil.java +++ b/platform/platform-api/src/com/intellij/ide/BrowserUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,8 @@ package com.intellij.ide; import com.intellij.CommonBundle; +import com.intellij.execution.ExecutionException; +import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.execution.util.ExecUtil; import com.intellij.openapi.application.*; import com.intellij.openapi.diagnostic.Logger; @@ -42,6 +44,7 @@ import javax.swing.*; import java.awt.*; import java.io.*; import java.lang.reflect.InvocationTargetException; +import java.net.MalformedURLException; import java.net.URL; import java.util.Arrays; import java.util.HashSet; @@ -58,20 +61,19 @@ public class BrowserUtil { // We have to violate the RFC since we need to distinguish // real schemes from local Windows paths; The only difference // with RFC is that we do not allow schemes with length=1 (in other case - // local paths like "C:/temp/index.html" whould be erroneously interpreted as + // local paths like "C:/temp/index.html" would be erroneously interpreted as // external URLs.) - @NonNls private static final Pattern ourExternalPrefix = Pattern.compile("^[\\w\\+\\.\\-]{2,}:"); - private static final Pattern ourAnchorsuffix = Pattern.compile("#(.*)$"); + private static final Pattern ourExternalPrefix = Pattern.compile("^[\\w\\+\\.\\-]{2,}:"); + private static final Pattern ourAnchorSuffix = Pattern.compile("#(.*)$"); - private BrowserUtil() { - } + private BrowserUtil() { } public static boolean isAbsoluteURL(String url) { return ourExternalPrefix.matcher(url.toLowerCase()).find(); } public static String getDocURL(String url) { - Matcher anchorMatcher = ourAnchorsuffix.matcher(url); + Matcher anchorMatcher = ourAnchorSuffix.matcher(url); if (anchorMatcher.find()) { return anchorMatcher.reset().replaceAll(""); @@ -81,7 +83,7 @@ public class BrowserUtil { } @Nullable - public static URL getURL(String url) throws java.net.MalformedURLException { + public static URL getURL(String url) throws MalformedURLException { if (!isAbsoluteURL(url)) { return new URL("file", "", url); } @@ -89,128 +91,95 @@ public class BrowserUtil { return VfsUtil.convertToURL(url); } - private static void launchBrowser(final String url, String[] command) { - try { - URL curl = getURL(url); + /** + * Main method: tries to launch a browser using every possible way. + * + * @param url an URL to open. + */ + public static void launchBrowser(@NonNls String url) { + LOG.debug("Launch browser: " + url); - if (curl != null) { - final String urlString = curl.toString(); - String[] commandLine; - if (SystemInfo.isWindows && isUseDefaultBrowser()) { - commandLine = new String[command.length + 2]; - System.arraycopy(command, 0, commandLine, 0, command.length); - commandLine[commandLine.length - 2] = "\"\""; - commandLine[commandLine.length - 1] = "\"" + redirectUrl(url, urlString) + "\""; - } - else { - commandLine = new String[command.length + 1]; - System.arraycopy(command, 0, commandLine, 0, command.length); - commandLine[commandLine.length - 1] = SystemInfo.isMac && isUseDefaultBrowser() ? escapeUrl(redirectUrl(url, urlString)) - : escapeUrl(urlString); - } - Runtime.getRuntime().exec(commandLine); - if (LOG.isDebugEnabled()) { - LOG.debug("Browser launched with command line: " + Arrays.toString(commandLine)); - } + if (url.startsWith("jar:")) { + url = extractFiles(url); + if (url == null) return; + } + + if (getGeneralSettingsInstance().isUseDefaultBrowser() && canStartDefaultBrowser()) { + final String[] command = getDefaultBrowserCommand(); + if (command != null) { + launchBrowserByCommand(url, command); } else { - showErrorMessage(IdeBundle.message("error.malformed.url", url), CommonBundle.getErrorTitle()); + launchBrowserUsingDesktopApi(url); } } - catch (final IOException e) { - showErrorMessage(IdeBundle.message("error.cannot.start.browser", e.getMessage()), - CommonBundle.getErrorTitle()); - } - } - - /** - * This method works around Windows 'start' command behaivor of dropping anchors from the url for local urls. - */ - private static String redirectUrl(String url, @NonNls String urlString) throws IOException { - if (url.indexOf('&') == -1 && (!urlString.startsWith("file:") || urlString.indexOf("#") == -1)) return urlString; - - File redirect = FileUtil.createTempFile("redirect", ".html"); - redirect.deleteOnExit(); - FileWriter writer = new FileWriter(redirect); - writer.write(""); - writer.close(); - return VfsUtil.pathToUrl(redirect.getAbsolutePath()); - } - - private static boolean isUseDefaultBrowser() { - Application application = ApplicationManager.getApplication(); - if (application == null) { - return true; - } else { - return getGeneralSettingsInstance().isUseDefaultBrowser(); + launchBrowserUsingStandardWay(url); } } - private static void showErrorMessage(final String message, final String title) { - final Application app = ApplicationManager.getApplication(); - if (app == null) { - return; // Not started yet. Not able to show message up. (Could happen in License panel under Linux). - } - - Runnable runnable = new Runnable() { - public void run() { - Messages.showMessageDialog(message, - title, - Messages.getErrorIcon()); - } - }; - - if (app.isDispatchThread()) { - runnable.run(); - } - else { - app.invokeLater(runnable, ModalityState.NON_MODAL); - } - } - - private static void launchBrowserUsingStandardWay(final String url) { - String[] command; - try { - String browserPath = getGeneralSettingsInstance().getBrowserPath(); - if (browserPath == null || browserPath.trim().length() == 0) { - showErrorMessage(IdeBundle.message("error.please.specify.path.to.web.browser"), - IdeBundle.message("title.browser.not.found")); - return; - } - - command = getOpenBrowserCommand(browserPath); - } - catch (NullPointerException e) { - // todo: fix the possible problem on startup, see SCR #35066 - command = getDefaultBrowserCommand(); - if (command == null) { - showErrorMessage(IdeBundle.message("error.please.open.url.manually", url, ApplicationNamesInfo.getInstance().getProductName()), - IdeBundle.message("title.browser.path.not.found")); - return; - } - } - // We do not need to check browserPath under Win32 - - launchBrowser(url, command); - } - private static GeneralSettings getGeneralSettingsInstance() { - final GeneralSettings settings = GeneralSettings.getInstance(); - if (settings != null) return settings; - return new GeneralSettings(); + final GeneralSettings settings = ApplicationManager.getApplication() != null ? GeneralSettings.getInstance() : null; + return settings != null ? settings : new GeneralSettings(); } - private static boolean launchDefaultBrowserUsingJdk6Api(String sUrl) { - try { - URL url = getURL(sUrl); - if (url == null) return false; - Desktop.getDesktop().browse(url.toURI()); - LOG.debug("Browser launched using JDK 1.6 API"); + public static boolean canStartDefaultBrowser() { + if (SystemInfo.isMac || SystemInfo.isWindows) { return true; } - catch (Exception e) { - return false; + else if (SystemInfo.isUnix && SystemInfo.hasXdgOpen) { + return true; + } + else if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) { + return true; + } + + return false; + } + + @Nullable + @NonNls + private static String[] getDefaultBrowserCommand() { + if (SystemInfo.isWindows9x) { + return new String[]{"command.com", "/c", "start"}; + } + else if (SystemInfo.isWindows) { + return new String[]{"cmd.exe", "/c", "start"}; + } + else if (SystemInfo.isMac) { + return new String[]{ExecUtil.getOpenCommandPath()}; + } + else if (SystemInfo.isUnix && SystemInfo.hasXdgOpen) { + return new String[]{"xdg-open"}; + } + + return null; + } + + private static void launchBrowserByCommand(final String url, @NotNull final String[] command) { + URL curl; + try { + curl = getURL(url); + } + catch (MalformedURLException ignored) { + curl = null; + } + if (curl == null) { + showErrorMessage(IdeBundle.message("error.malformed.url", url), CommonBundle.getErrorTitle()); + return; + } + + try { + final GeneralCommandLine commandLine = new GeneralCommandLine(command); + commandLine.addParameter(curl.toString()); + commandLine.createProcess(); + + if (LOG.isDebugEnabled()) { + LOG.debug("Browser launched with command line: " + commandLine.getCommandLineString()); + } + } + catch (final ExecutionException e) { + showErrorMessage(IdeBundle.message("error.cannot.start.browser", e.getMessage()), CommonBundle.getErrorTitle()); } } @@ -224,6 +193,84 @@ public class BrowserUtil { } } + private static boolean launchBrowserUsingDesktopApi(final String sUrl) { + try { + URL url = getURL(sUrl); + if (url == null) return false; + Desktop.getDesktop().browse(url.toURI()); + LOG.debug("Browser launched using JDK 1.6 API"); + return true; + } + catch (Exception e) { + return false; + } + } + + private static void launchBrowserUsingStandardWay(final String url) { + String browserPath = getGeneralSettingsInstance().getBrowserPath(); + if (StringUtil.isEmptyOrSpaces(browserPath)) { + showErrorMessage(IdeBundle.message("error.please.specify.path.to.web.browser"), IdeBundle.message("title.browser.not.found")); + return; + } + + launchBrowserByCommand(url, getOpenBrowserCommand(browserPath)); + } + + /** + * @deprecated use {@link #getOpenBrowserCommand(String)} instead + */ + @SuppressWarnings({"UnusedDeclaration"}) + public static String[] getOpenBrowserCommand(final @NonNls @NotNull String browserPath, final String... parameters) { + return getOpenBrowserCommand(browserPath); + } + + public static String[] getOpenBrowserCommand(final @NonNls @NotNull String browserPath) { + final String[] command; + if (SystemInfo.isMac) { + if (new File(browserPath).isFile()) { + // versions before 10.6 don't allow to pass command line arguments to browser via 'open' command + // so we use full path to browser executable in such case + command = new String[] {browserPath}; + } + else { + command = new String[]{ExecUtil.getOpenCommandPath(), "-a", browserPath}; + } + } + else if (SystemInfo.isWindows) { + if (new File(browserPath).isFile()) { + command = new String[]{browserPath}; + } + else { + command = new String[]{SystemInfo.isWindows9x ? "command.com" : "cmd.exe", "/c", "start", browserPath}; + } + } + else { + command = new String[]{browserPath}; + } + return command; + } + + private static void showErrorMessage(final String message, final String title) { + final Application app = ApplicationManager.getApplication(); + if (app == null) { + return; // Not started yet. Not able to show message up. (Could happen in License panel under Linux). + } + + Runnable runnable = new Runnable() { + public void run() { + Messages.showMessageDialog(message, title, Messages.getErrorIcon()); + } + }; + + if (app.isDispatchThread()) { + runnable.run(); + } + else { + app.invokeLater(runnable, ModalityState.NON_MODAL); + } + } + + @Nullable private static String extractFiles(String url) { try { int sharpPos = url.indexOf('#'); @@ -350,100 +397,10 @@ public class BrowserUtil { return new File(PathManager.getSystemPath(), "ExtractedFiles"); } - public static void launchBrowser(@NonNls String url) { - LOG.debug("Launch browser: " + url); - if (url.startsWith("jar:")) { - url = extractFiles(url); - if (url == null) return; - } - if (canStartDefaultBrowser() && isUseDefaultBrowser()) { - if (SystemInfo.isLinux && launchDefaultBrowserUsingJdk6Api(url)) { - return; - } - - launchBrowser(url, getDefaultBrowserCommand()); - } - else { - launchBrowserUsingStandardWay(url); - } - } - - @NonNls - private static String[] getDefaultBrowserCommand() { - if (SystemInfo.isWindows9x) { - return new String[]{"command.com", "/c", "start"}; - } - else if (SystemInfo.isWindows) { - return new String[]{"cmd.exe", "/c", "start"}; - } - else if (SystemInfo.isMac) { - return new String[]{ExecUtil.getOpenCommandPath()}; - } - else if (SystemInfo.isUnix) { - return new String[]{"mozilla"}; - } - else { - return null; - } - } - - public static boolean canStartDefaultBrowser() { - if (SystemInfo.isMac || SystemInfo.isWindows) { - return true; - } - - if (SystemInfo.isLinux && Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) { - return true; - } - - return false; - } - public static boolean isOpenCommandSupportArgs() { return SystemInfo.isMacOSSnowLeopard; } - /** - * @deprecated use {@link #getOpenBrowserCommand(String)} instead - */ - public static String[] getOpenBrowserCommand(final @NonNls @NotNull String browserPath, final String... parameters) { - return getOpenBrowserCommand(browserPath); - } - - public static String[] getOpenBrowserCommand(final @NonNls @NotNull String browserPath) { - String[] command; - if (SystemInfo.isMac) { - File browserExecutable = new File(browserPath); - if (browserExecutable.isFile()) { - //versions before 10.6 don't allow to pass command line arguments to browser via 'open' command so we use full path to browser executable in such cases - command = new String[] {browserPath}; - } - else { - command = new String[]{ExecUtil.getOpenCommandPath(), "-a", browserPath}; - } - } - else if (SystemInfo.isWindows9x) { - if (browserPath.indexOf(File.separatorChar) != -1) { - command = new String[]{browserPath}; - } - else { - command = new String[]{"command.com", "/c", "start", browserPath}; - } - } - else if (SystemInfo.isWindows) { - if (browserPath.indexOf(File.separatorChar) != -1) { - command = new String[]{browserPath}; - } - else { - command = new String[]{"cmd.exe", "/c", "start", browserPath}; - } - } - else { - command = new String[]{browserPath}; - } - return command; - } - private static class ConfirmExtractDialog extends OptionsDialog { private ConfirmExtractDialog() { super(null); diff --git a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java index 2e21403db49b..b892cd36e489 100644 --- a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java +++ b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java @@ -4811,9 +4811,13 @@ public class AbstractTreeUi { public boolean isInStructure(@Nullable Object element) { Object eachParent = element; + final AbstractTreeStructure structure = getTreeStructure(); + + if (structure == null) return false; + while (eachParent != null) { - if (getTreeStructure().getRootElement().equals(eachParent)) return true; - eachParent = getTreeStructure().getParentElement(eachParent); + if (Comparing.equal(structure.getRootElement(), eachParent)) return true; + eachParent = structure.getParentElement(eachParent); } return false; diff --git a/platform/platform-api/src/com/intellij/openapi/diff/DiffApplication.java b/platform/platform-api/src/com/intellij/openapi/diff/DiffApplication.java index 97d72513e9bf..e81347ff2d80 100644 --- a/platform/platform-api/src/com/intellij/openapi/diff/DiffApplication.java +++ b/platform/platform-api/src/com/intellij/openapi/diff/DiffApplication.java @@ -111,6 +111,8 @@ public class DiffApplication implements ApplicationStarterEx { settings.showInFrame = false; diffManager.showDiff(d1, d2, settings, null); } else { + file1.refresh(false, false); + file2.refresh(false, false); SimpleDiffRequest request = SimpleDiffRequest.compareFiles(file1, file2, null); request.addHint(DiffTool.HINT_SHOW_MODAL_DIALOG); DiffManager.getInstance().getIdeaDiffTool().show(request); diff --git a/platform/platform-api/src/com/intellij/openapi/diff/DiffRequest.java b/platform/platform-api/src/com/intellij/openapi/diff/DiffRequest.java index 388f25f7fc68..0f78e7a4e38a 100644 --- a/platform/platform-api/src/com/intellij/openapi/diff/DiffRequest.java +++ b/platform/platform-api/src/com/intellij/openapi/diff/DiffRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,10 +30,11 @@ import java.util.*; * A request for a diff or merge operation. */ public abstract class DiffRequest { + @NonNls private static final String COMMON_DIFF_GROUP_KEY = "DiffWindow"; + private String myGroupKey = COMMON_DIFF_GROUP_KEY; private final Project myProject; private ToolbarAddons myToolbarAddons = ToolbarAddons.NOTHING; - @NonNls private static final String COMMON_DIFF_GROUP_KEY = "DiffWindow"; private Factory myBottomComponentFactory = null; private final HashSet myHints = new HashSet(); private final Map myGenericData; @@ -59,6 +60,7 @@ public abstract class DiffRequest { /** * @return contents to compare */ + @NotNull public abstract DiffContent[] getContents(); /** @@ -79,7 +81,7 @@ public abstract class DiffRequest { } /** - * Work in progess. Don't rely on this functionality
+ * Work in progress. Don't rely on this functionality
* @return not null (possibly empty) collection of hints for diff tool. */ public Collection getHints() { diff --git a/platform/platform-api/src/com/intellij/openapi/diff/SimpleContent.java b/platform/platform-api/src/com/intellij/openapi/diff/SimpleContent.java index fe6157574020..42e812a2f3c0 100644 --- a/platform/platform-api/src/com/intellij/openapi/diff/SimpleContent.java +++ b/platform/platform-api/src/com/intellij/openapi/diff/SimpleContent.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.SystemProperties; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.*; import java.nio.charset.Charset; @@ -38,6 +39,7 @@ import java.nio.ByteBuffer; */ public class SimpleContent extends DiffContent { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.diff.SimpleContent"); + private final byte[] myOriginalBytes; private final String myOriginalText; private final LineSeparators myLineSeparators = new LineSeparators(); @@ -53,7 +55,7 @@ public class SimpleContent extends DiffContent { this(text, null); } - public SimpleContent(@NotNull String text, FileType type) { + public SimpleContent(@NotNull String text, @Nullable FileType type) { this(text, type, EditorFactory.getInstance()); } diff --git a/platform/platform-api/src/com/intellij/openapi/diff/SimpleDiffRequest.java b/platform/platform-api/src/com/intellij/openapi/diff/SimpleDiffRequest.java index 0d0171c06971..2f82543a52a8 100644 --- a/platform/platform-api/src/com/intellij/openapi/diff/SimpleDiffRequest.java +++ b/platform/platform-api/src/com/intellij/openapi/diff/SimpleDiffRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,6 @@ */ package com.intellij.openapi.diff; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; @@ -24,18 +23,20 @@ import org.jetbrains.annotations.NotNull; * Two contents for general diff */ public class SimpleDiffRequest extends DiffRequest { - private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.diff.SimpleDiffRequest"); private final DiffContent[] myContents = new DiffContent[2]; private final String[] myContentTitles = new String[2]; private String myWindowTitle; - public SimpleDiffRequest(Project project, String windowtitle) { + public SimpleDiffRequest(Project project, String windowTitle) { super(project); - myWindowTitle = windowtitle; + myWindowTitle = windowTitle; } + @NotNull public DiffContent[] getContents() { return myContents; } + public String[] getContentTitles() { return myContentTitles; } + public String getWindowTitle() { return myWindowTitle; } public void setContents(@NotNull DiffContent content1, @NotNull DiffContent content2) { @@ -75,6 +76,7 @@ public class SimpleDiffRequest extends DiffRequest { super(project, title); } + @NotNull public DiffContent[] getContents() { return new DiffContent[]{ DiffContent.fromFile(getProject(), myVirtualFiles[0]), diff --git a/platform/platform-api/src/com/intellij/openapi/editor/event/MockDocumentEvent.java b/platform/platform-api/src/com/intellij/openapi/editor/event/MockDocumentEvent.java index 61df2222ab78..9efef1db5d3c 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/event/MockDocumentEvent.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/event/MockDocumentEvent.java @@ -22,7 +22,7 @@ public class MockDocumentEvent extends DocumentEvent { private final int myOffset; private final long myTimestamp; - public MockDocumentEvent(Document document, int offset) { + public MockDocumentEvent(@NotNull Document document, int offset) { super(document); myOffset = offset; myTimestamp = document.getModificationStamp(); @@ -45,10 +45,12 @@ public class MockDocumentEvent extends DocumentEvent { return 0; } + @NotNull public CharSequence getOldFragment() { return ""; } + @NotNull public CharSequence getNewFragment() { return ""; } diff --git a/platform/platform-api/src/com/intellij/openapi/fileChooser/FileElement.java b/platform/platform-api/src/com/intellij/openapi/fileChooser/FileElement.java index 8b18d2c56271..c18bd603b36e 100644 --- a/platform/platform-api/src/com/intellij/openapi/fileChooser/FileElement.java +++ b/platform/platform-api/src/com/intellij/openapi/fileChooser/FileElement.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -67,7 +67,10 @@ public class FileElement { if (myName != null) { return myName; } - return myFile.getName(); + else if (myFile != null) { + return myFile.getName(); + } + return ""; } public final String getName() { return myName; } diff --git a/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java b/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java index 093a628d51a7..ae9ed058fe81 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java @@ -108,9 +108,9 @@ public abstract class DialogWrapper { private boolean myCrossClosesWindow = true; private Insets myButtonMargins = new Insets(2, 16, 2, 16); - private Action myOKAction; - private Action myCancelAction; - private Action myHelpAction; + protected Action myOKAction; + protected Action myCancelAction; + protected Action myHelpAction; private JButton[] myButtons; private boolean myClosed = false; @@ -1468,8 +1468,8 @@ public abstract class DialogWrapper { protected abstract void doAction(ActionEvent e); } - private class OkAction extends DialogWrapperAction { - private OkAction() { + protected class OkAction extends DialogWrapperAction { + protected OkAction() { super(CommonBundle.getOkButtonText()); putValue(DEFAULT_ACTION, Boolean.TRUE); } @@ -1484,7 +1484,7 @@ public abstract class DialogWrapper { } } - private class CancelAction extends DialogWrapperAction { + protected class CancelAction extends DialogWrapperAction { private CancelAction() { super(CommonBundle.getCancelButtonText()); } diff --git a/platform/platform-api/src/com/intellij/openapi/ui/Messages.java b/platform/platform-api/src/com/intellij/openapi/ui/Messages.java index c8fd287a42f5..b9118e713be8 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/Messages.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/Messages.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -906,7 +906,7 @@ public class Messages { for (int i = 0; i < myOptions.length; i++) { String option = myOptions[i]; final int exitCode = i; - actions[i] = new AbstractAction(option) { + actions[i] = new AbstractAction(UIUtil.replaceMnemonicAmpersand(option)) { public void actionPerformed(ActionEvent e) { close(exitCode, true); } @@ -1011,7 +1011,7 @@ public class Messages { messageComponent.setCaretPosition(0); } - if (UIUtil.isUnderNimbusLookAndFeel() || UIUtil.isUnderGTKLookAndFeel()) { + if (UIUtil.isUnderNimbusLookAndFeel()) { messageComponent.setOpaque(false); messageComponent.setBackground(UIUtil.TRANSPARENT_COLOR); } diff --git a/platform/platform-api/src/com/intellij/openapi/ui/PanelWithActionsAndCloseButton.java b/platform/platform-api/src/com/intellij/openapi/ui/PanelWithActionsAndCloseButton.java index 9471a3f8fb53..c0758be537f4 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/PanelWithActionsAndCloseButton.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/PanelWithActionsAndCloseButton.java @@ -59,9 +59,12 @@ public abstract class PanelWithActionsAndCloseButton extends JPanel implements D myToolbarGroup.add(ActionManager.getInstance().getAction(IdeActions.ACTION_CONTEXT_HELP)); - add(ActionManager.getInstance().createActionToolbar(ActionPlaces.FILEHISTORY_VIEW_TOOLBAR, myToolbarGroup, false) - .getComponent(), BorderLayout.WEST); - add(createCenterPanel(), BorderLayout.CENTER); + ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.FILEHISTORY_VIEW_TOOLBAR, myToolbarGroup, false); + JComponent centerPanel = createCenterPanel(); + toolbar.setTargetComponent(centerPanel); + + add(toolbar.getComponent(), BorderLayout.WEST); + add(centerPanel, BorderLayout.CENTER); } public Object getData(String dataId) { diff --git a/platform/platform-api/src/com/intellij/openapi/ui/SimpleToolWindowPanel.java b/platform/platform-api/src/com/intellij/openapi/ui/SimpleToolWindowPanel.java index 5db53a0c3157..8198230777a4 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/SimpleToolWindowPanel.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/SimpleToolWindowPanel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import com.intellij.ui.switcher.QuickActionProvider; import com.intellij.util.ui.AwtVisitor; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; @@ -87,6 +88,7 @@ public class SimpleToolWindowPanel extends JPanel implements QuickActionProvider repaint(); } + @Nullable public Object getData(@NonNls String dataId) { return QuickActionProvider.KEY.is(dataId) && myProvideQuickActions ? this : null; } diff --git a/platform/platform-api/src/com/intellij/ui/components/labels/LinkLabel.java b/platform/platform-api/src/com/intellij/ui/components/labels/LinkLabel.java index 8b948fee4ab6..5169e7a4e937 100644 --- a/platform/platform-api/src/com/intellij/ui/components/labels/LinkLabel.java +++ b/platform/platform-api/src/com/intellij/ui/components/labels/LinkLabel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.wm.StatusBar; import com.intellij.ui.UI; import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.border.Border; @@ -60,20 +61,24 @@ public class LinkLabel extends JLabel { this("", LINK); } - public LinkLabel(String text, Icon icon) { + public LinkLabel(String text, @Nullable Icon icon) { this(text, icon, null, null, null); } - public LinkLabel(String text, Icon icon, LinkListener aListener) { + public LinkLabel(String text, @Nullable Icon icon, @Nullable LinkListener aListener) { this(text, icon, aListener, null, null); } - public LinkLabel(String text, Icon icon, LinkListener aListener, Object aLinkData) { + public LinkLabel(String text, @Nullable Icon icon, @Nullable LinkListener aListener, @Nullable Object aLinkData) { this(text, icon, aListener, aLinkData, null); } - public LinkLabel(String text, Icon icon, LinkListener aListener, Object aLinkData, String aVisitedLinksKey) { - super(text, icon, JLabel.LEFT); + public LinkLabel(String text, + @Nullable Icon icon, + @Nullable LinkListener aListener, + @Nullable Object aLinkData, + @Nullable String aVisitedLinksKey) { + super(text, icon, SwingConstants.LEFT); setOpaque(false); setListener(aListener, aLinkData); @@ -92,7 +97,7 @@ public class LinkLabel extends JLabel { myHoveringIcon = iconForHovering; } - public void setListener(LinkListener listener, Object linkData) { + public void setListener(LinkListener listener, @Nullable Object linkData) { myLinkListener = listener; myLinkData = linkData; } diff --git a/platform/platform-api/src/com/intellij/ui/navigation/Place.java b/platform/platform-api/src/com/intellij/ui/navigation/Place.java index d07c935dc48f..cc88c74b6745 100644 --- a/platform/platform-api/src/com/intellij/ui/navigation/Place.java +++ b/platform/platform-api/src/com/intellij/ui/navigation/Place.java @@ -97,7 +97,7 @@ public class Place implements ComparableObject { public static ActionCallback goFurther(Object object, Place place, final boolean requestFocus) { if (object instanceof Navigator) { - return ((Navigator)object).navigateTo(place, false); + return ((Navigator)object).navigateTo(place, requestFocus); } else { return new ActionCallback.Done(); } diff --git a/platform/platform-api/src/com/intellij/ui/tabs/impl/ActionButton.java b/platform/platform-api/src/com/intellij/ui/tabs/impl/ActionButton.java index 2a82c3e3de12..3dc1fe1f2b56 100644 --- a/platform/platform-api/src/com/intellij/ui/tabs/impl/ActionButton.java +++ b/platform/platform-api/src/com/intellij/ui/tabs/impl/ActionButton.java @@ -72,7 +72,7 @@ class ActionButton extends IconButton implements ActionListener { } public boolean update() { - AnActionEvent event = createAnEvent(null); + AnActionEvent event = createAnEvent(null, 0); if (event == null) return false; @@ -107,17 +107,17 @@ class ActionButton extends IconButton implements ActionListener { } public void actionPerformed(final ActionEvent e) { - AnActionEvent event = createAnEvent(null); + AnActionEvent event = createAnEvent(null, e.getModifiers()); if (event != null && ActionUtil.lastUpdateAndCheckDumb(myAction, event, true)) { myAction.actionPerformed(event); } } @Nullable - private AnActionEvent createAnEvent(InputEvent e) { - Presentation presentation = (Presentation)myAction.getTemplatePresentation().clone(); + private AnActionEvent createAnEvent(InputEvent e, final int modifiers) { + Presentation presentation = myAction.getTemplatePresentation().clone(); DataContext context = DataManager.getInstance().getDataContext(myTabInfo.getComponent()); - return new AnActionEvent(e, context, myPlace != null ? myPlace : ActionPlaces.UNKNOWN, presentation, myTabs.myActionManager, 0); + return new AnActionEvent(e, context, myPlace != null ? myPlace : ActionPlaces.UNKNOWN, presentation, myTabs.myActionManager, modifiers); } public void setAutoHide(final boolean autoHide) { diff --git a/platform/platform-api/src/com/intellij/util/ui/OptionsDialog.java b/platform/platform-api/src/com/intellij/util/ui/OptionsDialog.java index 76425e774f16..856ee05b2227 100644 --- a/platform/platform-api/src/com/intellij/util/ui/OptionsDialog.java +++ b/platform/platform-api/src/com/intellij/util/ui/OptionsDialog.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package com.intellij.util.ui; import com.intellij.CommonBundle; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; +import org.jetbrains.annotations.Nullable; import java.awt.*; @@ -50,7 +51,7 @@ public abstract class OptionsDialog extends DialogWrapper { } } - protected OptionsDialog(Project project) { + protected OptionsDialog(@Nullable Project project) { super(project, true); myProject = project; setDoNotAskOption(new MyDoNotAsk()); diff --git a/platform/platform-impl/src/com/intellij/application/options/PathMacrosImpl.java b/platform/platform-impl/src/com/intellij/application/options/PathMacrosImpl.java index bdf488d99fc6..27e2c6448614 100644 --- a/platform/platform-impl/src/com/intellij/application/options/PathMacrosImpl.java +++ b/platform/platform-impl/src/com/intellij/application/options/PathMacrosImpl.java @@ -18,6 +18,7 @@ package com.intellij.application.options; import com.google.common.collect.ImmutableSet; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.PathMacros; +import com.intellij.openapi.application.PathManager; import com.intellij.openapi.components.ApplicationComponent; import com.intellij.openapi.components.ExpandMacroToPathMap; import com.intellij.openapi.diagnostic.Logger; @@ -25,6 +26,8 @@ import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.NamedJDOMExternalizable; import com.intellij.openapi.util.RoamingTypeDisabled; import com.intellij.openapi.util.WriteExternalException; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.SystemProperties; import com.intellij.util.concurrency.JBReentrantReadWriteLock; import com.intellij.util.concurrency.LockFactory; import com.intellij.util.containers.ContainerUtil; @@ -181,6 +184,13 @@ public class PathMacrosImpl extends PathMacros implements ApplicationComponent, if (!myIgnoredMacros.contains(name)) myIgnoredMacros.add(name); } + public static Map getGlobalSystemMacros() { + final Map map = new HashMap(); + map.put(APPLICATION_HOME_MACRO_NAME, PathManager.getHomePath()); + map.put(USER_HOME_MACRO_NAME, getUserHome()); + return map; + } + @Override public boolean isIgnoredMacroName(@NotNull String macro) { return myIgnoredMacros.contains(macro); @@ -348,4 +358,8 @@ public class PathMacrosImpl extends PathMacros implements ApplicationComponent, myLock.readLock().unlock(); } } + + public static String getUserHome() { + return StringUtil.trimEnd(SystemProperties.getUserHome(), "/"); + } } diff --git a/platform/platform-impl/src/com/intellij/diagnostic/VMOptions.java b/platform/platform-impl/src/com/intellij/diagnostic/VMOptions.java index 21ffe2f297a1..03774ed51f10 100644 --- a/platform/platform-impl/src/com/intellij/diagnostic/VMOptions.java +++ b/platform/platform-impl/src/com/intellij/diagnostic/VMOptions.java @@ -226,7 +226,7 @@ public class VMOptions { } final String productName = ApplicationNamesInfo.getInstance().getProductName().toLowerCase(); - final String platformSuffix = (SystemInfo.is64Bit && !SystemInfo.isLinux) ? "64" : ""; + final String platformSuffix = SystemInfo.is64Bit ? "64" : ""; final String osSuffix = SystemInfo.isWindows ? ".exe" : ""; return PathManager.getBinPath() + File.separatorChar + productName + platformSuffix + osSuffix + ".vmoptions"; } diff --git a/platform/platform-impl/src/com/intellij/ide/actions/CloseAllEditorsButActiveAction.java b/platform/platform-impl/src/com/intellij/ide/actions/CloseAllEditorsButActiveAction.java index be19cd8f24e2..443a10030ec2 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/CloseAllEditorsButActiveAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/CloseAllEditorsButActiveAction.java @@ -33,13 +33,7 @@ public class CloseAllEditorsButActiveAction extends AnAction implements DumbAwar VirtualFile selectedFile; final EditorWindow window = e.getData(EditorWindow.DATA_KEY); if (window != null){ - selectedFile = e.getData(PlatformDataKeys.VIRTUAL_FILE); - final VirtualFile[] files = window.getFiles(); - for (final VirtualFile file : files) { - if (file != selectedFile && !window.isFilePinned(file)) { - window.closeFile(file); - } - } + window.closeAllExcept(e.getData(PlatformDataKeys.VIRTUAL_FILE)); return; } selectedFile = fileEditorManager.getSelectedFiles()[0]; diff --git a/platform/platform-impl/src/com/intellij/ide/highlighter/custom/SyntaxTable.java b/platform/platform-impl/src/com/intellij/ide/highlighter/custom/SyntaxTable.java index e17ef844993d..8301a92cb953 100644 --- a/platform/platform-impl/src/com/intellij/ide/highlighter/custom/SyntaxTable.java +++ b/platform/platform-impl/src/com/intellij/ide/highlighter/custom/SyntaxTable.java @@ -29,6 +29,7 @@ public class SyntaxTable implements Cloneable { private Set myKeywords4; private String myLineComment; + public boolean lineCommentOnlyAtStart; private String myStartComment; private String myEndComment; @@ -175,6 +176,7 @@ public class SyntaxTable implements Cloneable { if (myHasBrackets != syntaxTable.myHasBrackets) return false; if (myHasParens != syntaxTable.myHasParens) return false; if (myHasStringEscapes != syntaxTable.myHasStringEscapes) return false; + if (lineCommentOnlyAtStart != syntaxTable.lineCommentOnlyAtStart) return false; return true; } diff --git a/platform/platform-impl/src/com/intellij/ide/highlighter/custom/impl/CustomFileTypeEditor.java b/platform/platform-impl/src/com/intellij/ide/highlighter/custom/impl/CustomFileTypeEditor.java index eed78729f8fe..6dd5efeeba2c 100644 --- a/platform/platform-impl/src/com/intellij/ide/highlighter/custom/impl/CustomFileTypeEditor.java +++ b/platform/platform-impl/src/com/intellij/ide/highlighter/custom/impl/CustomFileTypeEditor.java @@ -21,42 +21,57 @@ import com.intellij.ide.highlighter.custom.SyntaxTable; import com.intellij.openapi.fileTypes.impl.AbstractFileType; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.SettingsEditor; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.*; import com.intellij.ui.components.JBList; +import com.intellij.util.ui.GridBag; +import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import javax.swing.*; +import javax.swing.event.DocumentEvent; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.util.Iterator; /** * @author Yura Cangea, dsl */ public class CustomFileTypeEditor extends SettingsEditor { - private final JTextField myFileTypeName = new JTextField(26); - private final JTextField myFileTypeDescr = new JTextField(26); + private final JTextField myFileTypeName = new JTextField(); + private final JTextField myFileTypeDescr = new JTextField(); private final JCheckBox myIgnoreCase = new JCheckBox(IdeBundle.message("checkbox.customfiletype.ignore.case")); private final JCheckBox mySupportBraces = new JCheckBox(IdeBundle.message("checkbox.customfiletype.support.paired.braces")); private final JCheckBox mySupportBrackets = new JCheckBox(IdeBundle.message("checkbox.customfiletype.support.paired.brackets")); private final JCheckBox mySupportParens = new JCheckBox(IdeBundle.message("checkbox.customfiletype.support.paired.parens")); private final JCheckBox mySupportEscapes = new JCheckBox(IdeBundle.message("checkbox.customfiletype.support.string.escapes")); - private final JTextField myLineComment = new JTextField(20); - private final JTextField myBlockCommentStart = new JTextField(20); - private final JTextField myBlockCommentEnd = new JTextField(20); - private final JTextField myHexPrefix = new JTextField(20); - private final JTextField myNumPostfixes = new JTextField(20); + private final JTextField myLineComment = new JTextField(5); + private final JCheckBox myCommentAtLineStart = new JCheckBox(UIUtil.replaceMnemonicAmpersand("&Only at line start")); + private final JTextField myBlockCommentStart = new JTextField(5); + private final JTextField myBlockCommentEnd = new JTextField(5); + private final JTextField myHexPrefix = new JTextField(5); - private final JList[] myKeywordsLists = new JList[]{new JBList(), new JBList(), new JBList(), new JBList()}; + private final JTextField myNumPostfixes = new JTextField(5); + private final JBList[] myKeywordsLists = new JBList[]{new JBList(), new JBList(), new JBList(), new JBList()}; private final DefaultListModel[] myKeywordModels = new DefaultListModel[]{new DefaultListModel(), new DefaultListModel(), new DefaultListModel(), new DefaultListModel()}; private final JButton[] myAddKeywordButtons = new JButton[4]; private final JButton[] myRemoveKeywordButtons = new JButton[4]; public CustomFileTypeEditor() { + myLineComment.getDocument().addDocumentListener(new DocumentAdapter() { + @Override + protected void textChanged(DocumentEvent e) { + boolean enabled = StringUtil.isNotEmpty(myLineComment.getText()); + myCommentAtLineStart.setEnabled(enabled); + if (!enabled) { + myCommentAtLineStart.setSelected(false); + } + } + }); + myCommentAtLineStart.setEnabled(false); } public void resetEditorFrom(AbstractFileType fileType) { @@ -72,23 +87,24 @@ public class CustomFileTypeEditor extends SettingsEditor { myHexPrefix.setText(table.getHexPrefix()); myNumPostfixes.setText(table.getNumPostfixChars()); myIgnoreCase.setSelected(table.isIgnoreCase()); + myCommentAtLineStart.setSelected(table.lineCommentOnlyAtStart); mySupportBraces.setSelected(table.isHasBraces()); mySupportBrackets.setSelected(table.isHasBrackets()); mySupportParens.setSelected(table.isHasParens()); mySupportEscapes.setSelected(table.isHasStringEscapes()); - for (Iterator i = table.getKeywords1().iterator(); i.hasNext();) { - myKeywordModels[0].addElement(i.next()); + for (String s : table.getKeywords1()) { + myKeywordModels[0].addElement(s); } - for (Iterator i = table.getKeywords2().iterator(); i.hasNext();) { - myKeywordModels[1].addElement(i.next()); + for (String s : table.getKeywords2()) { + myKeywordModels[1].addElement(s); } - for (Iterator i = table.getKeywords3().iterator(); i.hasNext();) { - myKeywordModels[2].addElement(i.next()); + for (String s : table.getKeywords3()) { + myKeywordModels[2].addElement(s); } - for (Iterator i = table.getKeywords4().iterator(); i.hasNext();) { - myKeywordModels[3].addElement(i.next()); + for (String s : table.getKeywords4()) { + myKeywordModels[3].addElement(s); } } } @@ -122,83 +138,56 @@ public class CustomFileTypeEditor extends SettingsEditor { JPanel panel = new JPanel(new BorderLayout()); JPanel fileTypePanel = new JPanel(new BorderLayout()); - JPanel _panel0 = new JPanel(new BorderLayout()); JPanel info = new JPanel(new GridBagLayout()); GridBagConstraints gc = new GridBagConstraints(); gc.gridx = 0; gc.gridy = 0; gc.anchor = GridBagConstraints.WEST; - gc.fill = GridBagConstraints.HORIZONTAL; + gc.fill = GridBagConstraints.BOTH; info.add(new JLabel(IdeBundle.message("editbox.customfiletype.name")), gc); gc.gridx = 1; gc.gridy = 0; - info.add(myFileTypeName); + gc.weightx = 1; + info.add(myFileTypeName, gc); + + gc.weightx = 0; gc.gridx = 0; - gc.gridy = 2; + gc.gridy = 1; info.add(new JLabel(IdeBundle.message("editbox.customfiletype.description")), gc); gc.gridx = 1; - gc.gridy = 2; info.add(myFileTypeDescr, gc); - gc.gridx = 0; - gc.gridy = 3; - _panel0.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 5)); - _panel0.add(info, BorderLayout.WEST); - fileTypePanel.add(_panel0, BorderLayout.NORTH); + info.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 5)); + fileTypePanel.add(info, BorderLayout.NORTH); - JPanel panel1 = new JPanel(); - panel1.setBorder(IdeBorderFactory.createTitledBorder(IdeBundle.message("group.customfiletype.syntax.highlighting"), false, false, true)); - JPanel highlighterPanel = panel1; + JPanel highlighterPanel = new JPanel(); + highlighterPanel.setBorder(IdeBorderFactory.createTitledBorder(IdeBundle.message("group.customfiletype.syntax.highlighting"), false, false, true)); highlighterPanel.setLayout(new BorderLayout()); - JPanel panel2 = new JPanel(); - panel2.setBorder(IdeBorderFactory.createTitledBorder(IdeBundle.message("group.customfiletype.options"), false, true, true)); - JPanel commentsAndNumbersPanel = panel2; + JPanel commentsAndNumbersPanel = new JPanel(); commentsAndNumbersPanel.setLayout(new GridBagLayout()); JPanel _panel1 = new JPanel(new BorderLayout()); - gc = new GridBagConstraints(); - gc.fill = GridBagConstraints.HORIZONTAL; - gc.anchor = GridBagConstraints.WEST; - gc.gridx = 0; - gc.gridy = 0; - commentsAndNumbersPanel.add(new JLabel(IdeBundle.message("editbox.customfiletype.line.comment")), gc); - gc.gridx = 1; - commentsAndNumbersPanel.add(myLineComment, gc); - gc.gridx = 0; - gc.gridy++; - commentsAndNumbersPanel.add(new JLabel(IdeBundle.message("editbox.customfiletype.block.comment.start")), gc); - gc.gridx = 1; - commentsAndNumbersPanel.add(myBlockCommentStart, gc); - gc.gridx = 0; - gc.gridy++; - commentsAndNumbersPanel.add(new JLabel(IdeBundle.message("editbox.customfiletype.block.comment.end")), gc); - gc.gridx = 1; - commentsAndNumbersPanel.add(myBlockCommentEnd, gc); - gc.gridx = 0; - gc.gridy++; - commentsAndNumbersPanel.add(new JLabel(IdeBundle.message("editbox.customfiletype.hex.prefix")), gc); - gc.gridx = 1; - commentsAndNumbersPanel.add(myHexPrefix, gc); - gc.gridx = 0; - gc.gridy++; - commentsAndNumbersPanel.add(new JLabel(IdeBundle.message("editbox.customfiletype.number.postfixes")), gc); - gc.gridx = 1; - commentsAndNumbersPanel.add(myNumPostfixes, gc); + GridBag gb = new GridBag().setDefaultFill(GridBagConstraints.HORIZONTAL).setDefaultAnchor(GridBagConstraints.WEST).setDefaultInsets(1, + 5, + 1, + 5); + commentsAndNumbersPanel.add(new JLabel(IdeBundle.message("editbox.customfiletype.line.comment")), gb.nextLine().next()); + commentsAndNumbersPanel.add(myLineComment, gb.next()); + commentsAndNumbersPanel.add(myCommentAtLineStart, gb.next().coverLine(2)); - gc.gridx = 0; - gc.gridy++; - commentsAndNumbersPanel.add(mySupportBraces, gc); + commentsAndNumbersPanel.add(new JLabel(IdeBundle.message("editbox.customfiletype.block.comment.start")), gb.nextLine().next()); + commentsAndNumbersPanel.add(myBlockCommentStart, gb.next()); + commentsAndNumbersPanel.add(new JLabel(IdeBundle.message("editbox.customfiletype.block.comment.end")), gb.next()); + commentsAndNumbersPanel.add(myBlockCommentEnd, gb.next()); - gc.gridx = 0; - gc.gridy++; - commentsAndNumbersPanel.add(mySupportBrackets, gc); + commentsAndNumbersPanel.add(new JLabel(IdeBundle.message("editbox.customfiletype.hex.prefix")), gb.nextLine().next()); + commentsAndNumbersPanel.add(myHexPrefix, gb.next()); + commentsAndNumbersPanel.add(new JLabel(IdeBundle.message("editbox.customfiletype.number.postfixes")), gb.next()); + commentsAndNumbersPanel.add(myNumPostfixes, gb.next()); - gc.gridx = 0; - gc.gridy++; - commentsAndNumbersPanel.add(mySupportParens, gc); - - gc.gridx = 0; - gc.gridy++; - commentsAndNumbersPanel.add(mySupportEscapes, gc); + commentsAndNumbersPanel.add(mySupportBraces, gb.nextLine().next().coverLine(2)); + commentsAndNumbersPanel.add(mySupportBrackets, gb.next().next().coverLine(2)); + commentsAndNumbersPanel.add(mySupportParens, gb.nextLine().next().coverLine(2)); + commentsAndNumbersPanel.add(mySupportEscapes, gb.next().next().coverLine(2)); _panel1.add(commentsAndNumbersPanel, BorderLayout.WEST); @@ -206,10 +195,11 @@ public class CustomFileTypeEditor extends SettingsEditor { highlighterPanel.add(_panel1, BorderLayout.NORTH); TabbedPaneWrapper tabbedPaneWrapper = new TabbedPaneWrapper(this); - tabbedPaneWrapper.addTab("1", createKeywordsPanel(0)); - tabbedPaneWrapper.addTab("2", createKeywordsPanel(1)); - tabbedPaneWrapper.addTab("3", createKeywordsPanel(2)); - tabbedPaneWrapper.addTab("4", createKeywordsPanel(3)); + tabbedPaneWrapper.getComponent().setBorder(IdeBorderFactory.createTitledBorder(IdeBundle.message("listbox.customfiletype.keywords"), false, false, true)); + tabbedPaneWrapper.addTab(" 1 ", createKeywordsPanel(0)); + tabbedPaneWrapper.addTab(" 2 ", createKeywordsPanel(1)); + tabbedPaneWrapper.addTab(" 3 ", createKeywordsPanel(2)); + tabbedPaneWrapper.addTab(" 4 ", createKeywordsPanel(3)); highlighterPanel.add(tabbedPaneWrapper.getComponent(), BorderLayout.CENTER); highlighterPanel.add(myIgnoreCase, BorderLayout.SOUTH); @@ -232,9 +222,7 @@ public class CustomFileTypeEditor extends SettingsEditor { } private JPanel createKeywordsPanel(final int index) { - JPanel panel = new JPanel(); - panel.setBorder(IdeBorderFactory.createTitledBorder(IdeBundle.message("listbox.customfiletype.keywords"), false, false, true)); - JPanel keywordsPanel = panel; + JPanel keywordsPanel = new JPanel(); keywordsPanel.setLayout(new BorderLayout()); keywordsPanel.add(ScrollPaneFactory.createScrollPane(myKeywordsLists[index]), BorderLayout.CENTER); @@ -284,6 +272,7 @@ public class CustomFileTypeEditor extends SettingsEditor { syntaxTable.setEndComment(myBlockCommentEnd.getText()); syntaxTable.setHexPrefix(myHexPrefix.getText()); syntaxTable.setNumPostfixChars(myNumPostfixes.getText()); + syntaxTable.lineCommentOnlyAtStart = myCommentAtLineStart.isSelected(); boolean ignoreCase = myIgnoreCase.isSelected(); syntaxTable.setIgnoreCase(ignoreCase); diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/ActionInstallPlugin.java b/platform/platform-impl/src/com/intellij/ide/plugins/ActionInstallPlugin.java index 292b75d536f8..cad6d94b8e2a 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/ActionInstallPlugin.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/ActionInstallPlugin.java @@ -32,15 +32,14 @@ import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.IconLoader; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.Function; import com.intellij.util.net.IOExceptionDialog; import org.jetbrains.annotations.NotNull; import javax.swing.event.HyperlinkEvent; import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; +import java.util.*; /** * @author lloix @@ -121,19 +120,23 @@ public class ActionInstallPlugin extends AnAction implements DumbAware { getPluginTable().updateUI(); final InstalledPluginsTableModel pluginsModel = (InstalledPluginsTableModel)installed.getPluginsModel(); final Set disabled = new HashSet(); + final Set disabledDependants = new HashSet(); for (PluginNode node : list) { final PluginId pluginId = node.getPluginId(); if (pluginsModel.isDisabled(pluginId)) { disabled.add(node); } - } - if (!disabled.isEmpty()) { - String message = "Updated plugin" + (disabled.size() > 1 ? "s are " : " is ") + "disabled. Would you like to enable " + (disabled.size() > 1 ? "them" : "it") + "?"; - if (Messages.showOkCancelDialog(host.pluginTable, message, CommonBundle.getWarningTitle(), Messages.getQuestionIcon()) == - DialogWrapper.OK_EXIT_CODE) { - pluginsModel.enableRows(disabled.toArray(new IdeaPluginDescriptor[disabled.size()]), true); + final List depends = node.getDepends(); + if (depends != null) { + for (PluginId dependantId : depends) { + final IdeaPluginDescriptor pluginDescriptor = PluginManager.getPlugin(dependantId); + if (pluginDescriptor != null && pluginsModel.isDisabled(dependantId)) { + disabledDependants.add(pluginDescriptor); + } + } } } + suggestToEnableInstalledPlugins(pluginsModel, disabled, disabledDependants, list); } else { notifyPluginsWereInstalled(); @@ -150,6 +153,60 @@ public class ActionInstallPlugin extends AnAction implements DumbAware { } } + private static void suggestToEnableInstalledPlugins(final InstalledPluginsTableModel pluginsModel, + final Set disabled, + final Set disabledDependants, + final ArrayList list) { + if (!disabled.isEmpty() || !disabledDependants.isEmpty()) { + String message = ""; + if (disabled.size() == 1) { + message = "Updated plugin '" + disabled.iterator().next().getName() + "' is disabled"; + } else if (!disabled.isEmpty()) { + message = "Updated plugins " + StringUtil.join(disabled, new Function() { + @Override + public String fun(IdeaPluginDescriptor pluginDescriptor) { + return pluginDescriptor.getName(); + } + }, ", ") + " are disabled."; + } + + if (!disabledDependants.isEmpty()) { + if (!message.isEmpty()) { + message += "\n"; + } + message += "Updated plugin" + (list.size() > 1 ? "s depend " : " depends ") + "on disabled"; + if (disabledDependants.size() == 1) { + message += " plugin '" + disabledDependants.iterator().next().getName() + "'."; + } else { + message += " plugins " + StringUtil.join(disabledDependants, new Function() { + @Override + public String fun(IdeaPluginDescriptor pluginDescriptor) { + return pluginDescriptor.getName(); + } + }, ", ") + "."; + } + } + message += "\nWould you like to enable plugins with dependencies?"; + + int result; + if (!disabled.isEmpty() && !disabledDependants.isEmpty()) { + result = + Messages.showYesNoCancelDialog(message, CommonBundle.getWarningTitle(), "Enable all", + "Enable updated plugin" + (disabled.size() > 1 ? "s" : ""), CommonBundle.getCancelButtonText(), + Messages.getQuestionIcon()); + } else { + result = Messages.showOkCancelDialog(message, CommonBundle.getWarningTitle(), "Enable", CommonBundle.getCancelButtonText(), Messages.getQuestionIcon()); + } + + if (result == DialogWrapper.OK_EXIT_CODE) { + disabled.addAll(disabledDependants); + pluginsModel.enableRows(disabled.toArray(new IdeaPluginDescriptor[disabled.size()]), true); + } else if (result == DialogWrapper.CANCEL_EXIT_CODE && !disabled.isEmpty()) { + pluginsModel.enableRows(disabled.toArray(new IdeaPluginDescriptor[disabled.size()]), true); + } + } + } + private void installedPluginsToModel(ArrayList list) { for (PluginNode pluginNode : list) { final String idString = pluginNode.getPluginId().getIdString(); diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/AvailablePluginsManagerMain.java b/platform/platform-impl/src/com/intellij/ide/plugins/AvailablePluginsManagerMain.java index 04da5ea0bba2..39eaad692359 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/AvailablePluginsManagerMain.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/AvailablePluginsManagerMain.java @@ -21,6 +21,7 @@ import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.actionSystem.ex.ComboBoxAction; +import com.intellij.openapi.extensions.PluginId; import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.updateSettings.impl.UpdateSettings; @@ -101,7 +102,25 @@ public class AvailablePluginsManagerMain extends PluginManagerMain { if (e.getClickCount() != 2) return; if (pluginTable.columnAtPoint(e.getPoint()) < 0) return; if (pluginTable.rowAtPoint(e.getPoint()) < 0) return; - new ActionInstallPlugin(AvailablePluginsManagerMain.this, installed).install(); + IdeaPluginDescriptor[] selection = pluginTable.getSelectedObjects(); + if (selection != null) { + boolean enabled = true; + for (IdeaPluginDescriptor descr : selection) { + if (descr instanceof PluginNode) { + enabled &= !PluginManagerColumnInfo.isDownloaded((PluginNode)descr); + if (((PluginNode)descr).getStatus() == PluginNode.STATUS_INSTALLED) { + enabled &= InstalledPluginsTableModel.hasNewerVersion(descr.getPluginId()); + } + } + else if (descr instanceof IdeaPluginDescriptorImpl) { + PluginId id = descr.getPluginId(); + enabled &= InstalledPluginsTableModel.hasNewerVersion(id); + } + } + if (enabled) { + new ActionInstallPlugin(AvailablePluginsManagerMain.this, installed).install(); + } + } } }); } diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/InstalledPluginsTableModel.java b/platform/platform-impl/src/com/intellij/ide/plugins/InstalledPluginsTableModel.java index 7985f2f04708..c813fd6d3448 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/InstalledPluginsTableModel.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/InstalledPluginsTableModel.java @@ -19,6 +19,9 @@ import com.intellij.ide.IdeBundle; import com.intellij.openapi.application.ApplicationNamesInfo; import com.intellij.openapi.application.ex.ApplicationInfoEx; import com.intellij.openapi.extensions.PluginId; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.Task; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.updateSettings.impl.PluginDownloader; @@ -37,6 +40,7 @@ import com.intellij.util.containers.hash.HashSet; import com.intellij.util.ui.ColumnInfo; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -114,7 +118,12 @@ public class InstalledPluginsTableModel extends PluginTableModel { updatePluginDependencies(); - updateRepositoryPlugins(); + ProgressManager.getInstance().run(new Task.Backgroundable(null, "Load custom plugin repositories data...") { + @Override + public void run(@NotNull ProgressIndicator indicator) { + updateRepositoryPlugins(); + } + }); } public void updateRepositoryPlugins() { diff --git a/platform/platform-impl/src/com/intellij/ide/ui/LafManagerImpl.java b/platform/platform-impl/src/com/intellij/ide/ui/LafManagerImpl.java index 1f4fd6388ea8..1b451d63bee9 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/LafManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/LafManagerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -308,9 +308,9 @@ public final class LafManagerImpl extends LafManager implements ApplicationCompo try { UIManager.setLookAndFeel(laf); } - catch (Exception exc) { + catch (Exception e) { Messages.showMessageDialog( - IdeBundle.message("error.cannot.set.look.and.feel", lookAndFeelInfo.getName()), + IdeBundle.message("error.cannot.set.look.and.feel", lookAndFeelInfo.getName(), e.getMessage()), CommonBundle.getErrorTitle(), Messages.getErrorIcon() ); @@ -325,9 +325,9 @@ public final class LafManagerImpl extends LafManager implements ApplicationCompo } UIManager.setLookAndFeel(laf); } - catch (Exception exc) { + catch (Exception e) { Messages.showMessageDialog( - IdeBundle.message("error.cannot.set.look.and.feel", lookAndFeelInfo.getName()), + IdeBundle.message("error.cannot.set.look.and.feel", lookAndFeelInfo.getName(), e.getMessage()), CommonBundle.getErrorTitle(), Messages.getErrorIcon() ); diff --git a/platform/platform-impl/src/com/intellij/idea/IdeaApplication.java b/platform/platform-impl/src/com/intellij/idea/IdeaApplication.java index 49af8ffddc52..cdbb5a984407 100644 --- a/platform/platform-impl/src/com/intellij/idea/IdeaApplication.java +++ b/platform/platform-impl/src/com/intellij/idea/IdeaApplication.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -139,12 +139,14 @@ public class IdeaApplication { UIManager.put("Panel.opaque", Boolean.TRUE); UIManager.installLookAndFeel("Quaqua", "ch.randelshofer.quaqua.QuaquaLookAndFeel"); } - else { - UIManager.installLookAndFeel("JGoodies Plastic", "com.jgoodies.looks.plastic.PlasticLookAndFeel"); - UIManager.installLookAndFeel("JGoodies Plastic 3D", "com.jgoodies.looks.plastic.Plastic3DLookAndFeel"); - UIManager.installLookAndFeel("JGoodies Plastic XP", "com.jgoodies.looks.plastic.PlasticXPLookAndFeel"); + + if (SystemInfo.isWindows) { UIManager.installLookAndFeel("JGoodies Windows L&F", "com.jgoodies.looks.windows.WindowsLookAndFeel"); } + + UIManager.installLookAndFeel("JGoodies Plastic", "com.jgoodies.looks.plastic.PlasticLookAndFeel"); + UIManager.installLookAndFeel("JGoodies Plastic 3D", "com.jgoodies.looks.plastic.Plastic3DLookAndFeel"); + UIManager.installLookAndFeel("JGoodies Plastic XP", "com.jgoodies.looks.plastic.PlasticXPLookAndFeel"); } protected class IdeStarter implements ApplicationStarter { diff --git a/platform/platform-impl/src/com/intellij/idea/StartupUtil.java b/platform/platform-impl/src/com/intellij/idea/StartupUtil.java index e30f09e9611a..0127e75b5b8d 100644 --- a/platform/platform-impl/src/com/intellij/idea/StartupUtil.java +++ b/platform/platform-impl/src/com/intellij/idea/StartupUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,8 +43,7 @@ public class StartupUtil { @NonNls public static final String NOSPLASH = "nosplash"; - private StartupUtil() { - } + private StartupUtil() { } public static void setDefaultLAF(String laf) { myDefaultLAF = laf; @@ -73,7 +72,7 @@ public class StartupUtil { } /** - * Checks if the program can run under the JDK it was started with + * Checks if the program can run under the JDK it was started with. */ private static boolean checkJdkVersion() { if (!"true".equals(System.getProperty("idea.no.jre.check"))) { @@ -111,16 +110,8 @@ public class StartupUtil { } if (activateStatus != SocketLock.ActivateStatus.NO_INSTANCE) { - if (isHeadless()) { //team server inspections - System.out.println("Only one instance of " + ApplicationNamesInfo.getInstance().getFullProductName() + " can be run at a time."); - return false; - } - if (activateStatus == SocketLock.ActivateStatus.CANNOT_ACTIVATE) { - JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), - "Only one instance of " + ApplicationNamesInfo.getInstance().getFullProductName() + - " can be run at a time.", - "Error", - JOptionPane.INFORMATION_MESSAGE); + if (isHeadless() || activateStatus == SocketLock.ActivateStatus.CANNOT_ACTIVATE) { + showError("Error", "Only one instance of " + ApplicationNamesInfo.getInstance().getFullProductName() + " can be run at a time."); } return false; } @@ -129,16 +120,17 @@ public class StartupUtil { } private static boolean checkTmpIsAccessible() { - if (!SystemInfo.isUnix) return true; + if (!SystemInfo.isUnix || SystemInfo.isMac) return true; final File tmp; try { - tmp = File.createTempFile("idea_check_", ".tmp"); + tmp = FileUtil.createTempFile("idea_check_", ".tmp"); FileUtil.writeToFile(tmp, "#!/bin/sh\n" + "exit 0"); } catch (IOException e) { - showError("Inaccessible Temp Directory", e.getMessage() + ".\nTemp directory is not accessible.\n" + + showError("Inaccessible Temp Directory", e.getMessage() + " (" + FileUtil.getTempDirectory() + ").\n" + + "Temp directory is not accessible.\n" + "Please set 'java.io.tmpdir' system property to point to a writable directory."); return false; } diff --git a/platform/platform-impl/src/com/intellij/notification/impl/IdeNotificationArea.java b/platform/platform-impl/src/com/intellij/notification/impl/IdeNotificationArea.java index ae7d7140ab17..6d8ead14ade1 100644 --- a/platform/platform-impl/src/com/intellij/notification/impl/IdeNotificationArea.java +++ b/platform/platform-impl/src/com/intellij/notification/impl/IdeNotificationArea.java @@ -30,7 +30,7 @@ import com.intellij.openapi.wm.CustomStatusBarWidget; import com.intellij.openapi.wm.IconLikeCustomStatusBarWidget; import com.intellij.openapi.wm.StatusBar; import com.intellij.openapi.wm.ToolWindow; -import com.intellij.ui.RowIcon; +import com.intellij.ui.LayeredIcon; import com.intellij.util.Alarm; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -110,11 +110,12 @@ public class IdeNotificationArea extends JLabel implements CustomStatusBarWidget } boolean stripesVisible = !UISettings.getInstance().HIDE_TOOL_STRIPES; ArrayList notifications = logModel.getNotifications(); - RowIcon icon = new RowIcon(2); - icon.setIcon(getPendingNotificationsIcon(EMPTY_ICON, getMaximumType(notifications)), 0); + LayeredIcon icon = new LayeredIcon(2); + Icon statusIcon = getPendingNotificationsIcon(EMPTY_ICON, getMaximumType(notifications)); + icon.setIcon(statusIcon, 0); final int count = notifications.size(); if (count > 0) { - icon.setIcon(new TextIcon(this, String.valueOf(count)), 1); + icon.setIcon(new TextIcon(this, String.valueOf(count)), 1, statusIcon.getIconWidth() - 2, 0); } if (stripesVisible && eventLog != null) { eventLog.setIcon(icon); @@ -170,7 +171,7 @@ public class IdeNotificationArea extends JLabel implements CustomStatusBarWidget public TextIcon(IdeNotificationArea component, String str) { myStr = str; myComponent = component; - myWidth = myComponent.getFontMetrics(calcFont()).stringWidth(myStr) + 2; + myWidth = myComponent.getFontMetrics(calcFont()).stringWidth(myStr) + 1; } @Override @@ -181,14 +182,14 @@ public class IdeNotificationArea extends JLabel implements CustomStatusBarWidget y += getIconHeight() - g.getFontMetrics().getDescent(); g.setColor(Color.BLACK); - g.drawString(myStr, x + 1, y); + g.drawString(myStr, x, y); g.setFont(originalFont); g.setColor(originalColor); } private Font calcFont() { - return myComponent.getFont().deriveFont(Font.BOLD).deriveFont((float) getIconHeight() * 2 / 3); + return myComponent.getFont().deriveFont(Font.BOLD).deriveFont((float) getIconHeight() * 3 / 5); } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/ApplicationPathMacroManager.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/ApplicationPathMacroManager.java index 134708f38230..1a93f02aff2f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/ApplicationPathMacroManager.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/ApplicationPathMacroManager.java @@ -19,4 +19,7 @@ package com.intellij.openapi.components.impl; * @author mike */ public class ApplicationPathMacroManager extends BasePathMacroManager { + public ApplicationPathMacroManager() { + super(null); + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/BasePathMacroManager.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/BasePathMacroManager.java index d29b0c7b035a..cb0c74515555 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/BasePathMacroManager.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/BasePathMacroManager.java @@ -17,14 +17,13 @@ package com.intellij.openapi.components.impl; import com.intellij.application.options.PathMacrosImpl; import com.intellij.application.options.ReplacePathToMacroMap; -import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.application.PathMacros; import com.intellij.openapi.components.ExpandMacroToPathMap; import com.intellij.openapi.components.PathMacroManager; import com.intellij.openapi.components.PathMacroMap; import com.intellij.openapi.components.TrackingPathMacroSubstitutor; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.SystemProperties; import com.intellij.util.containers.FactoryMap; import org.jdom.Element; import org.jetbrains.annotations.NonNls; @@ -36,6 +35,11 @@ import java.util.*; public class BasePathMacroManager extends PathMacroManager { private PathMacrosImpl myPathMacros; + + public BasePathMacroManager(@Nullable PathMacros pathMacros) { + myPathMacros = (PathMacrosImpl)pathMacros; + } + protected static void addFileHierarchyReplacements(ReplacePathToMacroMap result, String variableName, @Nullable String _path, @Nullable String stopAt) { @@ -74,22 +78,18 @@ public class BasePathMacroManager extends PathMacroManager { public ExpandMacroToPathMap getExpandMacroMap() { ExpandMacroToPathMap result = new ExpandMacroToPathMap(); - result.addMacroExpand(PathMacrosImpl.APPLICATION_HOME_MACRO_NAME, PathManager.getHomePath()); - result.addMacroExpand(PathMacrosImpl.USER_HOME_MACRO_NAME, getUserHome()); + for (Map.Entry entry : PathMacrosImpl.getGlobalSystemMacros().entrySet()) { + result.addMacroExpand(entry.getKey(), entry.getValue()); + } getPathMacros().addMacroExpands(result); return result; } - protected static String getUserHome() { - return StringUtil.trimEnd(SystemProperties.getUserHome(), "/"); - } - - public ReplacePathToMacroMap getReplacePathMap() { ReplacePathToMacroMap result = new ReplacePathToMacroMap(); - - result.addMacroReplacement(PathManager.getHomePath(), PathMacrosImpl.APPLICATION_HOME_MACRO_NAME); - result.addMacroReplacement(getUserHome(), PathMacrosImpl.USER_HOME_MACRO_NAME); + for (Map.Entry entry : PathMacrosImpl.getGlobalSystemMacros().entrySet()) { + result.addMacroReplacement(entry.getValue(), entry.getKey()); + } getPathMacros().addMacroReplacements(result); return result; } diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/ProjectPathMacroManager.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/ProjectPathMacroManager.java index 1c9f79824353..e5ea2c207571 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/ProjectPathMacroManager.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/ProjectPathMacroManager.java @@ -17,10 +17,10 @@ package com.intellij.openapi.components.impl; import com.intellij.application.options.PathMacrosImpl; import com.intellij.application.options.ReplacePathToMacroMap; +import com.intellij.openapi.application.PathMacros; import com.intellij.openapi.components.ExpandMacroToPathMap; import com.intellij.openapi.components.PathMacroMap; import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ex.ProjectEx; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.Nullable; @@ -28,9 +28,10 @@ import org.jetbrains.annotations.Nullable; import java.io.File; public class ProjectPathMacroManager extends BasePathMacroManager { - private final ProjectEx myProject; + private final Project myProject; - public ProjectPathMacroManager(final ProjectEx project) { + public ProjectPathMacroManager(PathMacros pathMacros, Project project) { + super(pathMacros); myProject = project; } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/actions/CompareClipboardWithSelection.java b/platform/platform-impl/src/com/intellij/openapi/diff/actions/CompareClipboardWithSelection.java index 57c2cbae7bbf..230c58b55d50 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/actions/CompareClipboardWithSelection.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/actions/CompareClipboardWithSelection.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,13 +26,13 @@ import com.intellij.openapi.ide.CopyPasteManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.TextRange; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; public class CompareClipboardWithSelection extends BaseDiffAction { - @Nullable protected DiffRequest getDiffData(DataContext dataContext) { Project project = PlatformDataKeys.PROJECT.getData(dataContext); @@ -65,10 +65,11 @@ public class CompareClipboardWithSelection extends BaseDiffAction { return !SystemInfo.isMac; } + @NotNull public DiffContent[] getContents() { if (myContents != null) return myContents; DiffContent clipboardContent = createClipboardContent(); - if (clipboardContent == null) return null; + if (clipboardContent == null) clipboardContent = new SimpleContent(""); myContents = new DiffContent[2]; myContents[0] = clipboardContent; diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/actions/CompareFileWithEditor.java b/platform/platform-impl/src/com/intellij/openapi/diff/actions/CompareFileWithEditor.java index 38a8c0e60445..85d005879f8c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/actions/CompareFileWithEditor.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/actions/CompareFileWithEditor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.NonNls; @@ -109,10 +110,11 @@ public class CompareFileWithEditor extends BaseDiffAction { return new String[]{getVirtualFileContentTitle(myFile), documentTitle}; } + @NotNull public DiffContent[] getContents() { return new DiffContent[]{ - DocumentContent.fromFile(getProject(), myFile), - DocumentContent.fromDocument(getProject(), myDocument) + DiffContent.fromFile(getProject(), myFile), + DiffContent.fromDocument(getProject(), myDocument) }; } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/mergeTool/MergeRequestImpl.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/mergeTool/MergeRequestImpl.java index 9e171439601e..6798ec93fbca 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/mergeTool/MergeRequestImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/mergeTool/MergeRequestImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,6 +29,7 @@ import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -36,6 +37,7 @@ import java.io.IOException; public class MergeRequestImpl extends MergeRequest { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.diff.impl.mergeTool.MergeRequestImpl"); + private final DiffContent[] myDiffContents = new DiffContent[3]; private String myWindowTitle = null; private String[] myVersionTitles = null; @@ -87,6 +89,7 @@ public class MergeRequestImpl extends MergeRequest { myDiffContents[2] = right; } + @NotNull public DiffContent[] getContents() { return myDiffContents; } public String[] getContentTitles() { return myVersionTitles; } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index f286def57c1f..90af164413ba 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -6090,6 +6090,11 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi Rectangle visibleArea = getScrollingModel().getVisibleArea(); startToUse = yPositionToLogicalLine(visibleArea.getLocation().y); endToUse = Math.min(endToUse, yPositionToLogicalLine(visibleArea.y + visibleArea.height)); + if (endToUse <= startToUse) { + // There is a possible case that there is the only soft-wrapped line, i.e. end == start. We still want to update the + // size container's width then. + endToUse = Math.min(myLineWidths.size(), startToUse + 1); + } } int maxWidth = 0; for (int i = startToUse; i < endToUse; i++) { diff --git a/platform/platform-impl/src/com/intellij/openapi/fileChooser/ex/FileChooserDialogImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileChooser/ex/FileChooserDialogImpl.java index a9e673168515..1c3aeb297301 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileChooser/ex/FileChooserDialogImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileChooser/ex/FileChooserDialogImpl.java @@ -21,7 +21,9 @@ import com.intellij.ide.util.PropertiesComponent; import com.intellij.ide.util.treeView.NodeRenderer; import com.intellij.idea.ActionsBundle; import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.application.*; +import com.intellij.openapi.application.ApplicationActivationListener; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileChooser.FileChooserDialog; import com.intellij.openapi.fileChooser.FileElement; @@ -30,7 +32,6 @@ import com.intellij.openapi.fileChooser.impl.FileChooserFactoryImpl; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.ui.TitlePanel; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; @@ -38,10 +39,12 @@ import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.IdeFrame; import com.intellij.ui.ScrollPaneFactory; +import com.intellij.ui.SideBorder; import com.intellij.ui.UIBundle; import com.intellij.ui.components.labels.LinkLabel; import com.intellij.ui.components.labels.LinkListener; import com.intellij.util.containers.HashMap; +import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.update.MergingUpdateQueue; import com.intellij.util.ui.update.UiNotifyConnector; import com.intellij.util.ui.update.Update; @@ -64,7 +67,6 @@ import java.util.List; import java.util.Map; public class FileChooserDialogImpl extends DialogWrapper implements FileChooserDialog, FileLookup { - private final FileChooserDescriptor myChooserDescriptor; protected FileSystemTreeImpl myFileSystemTree; @@ -73,30 +75,31 @@ public class FileChooserDialogImpl extends DialogWrapper implements FileChooserD private VirtualFile[] myChosenFiles = VirtualFile.EMPTY_ARRAY; private JPanel myNorthPanel; - private TextFieldAction myTextFieldAction; - protected FileTextFieldImpl myPathTextField; - private JComponent myPathTextFieldWrapper; private MergingUpdateQueue myUiUpdater; - private boolean myTreeIsUpdating; public static DataKey PATH_FIELD = DataKey.create("PathField"); - public FileChooserDialogImpl(FileChooserDescriptor chooserDescriptor, Project project) { + public FileChooserDialogImpl(@NotNull final FileChooserDescriptor chooserDescriptor, Project project) { super(project, true); myProject = project; myChooserDescriptor = chooserDescriptor; - setTitle(UIBundle.message("file.chooser.default.title")); + setTitle(getChooserTitle(chooserDescriptor)); } - public FileChooserDialogImpl(FileChooserDescriptor chooserDescriptor, Component parent) { + public FileChooserDialogImpl(@NotNull final FileChooserDescriptor chooserDescriptor, Component parent) { super(parent, true); myChooserDescriptor = chooserDescriptor; - setTitle(UIBundle.message("file.chooser.default.title")); + setTitle(getChooserTitle(chooserDescriptor)); + } + + private static String getChooserTitle(final FileChooserDescriptor descriptor) { + final String title = descriptor.getTitle(); + return title != null ? title : UIBundle.message("file.chooser.default.title"); } @NotNull @@ -155,13 +158,14 @@ public class FileChooserDialogImpl extends DialogWrapper implements FileChooserD @Nullable protected final JComponent createTitlePane() { - final String title = myChooserDescriptor.getTitle(); final String description = myChooserDescriptor.getDescription(); - if ((StringUtil.isEmptyOrSpaces(title) || title.equals(UIBundle.message("file.chooser.default.title"))) && - StringUtil.isEmptyOrSpaces(description)) { - return null; - } - return new TitlePanel(title, description); + if (StringUtil.isEmptyOrSpaces(description)) return null; + + final JLabel label = new JLabel(description); + label.setBorder(BorderFactory.createCompoundBorder( + new SideBorder(UIUtil.getPanelBackground().darker(), SideBorder.BOTTOM), + BorderFactory.createEmptyBorder(0, 5, 10, 5))); + return label; } protected JComponent createCenterPanel() { @@ -271,7 +275,7 @@ public class FileChooserDialogImpl extends DialogWrapper implements FileChooserD myChooserDescriptor.validateSelectedFiles(selectedFiles); } catch (Exception e) { - Messages.showErrorDialog(getContentPane(), e.getMessage(), UIBundle.message("file.chooser.default.title")); + Messages.showErrorDialog(getContentPane(), e.getMessage(), getTitle()); return; } @@ -280,6 +284,7 @@ public class FileChooserDialogImpl extends DialogWrapper implements FileChooserD close(CANCEL_EXIT_CODE); return; } + //noinspection AssignmentToStaticFieldFromInstanceMethod ourLastFile = selectedFiles[selectedFiles.length - 1]; super.doOKAction(); @@ -372,7 +377,6 @@ public class FileChooserDialogImpl extends DialogWrapper implements FileChooserD } public void treeCollapsed(TreeExpansionEvent event) { - //Do not unwatch here!!! } } @@ -552,6 +556,7 @@ public class FileChooserDialogImpl extends DialogWrapper implements FileChooserD myTreeIsUpdating = false; setErrorText(null); if (requestFocus) { + //noinspection SSBasedInspection SwingUtilities.invokeLater(new Runnable() { public void run() { myFileSystemTree.getTree().requestFocus(); diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java index a5e49d3bacb1..20a19762b1b8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java @@ -57,6 +57,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; +import java.awt.event.InputEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; @@ -385,6 +386,7 @@ final class EditorTabbedContainer implements Disposable, CloseAction.CloseTarget e.getPresentation().setIcon(myTabs.isEditorTabs() ? myNewIcon : myIcon); e.getPresentation().setHoveredIcon(myTabs.isEditorTabs()? myNewHoveredIcon : myHoveredIcon); e.getPresentation().setVisible(UISettings.getInstance().SHOW_CLOSE_BUTTON); + e.getPresentation().setText("Close. Alt-click to close others."); } public void actionPerformed(final AnActionEvent e) { @@ -399,8 +401,13 @@ final class EditorTabbedContainer implements Disposable, CloseAction.CloseTarget } if (window != null) { - if (window.findFileComposite(file) != null) { - mgr.closeFile(file, window); + if ((e.getModifiers() & InputEvent.ALT_MASK) != 0) { + window.closeAllExcept(file); + } + else { + if (window.findFileComposite(file) != null) { + mgr.closeFile(file, window); + } } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java index fa53d26b2443..0f1e765f909b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java @@ -103,6 +103,15 @@ public class EditorWindow { return myPanel.isShowing(); } + public void closeAllExcept(final VirtualFile selectedFile) { + final VirtualFile[] files = getFiles(); + for (final VirtualFile file : files) { + if (file != selectedFile && !isFilePinned(file)) { + closeFile(file); + } + } + } + private static class AdaptiveBorder implements Border { @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java index f1881c6cb742..b99f84e8751e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java @@ -31,6 +31,7 @@ import com.intellij.openapi.components.ProjectComponent; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.editor.impl.EditorComponentImpl; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.fileEditor.*; import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; @@ -58,6 +59,8 @@ import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.openapi.wm.WindowManager; import com.intellij.openapi.wm.ex.StatusBarEx; +import com.intellij.openapi.wm.impl.IdeFrameImpl; +import com.intellij.ui.FocusTrackback; import com.intellij.ui.docking.DockContainer; import com.intellij.ui.docking.DockManager; import com.intellij.ui.tabs.impl.JBTabsImpl; @@ -1419,11 +1422,14 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec private final class MyVirtualFileListener extends VirtualFileAdapter { public void beforeFileDeletion(VirtualFileEvent e) { assertDispatchThread(); + + boolean moveFocus = moveFocusOnDelete(); + final VirtualFile file = e.getFile(); final VirtualFile[] openFiles = getOpenFiles(); for (int i = openFiles.length - 1; i >= 0; i--) { if (VfsUtilCore.isAncestor(file, openFiles[i], false)) { - closeFile(openFiles[i], true, true); + closeFile(openFiles[i], moveFocus, true); } } } @@ -1469,6 +1475,18 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec } } + private static boolean moveFocusOnDelete() { + final Window window = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow(); + if (window != null) { + final Component component = FocusTrackback.getFocusFor(window); + if (component != null) { + return component instanceof EditorComponentImpl; + } + return window instanceof IdeFrameImpl; + } + return true; + } + public boolean isInsideChange() { return getSplitters().isInsideChange(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/AbstractFileType.java b/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/AbstractFileType.java index e71e53459c11..8d0fb3ca0383 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/AbstractFileType.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/AbstractFileType.java @@ -55,6 +55,7 @@ public class AbstractFileType extends UserFileType implements @NonNls private static final String VALUE_HAS_BRACKETS = "HAS_BRACKETS"; @NonNls private static final String VALUE_HAS_PARENS = "HAS_PARENS"; @NonNls private static final String VALUE_HAS_STRING_ESCAPES = "HAS_STRING_ESCAPES"; + @NonNls private static final String VALUE_LINE_COMMENT_AT_START = "LINE_COMMENT_AT_START"; @NonNls private static final String ELEMENT_KEYWORDS = "keywords"; @NonNls private static final String ATTRIBUTE_IGNORE_CASE = "ignore_case"; @NonNls private static final String ELEMENT_KEYWORD = "keyword"; @@ -139,6 +140,9 @@ public class AbstractFileType extends UserFileType implements else if (VALUE_NUM_POSTFIXES.equals(name)) { table.setNumPostfixChars(value); } + else if (VALUE_LINE_COMMENT_AT_START.equals(name)) { + table.lineCommentOnlyAtStart = Boolean.valueOf(value).booleanValue(); + } else if (VALUE_HAS_BRACES.equals(name)) { table.setHasBraces(Boolean.valueOf(value).booleanValue()); } @@ -218,6 +222,7 @@ public class AbstractFileType extends UserFileType implements addElementOption(optionsElement, VALUE_HAS_BRACES, table.isHasBraces()); addElementOption(optionsElement, VALUE_HAS_PARENS, table.isHasParens()); addElementOption(optionsElement, VALUE_HAS_STRING_ESCAPES, table.isHasStringEscapes()); + addElementOption(optionsElement, VALUE_LINE_COMMENT_AT_START, table.lineCommentOnlyAtStart); highlightingElement.addContent(optionsElement); diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeKeyEventDispatcher.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeKeyEventDispatcher.java index d51391ad7c5e..28001031f8e4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeKeyEventDispatcher.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeKeyEventDispatcher.java @@ -34,6 +34,7 @@ import com.intellij.openapi.keymap.impl.keyGestures.KeyboardGestureProcessor; import com.intellij.openapi.keymap.impl.ui.ShortcutTextField; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.TypingTarget; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.ui.popup.ListPopupStep; @@ -621,6 +622,8 @@ public final class IdeKeyEventDispatcher implements Disposable { myContext.setFoundComponent(null); myContext.getActions().clear(); + if (isControlEnterOnDialog(component, sc)) return myContext; + boolean hasSecondStroke = false; // here we try to find "local" shortcuts @@ -699,6 +702,11 @@ public final class IdeKeyEventDispatcher implements Disposable { return myContext; } + private static KeyboardShortcut CONTROL_ENTER = KeyboardShortcut.fromString("control ENTER"); + private static boolean isControlEnterOnDialog(Component component, Shortcut sc) { + return CONTROL_ENTER.equals(sc) && DialogWrapper.findInstance(component) != null; + } + /** * @return true if action is added and has second stroke */ diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditor.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditor.java index 4e6a613cb055..f126a810cb8d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditor.java +++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditor.java @@ -104,7 +104,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat private final Wrapper mySearchWrapper = new Wrapper(); private final JPanel myLeftSide; - private boolean myFilterFocumentWasChanged; + private boolean myFilterDocumentWasChanged; //[back/forward] private ActionToolbar myToolbar; private Window myWindow; private final PropertiesComponent myProperties; @@ -142,12 +142,12 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat myTree = new OptionsTree(myProject, groups, getContext()) { @Override protected void onTreeKeyEvent(final KeyEvent e) { - myFilterFocumentWasChanged = false; + myFilterDocumentWasChanged = false; try { mySearch.keyEventToTextField(e); } finally { - if (myFilterFocumentWasChanged && !isFilterFieldVisible()) { + if (myFilterDocumentWasChanged && !isFilterFieldVisible()) { setFilterFieldVisible(true, false, false); } } @@ -883,7 +883,7 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat final ActionCallback callback = fireUpdate(adjustSelection ? myTree.findNodeFor(toSelect) : null, adjustSelection, now); - myFilterFocumentWasChanged = true; + myFilterDocumentWasChanged = true; return callback; } diff --git a/platform/platform-impl/src/com/intellij/openapi/ui/impl/DialogWrapperPeerImpl.java b/platform/platform-impl/src/com/intellij/openapi/ui/impl/DialogWrapperPeerImpl.java index d3e4871fe115..e4d4b75d5fb6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/ui/impl/DialogWrapperPeerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/ui/impl/DialogWrapperPeerImpl.java @@ -491,6 +491,7 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra private Dimension myInitialSize; private String myDimensionServiceKey; private boolean myOpened = false; + private boolean myActivated = false; private FocusTrackback myFocusTrackback; private MyDialog.MyWindowListener myWindowListener; @@ -896,7 +897,10 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra return; } - + if (myActivated) { + return; + } + myActivated = true; JComponent toFocus = wrapper == null ? null : wrapper.getPreferredFocusedComponent(); if (toFocus == null) { toFocus = getRootPane().getDefaultButton(); diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java index 4df44f1f95c7..476dde4d0714 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java @@ -175,7 +175,7 @@ public final class UpdateChecker { if (installedPlugin != null) { if (StringUtil.compareVersionNumbers(loadedPlugin.getVersion(), installedPlugin.getVersion()) > 0) { updateSettings.myOutdatedPlugins.add(idString); - if (((IdeaPluginDescriptorImpl)installedPlugin).isEnabled()) { + if (installedPlugin.isEnabled()) { final PluginDownloader downloader = PluginDownloader.createDownloader(loadedPlugin); if (downloader.prepareToInstall()) { downloaded.add(downloader); diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFS.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFS.java index 0d387162d9fc..373447631020 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFS.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFS.java @@ -352,11 +352,10 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent { } @Override - public void setTimeStamp(@NotNull final VirtualFile file, final long modstamp) throws IOException { + public void setTimeStamp(@NotNull final VirtualFile file, final long modStamp) throws IOException { final int id = getFileId(file); - - FSRecords.setTimestamp(id, modstamp); - getDelegate(file).setTimeStamp(file, modstamp); + FSRecords.setTimestamp(id, modStamp); + getDelegate(file).setTimeStamp(file, modStamp); } private static int getFileId(final VirtualFile file) { @@ -1101,7 +1100,7 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent { } @TestOnly - public void cleanPersistedContents() { + public static void cleanPersistedContents() { try { final int[] roots = FSRecords.listRoots(); for (int root : roots) { diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java index 9360c401f53d..cbe973491f77 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ */ package com.intellij.openapi.vfs.newvfs.persistent; +import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.newvfs.ManagingFS; @@ -122,8 +123,10 @@ public class RefreshWorker { else { long currentTimestamp = persistence.getTimeStamp(file); long upToDateTimestamp = delegate.getTimeStamp(file); + long currentLength = SystemInfo.isUnix ? persistence.getLength(file) : -1; + long upToDateLength = SystemInfo.isUnix ? delegate.getLength(file) : -1; - if (currentTimestamp != upToDateTimestamp) { + if (currentTimestamp != upToDateTimestamp || currentLength != upToDateLength) { scheduleUpdateContent(file); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/StripeButton.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/StripeButton.java index bd9f76961f24..3d055759b555 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/StripeButton.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/StripeButton.java @@ -34,10 +34,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.border.Border; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseEvent; -import java.awt.event.MouseMotionAdapter; +import java.awt.event.*; import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; @@ -63,6 +60,8 @@ public final class StripeButton extends AnchoredButton implements ActionListener private JLabel myDragButtonImage; private Point myPressedPoint; private Stripe myLastStripe; + private KeyEventDispatcher myDragKeyEventDispatcher; + private boolean myDragCancelled = false; StripeButton(@NotNull final InternalDecorator decorator, ToolWindowsPane pane) { myDecorator = decorator; @@ -172,6 +171,7 @@ public final class StripeButton extends AnchoredButton implements ActionListener } private void processDrag(final MouseEvent e) { + if (myDragCancelled) return; if (!isDraggingNow()) { if (myPressedPoint == null) return; if (isWithinDeadZone(e)) return; @@ -190,6 +190,8 @@ public final class StripeButton extends AnchoredButton implements ActionListener myDragButtonImage.setSize(myDragButtonImage.getPreferredSize()); setVisible(false); myPane.startDrag(); + myDragKeyEventDispatcher = new DragKeyEventDispatcher(); + KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(myDragKeyEventDispatcher); } if (!isDraggingNow()) return; @@ -217,6 +219,18 @@ public final class StripeButton extends AnchoredButton implements ActionListener myLastStripe = stripe; } + private class DragKeyEventDispatcher implements KeyEventDispatcher { + @Override + public boolean dispatchKeyEvent(KeyEvent e) { + if (isDraggingNow() && e.getKeyCode() == KeyEvent.VK_ESCAPE && e.getID() == KeyEvent.KEY_PRESSED) { + myDragCancelled = true; + finishDragging(); + return true; + } + return false; + } + } + private boolean isWithinDeadZone(final MouseEvent e) { return Math.abs(myPressedPoint.x - e.getPoint().x) < MouseDragHelper.DRAG_START_DEADZONE && Math.abs(myPressedPoint.y - e.getPoint().y) < MouseDragHelper .DRAG_START_DEADZONE; @@ -244,6 +258,7 @@ public final class StripeButton extends AnchoredButton implements ActionListener if (MouseEvent.MOUSE_PRESSED == e.getID()) { myPressedPoint = e.getPoint(); myPressedWhenSelected = isSelected(); + myDragCancelled = false; } else if (MouseEvent.MOUSE_RELEASED == e.getID()) { finishDragging(); @@ -361,6 +376,10 @@ public final class StripeButton extends AnchoredButton implements ActionListener myLastStripe.finishDrop(); myLastStripe = null; } + if (myDragKeyEventDispatcher != null) { + KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(myDragKeyEventDispatcher); + myDragKeyEventDispatcher = null; + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java index 2967be12aeee..d96b8b17f2b8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java @@ -39,6 +39,7 @@ import com.intellij.openapi.project.DumbAwareRunnable; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.startup.StartupManager; +import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.popup.Balloon; import com.intellij.openapi.ui.popup.JBPopupFactory; @@ -2186,6 +2187,9 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements if (root != null) { JComponent toFocus = IdeFocusTraversalPolicy.getPreferredFocusedComponent(root); if (toFocus != null) { + if (DialogWrapper.findInstance(toFocus) != null) { + return new ActionCallback.Done(); //IDEA-80929 + } return IdeFocusManager.findInstanceByComponent(toFocus).requestFocus(toFocus, forced); } } diff --git a/platform/platform-impl/src/com/intellij/ui/FocusTrackback.java b/platform/platform-impl/src/com/intellij/ui/FocusTrackback.java index 583474d1ed5f..26bb96bcf27d 100644 --- a/platform/platform-impl/src/com/intellij/ui/FocusTrackback.java +++ b/platform/platform-impl/src/com/intellij/ui/FocusTrackback.java @@ -22,7 +22,6 @@ import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.ExpirableRunnable; @@ -136,7 +135,7 @@ public class FocusTrackback { myLocalFocusOwner = component; } - private static Component getFocusFor(Window parent) { + public static Component getFocusFor(Window parent) { final WeakReference ref = ourRootWindowToFocusedMap.get(parent); return ref != null ? ref.get() : null; } diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties index d8e07adae612..a2613b7af5c5 100644 --- a/platform/platform-resources-en/src/messages/IdeBundle.properties +++ b/platform/platform-resources-en/src/messages/IdeBundle.properties @@ -3,7 +3,6 @@ error.malformed.url=Malformed url: {0} error.cannot.start.browser=Cannot start browser: {0} error.please.specify.path.to.web.browser=Please specify a path to web browser in File | Settings | Web Browsers title.browser.not.found=Browser Not Found -error.please.open.url.manually=Please open URL ({0}) manually. {1} can''t open it in browser title.browser.path.not.found=Browser Path Not Found action.sort.alphabetically=Sort Alphabetically button.finish=&Finish @@ -201,7 +200,6 @@ button.add=&Add... editbox.customfiletype.name=Name: editbox.customfiletype.description=Description: group.customfiletype.syntax.highlighting=Syntax Highlighting -group.customfiletype.options=Options checkbox.customfiletype.ignore.case=&Ignore case checkbox.customfiletype.support.paired.braces=Support paired b&races checkbox.customfiletype.support.paired.brackets=Support paired bra&ckets @@ -634,7 +632,7 @@ checkbox.use.antialiased.font.in.editor=Use anti-aliased font # this string must start with "IDEA" idea.default.look.and.feel=IDEA (4.5 default) confirm.set.look.and.feel=&Set look and feel -error.cannot.set.look.and.feel=Cannot set {0} look and feel +error.cannot.set.look.and.feel=Cannot set {0} look and feel:
{1} warning.problem.laf.1=GTK+ look and feel is known to be problematic on a JDK prior to 1.6 b12.
Please choose another look and feel, or upgrade your JDK. More info... error.adding.action.without.icon.to.toolbar=You are adding an action without icon to the toolbar. The default icon will be added to this action. title.unable.to.add.action.without.icon.to.toolbar=Unable to add action without icon to the toolbar diff --git a/platform/platform-resources-en/src/messages/VcsBundle.properties b/platform/platform-resources-en/src/messages/VcsBundle.properties index 18c5c7972d28..335d1dcfe0d3 100644 --- a/platform/platform-resources-en/src/messages/VcsBundle.properties +++ b/platform/platform-resources-en/src/messages/VcsBundle.properties @@ -92,7 +92,7 @@ action.name.checkin.directory={0} Directory action.name.checkin.file={0} File action.name.checkin.directories={0} Directories action.name.checkin.files={0} Files -action.name.commit.project=Comm_it Changes +action.name.commit.project=Comm&it Changes column.name.revision.list.author=Author column.name.revisions.list.filter=Date column.name.revisions.list.branch=Branch @@ -269,7 +269,7 @@ changes.newchangelist.warning.already.exists.title=Wrong Changelist Name commit.dialog.no.changes.detected.text=No changes detected commit.dialog.no.changes.detected.title=Nothing to commit commit.dialog.title=Commit Changes -commit.dialog.default.commit.operation.name=Comm_it +commit.dialog.default.commit.operation.name=Comm&it commit.dialog.include.action.name=Include into commit commit.dialog.failed.commit.template=Failed commit: {0} commit.dialog.completed.successfully=Completed successfully diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index 2d36ef88f549..0b87b66a01b1 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -443,7 +443,6 @@ - @@ -653,7 +652,7 @@ - + @@ -698,7 +697,6 @@ serviceImplementation="com.intellij.openapi.vcs.impl.CodeSmellDetectorImpl"/> - diff --git a/platform/platform-resources/src/idea/PlatformActions.xml b/platform/platform-resources/src/idea/PlatformActions.xml index cfe8b1fa5ef4..21075aa6d238 100644 --- a/platform/platform-resources/src/idea/PlatformActions.xml +++ b/platform/platform-resources/src/idea/PlatformActions.xml @@ -227,9 +227,12 @@ - - - + + + + + + @@ -389,7 +392,7 @@ - + diff --git a/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTest.groovy b/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTest.groovy index b6f0c53e3a68..7311244aae15 100644 --- a/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTest.groovy +++ b/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTest.groovy @@ -26,7 +26,8 @@ class CustomFileTypeLexerTest extends CustomFileTypeLexerTestBase { protected SyntaxTable createSyntaxTable() { SyntaxTable table = new SyntaxTable(); - table.lineComment = '' + table.lineComment = ';' + table.lineCommentOnlyAtStart = true table.addKeyword1("if"); table.addKeyword1("then"); @@ -44,4 +45,15 @@ class CustomFileTypeLexerTest extends CustomFileTypeLexerTestBase { ['if', ' ', 'length', '(', 'variable', ')', 'then', ' ', 'return', ' ', '1'] as String[]) } + + public void testFortranComments() { + checkTypesAndTokens(''' +foo;noncomment +;comment + ;noncomment +''', + [WHITESPACE, IDENTIFIER, PUNCTUATION, IDENTIFIER, WHITESPACE, LINE_COMMENT, WHITESPACE, PUNCTUATION, IDENTIFIER, WHITESPACE] as IElementType[], + ['\n', 'foo', ';', 'noncomment', '\n', ';comment', '\n ', ';', 'noncomment', '\n'] as String[]) + + } } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/components/impl/PathMacroManagerTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/components/impl/PathMacroManagerTest.java index 47e6857aeabb..4d7ee34cd7d1 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/components/impl/PathMacroManagerTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/components/impl/PathMacroManagerTest.java @@ -3,15 +3,12 @@ package com.intellij.openapi.components.impl; import com.intellij.application.options.PathMacrosImpl; import com.intellij.application.options.ReplacePathToMacroMap; import com.intellij.mock.MockFileSystem; -import com.intellij.openapi.Disposable; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.application.PathMacros; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.application.ex.ApplicationEx; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.ex.ProjectEx; -import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; @@ -19,6 +16,7 @@ import com.intellij.util.SystemProperties; import com.intellij.util.io.fs.FileSystem; import com.intellij.util.io.fs.IFileSystem; import org.hamcrest.Description; +import org.jetbrains.annotations.Nullable; import org.jmock.Expectations; import org.jmock.Mockery; import org.jmock.api.Action; @@ -57,7 +55,6 @@ public class PathMacroManagerTest { private IFileSystem myOldFileSystem; protected MockFileSystem myFileSystem; protected PicoContainer myAppPico; - private Disposable myDisposable = Disposer.newDisposable(); @Before public final void setupApplication() throws Exception { @@ -66,9 +63,12 @@ public class PathMacroManagerTest { context.checking(new Expectations() { { - allowing(myApplication).isUnitTestMode(); will(returnValue(false)); - allowing(myApplication).getName(); will(returnValue("IDEA")); - allowing(myApplication).getPicoContainer(); will(returnValue(myAppPico)); + allowing(myApplication).isUnitTestMode(); + will(returnValue(false)); + allowing(myApplication).getName(); + will(returnValue("IDEA")); + allowing(myApplication).getPicoContainer(); + will(returnValue(myAppPico)); //some tests leave invokeLaters after them... allowing(myApplication).invokeLater(with(any(Runnable.class)), with(any(ModalityState.class))); @@ -81,6 +81,7 @@ public class PathMacroManagerTest { } @Override + @Nullable public Object invoke(final Invocation invocation) throws Throwable { ((Runnable)invocation.getParameter(0)).run(); return null; @@ -88,8 +89,6 @@ public class PathMacroManagerTest { }); } }); - - ApplicationManager.setApplication(myApplication, myDisposable); } @Before @@ -99,12 +98,6 @@ public class PathMacroManagerTest { FileSystem.FILE_SYSTEM = myFileSystem; } - @After - public final void restoreApplication() throws Exception { - Disposer.dispose(myDisposable); - myDisposable = null; - } - @After public final void restoreFilesystem() throws Exception { FileSystem.FILE_SYSTEM = myOldFileSystem; @@ -145,7 +138,7 @@ public class PathMacroManagerTest { setUpMocks("/tmp/foo"); - final ReplacePathToMacroMap replacePathMap = new ModulePathMacroManager(myModule).getReplacePathMap(); + final ReplacePathToMacroMap replacePathMap = new ModulePathMacroManager(myPathMacros, myModule).getReplacePathMap(); final String s = mapToString(replacePathMap); assertEquals("file:/tmp/foo/module -> file:$MODULE_DIR$\n" + "file://tmp/foo/module -> file:/$MODULE_DIR$\n" + @@ -190,7 +183,7 @@ public class PathMacroManagerTest { setUpMocks("/tmp/foo"); - final ReplacePathToMacroMap replacePathMap = new ProjectPathMacroManager(myProject).getReplacePathMap(); + final ReplacePathToMacroMap replacePathMap = new ProjectPathMacroManager(myPathMacros, myProject).getReplacePathMap(); final String s = mapToString(replacePathMap); assertEquals("file:/tmp/foo -> file:$PROJECT_DIR$\n" + "file://tmp/foo -> file:/$PROJECT_DIR$\n" + @@ -228,7 +221,7 @@ public class PathMacroManagerTest { setUpMocks(USER_HOME + "/IdeaProjects/foo"); - final ReplacePathToMacroMap replacePathMap = new ModulePathMacroManager(myModule).getReplacePathMap(); + final ReplacePathToMacroMap replacePathMap = new ModulePathMacroManager(myPathMacros, myModule).getReplacePathMap(); final String s = mapToString(replacePathMap); assertEquals("file:" + USER_HOME + "/IdeaProjects/foo/module -> file:$MODULE_DIR$\n" + "file:/" + USER_HOME + "/IdeaProjects/foo/module -> file:/$MODULE_DIR$\n" + diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/diff/impl/external/DiffManagerTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/diff/impl/external/DiffManagerTest.java index e3d532d2aabe..525bcac7b374 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/diff/impl/external/DiffManagerTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/diff/impl/external/DiffManagerTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.intellij.openapi.diff.impl.external; import com.intellij.openapi.diff.BinaryContent; @@ -7,6 +22,7 @@ import com.intellij.openapi.diff.DiffTool; import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.util.ArrayUtil; import junit.framework.TestCase; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -37,7 +53,7 @@ public class DiffManagerTest extends TestCase { return canShowImpl(request); } - private boolean canShowImpl(DiffRequest request) { + private static boolean canShowImpl(DiffRequest request) { return request.getContents().length == 4; } @@ -66,6 +82,7 @@ public class DiffManagerTest extends TestCase { return ArrayUtil.toStringArray(myContentTitles); } + @NotNull @Override public DiffContent[] getContents() { return myDiffContents.toArray(new DiffContent[myDiffContents.size()]); diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/CutLineBackwardActionTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/CutLineBackwardActionTest.java index 734b33c352a0..d3afe5be6e5d 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/CutLineBackwardActionTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/CutLineBackwardActionTest.java @@ -65,7 +65,7 @@ public class CutLineBackwardActionTest extends LightPlatformCodeInsightTestCase } private void doTest(@NotNull String before, @NotNull String after) throws IOException { - configureFromFileText(getTestName(false) + ".java", before); + configureFromFileText(getTestName(false) + ".txt", before); cutLineBackward(); checkResultByText(after); } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/CutLineEndActionsTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/CutLineEndActionsTest.java index 45d232865576..e570e9d2445b 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/CutLineEndActionsTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/CutLineEndActionsTest.java @@ -78,7 +78,7 @@ public class CutLineEndActionsTest extends LightPlatformCodeInsightTestCase { } private void doTest(@NotNull String before, @NotNull String after) throws IOException { - configureFromFileText(getTestName(false) + ".java", before); + configureFromFileText(getTestName(false) + ".txt", before); cutToLineEnd(); checkResultByText(after); } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/KillRegionActionTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/KillRegionActionTest.java index c6168b49cc7f..818257c04443 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/KillRegionActionTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/KillRegionActionTest.java @@ -29,7 +29,7 @@ import java.awt.datatransfer.Transferable; public class KillRegionActionTest extends AbstractRegionToKillRingTest { protected void doTest(@NotNull String text) throws Exception { - configureFromFileText(getTestName(false) + ".java", text); + configureFromFileText(getTestName(false) + ".txt", text); Pair parseResult = parse(); killRegion(); if (parseResult.first != null) { diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/KillRingSaveActionTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/KillRingSaveActionTest.java index b06f803c503e..21c9e780625b 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/KillRingSaveActionTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/KillRingSaveActionTest.java @@ -29,7 +29,7 @@ import java.awt.datatransfer.Transferable; public class KillRingSaveActionTest extends AbstractRegionToKillRingTest { protected void doTest(@NotNull String text) throws Exception { - configureFromFileText(getTestName(false) + ".java", text); + configureFromFileText(getTestName(false) + ".txt", text); Pair parseResult = parse(); String textBefore = myEditor.getDocument().getText(); killRingSave(); diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/KillToWordEndActionTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/KillToWordEndActionTest.java index 3a069eb7b5e7..11e54f1e6f15 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/KillToWordEndActionTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/KillToWordEndActionTest.java @@ -85,7 +85,7 @@ public class KillToWordEndActionTest extends LightPlatformCodeInsightTestCase { } private void doTest(@NotNull String before, @NotNull String after) throws IOException { - configureFromFileText(getTestName(false) + ".java", before); + configureFromFileText(getTestName(false) + ".txt", before); killToWordEnd(); checkResultByText(after); } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/KillToWordStartActionTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/KillToWordStartActionTest.java index 099e0a5e8a0d..cb185029e100 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/KillToWordStartActionTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/KillToWordStartActionTest.java @@ -85,7 +85,7 @@ public class KillToWordStartActionTest extends LightPlatformCodeInsightTestCase } private void doTest(@NotNull String before, @NotNull String after) throws IOException { - configureFromFileText(getTestName(false) + ".java", before); + configureFromFileText(getTestName(false) + ".txt", before); killToWordStart(); checkResultByText(after); } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/LocalFileSystemTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/LocalFileSystemTest.java index c6669ea819b3..3dc2dd5ef977 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/LocalFileSystemTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/LocalFileSystemTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,10 +20,7 @@ import com.intellij.ide.GeneralSettings; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vfs.LocalFileSystem; -import com.intellij.openapi.vfs.SafeWriteRequestor; -import com.intellij.openapi.vfs.VfsUtil; -import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.*; import com.intellij.openapi.vfs.newvfs.ManagingFS; import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS; import com.intellij.testFramework.PlatformLangTestCase; @@ -269,13 +266,13 @@ public class LocalFileSystemTest extends PlatformLangTestCase { FileUtil.writeToFile(file, "hello"); VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file); assertNotNull(virtualFile); - String s = VfsUtil.loadText(virtualFile); + String s = VfsUtilCore.loadText(virtualFile); assertEquals("hello", s); assertEquals(5, virtualFile.getLength()); FileUtil.writeToFile(file, "new content"); - ((PersistentFS)ManagingFS.getInstance()).cleanPersistedContents(); - s = VfsUtil.loadText(virtualFile); + PersistentFS.cleanPersistedContents(); + s = VfsUtilCore.loadText(virtualFile); assertEquals("new content", s); assertEquals(11, virtualFile.getLength()); } @@ -307,7 +304,7 @@ public class LocalFileSystemTest extends PlatformLangTestCase { final VirtualFile check = LocalFileSystem.getInstance().findFileByIoFile(hardLinkFile); assertNotNull(check); - assertEquals("hello", VfsUtil.loadText(check)); + assertEquals("hello", VfsUtilCore.loadText(check)); } finally { GeneralSettings.getInstance().setUseSafeWrite(safeWrite); diff --git a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java index 3165c27634dc..58c841027f5d 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -75,7 +75,6 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.vfs.encoding.EncodingManager; import com.intellij.openapi.vfs.encoding.EncodingManagerImpl; -import com.intellij.openapi.vfs.newvfs.ManagingFS; import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS; import com.intellij.profile.codeInspection.InspectionProfileManager; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; @@ -184,7 +183,7 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da } private static void cleanPersistedVFSContent() { - ((PersistentFS)ManagingFS.getInstance()).cleanPersistedContents(); + PersistentFS.cleanPersistedContents(); } public static boolean isLight(Project project) { diff --git a/platform/testFramework/src/com/intellij/testFramework/ParsingTestCase.java b/platform/testFramework/src/com/intellij/testFramework/ParsingTestCase.java index 85b0685884e9..81275c29dd81 100644 --- a/platform/testFramework/src/com/intellij/testFramework/ParsingTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/ParsingTestCase.java @@ -51,17 +51,14 @@ import com.intellij.util.messages.MessageBus; import com.intellij.util.messages.MessageBusFactory; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import org.picocontainer.ComponentAdapter; -import org.picocontainer.MutablePicoContainer; -import org.picocontainer.PicoContainer; -import org.picocontainer.PicoInitializationException; -import org.picocontainer.PicoIntrospectionException; +import org.picocontainer.*; import org.picocontainer.defaults.AbstractComponentAdapter; import java.io.File; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; +import java.util.Set; public abstract class ParsingTestCase extends PlatformLiteFixture { protected String myFilePrefix = ""; @@ -201,7 +198,7 @@ public abstract class ParsingTestCase extends PlatformLiteFixture { assertEquals("doc text mismatch", text, myFile.getViewProvider().getDocument().getText()); assertEquals("psi text mismatch", text, myFile.getText()); if (checkResult){ - checkResult(name + ".txt", myFile); + checkResult(name, myFile); } else{ toParseTreeText(myFile, skipSpaces(), includeRanges()); @@ -218,7 +215,7 @@ public abstract class ParsingTestCase extends PlatformLiteFixture { myFile = createPsiFile(name, text); ensureParsed(myFile); assertEquals(text, myFile.getText()); - checkResult(name + suffix + ".txt", myFile); + checkResult(name + suffix, myFile); } protected void doCodeTest(String code) throws IOException { @@ -226,7 +223,7 @@ public abstract class ParsingTestCase extends PlatformLiteFixture { myFile = createPsiFile("a", code); ensureParsed(myFile); assertEquals(code, myFile.getText()); - checkResult(myFilePrefix + name + ".txt", myFile); + checkResult(myFilePrefix + name, myFile); } protected PsiFile createPsiFile(String name, String text) { @@ -253,15 +250,18 @@ public abstract class ParsingTestCase extends PlatformLiteFixture { String targetDataName, boolean skipSpaces, boolean printRanges) throws IOException { - final PsiElement[] psiRoots = checkAllPsiRoots? file.getPsiRoots() : PsiElement.EMPTY_ARRAY; - if(psiRoots.length > 1){ - for (int i = 0; i < psiRoots.length; i++) { - final PsiElement psiRoot = psiRoots[i]; - doCheckResult(myFullDataPath, targetDataName + "." + i, toParseTreeText(psiRoot, skipSpaces, printRanges).trim()); - } + FileViewProvider provider = file.getViewProvider(); + Set languages = provider.getLanguages(); + + if (!checkAllPsiRoots || languages.size() == 1) { + doCheckResult(myFullDataPath, targetDataName + ".txt", toParseTreeText(file, skipSpaces, printRanges).trim()); + return; } - else{ - doCheckResult(myFullDataPath, targetDataName, toParseTreeText(file, skipSpaces, printRanges).trim()); + + for (Language language : languages) { + PsiFile root = provider.getPsi(language); + String expectedName = targetDataName + "." + language.getID() + ".txt"; + doCheckResult(myFullDataPath, expectedName, toParseTreeText(root, skipSpaces, printRanges).trim()); } } @@ -297,8 +297,7 @@ public abstract class ParsingTestCase extends PlatformLiteFixture { } private static String doLoadFile(String myFullDataPath, String name) throws IOException { - String fullName = myFullDataPath + File.separatorChar + name; - String text = FileUtil.loadFile(new File(fullName), CharsetToolkit.UTF8).trim(); + String text = FileUtil.loadFile(new File(myFullDataPath, name), CharsetToolkit.UTF8).trim(); text = StringUtil.convertLineSeparators(text); return text; } diff --git a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java index 867b6e25909f..7c92f6ebc3b8 100644 --- a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -55,7 +55,6 @@ import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.impl.VirtualFilePointerManagerImpl; import com.intellij.openapi.vfs.impl.local.LocalFileSystemImpl; -import com.intellij.openapi.vfs.newvfs.ManagingFS; import com.intellij.openapi.vfs.newvfs.impl.VirtualDirectoryImpl; import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS; import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager; @@ -154,7 +153,7 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro } private static void cleanPersistedVFSContent() { - ((PersistentFS)ManagingFS.getInstance()).cleanPersistedContents(); + PersistentFS.cleanPersistedContents(); } @Override diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java index 5c5a7f2a0fae..35d852f8cacd 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java @@ -1113,6 +1113,10 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig @Override public boolean isToolEnabled(HighlightDisplayKey key, PsiElement element) { + return isToolEnabled(key); + } + + public boolean isToolEnabled(HighlightDisplayKey key) { return key != null && key.toString() != null && myAvailableTools.containsKey(key.toString()); } diff --git a/platform/util/src/com/intellij/openapi/util/io/FileSystemUtil.java b/platform/util/src/com/intellij/openapi/util/io/FileSystemUtil.java index d46a663babf1..cd2d7186e619 100644 --- a/platform/util/src/com/intellij/openapi/util/io/FileSystemUtil.java +++ b/platform/util/src/com/intellij/openapi/util/io/FileSystemUtil.java @@ -22,17 +22,15 @@ import com.sun.jna.Library; import com.sun.jna.Memory; import com.sun.jna.Native; import com.sun.jna.Pointer; -import com.sun.org.apache.bcel.internal.generic.NEW; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; -import java.io.IOException; import java.lang.reflect.Array; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.*; +// todo[r.sh] read attributes in one shot (IDEA 12) // todo[r.sh] use NIO2 API after migration to JDK 7 public class FileSystemUtil { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.util.io.FileSystemUtil"); diff --git a/platform/util/src/com/intellij/util/FunctionWithTimeout.java b/platform/util/src/com/intellij/util/FunctionWithTimeout.java new file mode 100644 index 000000000000..a712f6482d3c --- /dev/null +++ b/platform/util/src/com/intellij/util/FunctionWithTimeout.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.util; + +import org.jetbrains.annotations.NotNull; + +/** + * @author Konstantin Bulenkov + */ +public abstract class FunctionWithTimeout { + protected abstract void updateValue(T initialValue); + + @NotNull + public T calculate(long timeout, @NotNull final T initialValue) { + TimeoutUtil.executeWithTimeout(timeout, new Runnable() { + @Override + public void run() { + updateValue(initialValue); + } + }); + return initialValue; + } +} diff --git a/platform/util/src/com/intellij/util/TimeoutUtil.java b/platform/util/src/com/intellij/util/TimeoutUtil.java new file mode 100644 index 000000000000..ac9b66d8e240 --- /dev/null +++ b/platform/util/src/com/intellij/util/TimeoutUtil.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.util; + +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * + * + * @author Konstantin Bulenkov + */ +public final class TimeoutUtil { + public static void executeWithTimeout(long timeout, long sleep, @NotNull final Runnable run) { + final long start = System.currentTimeMillis(); + final AtomicBoolean done = new AtomicBoolean(false); + final Thread thread = new Thread("Fast Function Thread@" + run.hashCode()) { + @Override + public void run() { + run.run(); + done.set(true); + } + }; + thread.start(); + + while (!done.get() && System.currentTimeMillis() - start < timeout) { + try { + //noinspection BusyWait + Thread.sleep(sleep); + } catch (InterruptedException e) { + break; + } + } + if (!thread.isInterrupted()) { + //noinspection deprecation + thread.stop(); + } + } + + public static void executeWithTimeout(long timeout, @NotNull final Runnable run) { + executeWithTimeout(timeout, 50, run); + } +} diff --git a/platform/util/src/com/intellij/util/containers/ContainerUtil.java b/platform/util/src/com/intellij/util/containers/ContainerUtil.java index 4e64bb40842c..190020b187aa 100644 --- a/platform/util/src/com/intellij/util/containers/ContainerUtil.java +++ b/platform/util/src/com/intellij/util/containers/ContainerUtil.java @@ -128,11 +128,11 @@ public class ContainerUtil { return list.subList(from, list.size()); } - public static void addAll(@NotNull Collection collection, @NotNull Iterable appendix) { + public static void addAll(@NotNull Collection collection, @NotNull Iterable appendix) { addAll(collection, appendix.iterator()); } - public static void addAll(@NotNull Collection collection, @NotNull Iterator iterator) { + public static void addAll(@NotNull Collection collection, @NotNull Iterator iterator) { while (iterator.hasNext()) { T o = iterator.next(); collection.add(o); @@ -516,7 +516,7 @@ public class ContainerUtil { return collect(FilteringIterator.create((Iterator)iterator, instanceOf)); } - public static void addAll(@NotNull Collection collection, @NotNull Enumeration enumeration) { + public static void addAll(@NotNull Collection collection, @NotNull Enumeration enumeration) { while (enumeration.hasMoreElements()) { T element = enumeration.nextElement(); collection.add(element); diff --git a/platform/util/src/com/intellij/util/io/PersistentHashMapValueStorage.java b/platform/util/src/com/intellij/util/io/PersistentHashMapValueStorage.java index 26daa4379a9c..d555b7fa414c 100644 --- a/platform/util/src/com/intellij/util/io/PersistentHashMapValueStorage.java +++ b/platform/util/src/com/intellij/util/io/PersistentHashMapValueStorage.java @@ -173,6 +173,9 @@ public class PersistentHashMapValueStorage { chunk = prevChunkAddress; chunkCount++; + if (result.length > mySize) { + throw new PersistentEnumeratorBase.CorruptedException(myFile); + } } } finally { diff --git a/platform/util/src/com/intellij/util/io/PersistentStringEnumerator.java b/platform/util/src/com/intellij/util/io/PersistentStringEnumerator.java index 3f98c07fcd1f..4a88a2a5490b 100644 --- a/platform/util/src/com/intellij/util/io/PersistentStringEnumerator.java +++ b/platform/util/src/com/intellij/util/io/PersistentStringEnumerator.java @@ -77,7 +77,11 @@ public class PersistentStringEnumerator extends PersistentEnumeratorDelegate 0, contentId); + if (ChangeListManagerImpl.DEBUG) { + System.out.println("LastUnchangedContentTracker.saveContentReference"); + System.out.println("file = " + file); + } + long stamp = file.getModificationStamp(); try { final DataOutputStream contentStream = ACQUIRED_CONTENT_ATTR.writeAttribute(file); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangeListRenderer.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangeListRenderer.java index 098086524ea1..c25ce3516530 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangeListRenderer.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangeListRenderer.java @@ -17,6 +17,7 @@ package com.intellij.openapi.vcs.changes.committed; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vcs.CachingCommittedChangesProvider; import com.intellij.openapi.vcs.VcsBundle; @@ -33,7 +34,6 @@ import javax.swing.plaf.basic.BasicTreeUI; import javax.swing.tree.DefaultMutableTreeNode; import java.awt.*; import java.util.Date; -import java.util.List; public class CommittedChangeListRenderer extends ColoredTreeCellRenderer { private static final SimpleTextAttributes LINK_ATTRIBUTES = new SimpleTextAttributes(SimpleTextAttributes.STYLE_UNDERLINE, Color.blue); @@ -148,18 +148,21 @@ public class CommittedChangeListRenderer extends ColoredTreeCellRenderer { myRenderer.appendTextWithLinks(description); } else if (descWidth < descMaxWidth && !truncated) { - final List pieces = myRenderer.appendTextWithLinks(description); + myRenderer.appendTextWithLinks(description); appendAlign(descMaxWidth); } else { final String moreMarker = VcsBundle.message("changes.browser.details.marker"); int moreWidth = fontMetrics.stringWidth(moreMarker); - description = truncateDescription(description, fontMetrics, (descMaxWidth - moreWidth - numberWidth)); + int remainingWidth = descMaxWidth - moreWidth - numberWidth; + description = truncateDescription(description, fontMetrics, remainingWidth); myRenderer.appendTextWithLinks(description); - // we don't have place for changelist number in this case - final int addWidth = fontMetrics.stringWidth(description + " "); - append(" ", SimpleTextAttributes.REGULAR_ATTRIBUTES); - append(moreMarker, LINK_ATTRIBUTES, new CommittedChangesTreeBrowser.MoreLauncher(myProject, changeList)); + if (!StringUtil.isEmpty(description)) { + append(" ", SimpleTextAttributes.REGULAR_ATTRIBUTES); + append(moreMarker, LINK_ATTRIBUTES, new CommittedChangesTreeBrowser.MoreLauncher(myProject, changeList)); + } else if (remainingWidth > 0) { + append(moreMarker, LINK_ATTRIBUTES, new CommittedChangesTreeBrowser.MoreLauncher(myProject, changeList)); + } // align value is for the latest added piece appendAlign(descMaxWidth); } @@ -168,13 +171,6 @@ public class CommittedChangeListRenderer extends ColoredTreeCellRenderer { append(date, SimpleTextAttributes.REGULAR_ATTRIBUTES); } - private void appendDescriptionAndNumber(final String description, final String number) { - myRenderer.appendTextWithLinks(description); - if (number != null) { - append(number, SimpleTextAttributes.GRAY_ATTRIBUTES); - } - } - private static String trimLastWord(final String description) { int pos = description.trim().lastIndexOf(' '); if (pos >= 0) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java index 8f9fee4eab25..675d50396695 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java @@ -1,9 +1,12 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at + * * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -21,6 +24,7 @@ import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vcs.VcsBundle; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; /** * @author irengrig @@ -48,6 +52,7 @@ public class ShowLineStatusRangeDiffAction extends BaseLineStatusRangeAction { private DiffRequest createDiffData() { return new DiffRequest(myLineStatusTracker.getProject()) { + @NotNull public DiffContent[] getContents() { return new DiffContent[]{createDiffContent(myLineStatusTracker.getUpToDateDocument(), myLineStatusTracker.getUpToDateRangeWithEndSymbol(myRange), null), diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java index d9f83fc1b4f5..8627536e625e 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java @@ -24,7 +24,9 @@ import com.intellij.openapi.actionSystem.ActionToolbar; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.actionSystem.impl.ActionToolbarImpl; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.ui.CaptionPanel; import com.intellij.ui.ScrollPaneFactory; +import com.intellij.ui.border.CustomLineBorder; import com.intellij.ui.components.panels.Wrapper; import com.intellij.util.containers.HashMap; import com.intellij.xdebugger.XDebugSession; @@ -85,6 +87,8 @@ public class XFramesView extends XDebugViewBase { myThreadComboBox.addItemListener(new MyItemListener()); final ActionToolbar toolbar = createToolbar(); Wrapper threadsPanel = new Wrapper(); + CustomLineBorder border = new CustomLineBorder(CaptionPanel.CNT_ACTIVE_COLOR, 0, 0, 1, 0); + threadsPanel.setBorder(border); threadsPanel.add(toolbar.getComponent(), BorderLayout.EAST); threadsPanel.add(myThreadComboBox, BorderLayout.CENTER); myMainPanel.add(threadsPanel, BorderLayout.NORTH); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesView.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesView.java index ea2d9f01d5bc..0818229d871c 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesView.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesView.java @@ -21,9 +21,12 @@ import com.intellij.ide.dnd.DnDManager; import com.intellij.ide.dnd.DnDNativeTarget; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.util.SystemInfo; import com.intellij.ui.AnActionButton; import com.intellij.ui.AnActionButtonRunnable; +import com.intellij.ui.CaptionPanel; import com.intellij.ui.ToolbarDecorator; +import com.intellij.ui.border.CustomLineBorder; import com.intellij.util.ArrayUtil; import com.intellij.util.ui.tree.TreeUtil; import com.intellij.xdebugger.XDebugSession; @@ -92,6 +95,10 @@ public class XWatchesView extends XDebugViewBase implements DnDNativeTarget { executeAction(XDebuggerActions.XREMOVE_WATCH); } }); + CustomLineBorder border = new CustomLineBorder(CaptionPanel.CNT_ACTIVE_COLOR, + SystemInfo.isMac ? 1 : 0, 0, + SystemInfo.isMac ? 0 : 1, 0); + decorator.setToolbarBorder(border); myDecoratedPanel = decorator.createPanel(); myDecoratedPanel.setBorder(null); diff --git a/plugins/IntelliLang/java-support/resources/javaInjections.xml b/plugins/IntelliLang/java-support/resources/javaInjections.xml index f685f36e0415..2c49267f9269 100644 --- a/plugins/IntelliLang/java-support/resources/javaInjections.xml +++ b/plugins/IntelliLang/java-support/resources/javaInjections.xml @@ -102,10 +102,12 @@ Session.createQuery (org.hibernate) + Session.createSQLQuery (org.hibernate) + diff --git a/plugins/android-designer/android-designer.iml b/plugins/android-designer/android-designer.iml new file mode 100644 index 000000000000..a6cb9856732d --- /dev/null +++ b/plugins/android-designer/android-designer.iml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/android-designer/src/META-INF/plugin.xml b/plugins/android-designer/src/META-INF/plugin.xml new file mode 100644 index 000000000000..b808ad518995 --- /dev/null +++ b/plugins/android-designer/src/META-INF/plugin.xml @@ -0,0 +1,17 @@ + + Android Designer + com.intellij.android-designer + JetBrains + + messages.AndroidDesignerBundle + + com.intellij.java-i18n + com.intellij.properties + org.jetbrains.android + com.intellij.ui-designer-new + + + + + + diff --git a/plugins/android-designer/src/com/intellij/android/designer/AndroidDesignerBundle.java b/plugins/android-designer/src/com/intellij/android/designer/AndroidDesignerBundle.java new file mode 100644 index 000000000000..6442f216e766 --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/AndroidDesignerBundle.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.android.designer; + +import com.intellij.CommonBundle; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.PropertyKey; + +import java.lang.ref.Reference; +import java.lang.ref.SoftReference; +import java.util.ResourceBundle; + +/** + * @author yole + */ +public class AndroidDesignerBundle { + private static Reference ourBundle; + + @NonNls private static final String BUNDLE = "messages.AndroidDesignerBundle"; + + private AndroidDesignerBundle() { + } + + public static String message(@PropertyKey(resourceBundle = BUNDLE) String key, Object... params) { + return CommonBundle.message(getBundle(), key, params); + } + + private static ResourceBundle getBundle() { + ResourceBundle bundle = null; + if (ourBundle != null) bundle = ourBundle.get(); + if (bundle == null) { + bundle = ResourceBundle.getBundle(BUNDLE); + ourBundle = new SoftReference(bundle); + } + return bundle; + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/AndroidDesignerEditor.java b/plugins/android-designer/src/com/intellij/android/designer/AndroidDesignerEditor.java new file mode 100644 index 000000000000..da32138b3de3 --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/AndroidDesignerEditor.java @@ -0,0 +1,65 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.android.designer; + +import com.intellij.openapi.fileEditor.FileEditorState; +import com.intellij.openapi.fileEditor.FileEditorStateLevel; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.uiDesigner.DesignerEditor; +import org.jetbrains.annotations.NotNull; + +/** + * @author Alexander Lobas + */ +public final class AndroidDesignerEditor extends DesignerEditor { + public AndroidDesignerEditor(Project project, VirtualFile file) { + super(project, file); + } + + @NotNull + @Override + public String getName() { + return AndroidDesignerBundle.message("editor.tab.title"); + } + + @Override + public boolean isValid() { + return true; // TODO: Auto-generated method stub + } + + @NotNull + @Override + public FileEditorState getState(@NotNull FileEditorStateLevel level) { + // TODO: Auto-generated method stub + return new FileEditorState() { + @Override + public boolean canBeMergedWith(FileEditorState otherState, FileEditorStateLevel level) { + return false; + } + }; + } + + @Override + public void setState(@NotNull FileEditorState state) { + // TODO: Auto-generated method stub + } + + @Override + public boolean isModified() { + return false; + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/AndroidDesignerEditorProvider.java b/plugins/android-designer/src/com/intellij/android/designer/AndroidDesignerEditorProvider.java new file mode 100644 index 000000000000..cb4e2796aa59 --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/AndroidDesignerEditorProvider.java @@ -0,0 +1,87 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.android.designer; + +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileEditor.*; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiFile; +import com.intellij.psi.xml.XmlFile; +import org.jdom.Element; +import org.jetbrains.android.dom.layout.LayoutDomFileDescription; +import org.jetbrains.android.facet.AndroidFacet; +import org.jetbrains.annotations.NotNull; + +/** + * @author Alexander Lobas + */ +public final class AndroidDesignerEditorProvider implements FileEditorProvider, DumbAware { + @Override + public boolean accept(@NotNull Project project, @NotNull VirtualFile file) { + Document document = FileDocumentManager.getInstance().getDocument(file); + if (document != null) { + PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document); + return psiFile instanceof XmlFile && + AndroidFacet.getInstance(psiFile) != null && + LayoutDomFileDescription.isLayoutFile((XmlFile)psiFile); + } + return false; + } + + @NotNull + @Override + public FileEditor createEditor(@NotNull Project project, @NotNull VirtualFile file) { + return new AndroidDesignerEditor(project, file); + } + + @Override + public void disposeEditor(@NotNull FileEditor editor) { + Disposer.dispose(editor); + } + + @NotNull + @Override + public FileEditorState readState(@NotNull Element sourceElement, @NotNull Project project, @NotNull VirtualFile file) { + // TODO: Auto-generated method stub + return new FileEditorState() { + @Override + public boolean canBeMergedWith(FileEditorState otherState, FileEditorStateLevel level) { + return false; + } + }; + } + + @Override + public void writeState(@NotNull FileEditorState state, @NotNull Project project, @NotNull Element targetElement) { + // TODO: Auto-generated method stub + } + + @NotNull + @Override + public String getEditorTypeId() { + return "android-designer"; + } + + @NotNull + @Override + public FileEditorPolicy getPolicy() { + return FileEditorPolicy.PLACE_BEFORE_DEFAULT_EDITOR; + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/messages/AndroidDesignerBundle.properties b/plugins/android-designer/src/messages/AndroidDesignerBundle.properties new file mode 100644 index 000000000000..d45742e29143 --- /dev/null +++ b/plugins/android-designer/src/messages/AndroidDesignerBundle.properties @@ -0,0 +1 @@ +editor.tab.title=Design \ No newline at end of file diff --git a/plugins/android/android.iml b/plugins/android/android.iml index 1acddaf410cf..b6502266fba7 100644 --- a/plugins/android/android.iml +++ b/plugins/android/android.iml @@ -61,6 +61,7 @@ +
diff --git a/plugins/android/rt/android-rt.iml b/plugins/android/rt/android-rt.iml new file mode 100644 index 000000000000..59171f56fad5 --- /dev/null +++ b/plugins/android/rt/android-rt.iml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidApt.java b/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidApt.java similarity index 73% rename from plugins/android/src/org/jetbrains/android/compiler/tools/AndroidApt.java rename to plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidApt.java index 465f38fbeeaf..7f112779b051 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidApt.java +++ b/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidApt.java @@ -16,13 +16,12 @@ package org.jetbrains.android.compiler.tools; import com.android.sdklib.IAndroidTarget; -import com.intellij.openapi.compiler.CompilerMessageCategory; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.io.FileUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.HashMap; -import org.jetbrains.android.compiler.AndroidCompileUtil; -import org.jetbrains.android.util.AndroidUtils; +import org.jetbrains.android.util.AndroidCommonUtils; +import org.jetbrains.android.util.AndroidCompilerMessageKind; import org.jetbrains.android.util.ExecutionUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -47,22 +46,22 @@ public final class AndroidApt { private AndroidApt() { } - public static Map> compile(@NotNull IAndroidTarget target, - int platformToolsRevision, - @NotNull String manifestFileOsPath, - @NotNull String aPackage, - @NotNull String outDirOsPath, - @NotNull String[] resourceDirsOsPaths, - @NotNull String[] libPackages, - boolean isLibrary) throws IOException { - final Map> messages = new HashMap>(); - messages.put(CompilerMessageCategory.ERROR, new ArrayList()); - messages.put(CompilerMessageCategory.INFORMATION, new ArrayList()); + public static Map> compile(@NotNull IAndroidTarget target, + int platformToolsRevision, + @NotNull String manifestFileOsPath, + @NotNull String aPackage, + @NotNull String outDirOsPath, + @NotNull String[] resourceDirsOsPaths, + @NotNull String[] libPackages, + boolean isLibrary) throws IOException { + final Map> messages = new HashMap>(); + messages.put(AndroidCompilerMessageKind.ERROR, new ArrayList()); + messages.put(AndroidCompilerMessageKind.INFORMATION, new ArrayList()); final File outOsDir = new File(outDirOsPath); if (!outOsDir.exists()) { if (!outOsDir.mkdirs()) { - messages.get(CompilerMessageCategory.ERROR).add("Unable to create directory " + outDirOsPath); + messages.get(AndroidCompilerMessageKind.ERROR).add("Unable to create directory " + outDirOsPath); } } @@ -71,55 +70,55 @@ public final class AndroidApt { /* We actually need to delete the manifest.java as it may become empty and in this case aapt doesn't generate an empty one, but instead doesn't touch it */ - final File manifestJavaFile = new File(packageFolderOsPath + File.separatorChar + AndroidUtils.MANIFEST_JAVA_FILE_NAME); + final File manifestJavaFile = new File(packageFolderOsPath + File.separatorChar + AndroidCommonUtils.MANIFEST_JAVA_FILE_NAME); if (manifestJavaFile.exists()) { if (!FileUtil.delete(manifestJavaFile)) { - messages.get(CompilerMessageCategory.ERROR).add("Unable to delete " + manifestJavaFile.getPath()); + messages.get(AndroidCompilerMessageKind.ERROR).add("Unable to delete " + manifestJavaFile.getPath()); } } - - final File rJavaFile = new File(packageFolderOsPath + File.separatorChar + AndroidUtils.R_JAVA_FILENAME); + + final File rJavaFile = new File(packageFolderOsPath + File.separatorChar + AndroidCommonUtils.R_JAVA_FILENAME); if (rJavaFile.exists()) { if (!FileUtil.delete(rJavaFile)) { - messages.get(CompilerMessageCategory.ERROR).add("Unable to delete " + rJavaFile.getPath()); + messages.get(AndroidCompilerMessageKind.ERROR).add("Unable to delete " + rJavaFile.getPath()); } } - + final File[] libRJavaFiles = new File[libPackages.length]; - + for (int i = 0; i < libPackages.length; i++) { final String libPackageFolderOsPath = FileUtil.toSystemDependentName(outDirOsPath + '/' + libPackages[i].replace('.', '/')); - libRJavaFiles[i] = new File(libPackageFolderOsPath + File.separatorChar + AndroidUtils.R_JAVA_FILENAME); + libRJavaFiles[i] = new File(libPackageFolderOsPath + File.separatorChar + AndroidCommonUtils.R_JAVA_FILENAME); } for (File libRJavaFile : libRJavaFiles) { if (libRJavaFile.exists()) { if (!FileUtil.delete(libRJavaFile)) { - messages.get(CompilerMessageCategory.ERROR).add("Unable to delete " + libRJavaFile.getPath()); + messages.get(AndroidCompilerMessageKind.ERROR).add("Unable to delete " + libRJavaFile.getPath()); } } } if (platformToolsRevision < 0 || platformToolsRevision > 7) { - Map> map = + Map> map = doCompile(target, manifestFileOsPath, outDirOsPath, resourceDirsOsPaths, libPackages, null, isLibrary); - if (map.get(CompilerMessageCategory.ERROR).isEmpty()) { + if (map.get(AndroidCompilerMessageKind.ERROR).isEmpty()) { makeFieldsNotFinal(libRJavaFiles); } - AndroidCompileUtil.addMessages(messages, map); + ExecutionUtil.addMessages(messages, map); return messages; } else { - Map> map; + Map> map; map = doCompile(target, manifestFileOsPath, outDirOsPath, resourceDirsOsPaths, ArrayUtil.EMPTY_STRING_ARRAY, null, false); - AndroidCompileUtil.addMessages(messages, map); + ExecutionUtil.addMessages(messages, map); for (String libPackage : libPackages) { map = doCompile(target, manifestFileOsPath, outDirOsPath, resourceDirsOsPaths, ArrayUtil.EMPTY_STRING_ARRAY, libPackage, false); - AndroidCompileUtil.addMessages(messages, map); + ExecutionUtil.addMessages(messages, map); } return messages; } @@ -148,13 +147,13 @@ public final class AndroidApt { } } - private static Map> doCompile(@NotNull IAndroidTarget target, - @NotNull String manifestFileOsPath, - @NotNull String outDirOsPath, - @NotNull String[] resourceDirsOsPaths, - @NotNull String[] extraPackages, - @Nullable String customPackage, - boolean nonConstantIds) + private static Map> doCompile(@NotNull IAndroidTarget target, + @NotNull String manifestFileOsPath, + @NotNull String outDirOsPath, + @NotNull String[] resourceDirsOsPaths, + @NotNull String[] extraPackages, + @Nullable String customPackage, + boolean nonConstantIds) throws IOException { final List args = new ArrayList(); @@ -174,7 +173,7 @@ public final class AndroidApt { args.add("--extra-packages"); args.add(toPackagesString(extraPackages)); } - + if (customPackage != null) { args.add("--custom-package"); args.add(customPackage); @@ -193,8 +192,8 @@ public final class AndroidApt { args.add("-I"); args.add(target.getPath(IAndroidTarget.ANDROID_JAR)); - LOG.info(AndroidUtils.command2string(args)); - return ExecutionUtil.execute(ArrayUtil.toStringArray(args)); + LOG.info(AndroidCommonUtils.command2string(args)); + return ExecutionUtil.doExecute(ArrayUtil.toStringArray(args)); } @NotNull @@ -209,9 +208,9 @@ public final class AndroidApt { return builder.toString(); } - public static Map> crunch(@NotNull IAndroidTarget target, - @NotNull List resPaths, - @NotNull String outputPath) throws IOException { + public static Map> crunch(@NotNull IAndroidTarget target, + @NotNull List resPaths, + @NotNull String outputPath) throws IOException { final ArrayList args = new ArrayList(); //noinspection deprecation @@ -227,19 +226,19 @@ public final class AndroidApt { args.add("-C"); args.add(outputPath); - LOG.info(AndroidUtils.command2string(args)); - return ExecutionUtil.execute(ArrayUtil.toStringArray(args)); + LOG.info(AndroidCommonUtils.command2string(args)); + return ExecutionUtil.doExecute(ArrayUtil.toStringArray(args)); } - public static Map> packageResources(@NotNull IAndroidTarget target, - int platformToolsRevision, - @NotNull String manifestPath, - @NotNull String[] resPaths, - @Nullable String osAssetsPath, - @NotNull String outputPath, - @Nullable String configFilter, - boolean debugMode, - int versionCode) throws IOException { + public static Map> packageResources(@NotNull IAndroidTarget target, + int platformToolsRevision, + @NotNull String manifestPath, + @NotNull String[] resPaths, + @Nullable String osAssetsPath, + @NotNull String outputPath, + @Nullable String configFilter, + boolean debugMode, + int versionCode) throws IOException { final ArrayList args = new ArrayList(); //noinspection deprecation @@ -290,7 +289,7 @@ public final class AndroidApt { args.add("-F"); args.add(outputPath); - LOG.info(AndroidUtils.command2string(args)); - return ExecutionUtil.execute(ArrayUtil.toStringArray(args)); + LOG.info(AndroidCommonUtils.command2string(args)); + return ExecutionUtil.doExecute(ArrayUtil.toStringArray(args)); } } diff --git a/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidDxRunner.java b/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidDxRunner.java similarity index 100% rename from plugins/android/src/org/jetbrains/android/compiler/tools/AndroidDxRunner.java rename to plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidDxRunner.java diff --git a/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidIdl.java b/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidIdl.java similarity index 74% rename from plugins/android/src/org/jetbrains/android/compiler/tools/AndroidIdl.java rename to plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidIdl.java index daa4083bef6a..16e0bc1a3175 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidIdl.java +++ b/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidIdl.java @@ -16,8 +16,8 @@ package org.jetbrains.android.compiler.tools; import com.android.sdklib.IAndroidTarget; -import com.intellij.openapi.compiler.CompilerMessageCategory; import com.intellij.util.ArrayUtil; +import org.jetbrains.android.util.AndroidCompilerMessageKind; import org.jetbrains.android.util.ExecutionUtil; import org.jetbrains.annotations.NotNull; @@ -36,20 +36,22 @@ public final class AndroidIdl { } @NotNull - public static Map> execute(@NotNull IAndroidTarget target, - @NotNull String file, - @NotNull String outFile, - @NotNull String[] sourceRootPaths) throws IOException { - List commands = new ArrayList(); - String frameworkAidlPath = target.getPath(IAndroidTarget.ANDROID_AIDL); + public static Map> execute(@NotNull IAndroidTarget target, + @NotNull String file, + @NotNull String outFile, + @NotNull String[] sourceRootPaths) throws IOException { + final List commands = new ArrayList(); + final String frameworkAidlPath = target.getPath(IAndroidTarget.ANDROID_AIDL); + commands.add(target.getPath(IAndroidTarget.AIDL)); commands.add("-p" + frameworkAidlPath); + for (String path : sourceRootPaths) { commands.add("-I" + path); } commands.add(file); commands.add(outFile); - return ExecutionUtil.execute(ArrayUtil.toStringArray(commands)); + return ExecutionUtil.doExecute(ArrayUtil.toStringArray(commands)); } } diff --git a/plugins/android/rt/src/org/jetbrains/android/util/AndroidCommonUtils.java b/plugins/android/rt/src/org/jetbrains/android/util/AndroidCommonUtils.java new file mode 100644 index 000000000000..450687945d47 --- /dev/null +++ b/plugins/android/rt/src/org/jetbrains/android/util/AndroidCommonUtils.java @@ -0,0 +1,32 @@ +package org.jetbrains.android.util; + +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.Iterator; + +/** + * @author Eugene.Kudelevsky + */ +public class AndroidCommonUtils { + @NonNls public static final Object MANIFEST_JAVA_FILE_NAME = "Manifest.java"; + public static final String R_JAVA_FILENAME = "R.java"; + + private AndroidCommonUtils() { + } + + public static String command2string(@NotNull Collection command) { + final StringBuilder builder = new StringBuilder(); + for (Iterator it = command.iterator(); it.hasNext(); ) { + String s = it.next(); + builder.append('['); + builder.append(s); + builder.append(']'); + if (it.hasNext()) { + builder.append(' '); + } + } + return builder.toString(); + } +} diff --git a/plugins/android/rt/src/org/jetbrains/android/util/AndroidCompilerMessageKind.java b/plugins/android/rt/src/org/jetbrains/android/util/AndroidCompilerMessageKind.java new file mode 100644 index 000000000000..6c8a8cb80c50 --- /dev/null +++ b/plugins/android/rt/src/org/jetbrains/android/util/AndroidCompilerMessageKind.java @@ -0,0 +1,8 @@ +package org.jetbrains.android.util; + +/** + * @author Eugene.Kudelevsky + */ +public enum AndroidCompilerMessageKind { + ERROR, INFORMATION, WARNING +} diff --git a/plugins/android/rt/src/org/jetbrains/android/util/AndroidOSProcessHandler.java b/plugins/android/rt/src/org/jetbrains/android/util/AndroidOSProcessHandler.java new file mode 100644 index 000000000000..1811d0e24fc7 --- /dev/null +++ b/plugins/android/rt/src/org/jetbrains/android/util/AndroidOSProcessHandler.java @@ -0,0 +1,61 @@ +package org.jetbrains.android.util; + +import com.intellij.execution.process.BaseOSProcessHandler; +import com.intellij.execution.process.ProcessOutputTypes; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Eugene.Kudelevsky + */ +public class AndroidOSProcessHandler extends BaseOSProcessHandler { + @NonNls private static final String IGNORING = "ignoring"; + @NonNls private static final String SKIPPING = "skipping"; + + private final List myInfoMessages = new ArrayList(); + private final List myErrorMessages = new ArrayList(); + + public AndroidOSProcessHandler(@NotNull final Process process, @Nullable final String commandLine) { + super(process, commandLine, null); + } + + @Override + public void notifyTextAvailable(String text, Key outputType) { + super.notifyTextAvailable(text, outputType); + + if (StringUtil.isEmptyOrSpaces(text)) { + return; + } + String[] lines = text.split("[\\n\\r]+"); + for (String line : lines) { + String l = line.toLowerCase(); + if (outputType == ProcessOutputTypes.STDOUT) { + myInfoMessages.add(line); + } + else if (outputType == ProcessOutputTypes.STDERR) { + if (l.contains(IGNORING) || l.contains(SKIPPING)) { + myInfoMessages.add(line); + } + else { + myErrorMessages.add(line); + } + } + } + } + + @NotNull + public List getInfoMessages() { + return myInfoMessages; + } + + @NotNull + public List getErrorMessages() { + return myErrorMessages; + } +} diff --git a/plugins/android/rt/src/org/jetbrains/android/util/ExecutionUtil.java b/plugins/android/rt/src/org/jetbrains/android/util/ExecutionUtil.java new file mode 100644 index 000000000000..a65663d4fc76 --- /dev/null +++ b/plugins/android/rt/src/org/jetbrains/android/util/ExecutionUtil.java @@ -0,0 +1,106 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.android.util; + +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Abstract external tool for compiler. + * + * @author Alexey Efimov + */ +public final class ExecutionUtil { + + private ExecutionUtil() { + } + + @NotNull + public static Map> doExecute(String... argv) throws IOException { + ProcessBuilder builder = new ProcessBuilder(argv); + ProcessResult result = readProcessOutput(builder.start()); + Map> messages = result.getMessages(); + int code = result.getExitCode(); + List errMessages = messages.get(AndroidCompilerMessageKind.ERROR); + + if (code != 0 && errMessages.isEmpty()) { + throw new IOException("Command \"" + concat(argv) + "\" execution failed with exit code " + code); + } + else { + if (code == 0) { + messages.get(AndroidCompilerMessageKind.INFORMATION).addAll(errMessages); + errMessages.clear(); + } + return messages; + } + } + + private static String concat(String... strs) { + StringBuilder builder = new StringBuilder(); + for (int i = 0, n = strs.length; i < n; i++) { + builder.append(strs[i]); + if (i < n - 1) { + builder.append(' '); + } + } + return builder.toString(); + } + + @NotNull + private static ProcessResult readProcessOutput(Process process) throws IOException { + final AndroidOSProcessHandler handler = new AndroidOSProcessHandler(process, ""); + handler.startNotify(); + handler.waitFor(); + int exitCode = handler.getProcess().exitValue(); + return new ProcessResult(handler.getInfoMessages(), handler.getErrorMessages(), exitCode); + } + + private static final class ProcessResult { + private final int myExitCode; + private final Map> myMessages; + + public ProcessResult(List information, List error, int exitCode) { + myExitCode = exitCode; + myMessages = new HashMap>(2); + myMessages.put(AndroidCompilerMessageKind.INFORMATION, information); + myMessages.put(AndroidCompilerMessageKind.ERROR, error); + } + + public Map> getMessages() { + return myMessages; + } + + public int getExitCode() { + return myExitCode; + } + } + + public static void addMessages(@NotNull Map> messages, @NotNull Map> toAdd) { + for (Map.Entry> entry : toAdd.entrySet()) { + List list = messages.get(entry.getKey()); + if (list == null) { + list = new ArrayList(); + messages.put(entry.getKey(), list); + } + list.addAll(entry.getValue()); + } + } +} diff --git a/plugins/android/src/org/jetbrains/android/AndroidProjectComponent.java b/plugins/android/src/org/jetbrains/android/AndroidProjectComponent.java index 65bff27a39de..e047daf6bb8b 100644 --- a/plugins/android/src/org/jetbrains/android/AndroidProjectComponent.java +++ b/plugins/android/src/org/jetbrains/android/AndroidProjectComponent.java @@ -19,15 +19,11 @@ import com.intellij.openapi.compiler.CompilerManager; import com.intellij.openapi.components.AbstractProjectComponent; import com.intellij.openapi.project.Project; import org.jetbrains.android.compiler.AndroidPrecompileTask; -import org.jetbrains.annotations.NotNull; /** * @author Eugene.Kudelevsky */ public class AndroidProjectComponent extends AbstractProjectComponent { - private volatile boolean myCompilationRunning = false; - private final Object COMPILATION_FLAG_LOCK = new Object(); - protected AndroidProjectComponent(Project project) { super(project); } @@ -35,26 +31,6 @@ public class AndroidProjectComponent extends AbstractProjectComponent { @Override public void projectOpened() { final CompilerManager manager = CompilerManager.getInstance(myProject); - manager.addBeforeTask(new AndroidPrecompileTask(this)); - } - - public void setCompilationStarted() { - synchronized (COMPILATION_FLAG_LOCK) { - myCompilationRunning = true; - } - } - - public void setCompilationFinished() { - synchronized (COMPILATION_FLAG_LOCK) { - myCompilationRunning = false; - } - } - - public void runIfNotInCompilation(@NotNull Runnable r) { - synchronized (COMPILATION_FLAG_LOCK) { - if (!myCompilationRunning) { - r.run(); - } - } + manager.addBeforeTask(new AndroidPrecompileTask()); } } diff --git a/plugins/android/src/org/jetbrains/android/actions/AndroidRegenerateRJavaFileAction.java b/plugins/android/src/org/jetbrains/android/actions/AndroidRegenerateRJavaFileAction.java index 43597a15b8b3..bce1ab0ace7e 100644 --- a/plugins/android/src/org/jetbrains/android/actions/AndroidRegenerateRJavaFileAction.java +++ b/plugins/android/src/org/jetbrains/android/actions/AndroidRegenerateRJavaFileAction.java @@ -26,6 +26,7 @@ import com.intellij.openapi.compiler.CompilerManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import org.jetbrains.android.compiler.AndroidAptCompiler; +import org.jetbrains.android.compiler.AndroidAutogeneratorMode; import org.jetbrains.android.compiler.AndroidCompileUtil; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.util.AndroidBundle; @@ -96,7 +97,10 @@ public class AndroidRegenerateRJavaFileAction extends AnAction { @Override public boolean execute(CompileContext context) { // todo: compatibility with background autogenerating - AndroidCompileUtil.generate(new AndroidAptCompiler(), context); + + for (Module module : modules) { + AndroidCompileUtil.generate(module, AndroidAutogeneratorMode.AAPT, context); + } return true; } }, new ModuleCompileScope(project, modules, false), AndroidBundle.message("android.compile.messages.generating.r.java.content.name"), diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java index 154a71673ab2..a2f70b19129c 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java @@ -17,19 +17,16 @@ package org.jetbrains.android.compiler; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.SdkConstants; -import com.intellij.compiler.impl.CompilerUtil; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.compiler.*; -import com.intellij.openapi.compiler.ex.CompileContextEx; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.containers.HashMap; +import com.intellij.util.ArrayUtil; import com.intellij.util.containers.HashSet; import org.jetbrains.android.compiler.tools.AndroidApt; import org.jetbrains.android.dom.manifest.Manifest; @@ -39,13 +36,13 @@ import org.jetbrains.android.facet.AndroidRootUtil; import org.jetbrains.android.maven.AndroidMavenUtil; import org.jetbrains.android.sdk.AndroidPlatform; import org.jetbrains.android.util.AndroidBundle; +import org.jetbrains.android.util.AndroidCommonUtils; import org.jetbrains.android.util.AndroidUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.DataInput; import java.io.DataOutput; -import java.io.File; import java.io.IOException; import java.util.*; @@ -58,6 +55,7 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.compiler.AndroidAptCompiler"); private static final GenerationItem[] EMPTY_GENERATION_ITEM_ARRAY = {}; + @Nullable @Override public VirtualFile getPresentableFile(CompileContext context, Module module, VirtualFile outputRoot, VirtualFile generatedFile) { return null; @@ -77,37 +75,15 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { public GenerationItem[] generate(final CompileContext context, final GenerationItem[] items, VirtualFile outputRootDirectory) { if (items != null && items.length > 0) { context.getProgressIndicator().setText(AndroidBundle.message("android.compile.messages.generating.r.java")); - Computable computation = new Computable() { - public GenerationItem[] compute() { - if (context.getProject().isDisposed()) { - return EMPTY_GENERATION_ITEM_ARRAY; - } - return doGenerate(context, items); - } - }; - GenerationItem[] generationItems = computation.compute(); - List generatedVFiles = new ArrayList(); - for (GenerationItem item : generationItems) { - final Set generatedFiles = ((AptGenerationItem)item).myGeneratedFile2Package.keySet(); - for (File generatedFile : generatedFiles) { - CompilerUtil.refreshIOFile(generatedFile); - CompilerUtil.refreshIOFile(generatedFile.getParentFile()); - VirtualFile generatedVFile = LocalFileSystem.getInstance().findFileByIoFile(generatedFile); - if (generatedVFile != null) { - generatedVFiles.add(generatedVFile); - } - } + if (!context.getProject().isDisposed()) { + return doGenerate(context, items, outputRootDirectory); } - if (context instanceof CompileContextEx) { - ((CompileContextEx)context).markGenerated(generatedVFiles); - } - return generationItems; } return EMPTY_GENERATION_ITEM_ARRAY; } - private static GenerationItem[] doGenerate(final CompileContext context, GenerationItem[] items) { + private static GenerationItem[] doGenerate(final CompileContext context, GenerationItem[] items, VirtualFile outputRootDirectory) { List results = new ArrayList(items.length); for (GenerationItem item : items) { if (item instanceof AptGenerationItem) { @@ -117,33 +93,19 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { continue; } + final String outputDirOsPath = FileUtil.toSystemDependentName(outputRootDirectory.getPath()); + try { - Map> messages = AndroidApt.compile(aptItem.myAndroidTarget, aptItem.myPlatformToolsRevision, - aptItem.myManifestFile.getPath(), aptItem.myPackage, - aptItem.mySourceRootPath, aptItem.myResourcesPaths, - aptItem.myLibraryPackages, aptItem.myIsLibrary); + Map> messages = AndroidCompileUtil.toCompilerMessageCategoryKeys( + AndroidApt.compile(aptItem.myAndroidTarget, aptItem.myPlatformToolsRevision, + aptItem.myManifestFile.getPath(), aptItem.myPackage, + outputDirOsPath, aptItem.myResourcesPaths, + aptItem.myLibraryPackages, aptItem.myIsLibrary)); AndroidCompileUtil.addMessages(context, messages); if (messages.get(CompilerMessageCategory.ERROR).isEmpty()) { results.add(aptItem); } - for (Map.Entry entry : aptItem.myGeneratedFile2Package.entrySet()) { - final File generatedFile = entry.getKey(); - final String aPackage = entry.getValue(); - - if (generatedFile.exists()) { - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - if (context.getProject().isDisposed() || aptItem.myModule.isDisposed()) { - return; - } - String className = FileUtil.getNameWithoutExtension(generatedFile); - AndroidCompileUtil.removeDuplicatingClasses(aptItem.myModule, aPackage, className, - generatedFile, aptItem.mySourceRootPath); - } - }); - } - } } catch (final IOException e) { LOG.info(e); @@ -183,22 +145,17 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { final Module myModule; final VirtualFile myManifestFile; final String[] myResourcesPaths; - final String mySourceRootPath; final IAndroidTarget myAndroidTarget; - final Map myGeneratedFile2Package; - final String myPackage; final String[] myLibraryPackages; final boolean myIsLibrary; - private final Set myNonExistingFiles; final int myPlatformToolsRevision; private AptGenerationItem(@NotNull Module module, @NotNull VirtualFile manifestFile, @NotNull String[] resourcesPaths, - @NotNull String sourceRootPath, @NotNull IAndroidTarget target, int platformToolsRevision, @NotNull String aPackage, @@ -207,55 +164,19 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { myModule = module; myManifestFile = manifestFile; myResourcesPaths = resourcesPaths; - mySourceRootPath = sourceRootPath; myAndroidTarget = target; myPackage = aPackage; myLibraryPackages = libPackages; myIsLibrary = isLibrary; myPlatformToolsRevision = platformToolsRevision; - - myGeneratedFile2Package = new HashMap(); - - myGeneratedFile2Package.put( - new File(sourceRootPath, aPackage.replace('.', File.separatorChar) + File.separator + AndroidUtils.R_JAVA_FILENAME), aPackage); - - for (String libPackage : myLibraryPackages) { - myGeneratedFile2Package - .put(new File(sourceRootPath, libPackage.replace('.', File.separatorChar) + File.separator + AndroidUtils.R_JAVA_FILENAME), - libPackage); - } - - myNonExistingFiles = new HashSet(); - - // We need to check only R.java files, not Manifest.java files, so add Manifest files LATER - for (File generatedFile : myGeneratedFile2Package.keySet()) { - if (!generatedFile.exists()) { - myNonExistingFiles.add(FileUtil.toSystemIndependentName(generatedFile.getPath())); - } - } - - myGeneratedFile2Package.put( - new File(sourceRootPath, aPackage.replace('.', File.separatorChar) + File.separator + AndroidUtils.MANIFEST_JAVA_FILE_NAME), - aPackage); - - for (String libraryPackage : myLibraryPackages) { - myGeneratedFile2Package.put( - new File(sourceRootPath, libraryPackage.replace('.', File.separatorChar) + File.separator + AndroidUtils.MANIFEST_JAVA_FILE_NAME), - libraryPackage); - } - } - - @NotNull - public Map getGeneratedFiles() { - return myGeneratedFile2Package; } public String getPath() { - return myPackage.replace('.', '/') + '/' + AndroidUtils.R_JAVA_FILENAME; + return myPackage.replace('.', '/') + '/' + AndroidCommonUtils.R_JAVA_FILENAME; } public ValidityState getValidityState() { - return new MyValidityState(myModule, myNonExistingFiles, myPlatformToolsRevision); + return new MyValidityState(myModule, Collections.emptySet(), myPlatformToolsRevision); } public Module getModule() { @@ -265,11 +186,6 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { public boolean isTestSource() { return false; } - - @NotNull - public String getPackageFolderPath() { - return FileUtil.toSystemDependentName(mySourceRootPath + '/' + myPackage.replace('.', '/')); - } } @Nullable @@ -338,13 +254,14 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { String sourceRootPath = facet.getAptGenSourceRootPath(); if (sourceRootPath == null) { myContext.addMessage(CompilerMessageCategory.ERROR, - AndroidBundle.message("android.compilation.error.apt.gen.not.specified", module.getName()), null, -1, -1); + AndroidBundle.message("android.compilation.error.apt.gen.not.specified", module.getName()), + null, -1, -1); continue; } final String[] libPackages = getLibPackages(module, packageName); - items.add(new AptGenerationItem(module, manifestFile, resPaths, sourceRootPath, target, platformToolsRevision, + items.add(new AptGenerationItem(module, manifestFile, resPaths, target, platformToolsRevision, packageName, libPackages, facet.getConfiguration().LIBRARY_PROJECT)); } } @@ -364,7 +281,7 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { } } - return result.toArray(new String[result.size()]); + return ArrayUtil.toStringArray(result); } } diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogenerator.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogenerator.java new file mode 100644 index 000000000000..5121f6a31a6f --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogenerator.java @@ -0,0 +1,628 @@ +package org.jetbrains.android.compiler; + +import com.android.AndroidConstants; +import com.android.sdklib.IAndroidTarget; +import com.intellij.compiler.impl.CompilerUtil; +import com.intellij.compiler.impl.ModuleCompileScope; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.compiler.CompileContext; +import com.intellij.openapi.compiler.CompilerMessageCategory; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.*; +import com.intellij.psi.search.FilenameIndex; +import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.HashMap; +import com.intellij.util.containers.HashSet; +import org.jetbrains.android.compiler.tools.AndroidApt; +import org.jetbrains.android.compiler.tools.AndroidIdl; +import org.jetbrains.android.dom.manifest.Manifest; +import org.jetbrains.android.facet.AndroidFacet; +import org.jetbrains.android.facet.AndroidRootUtil; +import org.jetbrains.android.fileTypes.AndroidIdlFileType; +import org.jetbrains.android.fileTypes.AndroidRenderscriptFileType; +import org.jetbrains.android.sdk.AndroidPlatform; +import org.jetbrains.android.util.AndroidBundle; +import org.jetbrains.android.util.AndroidCommonUtils; +import org.jetbrains.android.util.AndroidCompilerMessageKind; +import org.jetbrains.android.util.AndroidUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.io.IOException; +import java.util.*; + +/** + * @author Eugene.Kudelevsky + */ +public class AndroidAutogenerator { + private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.compiler.AndroidAutogenerator"); + + private AndroidAutogenerator() { + } + + public static void run(@NotNull AndroidAutogeneratorMode mode, @NotNull AndroidFacet facet, @NotNull CompileContext context) { + final Set obsoleteFiles = new HashSet(facet.getAutogeneratedFiles(mode)); + + switch (mode) { + case AAPT: + runAapt(facet, context); + break; + case AIDL: + runAidl(facet, context); + break; + case RENDERSCRIPT: + runRenderscript(facet, context); + break; + default: + LOG.error("Unknown mode" + mode); + } + obsoleteFiles.removeAll(facet.getAutogeneratedFiles(mode)); + + for (String path : obsoleteFiles) { + final File file = new File(path); + + if (file.isFile()) { + FileUtil.delete(file); + CompilerUtil.refreshIOFile(file); + } + } + } + + private static void runAapt(@NotNull final AndroidFacet facet, @NotNull final CompileContext context) { + final Module module = facet.getModule(); + + final AptAutogenerationItem item = ApplicationManager.getApplication().runReadAction(new Computable() { + @Nullable + @Override + public AptAutogenerationItem compute() { + if (module.isDisposed() || module.getProject().isDisposed()) { + return null; + } + + final AndroidPlatform platform = facet.getConfiguration().getAndroidPlatform(); + if (platform == null) { + context.addMessage(CompilerMessageCategory.ERROR, + AndroidBundle.message("android.compilation.error.specify.platform", module.getName()), null, -1, -1); + return null; + } + + final IAndroidTarget target = platform.getTarget(); + final int platformToolsRevision = platform.getSdk().getPlatformToolsRevision(); + final String[] resPaths = AndroidCompileUtil.collectResourceDirs(facet, false, context); + + if (resPaths.length == 0) { + return null; + } + + final VirtualFile manifestFile = AndroidRootUtil.getManifestFileForCompiler(facet); + if (manifestFile == null) { + context.addMessage(CompilerMessageCategory.ERROR, AndroidBundle.message("android.compilation.error.manifest.not.found"), + null, -1, -1); + return null; + } + + final Manifest manifest = AndroidUtils.loadDomElement(module, manifestFile, Manifest.class); + if (manifest == null) { + context.addMessage(CompilerMessageCategory.ERROR, "Cannot parse file", manifestFile.getUrl(), -1, -1); + return null; + } + + String packageName = manifest.getPackage().getValue(); + if (packageName != null) { + packageName = packageName.trim(); + } + + if (packageName == null || packageName.length() <= 0) { + context.addMessage(CompilerMessageCategory.ERROR, AndroidBundle.message("package.not.found.error"), manifestFile.getUrl(), + -1, -1); + return null; + } + + final String sourceRootPath = facet.getAptGenSourceRootPath(); + if (sourceRootPath == null) { + context.addMessage(CompilerMessageCategory.ERROR, + AndroidBundle.message("android.compilation.error.apt.gen.not.specified", module.getName()), + null, -1, -1); + return null; + } + + final Map genFilePath2Package = new HashMap(); + + final String packageDir = packageName.replace('.', '/') + '/'; + genFilePath2Package.put(packageDir + AndroidCommonUtils.MANIFEST_JAVA_FILE_NAME, packageName); + genFilePath2Package.put(packageDir + AndroidCommonUtils.R_JAVA_FILENAME, packageName); + + final String manifestFileOsPath = FileUtil.toSystemDependentName(manifestFile.getPath()); + + return new AptAutogenerationItem(target, platformToolsRevision, manifestFileOsPath, packageName, sourceRootPath, resPaths, + facet.getConfiguration().LIBRARY_PROJECT, genFilePath2Package); + } + }); + + if (item == null) { + return; + } + + final Set filesToCheck = new HashSet(); + + for (String genFileRelPath : item.myGenFileRelPath2package.keySet()) { + final String genFileFullPath = item.myOutputDirOsPath + '/' + genFileRelPath; + + if (new File(genFileFullPath).exists()) { + final VirtualFile genFile = LocalFileSystem.getInstance().findFileByPath(genFileFullPath); + + if (genFile != null) { + filesToCheck.add(genFile); + } + } + } + + if (!ensureFilesWritable(module.getProject(), filesToCheck)) { + return; + } + + File tempOutDir = null; + + try { + // Aapt generation can be very long, so we generate it in temp directory first + tempOutDir = FileUtil.createTempDirectory("android_apt_autogeneration", "tmp"); + + final Map> messages = + AndroidApt.compile(item.myTarget, item.myPlatformToolsRevision, item.myManifestFileOsPath, item.myPackage, + tempOutDir.getPath(), item.myResDirOsPaths, ArrayUtil.EMPTY_STRING_ARRAY, item.myLibrary); + + if (messages.get(AndroidCompilerMessageKind.ERROR).size() == 0) { + for (String genFileRelPath : item.myGenFileRelPath2package.keySet()) { + final File srcFile = new File(tempOutDir.getPath() + '/' + genFileRelPath); + + if (srcFile.isFile()) { + final File dstFile = new File(item.myOutputDirOsPath + '/' + genFileRelPath); + + if (dstFile.exists()) { + if (!FileUtil.delete(dstFile)) { + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + if (module.isDisposed() || module.getProject().isDisposed()) { + return; + } + context.addMessage(CompilerMessageCategory.ERROR, + "Cannot delete " + FileUtil.toSystemDependentName(dstFile.getPath()), null, -1, -1); + } + }); + } + } + FileUtil.rename(srcFile, dstFile); + } + } + } + AndroidCompileUtil.addMessages(context, AndroidCompileUtil.toCompilerMessageCategoryKeys(messages)); + + for (Map.Entry entry : item.myGenFileRelPath2package.entrySet()) { + final String path = item.myOutputDirOsPath + '/' + entry.getKey(); + final String aPackage = entry.getValue(); + final File file = new File(path); + CompilerUtil.refreshIOFile(file); + + removeAllFilesWithSameName(module, file, item.myOutputDirOsPath); + removeDuplicateClasses(module, aPackage, file, item.myOutputDirOsPath); + } + + final VirtualFile genSourceRoot = LocalFileSystem.getInstance().findFileByPath(item.myOutputDirOsPath); + if (genSourceRoot != null) { + genSourceRoot.refresh(false, true); + } + + if (messages.get(AndroidCompilerMessageKind.ERROR).size() == 0) { + facet.clearAutogeneratedFiles(AndroidAutogeneratorMode.AAPT); + + for (String relPath : item.myGenFileRelPath2package.keySet()) { + final VirtualFile genFile = LocalFileSystem.getInstance().findFileByPath(item.myOutputDirOsPath + '/' + relPath); + + if (genFile != null && genFile.exists()) { + facet.markFileAutogenerated(AndroidAutogeneratorMode.AAPT, genFile); + } + } + } + } + catch (final IOException e) { + LOG.info(e); + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + if (module.getProject().isDisposed()) return; + context.addMessage(CompilerMessageCategory.ERROR, "I/O error: " + e.getMessage(), null, -1, -1); + } + }); + } + finally { + if (tempOutDir != null) { + FileUtil.delete(tempOutDir); + } + } + } + + private static void removeAllFilesWithSameName(@NotNull final Module module, @NotNull File file, @NotNull String directoryPath) { + final VirtualFile vFile = LocalFileSystem.getInstance().findFileByIoFile(file); + final VirtualFile genDir = LocalFileSystem.getInstance().findFileByPath(directoryPath); + + if (vFile == null || genDir == null) { + return; + } + final Collection files = + FilenameIndex.getVirtualFilesByName(module.getProject(), file.getName(), module.getModuleScope(false)); + + final List filesToDelete = new ArrayList(); + + for (final VirtualFile f : files) { + if (f != vFile && VfsUtilCore.isAncestor(genDir, f, true)) { + filesToDelete.add(f); + } + } + + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + for (VirtualFile f : filesToDelete) { + if (f.isValid() && f.exists()) { + try { + f.delete(module.getProject()); + } + catch (IOException e) { + LOG.error(e); + } + } + } + } + }); + } + }); + } + + private static void runAidl(@NotNull final AndroidFacet facet, @NotNull final CompileContext context) { + final Module module = facet.getModule(); + final ModuleCompileScope moduleCompileScope = new ModuleCompileScope(module, false); + final VirtualFile[] files = moduleCompileScope.getFiles(AndroidIdlFileType.ourFileType, true); + final List items = new ArrayList(); + + for (final VirtualFile file : files) { + final IdlAutogenerationItem item = ApplicationManager.getApplication().runReadAction(new Computable() { + @Nullable + @Override + public IdlAutogenerationItem compute() { + if (module.isDisposed() || module.getProject().isDisposed()) { + return null; + } + + final IAndroidTarget target = facet.getConfiguration().getAndroidTarget(); + if (target == null) { + context.addMessage(CompilerMessageCategory.ERROR, + AndroidBundle.message("android.compilation.error.specify.platform", module.getName()), null, -1, -1); + return null; + } + + final String packageName = AndroidUtils.getPackageName(module, file); + if (packageName == null) { + context.addMessage(CompilerMessageCategory.ERROR, "Cannot compute package for file", file.getUrl(), -1, -1); + return null; + } + + final String sourceRootPath = facet.getAidlGenSourceRootPath(); + if (sourceRootPath == null) { + context.addMessage(CompilerMessageCategory.ERROR, + AndroidBundle.message("android.compilation.error.apt.gen.not.specified", module.getName()), null, -1, -1); + return null; + } + + final VirtualFile[] sourceRoots = AndroidPackagingCompiler.getSourceRootsForModuleAndDependencies(module, false); + final String[] sourceRootOsPaths = AndroidCompileUtil.toOsPaths(sourceRoots); + + final String outFileOsPath = FileUtil.toSystemDependentName( + sourceRootPath + '/' + packageName.replace('.', '/') + '/' + file.getNameWithoutExtension() + ".java"); + + return new IdlAutogenerationItem(file, target, outFileOsPath, sourceRootOsPaths, sourceRootPath, packageName); + } + }); + + if (item != null) { + items.add(item); + } + } + + final Set filesToCheck = new HashSet(); + + for (IdlAutogenerationItem item : items) { + if (new File(FileUtil.toSystemDependentName(item.myFile.getPath())).exists()) { + filesToCheck.add(item.myFile); + } + } + + if (!ensureFilesWritable(module.getProject(), filesToCheck)) { + return; + } + + facet.clearAutogeneratedFiles(AndroidAutogeneratorMode.AIDL); + + for (IdlAutogenerationItem item : items) { + final VirtualFile file = item.myFile; + final String fileOsPath = FileUtil.toSystemDependentName(file.getPath()); + + try { + final Map> messages = AndroidCompileUtil.toCompilerMessageCategoryKeys( + AndroidIdl.execute(item.myTarget, fileOsPath, item.myOutFileOsPath, item.mySourceRootOsPaths)); + + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + if (module.getProject().isDisposed()) return; + + for (CompilerMessageCategory category : messages.keySet()) { + List messageList = messages.get(category); + for (String message : messageList) { + context.addMessage(category, message, file.getUrl(), -1, -1); + } + } + } + }); + + removeDuplicateClasses(module, item.myPackage, new File(item.myOutFileOsPath), item.myOutDirOsPath); + + final VirtualFile genDir = LocalFileSystem.getInstance().findFileByPath(item.myOutDirOsPath); + if (genDir != null) { + genDir.refresh(false, true); + } + + final VirtualFile outFile = LocalFileSystem.getInstance().findFileByPath(item.myOutFileOsPath); + if (outFile != null && outFile.exists()) { + facet.markFileAutogenerated(AndroidAutogeneratorMode.AIDL, outFile); + } + } + catch (final IOException e) { + LOG.info(e); + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + if (module.getProject().isDisposed()) return; + context.addMessage(CompilerMessageCategory.ERROR, e.getMessage(), file.getUrl(), -1, -1); + } + }); + } + } + } + + private static void runRenderscript(@NotNull final AndroidFacet facet, @NotNull final CompileContext context) { + final Module module = facet.getModule(); + + final ModuleCompileScope moduleCompileScope = new ModuleCompileScope(module, false); + final VirtualFile[] files = moduleCompileScope.getFiles(AndroidRenderscriptFileType.INSTANCE, true); + + facet.clearAutogeneratedFiles(AndroidAutogeneratorMode.RENDERSCRIPT); + + for (final VirtualFile file : files) { + final RenderscriptAutogenerationItem item = + ApplicationManager.getApplication().runReadAction(new Computable() { + @Nullable + @Override + public RenderscriptAutogenerationItem compute() { + final AndroidPlatform platform = facet.getConfiguration().getAndroidPlatform(); + if (platform == null) { + context.addMessage(CompilerMessageCategory.ERROR, + AndroidBundle.message("android.compilation.error.specify.platform", module.getName()), null, -1, -1); + return null; + } + + final IAndroidTarget target = platform.getTarget(); + final String sdkLocation = platform.getSdk().getLocation(); + + final String packageName = AndroidUtils.getPackageName(module, file); + if (packageName == null) { + context.addMessage(CompilerMessageCategory.ERROR, "Cannot compute package for file", file.getUrl(), -1, -1); + return null; + } + + final String resourceDirPath = AndroidRootUtil.getResourceDirPath(facet); + assert resourceDirPath != null; + + final String sourceRootPath = AndroidRootUtil.getRenderscriptGenSourceRootPath(module); + if (sourceRootPath == null) { + return null; + } + + final String rawDirPath = resourceDirPath + '/' + AndroidConstants.FD_RES_RAW; + + return new RenderscriptAutogenerationItem(sdkLocation, target, sourceRootPath, rawDirPath); + } + }); + + if (item == null) { + continue; + } + + File tempOutDir = null; + + try { + tempOutDir = FileUtil.createTempDirectory("android_renderscript_autogeneration", "tmp"); + + final Map> messages = AndroidRenderscriptCompiler. + launchRenderscriptCompiler(module.getProject(), item.mySdkLocation, item.myTarget, file, tempOutDir.getPath(), item.myRawDirPath); + + if (messages.get(CompilerMessageCategory.ERROR).size() == 0) { + final List newFiles = new ArrayList(); + moveAllFiles(tempOutDir, new File(item.myGenDirPath), newFiles); + + for (File newFile : newFiles) { + final VirtualFile newVFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(newFile); + + if (newVFile != null) { + facet.markFileAutogenerated(AndroidAutogeneratorMode.RENDERSCRIPT, newVFile); + } + } + } + + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + if (module.getProject().isDisposed()) { + return; + } + + for (final CompilerMessageCategory category : messages.keySet()) { + final List messageList = messages.get(category); + for (final String message : messageList) { + context.addMessage(category, message, file.getUrl(), -1, -1); + } + } + } + }); + + final VirtualFile genDir = LocalFileSystem.getInstance().findFileByPath(item.myGenDirPath); + if (genDir != null) { + genDir.refresh(false, true); + } + } + catch (final IOException e) { + LOG.info(e); + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + if (module.getProject().isDisposed()) return; + context.addMessage(CompilerMessageCategory.ERROR, e.getMessage(), file.getUrl(), -1, -1); + } + }); + } + finally { + if (tempOutDir != null) { + FileUtil.delete(tempOutDir); + } + } + } + } + + private static void moveAllFiles(@NotNull File from, @NotNull File to, @NotNull Collection newFiles) throws IOException { + if (from.isFile()) { + FileUtil.rename(from, to); + newFiles.add(to); + } + else { + final File[] children = from.listFiles(); + + if (children != null) { + for (File child : children) { + moveAllFiles(child, new File(to, child.getName()), newFiles); + } + } + } + } + + private static boolean ensureFilesWritable(@NotNull final Project project, @NotNull final Collection filesToCheck) { + if (filesToCheck.size() == 0) { + return true; + } + final boolean[] run = {false}; + + ApplicationManager.getApplication().invokeAndWait(new Runnable() { + @Override + public void run() { + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + run[0] = !project.isDisposed() && + ReadonlyStatusHandler.ensureFilesWritable(project, filesToCheck.toArray(new VirtualFile[filesToCheck.size()])); + } + }); + } + }, ModalityState.defaultModalityState()); + + return run[0]; + } + + private static void removeDuplicateClasses(@NotNull final Module module, + @NotNull final String aPackage, + @NotNull final File generatedFile, + @NotNull final String sourceRootPath) { + if (generatedFile.exists()) { + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + if (module.getProject().isDisposed() || module.isDisposed()) { + return; + } + String className = FileUtil.getNameWithoutExtension(generatedFile); + AndroidCompileUtil.removeDuplicatingClasses(module, aPackage, className, generatedFile, sourceRootPath); + } + }); + } + } + + private static class AptAutogenerationItem { + final IAndroidTarget myTarget; + final int myPlatformToolsRevision; + final String myManifestFileOsPath; + final String myPackage; + final String myOutputDirOsPath; + final String[] myResDirOsPaths; + final boolean myLibrary; + final Map myGenFileRelPath2package; + + private AptAutogenerationItem(@NotNull IAndroidTarget target, + int platformToolsRevision, + @NotNull String manifestFileOsPath, + @NotNull String aPackage, + @NotNull String outputDirOsPath, + @NotNull String[] resDirOsPaths, + boolean library, + @NotNull Map genFileRelPath2package) { + myTarget = target; + myPlatformToolsRevision = platformToolsRevision; + myManifestFileOsPath = manifestFileOsPath; + myPackage = aPackage; + myOutputDirOsPath = outputDirOsPath; + myResDirOsPaths = resDirOsPaths; + myLibrary = library; + myGenFileRelPath2package = genFileRelPath2package; + } + } + + private static class IdlAutogenerationItem { + final VirtualFile myFile; + final IAndroidTarget myTarget; + final String myOutFileOsPath; + final String[] mySourceRootOsPaths; + final String myOutDirOsPath; + final String myPackage; + + private IdlAutogenerationItem(@NotNull VirtualFile file, + @NotNull IAndroidTarget target, + @NotNull String outFileOsPath, + @NotNull String[] sourceRootOsPaths, + @NotNull String outDirOsPath, + @NotNull String aPackage) { + myFile = file; + myTarget = target; + myOutFileOsPath = outFileOsPath; + mySourceRootOsPaths = sourceRootOsPaths; + myOutDirOsPath = outDirOsPath; + myPackage = aPackage; + } + } + + private static class RenderscriptAutogenerationItem { + final String mySdkLocation; + final IAndroidTarget myTarget; + final String myGenDirPath; + final String myRawDirPath; + + private RenderscriptAutogenerationItem(@NotNull String sdkLocation, + @NotNull IAndroidTarget target, + @NotNull String genDirPath, + @NotNull String rawDirPath) { + mySdkLocation = sdkLocation; + myTarget = target; + myGenDirPath = genDirPath; + myRawDirPath = rawDirPath; + } + } +} diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogeneratorMode.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogeneratorMode.java new file mode 100644 index 000000000000..7b8852e674a0 --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogeneratorMode.java @@ -0,0 +1,8 @@ +package org.jetbrains.android.compiler; + +/** + * @author Eugene.Kudelevsky + */ +public enum AndroidAutogeneratorMode { + AAPT, AIDL, RENDERSCRIPT +} diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java index 90a34eef8812..039ff5c9768f 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java @@ -17,6 +17,8 @@ package org.jetbrains.android.compiler; import com.android.resources.ResourceType; import com.intellij.CommonBundle; +import com.intellij.compiler.CompilerConfiguration; +import com.intellij.compiler.CompilerConfigurationImpl; import com.intellij.compiler.impl.CompileContextImpl; import com.intellij.compiler.impl.ModuleCompileScope; import com.intellij.compiler.options.CompileStepBeforeRun; @@ -27,6 +29,8 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.compiler.*; import com.intellij.openapi.compiler.Compiler; +import com.intellij.openapi.compiler.options.ExcludeEntryDescription; +import com.intellij.openapi.compiler.options.ExcludedEntriesConfiguration; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.Module; @@ -35,7 +39,6 @@ import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.*; import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; @@ -46,8 +49,8 @@ import com.intellij.psi.PsiFile; import com.intellij.psi.search.FileTypeIndex; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashSet; -import org.jetbrains.android.AndroidProjectComponent; import org.jetbrains.android.dom.resources.Attr; import org.jetbrains.android.dom.resources.DeclareStyleable; import org.jetbrains.android.dom.resources.ResourceElement; @@ -58,7 +61,9 @@ import org.jetbrains.android.fileTypes.AndroidIdlFileType; import org.jetbrains.android.fileTypes.AndroidRenderscriptFileType; import org.jetbrains.android.resourceManagers.LocalResourceManager; import org.jetbrains.android.sdk.AndroidPlatform; +import org.jetbrains.android.util.AndroidCompilerMessageKind; import org.jetbrains.android.util.AndroidUtils; +import org.jetbrains.android.util.ExecutionUtil; import org.jetbrains.android.util.ResourceEntry; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -77,16 +82,16 @@ import java.util.regex.Pattern; public class AndroidCompileUtil { private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.compiler.AndroidCompileUtil"); private static Pattern R_PATTERN = Pattern.compile("R(\\$.*)?\\.class"); - + private static final Pattern ourMessagePattern = Pattern.compile("(.+):(\\d+):.+"); private static final Key RELEASE_BUILD_KEY = new Key("RELEASE_BUILD_KEY"); @NonNls private static final String RESOURCES_CACHE_DIR_NAME = "res-cache"; @NonNls private static final String GEN_MODULE_PREFIX = "~generated_"; - + @NonNls private static final String PROGUARD_CFG_FILE_NAME = "proguard.cfg"; @NonNls public static final String CLASSES_JAR_FILE_NAME = "classes.jar"; - + @NonNls private static final String[] SCALA_TEST_CONFIGURATIONS = {"ScalaTestRunConfiguration", "SpecsRunConfiguration", "Specs2RunConfiguration"}; @@ -94,6 +99,29 @@ public class AndroidCompileUtil { private AndroidCompileUtil() { } + @NotNull + public static Map toCompilerMessageCategoryKeys(@NotNull Map map) { + final Map result = new HashMap(); + + for (Map.Entry entry : map.entrySet()) { + final AndroidCompilerMessageKind key = entry.getKey(); + final T value = entry.getValue(); + + switch (key) { + case ERROR: + result.put(CompilerMessageCategory.ERROR, value); + break; + case INFORMATION: + result.put(CompilerMessageCategory.INFORMATION, value); + break; + case WARNING: + result.put(CompilerMessageCategory.WARNING, value); + break; + } + } + return result; + } + @Nullable public static VirtualFile getProguardConfigFile(@NotNull AndroidFacet facet) { final VirtualFile root = AndroidRootUtil.getMainContentRoot(facet); @@ -166,7 +194,7 @@ public class AndroidCompileUtil { if (root == anchor) { return; } - + VirtualFile parent = anchor.getParent(); if (parent == null) { return; @@ -191,7 +219,7 @@ public class AndroidCompileUtil { return; } Set rootsToExclude = new HashSet(); - collectChildrenRecursively(excludedRoot, root, rootsToExclude); + collectChildrenRecursively(excludedRoot, root, rootsToExclude); final ModifiableRootModel model = manager.getModifiableModel(); ContentEntry contentEntry = findContentEntryForRoot(model, excludedRoot); if (contentEntry != null) { @@ -218,7 +246,7 @@ public class AndroidCompileUtil { } }); } - + @NotNull private static String getGenModuleName(@NotNull Module module) { return GEN_MODULE_PREFIX + module.getName(); @@ -259,17 +287,40 @@ public class AndroidCompileUtil { if (root != null) { final ModuleRootManager manager = ModuleRootManager.getInstance(module); unexcludeRootIfNeccessary(root, manager); + + boolean markedAsSource = false; + for (VirtualFile existingRoot : manager.getSourceRoots()) { - if (existingRoot == root) return; - } - ApplicationManager.getApplication().runWriteAction(new Runnable() { - public void run() { - addSourceRoot(manager, root); + if (existingRoot == root) { + markedAsSource = true; } - }); + } + + if (!markedAsSource) { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + addSourceRoot(manager, root); + } + }); + } + + excludeFromCompilation(project, root); } } + private static void excludeFromCompilation(@NotNull Project project, @NotNull VirtualFile dir) { + final ExcludedEntriesConfiguration configuration = + ((CompilerConfigurationImpl)CompilerConfiguration.getInstance(project)).getExcludedEntriesConfiguration(); + + for (ExcludeEntryDescription description : configuration.getExcludeEntryDescriptions()) { + if (description.getVirtualFile() == dir) { + return; + } + } + + configuration.addExcludeEntryDescription(new ExcludeEntryDescription(dir, true, false, project)); + } + private static void removeGenModule(@NotNull final Module libModule) { final String genModuleName = getGenModuleName(libModule); final ModuleManager moduleManager = ModuleManager.getInstance(libModule.getProject()); @@ -295,7 +346,7 @@ public class AndroidCompileUtil { } final VirtualFile moduleFile = genModule.getModuleFile(); moduleManager.disposeModule(genModule); - + if (moduleFile != null) { ApplicationManager.getApplication().invokeLater(new Runnable() { @Override @@ -338,132 +389,70 @@ public class AndroidCompileUtil { return contentEntry; } - public static void generate(final Module module, final GeneratingCompiler compiler, boolean withDependentModules) { + public static void generate(final Module module, final AndroidAutogeneratorMode mode, boolean withDependentModules) { if (withDependentModules) { Set modules = new HashSet(); collectModules(module, modules, ModuleManager.getInstance(module.getProject()).getModules()); for (Module module1 : modules) { - generate(module1, compiler); + generate(module1, mode); } } else { - generate(module, compiler); + generate(module, mode); } } - public static void generate(final Module module, final GeneratingCompiler compiler) { + public static void generate(final Module module, final AndroidAutogeneratorMode mode) { final AndroidFacet facet = AndroidFacet.getInstance(module); if (facet != null) { - facet.scheduleSourceRegenerating(compiler); + facet.scheduleSourceRegenerating(mode); } } - public static void doGenerate(final Module module, final GeneratingCompiler compiler) { + public static boolean doGenerate(final Module module, final AndroidAutogeneratorMode mode) { final Project project = module.getProject(); - final AndroidProjectComponent component = ApplicationManager.getApplication().runReadAction(new Computable() { - @Nullable - @Override - public AndroidProjectComponent compute() { - return !project.isDisposed() ? project.getComponent(AndroidProjectComponent.class) : null; - } - }); - if (component == null) { - return; - } - component.runIfNotInCompilation(new Runnable() { - @Override + assert !ApplicationManager.getApplication().isDispatchThread(); + final CompileContext[] contextWrapper = new CompileContext[1]; + + ApplicationManager.getApplication().runReadAction(new Runnable() { public void run() { - assert !ApplicationManager.getApplication().isDispatchThread(); - final CompileContext[] contextWrapper = new CompileContext[1]; - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - if (project.isDisposed()) return; - CompilerTask task = new CompilerTask(project, true, "Android auto-generation", true); - CompileScope scope = new ModuleCompileScope(module, false); - contextWrapper[0] = new CompileContextImpl(project, task, scope, null, false, false); - } - }); - generate(compiler, contextWrapper[0]); + if (project.isDisposed()) return; + CompilerTask task = new CompilerTask(project, true, "Android auto-generation", true); + CompileScope scope = new ModuleCompileScope(module, false); + contextWrapper[0] = new CompileContextImpl(project, task, scope, null, false, false); } }); + generate(module, mode, contextWrapper[0]); + + return contextWrapper[0].getMessages(CompilerMessageCategory.ERROR).length == 0; } public static boolean isModuleAffected(CompileContext context, Module module) { return ArrayUtil.find(context.getCompileScope().getAffectedModules(), module) >= 0; } - public static void generate(GeneratingCompiler compiler, final CompileContext context) { + public static void generate(final Module module, AndroidAutogeneratorMode mode, final CompileContext context) { if (context == null) { return; } - - final Set affectedModules = new HashSet(); - Collections.addAll(affectedModules, context.getCompileScope().getAffectedModules()); - + + final AndroidFacet facet = AndroidFacet.getInstance(module); + if (facet == null) { + return; + } + ApplicationManager.getApplication().invokeAndWait(new Runnable() { @Override public void run() { - for (Module module : affectedModules) { - if (module.isDisposed() || module.getProject().isDisposed()) { - continue; - } - - final AndroidFacet facet = AndroidFacet.getInstance(module); - if (facet != null) { - AndroidCompileUtil.createGenModulesAndSourceRoots(facet); - } + if (facet.getModule().isDisposed() || facet.getModule().getProject().isDisposed()) { + return; } + AndroidCompileUtil.createGenModulesAndSourceRoots(facet); } }, ModalityState.defaultModalityState()); - - List itemsToGenerate = new ArrayList(); - for (GeneratingCompiler.GenerationItem item : compiler.getGenerationItems(context)) { - if (affectedModules.contains(item.getModule())) { - itemsToGenerate.add(item); - } - } - GeneratingCompiler.GenerationItem[] items = itemsToGenerate.toArray(new GeneratingCompiler.GenerationItem[itemsToGenerate.size()]); - - final boolean[] run = {true}; - final VirtualFile[] files = getFilesToCheckReadonlyStatus(items); - if (files.length > 0) { - ApplicationManager.getApplication().invokeAndWait(new Runnable() { - @Override - public void run() { - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - final Project project = context.getProject(); - run[0] = !project.isDisposed() && ReadonlyStatusHandler.ensureFilesWritable(project, files); - } - }); - } - }, ModalityState.defaultModalityState()); - } - - if (run[0]) { - compiler.generate(context, items, null); - } - } - - private static VirtualFile[] getFilesToCheckReadonlyStatus(GeneratingCompiler.GenerationItem[] items) { - List filesToCheck = new ArrayList(); - for (GeneratingCompiler.GenerationItem item : items) { - if (item instanceof AndroidAptCompiler.AptGenerationItem) { - final Set generatedFiles = ((AndroidAptCompiler.AptGenerationItem)item).getGeneratedFiles().keySet(); - for (File generatedFile : generatedFiles) { - if (generatedFile.exists()) { - VirtualFile generatedVFile = LocalFileSystem.getInstance().findFileByIoFile(generatedFile); - if (generatedVFile != null) { - filesToCheck.add(generatedVFile); - } - } - } - } - } - return VfsUtil.toVirtualFileArray(filesToCheck); + AndroidAutogenerator.run(mode, facet, context); } private static void collectModules(Module module, Set result, Module[] allModules) { @@ -530,15 +519,15 @@ public class AndroidCompileUtil { final Project project = facet.getModule().getProject(); final IntermediateOutputCompiler pngFilesCachingCompiler = collectResCacheDirs ? Extensions.findExtension(Compiler.EP_NAME, project, AndroidPngFilesCachingCompiler.class) : null; - + if (collectResCacheDirs) { assert pngFilesCachingCompiler != null; } - + final List result = new ArrayList(); doCollectResourceDirs(facet, collectResCacheDirs, result, context); - + for (AndroidFacet depFacet : AndroidUtils.getAllAndroidDependencies(facet.getModule(), true)) { doCollectResourceDirs(depFacet, collectResCacheDirs, result, context); } @@ -623,11 +612,11 @@ public class AndroidCompileUtil { public static boolean isFullBuild(@NotNull CompileContext context) { final RunConfiguration runConfiguration = CompileStepBeforeRun.getRunConfiguration(context); - + if (runConfiguration == null) { return true; } - + if (runConfiguration instanceof JUnitConfiguration) { return false; } @@ -802,7 +791,7 @@ public class AndroidCompileUtil { boolean packRClasses, @NotNull List> files) throws IOException { - + if (file.isDirectory()) { final File[] children = file.listFiles(); @@ -816,13 +805,13 @@ public class AndroidCompileUtil { if (!FileUtil.getExtension(file.getName()).equals("class")) { return; } - + if (!packRClasses && R_PATTERN.matcher(file.getName()).matches()) { return; } final String rootPath = rootDirectory.getAbsolutePath(); - + String path = file.getAbsolutePath(); path = FileUtil.toSystemIndependentName(path.substring(rootPath.length())); if (path.charAt(0) == '/') { @@ -861,4 +850,12 @@ public class AndroidCompileUtil { } return classFilesDirOsPaths; } + + // can't be invoked from dispatch thread + @NotNull + public static Map> execute(String... argv) throws IOException { + assert !ApplicationManager.getApplication().isDispatchThread(); + final Map> messages = ExecutionUtil.doExecute(argv); + return toCompilerMessageCategoryKeys(messages); + } } \ No newline at end of file diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidIdlCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidIdlCompiler.java index dddc60b173d4..0c74c8766383 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidIdlCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidIdlCompiler.java @@ -17,18 +17,15 @@ package org.jetbrains.android.compiler; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.SdkConstants; -import com.intellij.compiler.impl.CompilerUtil; import com.intellij.facet.FacetManager; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.compiler.*; -import com.intellij.openapi.compiler.ex.CompileContextEx; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.android.compiler.tools.AndroidIdl; import org.jetbrains.android.facet.AndroidFacet; @@ -39,7 +36,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.DataInput; -import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -59,6 +55,7 @@ public class AndroidIdlCompiler implements SourceGeneratingCompiler { myProject = project; } + @Nullable @Override public VirtualFile getPresentableFile(CompileContext context, Module module, VirtualFile outputRoot, VirtualFile generatedFile) { return null; @@ -71,23 +68,7 @@ public class AndroidIdlCompiler implements SourceGeneratingCompiler { public GenerationItem[] generate(CompileContext context, GenerationItem[] items, VirtualFile outputRootDirectory) { if (items != null && items.length > 0) { context.getProgressIndicator().setText("Generating AIDL files..."); - //Application application = ApplicationManager.getApplication(); - GenerationItem[] generationItems = /*application.runReadAction(new GenerateAction(context, items))*/ doGenerate(context, items); - List generatedVFiles = new ArrayList(); - for (GenerationItem item : generationItems) { - File generatedFile = ((IdlGenerationItem)item).myGeneratedFile; - if (generatedFile != null) { - CompilerUtil.refreshIOFile(generatedFile); - VirtualFile generatedVFile = LocalFileSystem.getInstance().findFileByIoFile(generatedFile); - if (generatedVFile != null) { - generatedVFiles.add(generatedVFile); - } - } - } - if (context instanceof CompileContextEx) { - ((CompileContextEx)context).markGenerated(generatedVFiles); - } - return generationItems; + return doGenerate(context, items, outputRootDirectory); } return EMPTY_GENERATION_ITEM_ARRAY; } @@ -103,7 +84,7 @@ public class AndroidIdlCompiler implements SourceGeneratingCompiler { @Nullable public ValidityState createValidityState(DataInput is) throws IOException { - return null; + return TimestampValidityState.load(is); } private final static class IdlGenerationItem implements GenerationItem { @@ -111,13 +92,10 @@ public class AndroidIdlCompiler implements SourceGeneratingCompiler { final VirtualFile myFile; final boolean myTestSource; final IAndroidTarget myAndroidTarget; - final File myGeneratedFile; final String myPackageName; - final String mySourceRootPath; public IdlGenerationItem(@NotNull Module module, @NotNull VirtualFile file, - @NotNull String sourceRootPath, boolean testSource, @NotNull IAndroidTarget androidTarget, @NotNull String packageName) { @@ -126,19 +104,16 @@ public class AndroidIdlCompiler implements SourceGeneratingCompiler { myTestSource = testSource; myAndroidTarget = androidTarget; myPackageName = packageName; - mySourceRootPath = sourceRootPath; - myGeneratedFile = - new File(sourceRootPath, packageName.replace('.', File.separatorChar) + File.separator + file.getNameWithoutExtension() + ".java"); } @Nullable public String getPath() { - return null; + return myPackageName.replace('.', '/') + '/' + myFile.getNameWithoutExtension() + ".java"; } @Nullable public ValidityState getValidityState() { - return null; + return new TimestampValidityState(myFile.getTimeStamp()); } public Module getModule() { @@ -198,21 +173,11 @@ public class AndroidIdlCompiler implements SourceGeneratingCompiler { return; } ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex(); - IdlGenerationItem generationItem = - new IdlGenerationItem(module, file, sourceRootPath, fileIndex.isInTestSourceContent(file), target, packageName); - if (myContext.isMake()) { - File generatedFile = generationItem.myGeneratedFile; - if (generatedFile == null || !generatedFile.exists() || generatedFile.lastModified() <= file.getModificationCount()) { - items.add(generationItem); - } - } - else { - items.add(generationItem); - } + items.add(new IdlGenerationItem(module, file, fileIndex.isInTestSourceContent(file), target, packageName)); } } - private static GenerationItem[] doGenerate(final CompileContext context, GenerationItem[] items) { + private static GenerationItem[] doGenerate(final CompileContext context, GenerationItem[] items, VirtualFile outputRootDirectory) { if (context.getProject().isDisposed()) { return EMPTY_GENERATION_ITEM_ARRAY; } @@ -229,8 +194,12 @@ public class AndroidIdlCompiler implements SourceGeneratingCompiler { VirtualFile[] sourceRoots = AndroidPackagingCompiler.getSourceRootsForModuleAndDependencies(idlItem.myModule, false); final String[] sourceRootPaths = AndroidCompileUtil.toOsPaths(sourceRoots); - final Map> messages = AndroidIdl - .execute(idlItem.myAndroidTarget, idlItem.myFile.getPath(), idlItem.myGeneratedFile.getPath(), sourceRootPaths); + final String outFilePath = FileUtil.toSystemDependentName( + outputRootDirectory.getPath() + '/' + idlItem.myPackageName.replace('.', '/') + '/' + + idlItem.myFile.getNameWithoutExtension() + ".java"); + + final Map> messages = AndroidCompileUtil.toCompilerMessageCategoryKeys( + AndroidIdl.execute(idlItem.myAndroidTarget, idlItem.myFile.getPath(), outFilePath, sourceRootPaths)); ApplicationManager.getApplication().runReadAction(new Runnable() { public void run() { @@ -241,17 +210,6 @@ public class AndroidIdlCompiler implements SourceGeneratingCompiler { if (messages.get(CompilerMessageCategory.ERROR).isEmpty()) { results.add(idlItem); } - if (idlItem.myGeneratedFile.exists()) { - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - if (idlItem.myModule.getProject().isDisposed()) return; - String className = FileUtil.getNameWithoutExtension(idlItem.myGeneratedFile); - AndroidCompileUtil.removeDuplicatingClasses(idlItem.myModule, idlItem.myPackageName, className, - idlItem.myGeneratedFile.exists() ? idlItem.myGeneratedFile : null, - idlItem.mySourceRootPath); - } - }); - } } catch (final IOException e) { ApplicationManager.getApplication().runReadAction(new Runnable() { diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidMavenResourcesCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidMavenResourcesCompiler.java index 17d70f0d0d1d..7025e7bebf79 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidMavenResourcesCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidMavenResourcesCompiler.java @@ -31,7 +31,7 @@ import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.AndroidRootUtil; import org.jetbrains.android.maven.AndroidMavenProvider; import org.jetbrains.android.maven.AndroidMavenUtil; -import org.jetbrains.android.util.AndroidUtils; +import org.jetbrains.android.util.AndroidCommonUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.maven.project.MavenProject; @@ -144,13 +144,13 @@ public class AndroidMavenResourcesCompiler implements SourceGeneratingCompiler { myModule = module; myPackage = aPackage; myGeneratedFile = - new File(sourceRootPath, aPackage.replace('.', File.separatorChar) + File.separator + AndroidUtils.R_JAVA_FILENAME); + new File(sourceRootPath, aPackage.replace('.', File.separatorChar) + File.separator + AndroidCommonUtils.R_JAVA_FILENAME); mySourceRootPath = sourceRootPath; } @Nullable public String getPath() { - return myPackage.replace('.', '/') + '/' + AndroidUtils.R_JAVA_FILENAME; + return myPackage.replace('.', '/') + '/' + AndroidCommonUtils.R_JAVA_FILENAME; } public ValidityState getValidityState() { diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidPngFilesCachingCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidPngFilesCachingCompiler.java index a4a2a76d1e71..248c180d07f3 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidPngFilesCachingCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidPngFilesCachingCompiler.java @@ -98,9 +98,9 @@ public class AndroidPngFilesCachingCompiler implements SourceGeneratingCompiler if (resCacheDirOsPath == null) { continue; } - - final Map> messages = - AndroidApt.crunch(item.getTarget(), Collections.singletonList(resDirOsPath), resCacheDirOsPath); + + final Map> messages = AndroidCompileUtil.toCompilerMessageCategoryKeys( + AndroidApt.crunch(item.getTarget(), Collections.singletonList(resDirOsPath), resCacheDirOsPath)); AndroidCompileUtil.addMessages(context, messages, null); if (context.getMessages(CompilerMessageCategory.ERROR).length == 0) { processedItems.add(item); diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidPrecompileTask.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidPrecompileTask.java index f8355f3b7b68..83b77b39ec26 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidPrecompileTask.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidPrecompileTask.java @@ -19,7 +19,10 @@ import com.intellij.compiler.CompilerConfiguration; import com.intellij.compiler.CompilerConfigurationImpl; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; -import com.intellij.openapi.compiler.*; +import com.intellij.openapi.compiler.CompilationStatusAdapter; +import com.intellij.openapi.compiler.CompileContext; +import com.intellij.openapi.compiler.CompileTask; +import com.intellij.openapi.compiler.CompilerManager; import com.intellij.openapi.compiler.options.ExcludeEntryDescription; import com.intellij.openapi.compiler.options.ExcludedEntriesConfiguration; import com.intellij.openapi.diagnostic.Logger; @@ -30,16 +33,13 @@ import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.hash.HashSet; -import org.jetbrains.android.AndroidProjectComponent; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.AndroidRootUtil; import org.jetbrains.android.sdk.AndroidPlatform; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.io.File; import java.util.Arrays; @@ -50,20 +50,12 @@ import java.util.Set; * @author Eugene.Kudelevsky */ public class AndroidPrecompileTask implements CompileTask { - private final AndroidProjectComponent myOwner; - private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.compiler.AndroidPrecompileTask"); - public AndroidPrecompileTask(@NotNull AndroidProjectComponent owner) { - myOwner = owner; - } - @Override public boolean execute(CompileContext context) { final Project project = context.getProject(); - myOwner.setCompilationStarted(); - ExcludedEntriesConfiguration configuration = ((CompilerConfigurationImpl)CompilerConfiguration.getInstance(project)).getExcludedEntriesConfiguration(); @@ -85,7 +77,7 @@ public class AndroidPrecompileTask implements CompileTask { }, indicator != null ? indicator.getModalityState() : ModalityState.NON_MODAL); if (context.isRebuild()) { - clearGenRootsAndResCache(facet, context); + clearResCache(facet, context); } final AndroidPlatform platform = facet.getConfiguration().getAndroidPlatform(); @@ -99,7 +91,7 @@ public class AndroidPrecompileTask implements CompileTask { excludeAllSourceRoots(module, configuration, addedEntries); } else { - unexcludeAllSourceRoots(module, configuration); + unexcludeAllSourceRoots(facet, configuration); } } } @@ -108,28 +100,11 @@ public class AndroidPrecompileTask implements CompileTask { LOG.debug("Files excluded by Android: " + addedEntries.size()); CompilerManager.getInstance(project).addCompilationStatusListener(new MyCompilationStatusListener(project, addedEntries), project); } - - CompilerManager.getInstance(project).addCompilationStatusListener(new CompilationStatusAdapter() { - @Override - public void compilationFinished(boolean aborted, int errors, int warnings, final CompileContext compileContext) { - ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { - @Override - public void run() { - myOwner.setCompilationFinished(); - } - }); - } - }, project); - return true; } - private static void clearGenRootsAndResCache(@NotNull AndroidFacet facet, @NotNull CompileContext context) { + private static void clearResCache(@NotNull AndroidFacet facet, @NotNull CompileContext context) { final Module module = facet.getModule(); - - removeAllPackages(AndroidRootUtil.getRenderscriptGenSourceRootPath(module), context); - removeAllPackages(facet.getAptGenSourceRootPath(), context); - removeAllPackages(facet.getAidlGenSourceRootPath(), context); final String dirPath = AndroidCompileUtil.findResourcesCacheDirectory(module, false, null); if (dirPath != null) { @@ -139,38 +114,36 @@ public class AndroidPrecompileTask implements CompileTask { } } } - - private static void removeAllPackages(@Nullable String sourceRootPath, @NotNull CompileContext context) { - final File sourceRoot = new File(sourceRootPath); - final File[] children = sourceRoot.listFiles(); - - if (children != null) { - for (File child : children) { - if (child.isDirectory() && - child.getName() != null && - StringUtil.isJavaIdentifier(child.getName())) { - - if (!FileUtil.delete(child)) { - context.addMessage(CompilerMessageCategory.ERROR, "Cannot delete file " + child.getAbsolutePath(), - null, -1, -1); - } - } - } - } - final VirtualFile vFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(sourceRoot); - - if (vFile != null) { - vFile.refresh(false, true); - } - } - - private static void unexcludeAllSourceRoots(Module module, + private static void unexcludeAllSourceRoots(AndroidFacet facet, ExcludedEntriesConfiguration configuration) { - final VirtualFile[] sourceRoots = ModuleRootManager.getInstance(module).getSourceRoots(); + final VirtualFile[] sourceRoots = ModuleRootManager.getInstance(facet.getModule()).getSourceRoots(); final Set sourceRootSet = new HashSet(); sourceRootSet.addAll(Arrays.asList(sourceRoots)); + final String aidlGenSourceRootPath = facet.getAidlGenSourceRootPath(); + if (aidlGenSourceRootPath != null) { + final VirtualFile aidlGenSourceRoot = LocalFileSystem.getInstance().findFileByPath(aidlGenSourceRootPath); + + if (aidlGenSourceRoot != null) { + sourceRootSet.remove(aidlGenSourceRoot); + } + } + + final String aptGenSourceRootPath = facet.getAptGenSourceRootPath(); + if (aptGenSourceRootPath != null) { + final VirtualFile aptGenSourceRoot = LocalFileSystem.getInstance().findFileByPath(aptGenSourceRootPath); + + if (aptGenSourceRoot != null) { + sourceRootSet.remove(aptGenSourceRoot); + } + } + + final VirtualFile rsGenRoot = AndroidRootUtil.getRenderscriptGenDir(facet.getModule()); + if (rsGenRoot != null) { + sourceRootSet.remove(rsGenRoot); + } + final ExcludeEntryDescription[] descriptions = configuration.getExcludeEntryDescriptions(); configuration.removeAllExcludeEntryDescriptions(); diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidProguardCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidProguardCompiler.java index 466dbf7512a3..fb3ed1174edb 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidProguardCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidProguardCompiler.java @@ -23,14 +23,19 @@ import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.AndroidRootUtil; import org.jetbrains.android.sdk.AndroidPlatform; import org.jetbrains.android.util.AndroidBundle; -import org.jetbrains.android.util.AndroidUtils; -import org.jetbrains.android.util.ExecutionUtil; +import org.jetbrains.android.util.AndroidCommonUtils; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.io.*; -import java.util.*; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; /** * @author Eugene.Kudelevsky @@ -250,8 +255,8 @@ public class AndroidProguardCompiler implements ClassPostProcessingCompiler { commands.add(quotePath(new File(logDirOutputOsPath, "mapping.txt").getAbsolutePath())); } - LOG.info(AndroidUtils.command2string(commands)); - return ExecutionUtil.execute(ArrayUtil.toStringArray(commands)); + LOG.info(AndroidCommonUtils.command2string(commands)); + return AndroidCompileUtil.execute(ArrayUtil.toStringArray(commands)); } private static String quotePath(String path) { diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidRenderscriptCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidRenderscriptCompiler.java index bb30b7b3ea2c..9dff00c3448f 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidRenderscriptCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidRenderscriptCompiler.java @@ -3,7 +3,6 @@ package org.jetbrains.android.compiler; import com.android.AndroidConstants; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.SdkConstants; -import com.intellij.compiler.impl.CompilerUtil; import com.intellij.facet.FacetManager; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.compiler.*; @@ -19,14 +18,15 @@ import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashSet; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.AndroidRootUtil; import org.jetbrains.android.fileTypes.AndroidRenderscriptFileType; import org.jetbrains.android.sdk.AndroidPlatform; import org.jetbrains.android.util.AndroidBundle; +import org.jetbrains.android.util.AndroidCommonUtils; import org.jetbrains.android.util.AndroidUtils; -import org.jetbrains.android.util.ExecutionUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -60,68 +60,64 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { } final VirtualFile[] files = context.getProjectCompileScope().getFiles(AndroidRenderscriptFileType.INSTANCE, true); - final List items = new ArrayList(files.length); - for (final VirtualFile file : files) { + final Map> module2files = new HashMap>(); + + for (VirtualFile file : files) { final Module module = context.getModuleByFile(file); - final AndroidFacet facet = FacetManager.getInstance(module).getFacetByType(AndroidFacet.ID); - if (facet != null) { - final AndroidPlatform platform = facet.getConfiguration().getAndroidPlatform(); - if (platform == null) { - context.addMessage(CompilerMessageCategory.ERROR, - AndroidBundle.message("android.compilation.error.specify.platform", module.getName()), null, -1, -1); - continue; + + if (module != null) { + Collection filesForModule = module2files.get(module); + + if (filesForModule == null) { + filesForModule = new ArrayList(); + module2files.put(module, filesForModule); } - final IAndroidTarget target = platform.getTarget(); - final String sdkLocation = platform.getSdk().getLocation(); - - final String packageName = AndroidUtils.getPackageName(module, file); - if (packageName == null) { - context.addMessage(CompilerMessageCategory.ERROR, "Cannot compute package for file", file.getUrl(), -1, -1); - continue; - } - - final String resourceDirPath = AndroidRootUtil.getResourceDirPath(facet); - assert resourceDirPath != null; - - addItem(context, file, facet, resourceDirPath, sdkLocation, target, packageName, items); - - if (facet.getConfiguration().LIBRARY_PROJECT) { - final HashSet usingModules = new HashSet(); - AndroidUtils.collectModulesDependingOn(module, usingModules); - - for (final Module module1 : usingModules) { - final AndroidFacet facet1 = AndroidFacet.getInstance(module1); - if (facet1 != null) { - addItem(context, file, facet1, resourceDirPath, sdkLocation, target, packageName, items); - } - } - } + filesForModule.add(file); } } + final List items = new ArrayList(files.length); + + for (Map.Entry> entry : module2files.entrySet()) { + final Module module = entry.getKey(); + final AndroidFacet facet = FacetManager.getInstance(module).getFacetByType(AndroidFacet.ID); + if (facet == null) { + continue; + } + + final AndroidPlatform platform = facet.getConfiguration().getAndroidPlatform(); + if (platform == null) { + context.addMessage(CompilerMessageCategory.ERROR, + AndroidBundle.message("android.compilation.error.specify.platform", module.getName()), null, -1, -1); + continue; + } + + final IAndroidTarget target = platform.getTarget(); + final String sdkLocation = platform.getSdk().getLocation(); + + final String resourceDirPath = AndroidRootUtil.getResourceDirPath(facet); + assert resourceDirPath != null; + + addItem(entry.getValue(), facet, resourceDirPath, sdkLocation, target, items); + } return items.toArray(new GenerationItem[items.size()]); } }); } - private static void addItem(@NotNull final CompileContext context, - @NotNull final VirtualFile sourceFile, + private static void addItem(@NotNull final Collection sourceFiles, @NotNull final AndroidFacet facet, @NotNull final String resourceDirPath, @NotNull String sdkLocation, @NotNull final IAndroidTarget target, - @NotNull final String packageName, @NotNull final List items) { final Module module = facet.getModule(); final String sourceRootPath = AndroidRootUtil.getRenderscriptGenSourceRootPath(module); if (sourceRootPath == null) { return; } - final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(context.getProject()).getFileIndex(); final String rawDirPath = resourceDirPath + '/' + AndroidConstants.FD_RES_RAW; - - items.add(new MyGenerationItem(module, sourceFile, sourceRootPath, packageName, rawDirPath, fileIndex.isInTestSourceContent(sourceFile), - sdkLocation, target)); + items.add(new MyGenerationItem(module, sourceFiles, rawDirPath, sdkLocation, target)); } @Override @@ -133,19 +129,13 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { } context.getProgressIndicator().setText("Compiling RenderScript files..."); - final GenerationItem[] generationItems = doGenerate(context, items); + final GenerationItem[] generationItems = doGenerate(context, items, outputRootDirectory); final Set generatedVFiles = new HashSet(); final HashSet visited = new HashSet(); - for (GenerationItem item : generationItems) { - final MyGenerationItem genItem = (MyGenerationItem)item; - final File genDir = new File(genItem.myGenRootPath); - CompilerUtil.refreshIODirectories(Arrays.asList(genDir)); - final VirtualFile generatedVFile = LocalFileSystem.getInstance().findFileByIoFile(genDir); - if (generatedVFile != null) { - AndroidUtils.collectFiles(generatedVFile, visited, generatedVFiles); - } - } + outputRootDirectory.refresh(false, true); + AndroidUtils.collectFiles(outputRootDirectory, visited, generatedVFiles); + if (context instanceof CompileContextEx) { ((CompileContextEx)context).markGenerated(generatedVFiles); } @@ -169,11 +159,27 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { return new MyValidityState(in); } - private static GenerationItem[] doGenerate(@NotNull final CompileContext context, @NotNull final GenerationItem[] items) { + private static GenerationItem[] doGenerate(@NotNull final CompileContext context, + @NotNull final GenerationItem[] items, + VirtualFile outputRootDirectory) { if (context.getProject().isDisposed()) { return EMPTY_GENERATION_ITEM_ARRAY; } + // we have one item per module there, so clear output directory + final String genRootPath = FileUtil.toSystemDependentName(outputRootDirectory.getPath()); + final File genRootDir = new File(genRootPath); + if (genRootDir.exists()) { + if (!FileUtil.delete(genRootDir)) { + context.addMessage(CompilerMessageCategory.ERROR, "Cannot delete directory " + genRootPath, null, -1, -1); + return EMPTY_GENERATION_ITEM_ARRAY; + } + if (!genRootDir.mkdir()) { + context.addMessage(CompilerMessageCategory.ERROR, "Cannot create directory " + genRootPath, null, -1, -1); + return EMPTY_GENERATION_ITEM_ARRAY; + } + } + final List results = new ArrayList(items.length); for (final GenerationItem item : items) { if (item instanceof MyGenerationItem) { @@ -183,33 +189,35 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { continue; } - try { - final Map> messages = launchRenderscriptCompiler(context.getProject(), - genItem.mySdkLocation, - genItem.myAndroidTarget, - genItem.mySourceFile, - genItem.myGenRootPath, - genItem.myRawDirPath); - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - if (context.getProject().isDisposed()) { - return; + for (final VirtualFile sourceFile : genItem.myFiles) { + try { + final Map> messages = launchRenderscriptCompiler(context.getProject(), + genItem.mySdkLocation, + genItem.myAndroidTarget, + sourceFile, + genRootPath, + genItem.myRawDirPath); + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + if (context.getProject().isDisposed()) { + return; + } + addMessages(context, messages, sourceFile.getUrl()); } - addMessages(context, messages, genItem.mySourceFile.getUrl()); - } - }); + }); - if (messages.get(CompilerMessageCategory.ERROR).isEmpty()) { - results.add(genItem); - } - } - catch (final IOException e) { - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - if (context.getProject().isDisposed()) return; - context.addMessage(CompilerMessageCategory.ERROR, e.getMessage(), genItem.mySourceFile.getUrl(), -1, -1); + if (messages.get(CompilerMessageCategory.ERROR).isEmpty()) { + results.add(genItem); } - }); + } + catch (final IOException e) { + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + if (context.getProject().isDisposed()) return; + context.addMessage(CompilerMessageCategory.ERROR, e.getMessage(), sourceFile.getUrl(), -1, -1); + } + }); + } } } } @@ -227,12 +235,12 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { } } - private static Map> launchRenderscriptCompiler(@NotNull Project project, - @NotNull final String sdkLocation, - @NotNull IAndroidTarget target, - @NotNull final VirtualFile sourceFile, - @NotNull final String genFolderPath, - @NotNull final String rawDirPath) + static Map> launchRenderscriptCompiler(@NotNull Project project, + @NotNull final String sdkLocation, + @NotNull IAndroidTarget target, + @NotNull final VirtualFile sourceFile, + @NotNull final String genFolderPath, + @NotNull final String rawDirPath) throws IOException { final List command = new ArrayList(); command.add( @@ -260,8 +268,8 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { command.add("-MD"); command.add(sourceFilePath); - LOG.info(AndroidUtils.command2string(command)); - return ExecutionUtil.execute(ArrayUtil.toStringArray(command)); + LOG.info(AndroidCommonUtils.command2string(command)); + return AndroidCompileUtil.execute(ArrayUtil.toStringArray(command)); } @Nullable @@ -288,43 +296,30 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { private static class MyGenerationItem implements GenerationItem { final Module myModule; final String mySdkLocation; - final VirtualFile mySourceFile; - final boolean myTestSource; + final Collection myFiles; final IAndroidTarget myAndroidTarget; - final String myGenRootPath; final String myRawDirPath; - final String myPackageName; - final boolean myFileExists; - final File myParentDirectory; public MyGenerationItem(@NotNull Module module, - @NotNull VirtualFile sourceFile, - @NotNull String genRootPath, - @NotNull String packageName, + @NotNull Collection files, @NotNull String rawDirPath, - boolean testSource, @NotNull String sdkLocation, @NotNull IAndroidTarget target) { myModule = module; - mySourceFile = sourceFile; + myFiles = files; myRawDirPath = rawDirPath; - myTestSource = testSource; mySdkLocation = sdkLocation; myAndroidTarget = target; - myGenRootPath = genRootPath; - myPackageName = packageName; - myParentDirectory = new File(myGenRootPath, myPackageName.replace('.', File.separatorChar)); - myFileExists = myParentDirectory.exists(); } @Nullable public String getPath() { - return null; + return ""; } @Nullable public ValidityState getValidityState() { - return new MyValidityState(mySourceFile, myFileExists); + return new MyValidityState(myFiles); } public Module getModule() { @@ -332,22 +327,28 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { } public boolean isTestSource() { - return myTestSource; + return false; } } - + private static class MyValidityState implements ValidityState { - private final long myTimestamp; - private final boolean myFileExists; - - public MyValidityState(@NotNull DataInput in) throws IOException { - myTimestamp = in.readLong(); - myFileExists = true; + private final Map myTimestamps = new HashMap(); + + MyValidityState(DataInput in) throws IOException { + final int size = in.readInt(); + + for (int i = 0; i < size; i++) { + final String path = in.readUTF(); + final long timestamp = in.readLong(); + + myTimestamps.put(path, timestamp); + } } - public MyValidityState(@NotNull VirtualFile file, boolean fileExists) { - myTimestamp = file.getTimeStamp(); - myFileExists = fileExists; + MyValidityState(@NotNull Collection files) { + for (VirtualFile file : files) { + myTimestamps.put(file.getPath(), file.getTimeStamp()); + } } @Override @@ -355,15 +356,17 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { if (!(otherState instanceof MyValidityState)) { return false; } - - final MyValidityState st = (MyValidityState)otherState; - return myTimestamp == st.myTimestamp && - myFileExists == st.myFileExists; + return ((MyValidityState)otherState).myTimestamps.equals(myTimestamps); } @Override public void save(DataOutput out) throws IOException { - out.writeLong(myTimestamp); + out.writeInt(myTimestamps.size()); + + for (Map.Entry entry : myTimestamps.entrySet()) { + out.writeUTF(entry.getKey()); + out.writeLong(entry.getValue()); + } } } } diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidResourcesPackagingCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidResourcesPackagingCompiler.java index 50783b06c374..920bd48041dc 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidResourcesPackagingCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidResourcesPackagingCompiler.java @@ -152,12 +152,14 @@ public class AndroidResourcesPackagingCompiler implements ClassPostProcessingCom ? item.myOutputPath + RELEASE_SUFFIX : item.myOutputPath; - Map> messages = AndroidApt.packageResources(item.myAndroidTarget, - item.myPlatformToolsRevision, - preprocessedManifestFile.getPath(), - item.myResourceDirPaths, - item.myAssetsDirPath, - outputPath, null, !releasePackage, 0); + Map> messages = AndroidCompileUtil.toCompilerMessageCategoryKeys( + AndroidApt.packageResources(item.myAndroidTarget, + item.myPlatformToolsRevision, + preprocessedManifestFile.getPath(), + item.myResourceDirPaths, + item.myAssetsDirPath, + outputPath, null, !releasePackage, 0)); + AndroidCompileUtil.addMessages(context, messages, presentableFilesMap); } catch (final IOException e) { diff --git a/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java b/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java index 5f097640f68d..a2e5c29d1997 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java +++ b/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java @@ -33,11 +33,11 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashSet; import com.intellij.util.text.DateFormatUtil; +import org.jetbrains.android.compiler.AndroidCompileUtil; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.sdk.AndroidPlatform; import org.jetbrains.android.util.AndroidBundle; import org.jetbrains.android.util.AndroidUtils; -import org.jetbrains.android.util.ExecutionUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -141,7 +141,7 @@ public class AndroidApkBuilder { map.putAll(map2); if (withAlignment && map.get(ERROR).size() == 0) { - map2 = ExecutionUtil.execute(zipAlignPath, "-f", "4", unalignedApk, finalApk); + map2 = AndroidCompileUtil.execute(zipAlignPath, "-f", "4", unalignedApk, finalApk); map.putAll(map2); } return map; diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java b/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java index 7b03bcc7f15c..de9e8f017cda 100644 --- a/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java +++ b/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java @@ -37,7 +37,6 @@ import com.intellij.facet.FacetTypeRegistry; import com.intellij.lang.properties.IProperty; import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.compiler.GeneratingCompiler; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtil; @@ -45,10 +44,9 @@ import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.roots.CompilerModuleExtension; -import com.intellij.openapi.roots.ModuleRootEvent; -import com.intellij.openapi.roots.ModuleRootListener; -import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.projectRoots.SdkAdditionalData; +import com.intellij.openapi.projectRoots.SdkModificator; +import com.intellij.openapi.roots.*; import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Comparing; @@ -66,18 +64,16 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.ProjectScope; import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.psi.xml.XmlTag; +import com.intellij.util.Alarm; import com.intellij.util.ArrayUtil; import com.intellij.util.Processor; import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashSet; -import com.intellij.util.ui.update.MergingUpdateQueue; -import com.intellij.util.ui.update.Update; import com.intellij.util.xml.ConvertContext; import com.intellij.util.xml.DomElement; import org.jetbrains.android.compiler.AndroidAptCompiler; +import org.jetbrains.android.compiler.AndroidAutogeneratorMode; import org.jetbrains.android.compiler.AndroidCompileUtil; -import org.jetbrains.android.compiler.AndroidIdlCompiler; -import org.jetbrains.android.compiler.AndroidRenderscriptCompiler; import org.jetbrains.android.dom.manifest.Manifest; import org.jetbrains.android.importDependencies.ImportDependenciesUtil; import org.jetbrains.android.resourceManagers.LocalResourceManager; @@ -113,27 +109,96 @@ public class AndroidFacet extends Facet { private final Map> myClassMaps = new HashMap>(); private final Object myClassMapLock = new Object(); - - private final Map, MergingUpdateQueue> mySourcesAutogeneratingQueueMap = new HashMap, MergingUpdateQueue>(); + + private final Set myDirtyModes = EnumSet.noneOf(AndroidAutogeneratorMode.class); + private final Map> myAutogeneratedFiles = new HashMap>(); + + private volatile boolean myAutogenerationEnabled = false; public AndroidFacet(@NotNull Module module, String name, @NotNull AndroidFacetConfiguration configuration) { super(getFacetType(), module, name, configuration, null); configuration.setFacet(this); - mySourcesAutogeneratingQueueMap.put(AndroidAptCompiler.class, createSourceGeneratingQueue("AndroidAptAutogeneratingQueue")); - mySourcesAutogeneratingQueueMap.put(AndroidIdlCompiler.class, createSourceGeneratingQueue("AndroidIdlAutogeneratingQueue")); - mySourcesAutogeneratingQueueMap - .put(AndroidRenderscriptCompiler.class, createSourceGeneratingQueue("AndroidRenderscriptAutogeneratingQueue")); + for (AndroidAutogeneratorMode mode : AndroidAutogeneratorMode.values()) { + createAlarm(mode); + } } - private MergingUpdateQueue createSourceGeneratingQueue(@NotNull String name) { - return new MergingUpdateQueue(name, 1000, false, null, this, null, false); + private Alarm createAlarm(@NotNull final AndroidAutogeneratorMode mode) { + final Alarm alarm = new Alarm(Alarm.ThreadToUse.OWN_THREAD, this); + alarm.addRequest(new Runnable() { + @Override + public void run() { + boolean regenerate; + + synchronized (myDirtyModes) { + regenerate = myDirtyModes.contains(mode); + } + regenerate = regenerate || isGeneratedFileRemoved(mode); + + if (myAutogenerationEnabled && regenerate) { + if (AndroidCompileUtil.doGenerate(getModule(), mode)) { + synchronized (myDirtyModes) { + myDirtyModes.remove(mode); + } + } + } + if (!alarm.isDisposed()) { + alarm.addRequest(this, 2000); + } + } + }, 2000); + return alarm; + } + + private boolean isGeneratedFileRemoved(@NotNull AndroidAutogeneratorMode mode) { + synchronized (myAutogeneratedFiles) { + final Set filePaths = myAutogeneratedFiles.get(mode); + + if (filePaths != null) { + for (String path : filePaths) { + final VirtualFile file = LocalFileSystem.getInstance().findFileByPath(path); + + if (file == null) { + return true; + } + } + } + } + return false; + } + + public void clearAutogeneratedFiles(@NotNull AndroidAutogeneratorMode mode) { + synchronized (myAutogeneratedFiles) { + final Set set = myAutogeneratedFiles.get(mode); + if (set != null) { + set.clear(); + } + } + } + + public void markFileAutogenerated(@NotNull AndroidAutogeneratorMode mode, @NotNull VirtualFile file) { + synchronized (myAutogeneratedFiles) { + Set set = myAutogeneratedFiles.get(mode); + + if (set == null) { + set = new HashSet(); + myAutogeneratedFiles.put(mode, set); + } + set.add(file.getPath()); + } + } + + @NotNull + public Set getAutogeneratedFiles(@NotNull AndroidAutogeneratorMode mode) { + synchronized (myAutogeneratedFiles) { + final Set set = myAutogeneratedFiles.get(mode); + return set != null ? new HashSet(set) : Collections.emptySet(); + } } private void activateSourceAutogenerating() { - for (MergingUpdateQueue queue : mySourcesAutogeneratingQueueMap.values()) { - queue.activate(); - } + myAutogenerationEnabled = true; } @Nullable @@ -325,8 +390,8 @@ public class AndroidFacet extends Facet { AndroidPlatform platform = getConfiguration().getAndroidPlatform(); AndroidSdk sdk = platform != null ? platform.getSdk() : null; Project project = getModule().getProject(); - if (sdk instanceof AndroidSdkImpl) { - SdkManager sdkManager = ((AndroidSdkImpl)sdk).getSdkManager(); + if (sdk != null) { + SdkManager sdkManager = sdk.getSdkManager(); myAvdManager = new AvdManager(sdkManager, AndroidUtils.getSdkLog(project)); } else { @@ -368,6 +433,9 @@ public class AndroidFacet extends Facet { if (ApplicationManager.getApplication().isUnitTestMode()) { return; } + + addResourceFolderToSdkRootsIfNecessary(); + ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { public void run() { Module module = getModule(); @@ -383,12 +451,12 @@ public class AndroidFacet extends Facet { myListener.setResourceSet(resourceSet); if (getConfiguration().REGENERATE_R_JAVA && AndroidAptCompiler.isToCompileModule(module, getConfiguration())) { - AndroidCompileUtil.generate(module, new AndroidAptCompiler()); + AndroidCompileUtil.generate(module, AndroidAutogeneratorMode.AAPT); } if (getConfiguration().REGENERATE_JAVA_BY_AIDL) { - AndroidCompileUtil.generate(module, new AndroidIdlCompiler(project)); + AndroidCompileUtil.generate(module, AndroidAutogeneratorMode.AIDL); } - AndroidCompileUtil.generate(module, new AndroidRenderscriptCompiler()); + AndroidCompileUtil.generate(module, AndroidAutogeneratorMode.RENDERSCRIPT); activateSourceAutogenerating(); } @@ -441,6 +509,42 @@ public class AndroidFacet extends Facet { } }); } + + private void addResourceFolderToSdkRootsIfNecessary() { + final Sdk sdk = ModuleRootManager.getInstance(getModule()).getSdk(); + if (sdk == null || !(sdk.getSdkType() instanceof AndroidSdkType)) { + return; + } + + final SdkAdditionalData data = sdk.getSdkAdditionalData(); + if (!(data instanceof AndroidSdkAdditionalData)) { + return; + } + + final AndroidPlatform platform = ((AndroidSdkAdditionalData)data).getAndroidPlatform(); + if (platform == null) { + return; + } + + final String resFolderPath = platform.getTarget().getPath(IAndroidTarget.RESOURCES); + if (resFolderPath == null) { + return; + } + + final VirtualFile resFolder = LocalFileSystem.getInstance().findFileByPath(resFolderPath); + if (resFolder == null) { + return; + } + + for (VirtualFile root : sdk.getRootProvider().getFiles(OrderRootType.CLASSES)) { + if (root == resFolder) { + return; + } + } + final SdkModificator modificator = sdk.getSdkModificator(); + modificator.addRoot(resFolder, OrderRootType.CLASSES); + modificator.commitChanges(); + } private static void updateDependenciesInPropertyFile(@NotNull final PropertiesFile projectProperties, @Nullable final Pair localProperties, @@ -736,19 +840,9 @@ public class AndroidFacet extends Facet { return moduleDirPath != null ? FileUtil.toSystemDependentName(moduleDirPath + path) : null; } - public void scheduleSourceRegenerating(@NotNull final GeneratingCompiler compiler) { - final MergingUpdateQueue queue = mySourcesAutogeneratingQueueMap.get(compiler.getClass()); - - if (queue == null) { - LOG.error("Autogenerating is not supported for compiler " + compiler.getClass().getCanonicalName()); - } - else { - queue.queue(new Update(this) { - @Override - public void run() { - AndroidCompileUtil.doGenerate(getModule(), compiler); - } - }); + public void scheduleSourceRegenerating(@NotNull final AndroidAutogeneratorMode mode) { + synchronized (myDirtyModes) { + myDirtyModes.add(mode); } } } diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.java b/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.java index 26cf05e4d4c8..9799c579ca92 100644 --- a/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.java +++ b/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.java @@ -37,8 +37,8 @@ import com.intellij.ui.components.JBLabel; import com.intellij.util.ArrayUtil; import com.intellij.util.ui.UIUtil; import org.jetbrains.android.compiler.AndroidAptCompiler; +import org.jetbrains.android.compiler.AndroidAutogeneratorMode; import org.jetbrains.android.compiler.AndroidCompileUtil; -import org.jetbrains.android.compiler.AndroidIdlCompiler; import org.jetbrains.android.maven.AndroidMavenProvider; import org.jetbrains.android.maven.AndroidMavenUtil; import org.jetbrains.android.util.AndroidBundle; @@ -437,10 +437,10 @@ public class AndroidFacetEditorTab extends FacetEditorTab { final Project project = module.getProject(); if (runApt) { - AndroidCompileUtil.generate(module, new AndroidAptCompiler(), true); + AndroidCompileUtil.generate(module, AndroidAutogeneratorMode.AAPT, true); } if (runIdl) { - AndroidCompileUtil.generate(module, new AndroidIdlCompiler(project)); + AndroidCompileUtil.generate(module, AndroidAutogeneratorMode.AIDL); } } } diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidResourceFilesListener.java b/plugins/android/src/org/jetbrains/android/facet/AndroidResourceFilesListener.java index e422429d59a3..37e9c4105441 100644 --- a/plugins/android/src/org/jetbrains/android/facet/AndroidResourceFilesListener.java +++ b/plugins/android/src/org/jetbrains/android/facet/AndroidResourceFilesListener.java @@ -18,7 +18,6 @@ package org.jetbrains.android.facet; import com.android.resources.ResourceFolderType; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.compiler.GeneratingCompiler; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtil; import com.intellij.openapi.project.DumbService; @@ -28,7 +27,9 @@ import com.intellij.openapi.vfs.*; import com.intellij.util.containers.HashSet; import com.intellij.util.ui.update.MergingUpdateQueue; import com.intellij.util.ui.update.Update; -import org.jetbrains.android.compiler.*; +import org.jetbrains.android.compiler.AndroidAptCompiler; +import org.jetbrains.android.compiler.AndroidAutogeneratorMode; +import org.jetbrains.android.compiler.AndroidCompileUtil; import org.jetbrains.android.dom.manifest.Manifest; import org.jetbrains.android.fileTypes.AndroidIdlFileType; import org.jetbrains.android.fileTypes.AndroidRenderscriptFileType; @@ -111,9 +112,6 @@ class AndroidResourceFilesListener extends VirtualFileAdapter { private void fileChanged(@NotNull final VirtualFileEvent e) { VirtualFile file = e.getFile(); - if (!file.isValid()) { - return; - } VirtualFile parent = e.getParent(); VirtualFile gp = parent != null ? parent.getParent() : null; @@ -146,18 +144,19 @@ class AndroidResourceFilesListener extends VirtualFileAdapter { return; } - final GeneratingCompiler compilerToRun = ApplicationManager.getApplication().runReadAction(new Computable() { - @Nullable - public GeneratingCompiler compute() { - return computeCompilerToRunAndInvalidateLocalAttributesMap(); - } - }); + final AndroidAutogeneratorMode autogenerationMode = + ApplicationManager.getApplication().runReadAction(new Computable() { + @Nullable + public AndroidAutogeneratorMode compute() { + return computeCompilerToRunAndInvalidateLocalAttributesMap(); + } + }); - if (compilerToRun == null) { + if (autogenerationMode == null) { return; } - if (compilerToRun instanceof AndroidAptCompiler && + if (autogenerationMode == AndroidAutogeneratorMode.AAPT && AndroidRootUtil.getManifestFile(myFacet.getModule()) != myEvent.getFile()) { final HashSet resourceSet = new HashSet(); @@ -173,11 +172,11 @@ class AndroidResourceFilesListener extends VirtualFileAdapter { myResourceSet = resourceSet; } } - AndroidCompileUtil.generate(myFacet.getModule(), compilerToRun, true); + AndroidCompileUtil.generate(myFacet.getModule(), autogenerationMode, true); } @Nullable - private GeneratingCompiler computeCompilerToRunAndInvalidateLocalAttributesMap() { + private AndroidAutogeneratorMode computeCompilerToRunAndInvalidateLocalAttributesMap() { if (myFacet.isDisposed()) { return null; } @@ -219,20 +218,20 @@ class AndroidResourceFilesListener extends VirtualFileAdapter { AndroidCompileUtil.removeDuplicatingClasses(myModule, myCachedPackage, AndroidUtils.R_CLASS_NAME, null, aptGenDirPath); } myCachedPackage = aPackage; - return new AndroidAptCompiler(); + return AndroidAutogeneratorMode.AAPT; } if (myFacet.getConfiguration().REGENERATE_JAVA_BY_AIDL && file.getFileType() == AndroidIdlFileType.ourFileType) { VirtualFile sourceRoot = findSourceRoot(myModule, file); if (sourceRoot != null && AndroidRootUtil.getAidlGenDir(module, myFacet) != sourceRoot) { - return new AndroidIdlCompiler(project); + return AndroidAutogeneratorMode.AIDL; } } if (file.getFileType() == AndroidRenderscriptFileType.INSTANCE) { final VirtualFile sourceRoot = findSourceRoot(myModule, file); if (sourceRoot != null && AndroidRootUtil.getRenderscriptGenDir(myModule) != sourceRoot) { - return new AndroidRenderscriptCompiler(); + return AndroidAutogeneratorMode.RENDERSCRIPT; } } return null; diff --git a/plugins/android/src/org/jetbrains/android/inspections/lint/AndroidLintInspectionBase.java b/plugins/android/src/org/jetbrains/android/inspections/lint/AndroidLintInspectionBase.java index af7f059585a4..13fdf69d297d 100644 --- a/plugins/android/src/org/jetbrains/android/inspections/lint/AndroidLintInspectionBase.java +++ b/plugins/android/src/org/jetbrains/android/inspections/lint/AndroidLintInspectionBase.java @@ -164,7 +164,7 @@ public abstract class AndroidLintInspectionBase extends GlobalInspectionTool { final PsiElement endElement = psiFile.findElementAt(range.getEndOffset() - 1); if (startElement != null && endElement != null) { - result.add(manager.createProblemDescriptor(startElement, endElement, message + "#loc", + result.add(manager.createProblemDescriptor(startElement, endElement, message, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false, getLocalQuickFixes(startElement, endElement, message))); } diff --git a/plugins/android/src/org/jetbrains/android/inspections/lint/TypographyQuickFix.java b/plugins/android/src/org/jetbrains/android/inspections/lint/TypographyQuickFix.java index 74e7e737cdc8..a290b68ee61d 100644 --- a/plugins/android/src/org/jetbrains/android/inspections/lint/TypographyQuickFix.java +++ b/plugins/android/src/org/jetbrains/android/inspections/lint/TypographyQuickFix.java @@ -2,6 +2,7 @@ package org.jetbrains.android.inspections.lint; import com.android.tools.lint.checks.TypographyDetector; import com.android.tools.lint.detector.api.Issue; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; @@ -42,7 +43,13 @@ class TypographyQuickFix implements AndroidLintQuickFix { final StringBuilder builder = new StringBuilder(value); for (TypographyDetector.ReplaceEdit edit : edits) { - builder.replace(edit.offset, edit.offset + edit.length, edit.replaceWith); + String with = edit.replaceWith; + + if (ApplicationManager.getApplication().isUnitTestMode()) { + with = with.replace('\u2013', '~').replace('\u2018', '{').replace('\u2019', '}'); + } + + builder.replace(edit.offset, edit.offset + edit.length, with); } final String newValue = builder.toString(); diff --git a/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleWizardStep.java b/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleWizardStep.java index 47942f407f1e..b4b88f75be4a 100644 --- a/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleWizardStep.java +++ b/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleWizardStep.java @@ -391,22 +391,20 @@ public class AndroidModuleWizardStep extends ModuleWizardStep { @NotNull private static String[] getAvds(@NotNull AndroidPlatform androidPlatform) { final AndroidSdk sdkObject = androidPlatform.getSdk(); - if (sdkObject instanceof AndroidSdkImpl) { - final SdkManager sdkManager = ((AndroidSdkImpl)sdkObject).getSdkManager(); - try { - final AvdManager avdManager = new AvdManager(sdkManager, new MessageBuildingSdkLog()); - final AvdInfo[] validAvds = avdManager.getValidAvds(); + final SdkManager sdkManager = sdkObject.getSdkManager(); + try { + final AvdManager avdManager = new AvdManager(sdkManager, new MessageBuildingSdkLog()); + final AvdInfo[] validAvds = avdManager.getValidAvds(); - final String[] avdNames = new String[validAvds.length]; - for (int i = 0; i < validAvds.length; i++) { - avdNames[i] = validAvds[i].getName(); - } - return avdNames; - } - catch (AndroidLocation.AndroidLocationException e) { - LOG.info(e); + final String[] avdNames = new String[validAvds.length]; + for (int i = 0; i < validAvds.length; i++) { + avdNames[i] = validAvds[i].getName(); } + return avdNames; + } + catch (AndroidLocation.AndroidLocationException e) { + LOG.info(e); + return ArrayUtil.EMPTY_STRING_ARRAY; } - return ArrayUtil.EMPTY_STRING_ARRAY; } } diff --git a/plugins/android/src/org/jetbrains/android/run/AndroidRunConfigurationBase.java b/plugins/android/src/org/jetbrains/android/run/AndroidRunConfigurationBase.java index 54e28b8b1012..9cd023bc9b39 100644 --- a/plugins/android/src/org/jetbrains/android/run/AndroidRunConfigurationBase.java +++ b/plugins/android/src/org/jetbrains/android/run/AndroidRunConfigurationBase.java @@ -51,8 +51,6 @@ import org.jetbrains.android.facet.AndroidFacetConfiguration; import org.jetbrains.android.logcat.AndroidLogFilterModel; import org.jetbrains.android.logcat.AndroidLogcatFiltersPreferences; import org.jetbrains.android.sdk.AndroidPlatform; -import org.jetbrains.android.sdk.AndroidSdk; -import org.jetbrains.android.sdk.AndroidSdkImpl; import org.jetbrains.android.util.AndroidBundle; import org.jetbrains.android.util.AndroidUtils; import org.jetbrains.annotations.NotNull; @@ -108,22 +106,17 @@ public abstract class AndroidRunConfigurationBase extends ModuleBasedConfigurati if (PREFERRED_AVD.length() > 0) { AvdManager avdManager = facet.getAvdManagerSilently(); if (avdManager == null) { - AndroidSdk sdk = facet.getConfiguration().getAndroidSdk(); - if (sdk instanceof AndroidSdkImpl) { - throw new RuntimeConfigurationError(AndroidBundle.message("avd.cannot.be.loaded.error")); - } + throw new RuntimeConfigurationError(AndroidBundle.message("avd.cannot.be.loaded.error")); } - if (avdManager != null) { - AvdInfo avdInfo = avdManager.getAvd(PREFERRED_AVD, false); - if (avdInfo == null) { - throw new RuntimeConfigurationError(AndroidBundle.message("avd.not.found.error", PREFERRED_AVD)); - } - if (!facet.isCompatibleAvd(avdInfo)) { - throw new RuntimeConfigurationError(AndroidBundle.message("avd.not.compatible.error", PREFERRED_AVD)); - } - if (avdInfo.getStatus() != AvdInfo.AvdStatus.OK) { - throw new RuntimeConfigurationError(AndroidBundle.message("avd.not.valid.error", PREFERRED_AVD)); - } + AvdInfo avdInfo = avdManager.getAvd(PREFERRED_AVD, false); + if (avdInfo == null) { + throw new RuntimeConfigurationError(AndroidBundle.message("avd.not.found.error", PREFERRED_AVD)); + } + if (!facet.isCompatibleAvd(avdInfo)) { + throw new RuntimeConfigurationError(AndroidBundle.message("avd.not.compatible.error", PREFERRED_AVD)); + } + if (avdInfo.getStatus() != AvdInfo.AvdStatus.OK) { + throw new RuntimeConfigurationError(AndroidBundle.message("avd.not.valid.error", PREFERRED_AVD)); } } checkConfiguration(facet); diff --git a/plugins/android/src/org/jetbrains/android/run/AndroidRunningState.java b/plugins/android/src/org/jetbrains/android/run/AndroidRunningState.java index 976b7eb14a90..a54a188a3fc1 100644 --- a/plugins/android/src/org/jetbrains/android/run/AndroidRunningState.java +++ b/plugins/android/src/org/jetbrains/android/run/AndroidRunningState.java @@ -54,7 +54,6 @@ import com.intellij.xdebugger.DefaultDebugProcessHandler; import org.jetbrains.android.actions.AndroidEnableDdmsAction; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.AvdsNotSupportedException; -import org.jetbrains.android.sdk.AndroidSdkImpl; import org.jetbrains.android.util.AndroidBundle; import org.jetbrains.android.util.AndroidOutputReceiver; import org.jetbrains.android.util.AndroidUtils; @@ -426,22 +425,17 @@ public abstract class AndroidRunningState implements RunProfileState, AndroidDeb myTargetDevices = targetDevices; } else if (myTargetChooser instanceof EmulatorTargetChooser) { - if (isAndroidSdk15OrHigher()) { - if (myAvdName == null) { - chooseAvd(); - } - if (myAvdName != null) { - myFacet.launchEmulator(myAvdName, myCommandLine, getProcessHandler()); - } - else if (getProcessHandler().isStartNotified()) { - message("Canceled", STDERR); - getProcessHandler().destroyProcess(); - return false; - } + if (myAvdName == null) { + chooseAvd(); } - else { + if (myAvdName != null) { myFacet.launchEmulator(myAvdName, myCommandLine, getProcessHandler()); } + else if (getProcessHandler().isStartNotified()) { + message("Canceled", STDERR); + getProcessHandler().destroyProcess(); + return false; + } } else { message("USB device not found", STDERR); @@ -485,10 +479,6 @@ public abstract class AndroidRunningState implements RunProfileState, AndroidDeb getProcessHandler().notifyTextAvailable(message + '\n', outputKey); } - private boolean isAndroidSdk15OrHigher() { - return myFacet.getConfiguration().getAndroidSdk() instanceof AndroidSdkImpl; - } - public void clientChanged(Client client, int changeMask) { synchronized (myDebugLock) { if (myDebugLauncher == null) { @@ -529,10 +519,6 @@ public abstract class AndroidRunningState implements RunProfileState, AndroidDeb @Nullable private Boolean isCompatibleDevice(@NotNull IDevice device) { - if (!isAndroidSdk15OrHigher()) { - return true; - } - if (myTargetChooser instanceof EmulatorTargetChooser) { if (device.isEmulator()) { String avdName = device.isEmulator() ? device.getAvdName() : null; @@ -747,7 +733,7 @@ public abstract class AndroidRunningState implements RunProfileState, AndroidDeb private boolean uploadApp(IDevice device, String remotePath, String localPath) throws IOException { if (myStopped) return false; message("Uploading file\n\tlocal path: " + localPath + "\n\tremote path: " + remotePath, STDOUT); - String exceptionMessage = null; + String exceptionMessage; String errorMessage; try { SyncService service = device.getSyncService(); diff --git a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdk.java b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdk.java index 58f9fbbd139e..877dc802f84c 100644 --- a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdk.java +++ b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdk.java @@ -18,10 +18,8 @@ package org.jetbrains.android.sdk; import com.android.ddmlib.AndroidDebugBridge; import com.android.ddmlib.DdmPreferences; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.ISdkLog; -import com.android.sdklib.SdkConstants; -import com.android.sdklib.SdkManager; +import com.android.sdklib.*; +import com.android.sdklib.internal.project.ProjectProperties; import com.intellij.CommonBundle; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; @@ -33,8 +31,10 @@ import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.io.FileUtil; import com.intellij.reference.SoftReference; import com.intellij.util.containers.HashMap; +import gnu.trove.TIntObjectHashMap; import org.jetbrains.android.actions.AndroidEnableDdmsAction; import org.jetbrains.android.util.AndroidUtils; +import org.jetbrains.android.util.BufferingFileWrapper; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -45,13 +45,9 @@ import java.util.Map; import static org.jetbrains.android.util.AndroidUtils.ADB; /** - * Created by IntelliJ IDEA. - * User: Eugene.Kudelevsky - * Date: Jun 2, 2009 - * Time: 2:35:49 PM - * To change this template use File | Settings | File Templates. + * @author Eugene.Kudelevsky */ -public abstract class AndroidSdk { +public class AndroidSdk { private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.sdk.AndroidSdk"); private static volatile boolean myDdmLibInitialized = false; @@ -63,11 +59,58 @@ public abstract class AndroidSdk { private final Map> myTargetDatas = new HashMap>(); - @NotNull - public abstract String getLocation(); + private final SdkManager mySdkManager; + private IAndroidTarget[] myTargets = null; + + private final int myPlatformToolsRevision; + + public AndroidSdk(@NotNull SdkManager sdkManager, @NotNull String sdkDirOsPath) { + mySdkManager = sdkManager; + + final File platformToolsPropFile = + new File(sdkDirOsPath + File.separatorChar + SdkConstants.FD_PLATFORM_TOOLS + File.separatorChar + SdkConstants.FN_SOURCE_PROP); + int platformToolsRevision = -1; + if (platformToolsPropFile.exists() && platformToolsPropFile.isFile()) { + final Map map = + ProjectProperties.parsePropertyFile(new BufferingFileWrapper(platformToolsPropFile), new MessageBuildingSdkLog()); + final String revision = map.get("Pkg.Revision"); + if (revision != null) { + try { + platformToolsRevision = Integer.parseInt(revision); + } + catch (NumberFormatException e) { + LOG.info(e); + } + } + } + myPlatformToolsRevision = platformToolsRevision > 0 ? platformToolsRevision : -1; + } @NotNull - public abstract IAndroidTarget[] getTargets(); + public String getLocation() { + String location = mySdkManager.getLocation(); + if (location.length() > 0) { + char lastChar = location.charAt(location.length() - 1); + if (lastChar == '/' || lastChar == File.separatorChar) { + return location.substring(0, location.length() - 1); + } + } + return location; + } + + @NotNull + public IAndroidTarget[] getTargets() { + if (myTargets == null) { + IAndroidTarget[] targets = mySdkManager.getTargets(); + if (targets != null) { + myTargets = new IAndroidTarget[targets.length]; + for (int i = 0; i < targets.length; i++) { + myTargets[i] = new MyTargetWrapper(targets[i]); + } + } + } + return myTargets; + } // be careful! target name is NOT unique @@ -98,28 +141,19 @@ public abstract class AndroidSdk { } @Nullable - public IAndroidTarget findTargetByLocation(@NotNull String location) { - for (IAndroidTarget target : getTargets()) { - String targetPath = FileUtil.toSystemIndependentName(target.getLocation()); - if (FileUtil.pathsEqual(location + '/', targetPath) || FileUtil.pathsEqual(location, targetPath)) { - return target; - } - } - return null; + public IAndroidTarget findTargetByHashString(@NotNull String hashString) { + final IAndroidTarget target = mySdkManager.getTargetFromHashString(hashString); + return target != null ? new MyTargetWrapper(target) : null; } - public abstract IAndroidTarget findTargetByHashString(@NotNull String hashString); - - public abstract int getPlatformToolsRevision(); + public int getPlatformToolsRevision() { + return myPlatformToolsRevision; + } @Nullable public static AndroidSdk parse(@NotNull String path, @NotNull ISdkLog log) { final SdkManager manager = AndroidSdkUtils.createSdkManager(path, log); - - if (manager != null) { - return new AndroidSdkImpl(manager, path); - } - return null; + return manager != null ? new AndroidSdk(manager, path) : null; } @Nullable @@ -172,6 +206,7 @@ public abstract class AndroidSdk { boolean finished = task.isFinished(); + //noinspection AssignmentToStaticFieldFromInstanceMethod myAdbCrashed = !finished; if (task.isCanceled()) { @@ -181,8 +216,9 @@ public abstract class AndroidSdk { if (!finished) { int result = Messages - .showOkCancelDialog(project, "ADB not responding. Please, kill \"" + SdkConstants.FN_ADB + "\" process manually and click 'Retry'", - CommonBundle.getErrorTitle(), "&Retry", "&Cancel", Messages.getErrorIcon()); + .showOkCancelDialog(project, + "ADB not responding. Please, kill \"" + SdkConstants.FN_ADB + "\" process manually and click 'Retry'", + CommonBundle.getErrorTitle(), "&Retry", "&Cancel", Messages.getErrorIcon()); if (result == 1) { forceInterrupt(t); @@ -223,6 +259,7 @@ public abstract class AndroidSdk { synchronized (myDdmsLock) { String adbPath = getAdbPath(); if (!myDdmLibInitialized) { + //noinspection AssignmentToStaticFieldFromInstanceMethod myDdmLibInitialized = true; DdmPreferences.setTimeOut(AndroidUtils.TIMEOUT); AndroidDebugBridge.init(AndroidEnableDdmsAction.isDdmsEnabled()); @@ -286,6 +323,11 @@ public abstract class AndroidSdk { return AndroidDebugBridge.getBridge(); } + @NotNull + public SdkManager getSdkManager() { + return mySdkManager; + } + @Nullable public AndroidTargetData getTargetData(@NotNull IAndroidTarget target) { final SoftReference targetDataRef = myTargetDatas.get(target); @@ -356,4 +398,206 @@ public abstract class AndroidSdk { } } } + + private static class MyTargetWrapper implements IAndroidTarget { + private final TIntObjectHashMap myAlternativePaths; + private final IAndroidTarget myWrapee; + + private MyTargetWrapper(@NotNull IAndroidTarget wrapee) { + myWrapee = wrapee; + myAlternativePaths = new TIntObjectHashMap(); + String oldPlatformToolsFolderPath = getOldPlatformToolsFolderPath(); + if (!canFindTool(AAPT)) { + myAlternativePaths.put(AAPT, oldPlatformToolsFolderPath + SdkConstants.FN_AAPT); + } + if (!canFindTool(AIDL)) { + myAlternativePaths.put(AIDL, oldPlatformToolsFolderPath + SdkConstants.FN_AIDL); + } + if (!canFindTool(DX)) { + myAlternativePaths.put(DX, oldPlatformToolsFolderPath + SdkConstants.FN_DX); + } + if (!canFindTool(DX_JAR)) { + myAlternativePaths.put(DX_JAR, oldPlatformToolsFolderPath + SdkConstants.FD_LIB + File.separator + SdkConstants.FN_DX_JAR); + } + } + + @Nullable + private String getOldPlatformToolsFolderPath() { + String platformLocation; + if (myWrapee.isPlatform()) { + platformLocation = myWrapee.getLocation(); + } + else { + IAndroidTarget parent = myWrapee.getParent(); + platformLocation = parent != null ? parent.getLocation() : null; + } + if (platformLocation == null) { + return null; + } + return platformLocation + SdkConstants.FD_TOOLS + File.separator; + } + + private boolean canFindTool(int pathId) { + String path = myWrapee.getPath(pathId); + return path != null && new File(path).exists(); + } + + @Override + public String getLocation() { + return myWrapee.getLocation(); + } + + @Override + public String getVendor() { + return myWrapee.getVendor(); + } + + @Override + public String getName() { + return myWrapee.getName(); + } + + @Override + public String getFullName() { + return myWrapee.getFullName(); + } + + @Override + public String getClasspathName() { + return myWrapee.getClasspathName(); + } + + @Override + public String getShortClasspathName() { + return myWrapee.getShortClasspathName(); + } + + @Override + public String getDescription() { + return myWrapee.getDescription(); + } + + @Override + public AndroidVersion getVersion() { + return myWrapee.getVersion(); + } + + @Override + public String getVersionName() { + return myWrapee.getVersionName(); + } + + @Override + public int getRevision() { + return myWrapee.getRevision(); + } + + @Override + public boolean isPlatform() { + return myWrapee.isPlatform(); + } + + @Override + public IAndroidTarget getParent() { + return myWrapee.getParent(); + } + + @Override + public String getPath(int pathId) { + String path = myAlternativePaths.get(pathId); + if (path != null) { + return path; + } + return myWrapee.getPath(pathId); + } + + @Override + public boolean hasRenderingLibrary() { + return myWrapee.hasRenderingLibrary(); + } + + @Override + public String[] getSkins() { + return myWrapee.getSkins(); + } + + @Override + public String getDefaultSkin() { + return myWrapee.getDefaultSkin(); + } + + @Override + public IOptionalLibrary[] getOptionalLibraries() { + return myWrapee.getOptionalLibraries(); + } + + @Override + public String[] getPlatformLibraries() { + return myWrapee.getPlatformLibraries(); + } + + @Override + public String getProperty(String name) { + return myWrapee.getProperty(name); + } + + @Override + public Integer getProperty(String name, Integer defaultValue) { + return myWrapee.getProperty(name, defaultValue); + } + + @Override + public Boolean getProperty(String name, Boolean defaultValue) { + return myWrapee.getProperty(name, defaultValue); + } + + @Override + public Map getProperties() { + return myWrapee.getProperties(); + } + + @Override + public int getUsbVendorId() { + return myWrapee.getUsbVendorId(); + } + + @Override + public ISystemImage[] getSystemImages() { + return myWrapee.getSystemImages(); + } + + @Override + public ISystemImage getSystemImage(String abiType) { + return myWrapee.getSystemImage(abiType); + } + + @Override + public boolean canRunOn(IAndroidTarget target) { + return myWrapee.canRunOn(target); + } + + @Override + public String hashString() { + return myWrapee.hashString(); + } + + @Override + public int compareTo(IAndroidTarget o) { + return myWrapee.compareTo(o); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof MyTargetWrapper)) { + return false; + } + MyTargetWrapper other = (MyTargetWrapper)obj; + return myWrapee.equals(other.myWrapee); + } + + @Override + public int hashCode() { + return myWrapee.hashCode(); + } + } } diff --git a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkImpl.java b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkImpl.java deleted file mode 100644 index f3911830d763..000000000000 --- a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkImpl.java +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright 2000-2010 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.android.sdk; - -import com.android.sdklib.*; -import com.android.sdklib.internal.project.ProjectProperties; -import com.intellij.openapi.diagnostic.Logger; -import gnu.trove.TIntObjectHashMap; -import org.jetbrains.android.util.BufferingFileWrapper; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.File; -import java.util.Map; - -/** - * Created by IntelliJ IDEA. - * User: Eugene.Kudelevsky - * Date: Jun 2, 2009 - * Time: 2:37:00 PM - * To change this template use File | Settings | File Templates. - */ -public class AndroidSdkImpl extends AndroidSdk { - private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.sdk.AndroidSdkImpl"); - private final SdkManager mySdkManager; - private IAndroidTarget[] myTargets = null; - - private final int myPlatformToolsRevision; - - public AndroidSdkImpl(@NotNull SdkManager sdkManager, @NotNull String sdkDirOsPath) { - mySdkManager = sdkManager; - - final File platformToolsPropFile = - new File(sdkDirOsPath + File.separatorChar + SdkConstants.FD_PLATFORM_TOOLS + File.separatorChar + SdkConstants.FN_SOURCE_PROP); - int platformToolsRevision = -1; - if (platformToolsPropFile.exists() && platformToolsPropFile.isFile()) { - final Map map = - ProjectProperties.parsePropertyFile(new BufferingFileWrapper(platformToolsPropFile), new MessageBuildingSdkLog()); - final String revision = map.get("Pkg.Revision"); - if (revision != null) { - try { - platformToolsRevision = Integer.parseInt(revision); - } - catch (NumberFormatException e) { - LOG.info(e); - } - } - } - myPlatformToolsRevision = platformToolsRevision > 0 ? platformToolsRevision : -1; - } - - @NotNull - public String getLocation() { - String location = mySdkManager.getLocation(); - if (location.length() > 0) { - char lastChar = location.charAt(location.length() - 1); - if (lastChar == '/' || lastChar == File.separatorChar) { - return location.substring(0, location.length() - 1); - } - } - return location; - } - - @NotNull - public IAndroidTarget[] getTargets() { - if (myTargets == null) { - IAndroidTarget[] targets = mySdkManager.getTargets(); - if (targets != null) { - myTargets = new IAndroidTarget[targets.length]; - for (int i = 0; i < targets.length; i++) { - myTargets[i] = new MyTargetWrapper(targets[i]); - } - } - } - return myTargets; - } - - @Override - public IAndroidTarget findTargetByHashString(@NotNull String hashString) { - final IAndroidTarget target = mySdkManager.getTargetFromHashString(hashString); - return target != null ? new MyTargetWrapper(target) : null; - } - - @NotNull - public SdkManager getSdkManager() { - return mySdkManager; - } - - public int getPlatformToolsRevision() { - return myPlatformToolsRevision; - } - - private static class MyTargetWrapper implements IAndroidTarget { - private final TIntObjectHashMap myAlternativePaths; - private final IAndroidTarget myWrapee; - - private MyTargetWrapper(@NotNull IAndroidTarget wrapee) { - myWrapee = wrapee; - myAlternativePaths = new TIntObjectHashMap(); - String oldPlatformToolsFolderPath = getOldPlatformToolsFolderPath(); - if (!canFindTool(AAPT)) { - myAlternativePaths.put(AAPT, oldPlatformToolsFolderPath + SdkConstants.FN_AAPT); - } - if (!canFindTool(AIDL)) { - myAlternativePaths.put(AIDL, oldPlatformToolsFolderPath + SdkConstants.FN_AIDL); - } - if (!canFindTool(DX)) { - myAlternativePaths.put(DX, oldPlatformToolsFolderPath + SdkConstants.FN_DX); - } - if (!canFindTool(DX_JAR)) { - myAlternativePaths.put(DX_JAR, oldPlatformToolsFolderPath + SdkConstants.FD_LIB + File.separator + SdkConstants.FN_DX_JAR); - } - } - - @Nullable - private String getOldPlatformToolsFolderPath() { - String platformLocation; - if (myWrapee.isPlatform()) { - platformLocation = myWrapee.getLocation(); - } - else { - IAndroidTarget parent = myWrapee.getParent(); - platformLocation = parent != null ? parent.getLocation() : null; - } - if (platformLocation == null) { - return null; - } - return platformLocation + SdkConstants.FD_TOOLS + File.separator; - } - - private boolean canFindTool(int pathId) { - String path = myWrapee.getPath(pathId); - return path != null && new File(path).exists(); - } - - @Override - public String getLocation() { - return myWrapee.getLocation(); - } - - @Override - public String getVendor() { - return myWrapee.getVendor(); - } - - @Override - public String getName() { - return myWrapee.getName(); - } - - @Override - public String getFullName() { - return myWrapee.getFullName(); - } - - @Override - public String getClasspathName() { - return myWrapee.getClasspathName(); - } - - @Override - public String getShortClasspathName() { - return myWrapee.getShortClasspathName(); - } - - @Override - public String getDescription() { - return myWrapee.getDescription(); - } - - @Override - public AndroidVersion getVersion() { - return myWrapee.getVersion(); - } - - @Override - public String getVersionName() { - return myWrapee.getVersionName(); - } - - @Override - public int getRevision() { - return myWrapee.getRevision(); - } - - @Override - public boolean isPlatform() { - return myWrapee.isPlatform(); - } - - @Override - public IAndroidTarget getParent() { - return myWrapee.getParent(); - } - - @Override - public String getPath(int pathId) { - String path = myAlternativePaths.get(pathId); - if (path != null) { - return path; - } - return myWrapee.getPath(pathId); - } - - @Override - public boolean hasRenderingLibrary() { - return myWrapee.hasRenderingLibrary(); - } - - @Override - public String[] getSkins() { - return myWrapee.getSkins(); - } - - @Override - public String getDefaultSkin() { - return myWrapee.getDefaultSkin(); - } - - @Override - public IOptionalLibrary[] getOptionalLibraries() { - return myWrapee.getOptionalLibraries(); - } - - @Override - public String[] getPlatformLibraries() { - return myWrapee.getPlatformLibraries(); - } - - @Override - public String getProperty(String name) { - return myWrapee.getProperty(name); - } - - @Override - public Integer getProperty(String name, Integer defaultValue) { - return myWrapee.getProperty(name, defaultValue); - } - - @Override - public Boolean getProperty(String name, Boolean defaultValue) { - return myWrapee.getProperty(name, defaultValue); - } - - @Override - public Map getProperties() { - return myWrapee.getProperties(); - } - - @Override - public int getUsbVendorId() { - return myWrapee.getUsbVendorId(); - } - - @Override - public ISystemImage[] getSystemImages() { - return myWrapee.getSystemImages(); - } - - @Override - public ISystemImage getSystemImage(String abiType) { - return myWrapee.getSystemImage(abiType); - } - - @Override - public boolean canRunOn(IAndroidTarget target) { - return myWrapee.canRunOn(target); - } - - @Override - public String hashString() { - return myWrapee.hashString(); - } - - @Override - public int compareTo(IAndroidTarget o) { - return myWrapee.compareTo(o); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof MyTargetWrapper)) { - return false; - } - MyTargetWrapper other = (MyTargetWrapper)obj; - return myWrapee.equals(other.myWrapee); - } - - @Override - public int hashCode() { - return myWrapee.hashCode(); - } - } -} diff --git a/plugins/android/src/org/jetbrains/android/util/AndroidResourceUtil.java b/plugins/android/src/org/jetbrains/android/util/AndroidResourceUtil.java index 553fb41e9c4a..d36a90ded8a2 100644 --- a/plugins/android/src/org/jetbrains/android/util/AndroidResourceUtil.java +++ b/plugins/android/src/org/jetbrains/android/util/AndroidResourceUtil.java @@ -99,7 +99,7 @@ public class AndroidResourceUtil { collectDirsForPackage(module, project, null, dirs, new HashSet(), onlyInOwnPackages); List rJavaFiles = new ArrayList(); for (PsiDirectory dir : dirs) { - VirtualFile file = dir.getVirtualFile().findChild(AndroidUtils.R_JAVA_FILENAME); + VirtualFile file = dir.getVirtualFile().findChild(AndroidCommonUtils.R_JAVA_FILENAME); if (file != null) { PsiFile psiFile = PsiManager.getInstance(project).findFile(file); if (psiFile instanceof PsiJavaFile) { diff --git a/plugins/android/src/org/jetbrains/android/util/AndroidUtils.java b/plugins/android/src/org/jetbrains/android/util/AndroidUtils.java index 9bc4c6a0675a..34333f8885fc 100644 --- a/plugins/android/src/org/jetbrains/android/util/AndroidUtils.java +++ b/plugins/android/src/org/jetbrains/android/util/AndroidUtils.java @@ -113,7 +113,6 @@ public class AndroidUtils { public static final Icon RESTART_LOGCAT_ICON = IconLoader.getIcon("/icons/restartLogcat.png"); public static final String NAMESPACE_KEY = "android"; public static final String SYSTEM_RESOURCE_PACKAGE = "android"; - public static final String R_JAVA_FILENAME = "R.java"; public static final String ANDROID_PACKAGE = "android"; public static final String VIEW_CLASS_NAME = ANDROID_PACKAGE + ".view.View"; public static final String APPLICATION_CLASS_NAME = "android.app.Application"; @@ -148,7 +147,6 @@ public class AndroidUtils { public static final String PROVIDER_CLASS_NAME = "android.content.ContentProvider"; @NonNls public static final String DEFAULT_PROPERTIES_FILE_NAME = "default.properties"; @NonNls public static final String PNG_EXTENSION = "png"; - @NonNls public static final Object MANIFEST_JAVA_FILE_NAME = "Manifest.java"; private AndroidUtils() { } @@ -259,7 +257,7 @@ public class AndroidUtils { } public static boolean isRClassFile(@NotNull AndroidFacet facet, @NotNull PsiFile file) { - if (file.getName().equals(R_JAVA_FILENAME) && file instanceof PsiJavaFile) { + if (file.getName().equals(AndroidCommonUtils.R_JAVA_FILENAME) && file instanceof PsiJavaFile) { PsiJavaFile javaFile = (PsiJavaFile)file; Manifest manifest = facet.getManifest(); if (manifest == null) return false; @@ -961,20 +959,6 @@ public class AndroidUtils { return xmlFiles; } - public static String command2string(@NotNull Collection command) { - final StringBuilder builder = new StringBuilder(); - for (Iterator it = command.iterator(); it.hasNext(); ) { - String s = it.next(); - builder.append('['); - builder.append(s); - builder.append(']'); - if (it.hasNext()) { - builder.append(' '); - } - } - return builder.toString(); - } - @Nullable public static String getProjectPropertyValue(Module module, String propertyName) { final String result = getPropertyValue(module, SdkConstants.FN_PROJECT_PROPERTIES, propertyName); diff --git a/plugins/android/src/org/jetbrains/android/util/ExecutionUtil.java b/plugins/android/src/org/jetbrains/android/util/ExecutionUtil.java deleted file mode 100644 index 9c5efe24f589..000000000000 --- a/plugins/android/src/org/jetbrains/android/util/ExecutionUtil.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright 2000-2010 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jetbrains.android.util; - -import com.intellij.execution.process.OSProcessHandler; -import com.intellij.execution.process.ProcessAdapter; -import com.intellij.execution.process.ProcessEvent; -import com.intellij.execution.process.ProcessOutputTypes; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.compiler.CompilerMessageCategory; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.text.StringUtil; -import org.jetbrains.annotations.NotNull; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Abstract external tool for compiler. - * - * @author Alexey Efimov - */ -public final class ExecutionUtil { - - private static final String IGNORING = "ignoring"; - private static final String SKIPPING = "skipping"; - - private ExecutionUtil() { - } - - // can't be invoked from dispatch thread - @NotNull - public static Map> execute(String... argv) throws IOException { - assert !ApplicationManager.getApplication().isDispatchThread(); - ProcessBuilder builder = new ProcessBuilder(argv); - ProcessResult result = readProcessOutput(builder.start()); - Map> messages = result.getMessages(); - int code = result.getExitCode(); - List errMessages = messages.get(CompilerMessageCategory.ERROR); - - if (code != 0 && errMessages.isEmpty()) { - throw new IOException(AndroidBundle.message("command.0.execution.failed.with.exit.code.1", concat(argv), code)); - } - else { - if (code == 0) { - messages.get(CompilerMessageCategory.INFORMATION).addAll(errMessages); - errMessages.clear(); - } - return messages; - } - } - - private static String concat(String... strs) { - StringBuilder builder = new StringBuilder(); - for (int i = 0, n = strs.length; i < n; i++) { - builder.append(strs[i]); - if (i < n - 1) { - builder.append(' '); - } - } - return builder.toString(); - } - - @NotNull - private static ProcessResult readProcessOutput(Process process) throws IOException { - assert !ApplicationManager.getApplication().isDispatchThread(); - OSProcessHandler handler = new OSProcessHandler(process, ""); - final List information = new ArrayList(); - final List error = new ArrayList(); - handler.addProcessListener(new ProcessAdapter() { - public void onTextAvailable(final ProcessEvent event, final Key outputType) { - String output = event.getText(); - if (StringUtil.isEmptyOrSpaces(output)) { - return; - } - String[] lines = output.split("[\\n\\r]+"); - for (String line : lines) { - String l = line.toLowerCase(); - if (outputType == ProcessOutputTypes.STDOUT) { - information.add(line); - } - else if (outputType == ProcessOutputTypes.STDERR) { - if (l.contains(IGNORING) || l.contains(SKIPPING)) { - information.add(line); - } - else { - error.add(line); - } - } - } - } - }); - handler.startNotify(); - handler.waitFor(); - int exitCode = handler.getProcess().exitValue(); - return new ProcessResult(information, error, exitCode); - } - - private static final class ProcessResult { - private final int myExitCode; - private final Map> myMessages; - - public ProcessResult(List information, List error, int exitCode) { - myExitCode = exitCode; - myMessages = new HashMap>(2); - myMessages.put(CompilerMessageCategory.INFORMATION, information); - myMessages.put(CompilerMessageCategory.ERROR, error); - } - - public Map> getMessages() { - return myMessages; - } - - public int getExitCode() { - return myExitCode; - } - } -} diff --git a/plugins/android/testData/lint/global/duplicateIcons/dup1.png b/plugins/android/testData/lint/global/duplicateIcons/dup1.png new file mode 100644 index 000000000000..3779d4d33dc0 Binary files /dev/null and b/plugins/android/testData/lint/global/duplicateIcons/dup1.png differ diff --git a/plugins/android/testData/lint/global/duplicateIcons/dup2.png b/plugins/android/testData/lint/global/duplicateIcons/dup2.png new file mode 100644 index 000000000000..3779d4d33dc0 Binary files /dev/null and b/plugins/android/testData/lint/global/duplicateIcons/dup2.png differ diff --git a/plugins/android/testData/lint/global/duplicateIcons/expected.xml b/plugins/android/testData/lint/global/duplicateIcons/expected.xml new file mode 100644 index 000000000000..f52bc6d402b0 --- /dev/null +++ b/plugins/android/testData/lint/global/duplicateIcons/expected.xml @@ -0,0 +1,8 @@ + + + + dup2.png + 1 + The following unrelated icon files have identical contents: dup1.png, dup2.png + + \ No newline at end of file diff --git a/plugins/android/testData/lint/global/duplicateIcons/other.png b/plugins/android/testData/lint/global/duplicateIcons/other.png new file mode 100644 index 000000000000..6adea8576647 Binary files /dev/null and b/plugins/android/testData/lint/global/duplicateIcons/other.png differ diff --git a/plugins/android/testData/lint/global/manifestOrder/AndroidManifest.xml b/plugins/android/testData/lint/global/manifestOrder/AndroidManifest.xml new file mode 100644 index 000000000000..2148ce24957d --- /dev/null +++ b/plugins/android/testData/lint/global/manifestOrder/AndroidManifest.xml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/plugins/android/testData/lint/global/manifestOrder/expected.xml b/plugins/android/testData/lint/global/manifestOrder/expected.xml new file mode 100644 index 000000000000..616700c5539d --- /dev/null +++ b/plugins/android/testData/lint/global/manifestOrder/expected.xml @@ -0,0 +1,8 @@ + + + + AndroidManifest.xml + 9 + <uses-sdk> tag appears after <application> tag + + \ No newline at end of file diff --git a/plugins/android/testData/lint/global/proguard/expected.xml b/plugins/android/testData/lint/global/proguard/expected.xml new file mode 100644 index 000000000000..81e12d62c562 --- /dev/null +++ b/plugins/android/testData/lint/global/proguard/expected.xml @@ -0,0 +1,8 @@ + + + + proguard.cfg + 1 + Obsolete proguard file; use -keepclasseswithmembers instead of -keepclasseswithmembernames + + \ No newline at end of file diff --git a/plugins/android/testData/lint/global/proguard/proguard.cfg b/plugins/android/testData/lint/global/proguard/proguard.cfg new file mode 100644 index 000000000000..160247cd3fac --- /dev/null +++ b/plugins/android/testData/lint/global/proguard/proguard.cfg @@ -0,0 +1,3 @@ +-keepclasseswithmembernames class * { + public (android."); +} \ No newline at end of file diff --git a/plugins/android/testData/lint/typographyDashes_after.xml b/plugins/android/testData/lint/typographyDashes_after.xml index 35404e3362b2..978f0b9e719d 100644 --- a/plugins/android/testData/lint/typographyDashes_after.xml +++ b/plugins/android/testData/lint/typographyDashes_after.xml @@ -1,4 +1,4 @@ - 10–20 + 10~20 \ No newline at end of file diff --git a/plugins/android/testData/lint/typographyQuotes_after.xml b/plugins/android/testData/lint/typographyQuotes_after.xml index f0539ff7ece6..782ef948f2e4 100644 --- a/plugins/android/testData/lint/typographyQuotes_after.xml +++ b/plugins/android/testData/lint/typographyQuotes_after.xml @@ -1,5 +1,5 @@ untitled303 - aba ‘aba’ + aba {aba} diff --git a/plugins/android/testSrc/org/jetbrains/android/AndroidLintTest.java b/plugins/android/testSrc/org/jetbrains/android/AndroidLintTest.java index dfcd39e34d20..004f2ea099f6 100644 --- a/plugins/android/testSrc/org/jetbrains/android/AndroidLintTest.java +++ b/plugins/android/testSrc/org/jetbrains/android/AndroidLintTest.java @@ -1,11 +1,20 @@ package org.jetbrains.android; +import com.intellij.analysis.AnalysisScope; import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ex.GlobalInspectionContextImpl; import com.intellij.codeInspection.ex.GlobalInspectionToolWrapper; +import com.intellij.codeInspection.ex.InspectionManagerEx; import com.intellij.openapi.application.Result; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.vfs.VirtualFile; -import org.jetbrains.android.inspections.lint.*; +import com.intellij.testFramework.InspectionTestUtil; +import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl; +import org.jetbrains.android.inspections.lint.AndroidAddStringResourceQuickFix; +import org.jetbrains.android.inspections.lint.AndroidLintExternalAnnotator; +import org.jetbrains.android.inspections.lint.AndroidLintInspectionBase; +import org.jetbrains.android.inspections.lint.AndroidLintInspectionToolProvider; import org.jetbrains.android.util.AndroidBundle; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -18,6 +27,7 @@ import java.io.IOException; */ public class AndroidLintTest extends AndroidTestCase { @NonNls private static final String BASE_PATH = "/lint/"; + @NonNls private static final String BASE_PATH_GLOBAL = BASE_PATH + "global/"; public AndroidLintTest() { super(false); @@ -140,7 +150,7 @@ public class AndroidLintTest extends AndroidTestCase { "/res/layout/layout.xml", "xml"); } - /*public void testTypographyDashes() throws Exception { + public void testTypographyDashes() throws Exception { doTestWithFix(new AndroidLintInspectionToolProvider.AndroidLintTypographyDashesInspection(), AndroidBundle.message("android.lint.inspections.replace.with.suggested.characters"), "/res/values/typography.xml", "xml"); @@ -150,7 +160,45 @@ public class AndroidLintTest extends AndroidTestCase { doTestWithFix(new AndroidLintInspectionToolProvider.AndroidLintTypographyQuotesInspection(), AndroidBundle.message("android.lint.inspections.replace.with.suggested.characters"), "/res/values/typography.xml", "xml"); - }*/ + } + + public void testProguard() throws Exception { + createManifest(); + myFixture.copyFileToProject(getGlobalTestDir() + "/proguard.cfg", "proguard.cfg"); + doGlobalInspectionTest(new AndroidLintInspectionToolProvider.AndroidLintProguardInspection()); + } + + public void testManifestOrder() throws Exception { + myFixture.copyFileToProject(getGlobalTestDir() + "/AndroidManifest.xml", "AndroidManifest.xml"); + doGlobalInspectionTest(new AndroidLintInspectionToolProvider.AndroidLintManifestOrderInspection()); + } + + public void testDuplicateIcons() throws Exception { + createManifest(); + myFixture.copyFileToProject(getGlobalTestDir() + "/dup1.png", "res/drawable/dup1.png"); + myFixture.copyFileToProject(getGlobalTestDir() + "/dup2.png", "res/drawable/dup2.png"); + myFixture.copyFileToProject(getGlobalTestDir() + "/other.png", "res/drawable/other.png"); + doGlobalInspectionTest(new AndroidLintInspectionToolProvider.AndroidLintIconDuplicatesInspection()); + } + + private void doGlobalInspectionTest(@NotNull AndroidLintInspectionBase inspection) { + final GlobalInspectionToolWrapper wrapper = new GlobalInspectionToolWrapper(inspection); + myFixture.enableInspections(wrapper); + + final AnalysisScope scope = new AnalysisScope(myModule); + scope.invalidate(); + + final InspectionManagerEx inspectionManager = (InspectionManagerEx)InspectionManager.getInstance(getProject()); + final GlobalInspectionContextImpl globalContext = + CodeInsightTestFixtureImpl.createGlobalContextForTool(scope, getProject(), inspectionManager, wrapper); + + InspectionTestUtil.runTool(wrapper, scope, globalContext, inspectionManager); + InspectionTestUtil.compareToolResults(wrapper, false, getTestDataPath() + getGlobalTestDir()); + } + + private String getGlobalTestDir() { + return BASE_PATH_GLOBAL + getTestName(true); + } private void doTestNoFix(@NotNull AndroidLintInspectionBase inspection, @NotNull String copyTo, @NotNull String extension) throws IOException { diff --git a/plugins/devkit/src/projectRoots/IdeaJdkConfigurable.java b/plugins/devkit/src/projectRoots/IdeaJdkConfigurable.java index 131689a805ca..324693e97f5e 100644 --- a/plugins/devkit/src/projectRoots/IdeaJdkConfigurable.java +++ b/plugins/devkit/src/projectRoots/IdeaJdkConfigurable.java @@ -22,6 +22,7 @@ import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.projectRoots.*; +import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl; import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.io.FileUtil; @@ -211,6 +212,7 @@ public class IdeaJdkConfigurable implements AdditionalDataConfigurable { modificator.commitChanges(); } }); + ((ProjectJdkImpl) myIdeaJdk).resetVersionString(); myModified = false; } diff --git a/plugins/eclipse/src/org/jetbrains/idea/eclipse/EclipseXml.java b/plugins/eclipse/src/org/jetbrains/idea/eclipse/EclipseXml.java index 3d38360c09c7..8503577ab94f 100644 --- a/plugins/eclipse/src/org/jetbrains/idea/eclipse/EclipseXml.java +++ b/plugins/eclipse/src/org/jetbrains/idea/eclipse/EclipseXml.java @@ -41,6 +41,7 @@ public interface EclipseXml { @NonNls String JRE_CONTAINER_SPECIFIC = JRE_CONTAINER + "/" + "org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType"; @NonNls String USER_LIBRARY = "org.eclipse.jdt.USER_LIBRARY"; @NonNls String JUNIT_CONTAINER = "org.eclipse.jdt.junit.JUNIT_CONTAINER"; + @NonNls String GROOVY_DSL_CONTAINER = "GROOVY_DSL_SUPPORT"; @NonNls String JUNIT3 = JUNIT_CONTAINER + "/" + "3.8.1"; @NonNls String JUNIT4 = JUNIT_CONTAINER + "/" + "4"; @NonNls String ECLIPSE_PLATFORM = "org.eclipse.pde.core.requiredPlugins"; diff --git a/plugins/eclipse/src/org/jetbrains/idea/eclipse/config/EclipseClasspathStorageProvider.java b/plugins/eclipse/src/org/jetbrains/idea/eclipse/config/EclipseClasspathStorageProvider.java index 28471448c01d..86867b40a344 100644 --- a/plugins/eclipse/src/org/jetbrains/idea/eclipse/config/EclipseClasspathStorageProvider.java +++ b/plugins/eclipse/src/org/jetbrains/idea/eclipse/config/EclipseClasspathStorageProvider.java @@ -148,6 +148,7 @@ public class EclipseClasspathStorageProvider implements ClasspathStorageProvider LocalFileSystem.getInstance().refreshAndFindFileByIoFile(target); } final CachedXmlDocumentSet fileCache = getFileCache(module); + DotProjectFileHelper.saveDotProjectFile(module, fileCache.getParent(EclipseXml.PROJECT_FILE)); fileCache.delete(oldEmlName); fileCache.register(newName + EclipseXml.IDEA_SETTINGS_POSTFIX, ClasspathStorage.getModuleDir(module)); fileCache.load(newName + EclipseXml.IDEA_SETTINGS_POSTFIX); diff --git a/plugins/eclipse/src/org/jetbrains/idea/eclipse/config/EclipseModuleManager.java b/plugins/eclipse/src/org/jetbrains/idea/eclipse/config/EclipseModuleManager.java index 6488c4a6b196..da5f40a100e3 100644 --- a/plugins/eclipse/src/org/jetbrains/idea/eclipse/config/EclipseModuleManager.java +++ b/plugins/eclipse/src/org/jetbrains/idea/eclipse/config/EclipseModuleManager.java @@ -62,6 +62,7 @@ public class EclipseModuleManager implements PersistentStateComponent{ private int myExpectedModuleSourcePlace; private Map mySrcPlace = new LinkedHashMap(); private String myInvalidJdk; + private boolean myGroovyDslSupport = false; public EclipseModuleManager(Module module) { myModule = module; @@ -75,6 +76,14 @@ public class EclipseModuleManager implements PersistentStateComponent{ return myInvalidJdk; } + public void setGroovyDslSupport() { + myGroovyDslSupport = true; + } + + public boolean isGroovyDslSupport() { + return myGroovyDslSupport; + } + public static EclipseModuleManager getInstance(Module module) { return ModuleServiceManager.getService(module, EclipseModuleManager.class); } diff --git a/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathReader.java b/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathReader.java index db948129570d..e00ca1c1e376 100644 --- a/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathReader.java +++ b/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathReader.java @@ -272,7 +272,12 @@ public class EclipseClasspathReader { final Library.ModifiableModel modifiableModel = library.getModifiableModel(); modifiableModel.addRoot(getJunitClsUrl(junitName.contains("4")), OrderRootType.CLASSES); modifiableModel.commit(); - } else { + } + else if (path.equals(EclipseXml.GROOVY_DSL_CONTAINER)) { + eclipseModuleManager.setGroovyDslSupport(); + eclipseModuleManager.registerSrcPlace(EclipseXml.GROOVY_DSL_CONTAINER, idx); + } + else { eclipseModuleManager.registerUnknownCons(path); addNamedLibrary(rootModel, new ArrayList(), exported, path, LibraryTablesRegistrar.APPLICATION_LEVEL); } diff --git a/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathWriter.java b/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathWriter.java index 959992f9a95a..cb6c69f8f5c5 100644 --- a/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathWriter.java +++ b/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathWriter.java @@ -64,7 +64,8 @@ public class EclipseClasspathWriter { @NonNls String outputPath = "bin"; final String compilerOutputUrl = myModel.getModuleExtension(CompilerModuleExtension.class).getCompilerOutputUrl(); - final String linkedPath = EclipseModuleManager.getInstance(myModel.getModule()).getEclipseLinkedVarPath(compilerOutputUrl); + final EclipseModuleManager eclipseModuleManager = EclipseModuleManager.getInstance(myModel.getModule()); + final String linkedPath = eclipseModuleManager.getEclipseLinkedVarPath(compilerOutputUrl); if (linkedPath != null) { outputPath = linkedPath; } else { @@ -77,6 +78,10 @@ public class EclipseClasspathWriter { outputPath = EPathUtil.collapse2EclipsePath(compilerOutputUrl, myModel); } } + if (eclipseModuleManager.isGroovyDslSupport()) { + final Integer place = eclipseModuleManager.getSrcPlace(EclipseXml.GROOVY_DSL_CONTAINER); + addOrderEntry(EclipseXml.CON_KIND, EclipseXml.GROOVY_DSL_CONTAINER, classpathElement, place != null ? place.intValue() : -1); + } final Element orderEntry = addOrderEntry(EclipseXml.OUTPUT_KIND, outputPath, classpathElement); setAttributeIfAbsent(orderEntry, EclipseXml.PATH_ATTR, EclipseXml.BIN_DIR); } diff --git a/plugins/gradle/resources/i18n/GradleBundle.properties b/plugins/gradle/resources/i18n/GradleBundle.properties index 0491c6ce225e..e85e37d53385 100644 --- a/plugins/gradle/resources/i18n/GradleBundle.properties +++ b/plugins/gradle/resources/i18n/GradleBundle.properties @@ -54,6 +54,11 @@ gradle.sync.change.type.intellij={0} local setting gradle.sync.change.type.conflict=Settings conflict gradle.sync.change.type.unchanged=Unchanged setting gradle.sync.change.type.confirmed=Confirmed settings diff +gradle.sync.change.entity.type.module=module +gradle.sync.change.entity.type.library.dependency=library dependency +gradle.sync.change.library.path=library ''{0}'' binary path +gradle.sync.change.project.name.text=project name +gradle.sync.change.project.language.level.text=project language level change gradle.library.resolve.progress.text=Resolving gradle libraries @@ -72,6 +77,8 @@ gradle.action.refresh.project.text=Refresh gradle project gradle.action.refresh.project.description=Allows to force linked gradle project refresh gradle.action.open.script.text=Open linked gradle project gradle.action.open.script.description=Allows to open project file of the linked gradle project at the editor +gradle.action.import.entity.text=Import +gradle.action.import.entity.description=Import target gradle entity gradle.settings.color.text.sample.conflict.node.name=node-with-conflicting-setup gradle.settings.color.text.sample.node.sync.name=node-with-same-setup diff --git a/plugins/gradle/src/META-INF/plugin.xml b/plugins/gradle/src/META-INF/plugin.xml index e347b9db2348..ff4374eb52a2 100644 --- a/plugins/gradle/src/META-INF/plugin.xml +++ b/plugins/gradle/src/META-INF/plugin.xml @@ -34,19 +34,31 @@ - - + + - + + + + + + + + + + + + @@ -57,10 +69,10 @@ - org.jetbrains.plugins.gradle.bootstrap.GradleBootstrap + org.jetbrains.plugins.gradle.sync.GradleProjectStructureChangesModel - org.jetbrains.plugins.gradle.sync.GradleProjectStructureChangesModel + org.jetbrains.plugins.gradle.sync.GradleProjectStructureHelper @@ -68,10 +80,14 @@ + + + + \ No newline at end of file diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleImportEntityAction.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleImportEntityAction.java new file mode 100644 index 000000000000..5000c5995b7e --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleImportEntityAction.java @@ -0,0 +1,131 @@ +package org.jetbrains.plugins.gradle.action; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.gradle.config.GradleTextAttributes; +import org.jetbrains.plugins.gradle.importing.GradleModuleDependencyImporter; +import org.jetbrains.plugins.gradle.importing.GradleModuleImporter; +import org.jetbrains.plugins.gradle.model.GradleLibraryDependency; +import org.jetbrains.plugins.gradle.model.GradleLibraryDependencyId; +import org.jetbrains.plugins.gradle.model.GradleModule; +import org.jetbrains.plugins.gradle.sync.GradleProjectStructureHelper; +import org.jetbrains.plugins.gradle.ui.GradleDataKeys; +import org.jetbrains.plugins.gradle.ui.GradleProjectStructureNode; +import org.jetbrains.plugins.gradle.util.GradleBundle; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * Imports target {@link GradleTextAttributes#GRADLE_LOCAL_CHANGE 'gradle local'} entity to the current intellij project. + *

+ * Not thread-safe. + * + * @author Denis Zhdanov + * @since 2/7/12 10:32 AM + */ +public class GradleImportEntityAction extends AnAction { + + private static final Logger LOG = Logger.getInstance("#" + GradleImportEntityAction.class.getName()); + + public GradleImportEntityAction() { + getTemplatePresentation().setText(GradleBundle.message("gradle.action.import.entity.text")); + getTemplatePresentation().setDescription(GradleBundle.message("gradle.action.import.entity.description")); + } + + @Override + public void update(AnActionEvent e) { + final Collection> nodes = getInterestedNodes(e.getDataContext()); + e.getPresentation().setEnabled(!nodes.isEmpty()); + } + + @Override + public void actionPerformed(AnActionEvent e) { + final Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext()); + if (project == null) { + LOG.warn("Can't import gradle-local entities. Reason: target intellij project is undefined"); + return; + } + + final Collection> nodes = getInterestedNodes(e.getDataContext()); + + // We need to import not only the selected nodes but their gradle-local parents as well. + List> nodesToImport = new ArrayList>(); + for (GradleProjectStructureNode node : nodes) { + collectHierarchyToImport(node, nodesToImport); + } + + GradleProjectStructureHelper projectStructureHelper = project.getComponent(GradleProjectStructureHelper.class); + GradleModuleImporter moduleImporter = ServiceManager.getService(GradleModuleImporter.class); + GradleModuleDependencyImporter dependencyImporter = ServiceManager.getService(GradleModuleDependencyImporter.class); + + for (GradleProjectStructureNode node : nodesToImport) { + switch (node.getType()) { + case MODULE: + final GradleModule gradleModule = projectStructureHelper.findGradleModuleByName(node.getDescriptor().getName()); + if (gradleModule != null) { + moduleImporter.importModule(gradleModule, project); + } + break; + case LIBRARY_DEPENDENCY: + final Object element = node.getDescriptor().getElement(); + if (!(element instanceof GradleLibraryDependencyId)) { + break; + } + GradleLibraryDependencyId id = (GradleLibraryDependencyId)element; + final GradleLibraryDependency dependency = projectStructureHelper.findLibraryDependency(id); + final Module intellijModule = projectStructureHelper.findIntellijModuleByName(id.getModuleName()); + if (dependency != null && intellijModule != null) { + dependencyImporter.importDependency(dependency, intellijModule); + } + break; + default: // Do nothing + } + } + } + + /** + * When particular gradle-local node is asked to be imported we need to import its gradle-local parent hierarchy as well. + *

+ * This method allows to collect all parent nodes of the given nodes that should be imported as well. + *

+ * Note: those nodes are added to the given collection starting from the topmost one. + * + * @param node target node + * @param storage target nodes storage + */ + private static void collectHierarchyToImport(@Nullable GradleProjectStructureNode node, + @NotNull Collection> storage) + { + if (node == null || node.getDescriptor().getAttributes() != GradleTextAttributes.GRADLE_LOCAL_CHANGE) { + return; + } + collectHierarchyToImport(node.getParent(), storage); + storage.add(node); + } + + @NotNull + private static Collection> getInterestedNodes(@NotNull DataContext context) { + final Collection> selectedNodes = GradleDataKeys.SYNC_TREE_NODE.getData(context); + if (selectedNodes == null) { + return Collections.emptyList(); + } + List> result = new ArrayList>(); + for (GradleProjectStructureNode node : selectedNodes) { + if (node.getDescriptor().getAttributes() == GradleTextAttributes.GRADLE_LOCAL_CHANGE) { + result.add(node); + } + } + return result; + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/bootstrap/GradleBootstrap.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/bootstrap/GradleBootstrap.java deleted file mode 100644 index 6472130b5019..000000000000 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/bootstrap/GradleBootstrap.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.jetbrains.plugins.gradle.bootstrap; - -import com.intellij.openapi.components.AbstractProjectComponent; -import com.intellij.openapi.project.DumbAwareRunnable; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.startup.StartupManager; -import com.intellij.openapi.wm.ToolWindow; -import com.intellij.openapi.wm.ToolWindowAnchor; -import com.intellij.openapi.wm.ex.ToolWindowManagerEx; -import com.intellij.ui.content.impl.ContentImpl; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.plugins.gradle.diff.PlatformFacade; -import org.jetbrains.plugins.gradle.sync.GradleProjectStructureChangesModel; -import org.jetbrains.plugins.gradle.sync.GradleProjectStructureChangesPanel; -import org.jetbrains.plugins.gradle.ui.GradleIcons; -import org.jetbrains.plugins.gradle.util.GradleBundle; - -/** - * Encapsulates initialisation routine of the gradle integration. - * - * @author Denis Zhdanov - * @since 11/3/11 4:01 PM - */ -public class GradleBootstrap extends AbstractProjectComponent { - - private static final String GRADLE_TOOL_WINDOW_ID = GradleBundle.message("gradle.name"); - - private final GradleProjectStructureChangesModel myChangesModel; - private final PlatformFacade myProjectStructureHelper; - - public GradleBootstrap(@NotNull Project project, - @NotNull GradleProjectStructureChangesModel changesModel, - @NotNull PlatformFacade projectStructureHelper) { - super(project); - myChangesModel = changesModel; - myProjectStructureHelper = projectStructureHelper; - } - - @Override - public void projectOpened() { - StartupManager.getInstance(myProject).registerPostStartupActivity(new DumbAwareRunnable() { - @Override - public void run() { - initToolWindow(); - } - }); - } - - private void initToolWindow() { - final ToolWindowManagerEx manager = ToolWindowManagerEx.getInstanceEx(myProject); - ToolWindow toolWindow = manager.registerToolWindow(GRADLE_TOOL_WINDOW_ID, false, ToolWindowAnchor.RIGHT); - toolWindow.setIcon(GradleIcons.GRADLE_ICON); - String syncTitle = GradleBundle.message("gradle.sync.title.tab"); - final GradleProjectStructureChangesPanel projectStructureChanges - = new GradleProjectStructureChangesPanel(myProject, myChangesModel, myProjectStructureHelper); - toolWindow.getContentManager().addContent(new ContentImpl(projectStructureChanges, syncTitle, true)); - } -} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleToolWindowPanel.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleToolWindowPanel.java index 7db8c237d79d..7cc983906126 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleToolWindowPanel.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleToolWindowPanel.java @@ -10,6 +10,7 @@ import com.intellij.util.messages.MessageBusConnection; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.diff.PlatformFacade; +import org.jetbrains.plugins.gradle.sync.GradleProjectStructureHelper; import org.jetbrains.plugins.gradle.util.GradleBundle; import org.jetbrains.plugins.gradle.ui.RichTextControlBuilder; @@ -43,14 +44,17 @@ public abstract class GradleToolWindowPanel extends SimpleToolWindowPanel { private final JPanel myContent = new JPanel(myLayout); private final Project myProject; - private final PlatformFacade myProjectStructureHelper; + private final PlatformFacade myProjectFacade; + private final GradleProjectStructureHelper myProjectStructureHelper; protected GradleToolWindowPanel(@NotNull Project project, - @Nullable PlatformFacade projectStructureHelper, + @Nullable PlatformFacade projectFacade, + @NotNull GradleProjectStructureHelper projectStructureHelper, @NotNull String place) { super(true); myProject = project; + myProjectFacade = projectFacade; myProjectStructureHelper = projectStructureHelper; final ActionManager actionManager = ActionManager.getInstance(); final ActionGroup actionGroup = (ActionGroup)actionManager.getAction(TOOL_WINDOW_TOOLBAR_ID); @@ -98,7 +102,12 @@ public abstract class GradleToolWindowPanel extends SimpleToolWindowPanel { } @NotNull - public PlatformFacade getProjectStructureHelper() { + public PlatformFacade getProjectFacade() { + return myProjectFacade; + } + + @NotNull + public GradleProjectStructureHelper getProjectStructureHelper() { return myProjectStructureHelper; } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleAbstractPropertyValueChange.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleAbstractConflictingPropertyChange.java similarity index 65% rename from plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleAbstractPropertyValueChange.java rename to plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleAbstractConflictingPropertyChange.java index f822b7c8df74..cad6ff1eada3 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleAbstractPropertyValueChange.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleAbstractConflictingPropertyChange.java @@ -19,19 +19,25 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** - * Defines contract for change that points to particular property value change. + * Defines general contract for a change that encapsulates information about conflicting property value of the matched gradle + * and intellij entities. + *

+ * For example we may match particular gradle library to an intellij library but they may have different set of attached binaries. + *

+ * Thread-safe. * * @author Denis Zhdanov * @since 11/15/11 7:57 PM + * @param target property value type */ -public abstract class GradleAbstractPropertyValueChange extends GradleAbstractProjectStructureChange { +public abstract class GradleAbstractConflictingPropertyChange extends GradleAbstractProjectStructureChange { + + private final String myPropertyDescription; + private final T myGradleValue; + private final T myIntellijValue; - private final String myProperyName; - private final T myGradleValue; - private final T myIntellijValue; - - public GradleAbstractPropertyValueChange(@NotNull String propertyName, @Nullable T gradleValue, @Nullable T intellijValue) { - myProperyName = propertyName; + public GradleAbstractConflictingPropertyChange(@NotNull String propertyDescription, @Nullable T gradleValue, @Nullable T intellijValue) { + myPropertyDescription = propertyDescription; myGradleValue = gradleValue; myIntellijValue = intellijValue; } @@ -56,7 +62,7 @@ public abstract class GradleAbstractPropertyValueChange extends GradleAbstrac public int hashCode() { int result = super.hashCode(); result = 31 * result + (myGradleValue != null ? myGradleValue.hashCode() : 0); - return 31 * result + (myIntellijValue != null ? myIntellijValue.hashCode() : 0); + return 31 * result + (myIntellijValue != null ? myIntellijValue.hashCode() : 0); } @Override @@ -65,16 +71,15 @@ public abstract class GradleAbstractPropertyValueChange extends GradleAbstrac if (o == null || getClass() != o.getClass()) return false; if (!super.equals(o)) return false; - GradleAbstractPropertyValueChange that = (GradleAbstractPropertyValueChange)o; + GradleAbstractConflictingPropertyChange that = (GradleAbstractConflictingPropertyChange)o; if (myGradleValue != null ? !myGradleValue.equals(that.myGradleValue) : that.myGradleValue != null) return false; if (myIntellijValue != null ? !myIntellijValue.equals(that.myIntellijValue) : that.myIntellijValue != null) return false; - return true; } @Override public String toString() { - return String.format("%s change: gradle='%s', intellij='%s'", myProperyName, myGradleValue, myIntellijValue); + return String.format("%s change: gradle='%s', intellij='%s'", myPropertyDescription, myGradleValue, myIntellijValue); } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleDiffUtil.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleDiffUtil.java index a6b51a7b8204..1f6d92224729 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleDiffUtil.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleDiffUtil.java @@ -37,7 +37,7 @@ public class GradleDiffUtil { @Override public void visit(@NotNull GradleModule module) { - currentChanges.add(new GradleModulePresenceChange(module, null)); + currentChanges.add(new GradleModulePresenceChange(module.getName(), null)); for (GradleDependency dependency : module.getDependencies()) { dependency.invite(this); } @@ -68,11 +68,14 @@ public class GradleDiffUtil { /** * Analogues to {@link #buildLocalChanges} but targets intellij entity. * + * @param gradleProject gradle project which structure is being compared to the intellij one * @param module target intellij-local module that doesn't present at the gradle side * @param currentChanges holder for the changes built during the current call */ - public static void buildLocalChanges(@NotNull Module module, @NotNull Set currentChanges) { - currentChanges.add(new GradleModulePresenceChange(null, module)); + public static void buildLocalChanges(@NotNull Module module, + @NotNull Set currentChanges) + { + currentChanges.add(new GradleModulePresenceChange(null, module.getName())); // TODO den process module sub-entities here (content roots and dependencies). } @@ -85,18 +88,20 @@ public class GradleDiffUtil { public static void buildLocalChanges(@NotNull LibraryOrderEntry libraryDependency, @NotNull Set currentChanges) { - currentChanges.add(new GradleLibraryDependencyPresenceChange(null, libraryDependency)); + final String libraryName = libraryDependency.getLibraryName(); + if (libraryName != null) { + currentChanges.add(new GradleLibraryDependencyPresenceChange(null, libraryDependency)); + } } /** * Performs argument type-based dispatch and delegates to one of strongly typed 'buildLocalChanges()' methods. * + * @param gradleProject gradle project which structure is being compared to the intellij one * @param entity target intellij-local entity that doesn't present at the gradle side * @param currentChanges holder for the changes built during the current call */ - public static void buildLocalChanges(@NotNull Object entity, - @NotNull Set currentChanges) - { + public static void buildLocalChanges(@NotNull Object entity, @NotNull Set currentChanges) { if (entity instanceof GradleEntity) { buildLocalChanges((GradleEntity)entity, currentChanges); } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleEntityPresenceChange.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleEntityPresenceChange.java index 9e7aedbff9c5..f0d06a4047dc 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleEntityPresenceChange.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleEntityPresenceChange.java @@ -15,6 +15,7 @@ */ package org.jetbrains.plugins.gradle.diff; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -22,13 +23,13 @@ import org.jetbrains.annotations.Nullable; * * @author Denis Zhdanov * @since 11/17/11 12:43 PM - * @param entity type at Gradle side - * @param entity type at IntelliJ IDEA side + * @param entity type */ -public abstract class GradleEntityPresenceChange extends GradleAbstractProjectStructureChange { +public abstract class GradleEntityPresenceChange extends GradleAbstractProjectStructureChange { - private final G myGradleEntity; - private final I myIntellijEntity; + private final T myGradleEntity; + private final T myIntellijEntity; + private final String myEntityName; /** * Creates new GradleEntityPresenceChange project. @@ -40,7 +41,11 @@ public abstract class GradleEntityPresenceChange extends GradleAbstractPro * @throws IllegalArgumentException if both of the given entities are defined or undefined. Expecting this constructor to be * called with one null argument and one non-null argument */ - public GradleEntityPresenceChange(@Nullable G gradleEntity, @Nullable I intellijEntity) throws IllegalArgumentException { + public GradleEntityPresenceChange(@NotNull String entityName, + @Nullable T gradleEntity, + @Nullable T intellijEntity) + throws IllegalArgumentException + { if (!(gradleEntity == null ^ intellijEntity == null)) { throw new IllegalArgumentException(String.format( "Can't construct %s object. Reason: expected that only gradle or intellij entity is null, actual: gradle='%s'; intellij='%s'", @@ -49,15 +54,16 @@ public abstract class GradleEntityPresenceChange extends GradleAbstractPro } myGradleEntity = gradleEntity; myIntellijEntity = intellijEntity; + myEntityName = entityName; } @Nullable - public G getGradleEntity() { + public T getGradleEntity() { return myGradleEntity; } @Nullable - public I getIntellijEntity() { + public T getIntellijEntity() { return myIntellijEntity; } @@ -83,6 +89,6 @@ public abstract class GradleEntityPresenceChange extends GradleAbstractPro @Override public String toString() { - return String.format("entity presence change: gradle='%s', intellij='%s'", myGradleEntity, myIntellijEntity); + return String.format("%s presence change: gradle='%s', intellij='%s'", myEntityName, myGradleEntity, myIntellijEntity); } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLanguageLevelChange.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLanguageLevelChange.java index 02ad57dad14e..b65d4f21ab65 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLanguageLevelChange.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLanguageLevelChange.java @@ -18,15 +18,16 @@ package org.jetbrains.plugins.gradle.diff; import com.intellij.pom.java.LanguageLevel; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.gradle.util.GradleBundle; /** * @author Denis Zhdanov * @since 11/15/11 8:05 PM */ -public class GradleLanguageLevelChange extends GradleAbstractPropertyValueChange { - +public class GradleLanguageLevelChange extends GradleAbstractConflictingPropertyChange { + public GradleLanguageLevelChange(@Nullable LanguageLevel gradleValue, @Nullable LanguageLevel intellijValue) { - super("project language level", gradleValue, intellijValue); + super(GradleBundle.message("gradle.sync.change.project.language.level.text"), gradleValue, intellijValue); } @Override diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryDependencyPresenceChange.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryDependencyPresenceChange.java index e89823d2ef92..f01b816e4dd4 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryDependencyPresenceChange.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryDependencyPresenceChange.java @@ -4,17 +4,21 @@ import com.intellij.openapi.roots.LibraryOrderEntry; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.model.GradleLibraryDependency; +import org.jetbrains.plugins.gradle.model.GradleLibraryDependencyId; +import org.jetbrains.plugins.gradle.util.GradleBundle; + +import static org.jetbrains.plugins.gradle.model.GradleLibraryDependencyId.of; /** * @author Denis Zhdanov * @since 1/24/12 9:48 AM */ -public class GradleLibraryDependencyPresenceChange extends GradleEntityPresenceChange { +public class GradleLibraryDependencyPresenceChange extends GradleEntityPresenceChange { - public GradleLibraryDependencyPresenceChange(@Nullable GradleLibraryDependency gradleEntity, @Nullable LibraryOrderEntry intellijEntity) - throws IllegalArgumentException + public GradleLibraryDependencyPresenceChange(@Nullable GradleLibraryDependency gradleDependency, + @Nullable LibraryOrderEntry intellijDependency) throws IllegalArgumentException { - super(gradleEntity, intellijEntity); + super(GradleBundle.message("gradle.sync.change.entity.type.library.dependency"), of(gradleDependency), of(intellijDependency)); } @Override diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryDependencyStructureChangesCalculator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryDependencyStructureChangesCalculator.java index 077f58b88e90..805783254879 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryDependencyStructureChangesCalculator.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryDependencyStructureChangesCalculator.java @@ -1,6 +1,7 @@ package org.jetbrains.plugins.gradle.diff; import com.intellij.openapi.roots.LibraryOrderEntry; +import com.intellij.openapi.roots.libraries.Library; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.gradle.model.GradleLibraryDependency; @@ -13,6 +14,12 @@ import java.util.Set; public class GradleLibraryDependencyStructureChangesCalculator implements GradleStructureChangesCalculator { + + private final GradleLibraryStructureChangesCalculator myLibraryCalculator; + + public GradleLibraryDependencyStructureChangesCalculator(@NotNull GradleLibraryStructureChangesCalculator libraryCalculator) { + myLibraryCalculator = libraryCalculator; + } @Override public void calculate(@NotNull GradleLibraryDependency gradleEntity, @@ -20,7 +27,11 @@ public class GradleLibraryDependencyStructureChangesCalculator @NotNull Set knownChanges, @NotNull Set currentChanges) { - // TODO den implement + final Library library = intellijEntity.getLibrary(); + if (library == null) { + return; + } + myLibraryCalculator.calculate(gradleEntity.getTarget(), library, knownChanges, currentChanges); } @NotNull @@ -33,7 +44,6 @@ public class GradleLibraryDependencyStructureChangesCalculator @NotNull @Override public Object getGradleKey(@NotNull GradleLibraryDependency entity, @NotNull Set knownChanges) { - // TODO den consider the known changes - return entity.getName(); + return myLibraryCalculator.getGradleKey(entity.getTarget(), knownChanges); } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryStructureChangesCalculator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryStructureChangesCalculator.java new file mode 100644 index 000000000000..f95d2d0c1dbf --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryStructureChangesCalculator.java @@ -0,0 +1,56 @@ +package org.jetbrains.plugins.gradle.diff; + +import com.intellij.openapi.roots.OrderRootType; +import com.intellij.openapi.roots.libraries.Library; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.model.GradleLibrary; +import org.jetbrains.plugins.gradle.model.LibraryPathType; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author Denis Zhdanov + * @since 2/3/12 11:17 AM + */ +public class GradleLibraryStructureChangesCalculator implements GradleStructureChangesCalculator { + + private final PlatformFacade myPlatformFacade; + + public GradleLibraryStructureChangesCalculator(@NotNull PlatformFacade platformFacade) { + myPlatformFacade = platformFacade; + } + + @Override + public void calculate(@NotNull GradleLibrary gradleEntity, + @NotNull Library intellijEntity, + @NotNull Set knownChanges, + @NotNull Set currentChanges) + { + final Set gradleBinaryPaths = new HashSet(gradleEntity.getPaths(LibraryPathType.BINARY)); + for (VirtualFile file : intellijEntity.getFiles(OrderRootType.CLASSES)) { + final String path = myPlatformFacade.getLocalFileSystemPath(file); + if (!gradleBinaryPaths.remove(path)) { + currentChanges.add(new GradleMismatchedLibraryPathChange(intellijEntity, null, path)); + } + } + + for (String binaryPath : gradleBinaryPaths) { + currentChanges.add(new GradleMismatchedLibraryPathChange(intellijEntity, binaryPath, null)); + } + } + + @NotNull + @Override + public Object getIntellijKey(@NotNull Library entity) { + return entity.getName(); + } + + @NotNull + @Override + public Object getGradleKey(@NotNull GradleLibrary entity, @NotNull Set knownChanges) { + // TODO den consider the known changes + return entity.getName(); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleMismatchedLibraryPathChange.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleMismatchedLibraryPathChange.java new file mode 100644 index 000000000000..c6dbdbcf2d9b --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleMismatchedLibraryPathChange.java @@ -0,0 +1,52 @@ +package org.jetbrains.plugins.gradle.diff; + +import com.intellij.openapi.roots.libraries.Library; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.gradle.util.GradleBundle; + +/** + * @author Denis Zhdanov + * @since 2/2/12 1:32 PM + */ +public class GradleMismatchedLibraryPathChange extends GradleAbstractConflictingPropertyChange { + + private final String myLibraryName; + + public GradleMismatchedLibraryPathChange(@NotNull Library entity, + @Nullable String gradleValue, + @Nullable String intellijValue) + throws IllegalArgumentException + { + super(GradleBundle.message("gradle.sync.change.library.path", entity.getName()), gradleValue, intellijValue); + myLibraryName = entity.getName(); + if (myLibraryName == null) { + throw new IllegalArgumentException(String.format("Can't create %s instance. Reason: given library has no name (%s)", + getClass().getName(), entity)); + } + } + + @NotNull + public String getLibraryName() { + return myLibraryName; + } + + @Override + public void invite(@NotNull GradleProjectStructureChangeVisitor visitor) { + visitor.visit(this); + } + + @Override + public int hashCode() { + return 31 * super.hashCode() + myLibraryName.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (!super.equals(o)) { + return false; + } + GradleMismatchedLibraryPathChange that = (GradleMismatchedLibraryPathChange)o; + return myLibraryName.equals(that.myLibraryName); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModulePresenceChange.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModulePresenceChange.java index 15fb4bcc1d8a..da7cbb4fdeb1 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModulePresenceChange.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModulePresenceChange.java @@ -15,19 +15,20 @@ */ package org.jetbrains.plugins.gradle.diff; -import com.intellij.openapi.module.Module; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.gradle.model.GradleModule; +import org.jetbrains.plugins.gradle.util.GradleBundle; /** * @author Denis Zhdanov * @since 11/17/11 12:50 PM */ -public class GradleModulePresenceChange extends GradleEntityPresenceChange { +public class GradleModulePresenceChange extends GradleEntityPresenceChange { - public GradleModulePresenceChange(@Nullable GradleModule gradleEntity, @Nullable Module intellijEntity) throws IllegalArgumentException { - super(gradleEntity, intellijEntity); + public GradleModulePresenceChange(@Nullable String gradleModuleName, @Nullable String intellijModuleName) + throws IllegalArgumentException + { + super(GradleBundle.message("gradle.sync.change.entity.type.module"), gradleModuleName, intellijModuleName); } @Override diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectRenameChange.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectRenameChange.java new file mode 100644 index 000000000000..1894ae972b28 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectRenameChange.java @@ -0,0 +1,22 @@ +package org.jetbrains.plugins.gradle.diff; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.util.GradleBundle; + +/** + * Describes project name change. + * + * @author Denis Zhdanov + * @since 11/3/11 3:54 PM + */ +public class GradleProjectRenameChange extends GradleAbstractConflictingPropertyChange { + + public GradleProjectRenameChange(@NotNull String gradleName, @NotNull String intellijName) { + super(GradleBundle.message("gradle.sync.change.project.name.text"), gradleName, intellijName); + } + + @Override + public void invite(@NotNull GradleProjectStructureChangeVisitor visitor) { + visitor.visit(this); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangeVisitor.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangeVisitor.java index 65310da6673c..0a41c198a88b 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangeVisitor.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangeVisitor.java @@ -24,8 +24,9 @@ import org.jetbrains.annotations.NotNull; * @since 11/16/11 8:48 PM */ public interface GradleProjectStructureChangeVisitor { - void visit(@NotNull GradleRenameChange change); - void visit(@NotNull GradleProjectStructureChange change); + void visit(@NotNull GradleProjectRenameChange change); + void visit(@NotNull GradleLanguageLevelChange change); void visit(@NotNull GradleModulePresenceChange change); void visit(@NotNull GradleLibraryDependencyPresenceChange change); + void visit(@NotNull GradleMismatchedLibraryPathChange change); } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangeVisitorAdapter.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangeVisitorAdapter.java index 76a108393c04..6e963b8ea895 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangeVisitorAdapter.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangeVisitorAdapter.java @@ -24,11 +24,11 @@ import org.jetbrains.annotations.NotNull; public class GradleProjectStructureChangeVisitorAdapter implements GradleProjectStructureChangeVisitor { @Override - public void visit(@NotNull GradleRenameChange change) { + public void visit(@NotNull GradleProjectRenameChange change) { } @Override - public void visit(@NotNull GradleProjectStructureChange change) { + public void visit(@NotNull GradleLanguageLevelChange change) { } @Override @@ -38,4 +38,8 @@ public class GradleProjectStructureChangeVisitorAdapter implements GradleProject @Override public void visit(@NotNull GradleLibraryDependencyPresenceChange change) { } + + @Override + public void visit(@NotNull GradleMismatchedLibraryPathChange change) { + } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangesCalculator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangesCalculator.java index c8f3236b71de..a8262463f61a 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangesCalculator.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangesCalculator.java @@ -70,13 +70,13 @@ public class GradleProjectStructureChangesCalculator implements GradleStructureC String gradleName = gradleProject.getName(); String intellijName = intellijProject.getName(); if (!gradleName.equals(intellijName)) { - currentChanges.add(new GradleRenameChange(GradleRenameChange.Entity.PROJECT, gradleName, intellijName)); + currentChanges.add(new GradleProjectRenameChange(gradleName, intellijName)); } } private void checkLanguageLevel(@NotNull GradleProject gradleProject, - @NotNull Project intellijProject, - @NotNull Set currentChanges) + @NotNull Project intellijProject, + @NotNull Set currentChanges) { LanguageLevel gradleLevel = gradleProject.getLanguageLevel(); LanguageLevel intellijLevel = myStructureHelper.getLanguageLevel(intellijProject); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleRenameChange.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleRenameChange.java deleted file mode 100644 index 6aaacfe104c6..000000000000 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleRenameChange.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.jetbrains.plugins.gradle.diff; - -import org.jetbrains.annotations.NotNull; - -/** - * Describes particular entity name change. - * - * @author Denis Zhdanov - * @since 11/3/11 3:54 PM - */ -public class GradleRenameChange extends GradleAbstractPropertyValueChange { - - public enum Entity { PROJECT, MODULE, LIBRARY } - - private final Entity myEntity; - - public GradleRenameChange(@NotNull Entity entity, @NotNull String gradleName, @NotNull String intellijName) { - super(entity.toString().toLowerCase(), gradleName, intellijName); - myEntity = entity; - } - - @NotNull - public Entity getEntity() { - return myEntity; - } - - @Override - public int hashCode() { - return 31 * super.hashCode() + myEntity.hashCode(); - } - - @Override - public boolean equals(Object o) { - if (!super.equals(o)) { - return false; - } - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - GradleRenameChange that = (GradleRenameChange)o; - return myEntity.equals(that.myEntity); - } - - @Override - public void invite(@NotNull GradleProjectStructureChangeVisitor visitor) { - visitor.visit(this); - } -} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/PlatformFacade.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/PlatformFacade.java index c03c12035d59..bc8c9302a5a3 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/PlatformFacade.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/PlatformFacade.java @@ -3,6 +3,8 @@ package org.jetbrains.plugins.gradle.diff; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.OrderEntry; +import com.intellij.openapi.roots.libraries.LibraryTable; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.java.LanguageLevel; import org.jetbrains.annotations.NotNull; @@ -27,6 +29,9 @@ import java.util.Collection; */ public interface PlatformFacade { + @NotNull + LibraryTable getProjectLibraryTable(@NotNull Project project); + @NotNull LanguageLevel getLanguageLevel(@NotNull Project project); @@ -41,4 +46,16 @@ public interface PlatformFacade { */ @NotNull Icon getProjectIcon(); + + /** + * Allows to derive from the given VFS file path that may be compared to the path used by the gradle api. + *

+ * Generally, this method is necessary for processing binary library paths - they point to jar files and VFS uses + * '!' marks in their paths internally. + * + * @param file target file + * @return given file's path that may be compared to the one used by the gradle api + */ + @NotNull + String getLocalFileSystemPath(@NotNull VirtualFile file); } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureHelperImpl.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/PlatformFacadeImpl.java similarity index 62% rename from plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureHelperImpl.java rename to plugins/gradle/src/org/jetbrains/plugins/gradle/diff/PlatformFacadeImpl.java index ff3fb2ada17a..84ae46eda4a4 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureHelperImpl.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/PlatformFacadeImpl.java @@ -1,13 +1,18 @@ package org.jetbrains.plugins.gradle.diff; import com.intellij.openapi.application.ex.ApplicationInfoEx; +import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.LanguageLevelProjectExtension; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.roots.OrderEntry; +import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable; +import com.intellij.openapi.roots.libraries.LibraryTable; import com.intellij.openapi.util.IconLoader; +import com.intellij.openapi.vfs.JarFileSystem; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.java.LanguageLevel; import org.jetbrains.annotations.NotNull; @@ -19,7 +24,13 @@ import java.util.Collection; * @author Denis Zhdanov * @since 1/26/12 11:54 AM */ -public class GradleProjectStructureHelperImpl implements PlatformFacade { +public class PlatformFacadeImpl implements PlatformFacade { + + @NotNull + @Override + public LibraryTable getProjectLibraryTable(@NotNull Project project) { + return ProjectLibraryTable.getInstance(project); + } @NotNull @Override @@ -44,4 +55,16 @@ public class GradleProjectStructureHelperImpl implements PlatformFacade { public Icon getProjectIcon() { return IconLoader.getIcon(ApplicationInfoEx.getInstanceEx().getSmallIconUrl()); } + + @NotNull + @Override + public String getLocalFileSystemPath(@NotNull VirtualFile file) { + if (file.getFileType() == FileTypes.ARCHIVE) { + final VirtualFile jar = JarFileSystem.getInstance().getVirtualFileForJar(file); + if (jar != null) { + return jar.getPath(); + } + } + return file.getPath(); + } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleContentRootImporter.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleContentRootImporter.java new file mode 100644 index 000000000000..16e0baf4b191 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleContentRootImporter.java @@ -0,0 +1,16 @@ +package org.jetbrains.plugins.gradle.importing; + +import com.intellij.openapi.module.Module; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.model.GradleContentRoot; + +/** + * @author Denis Zhdanov + * @since 2/7/12 3:20 PM + */ +public class GradleContentRootImporter { + + public void importContentRoots(@NotNull Iterable contentRoots, @NotNull Module module) { + // TODO den implement + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModuleDependencyImporter.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModuleDependencyImporter.java new file mode 100644 index 000000000000..ada5a3a5d389 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModuleDependencyImporter.java @@ -0,0 +1,152 @@ +package org.jetbrains.plugins.gradle.importing; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.roots.*; +import com.intellij.openapi.roots.libraries.Library; +import com.intellij.openapi.roots.libraries.LibraryTable; +import com.intellij.openapi.vfs.JarFileSystem; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.diff.PlatformFacade; +import org.jetbrains.plugins.gradle.model.*; +import org.jetbrains.plugins.gradle.util.GradleLog; + +import java.io.File; +import java.util.*; + +/** + * @author Denis Zhdanov + * @since 2/7/12 3:23 PM + */ +public class GradleModuleDependencyImporter { + + private static final Map LIBRARY_ROOT_MAPPINGS + = new EnumMap(LibraryPathType.class); + static { + LIBRARY_ROOT_MAPPINGS.put(LibraryPathType.BINARY, OrderRootType.CLASSES); + LIBRARY_ROOT_MAPPINGS.put(LibraryPathType.SOURCE, OrderRootType.SOURCES); + LIBRARY_ROOT_MAPPINGS.put(LibraryPathType.DOC, JavadocOrderRootType.getInstance()); + assert LibraryPathType.values().length == LIBRARY_ROOT_MAPPINGS.size(); + } + + @NotNull private final PlatformFacade myPlatformFacade; + + public GradleModuleDependencyImporter(@NotNull PlatformFacade platformFacade) { + myPlatformFacade = platformFacade; + } + + public void importDependency(@NotNull GradleDependency dependency, @NotNull Module module) { + importDependencies(Collections.singleton(dependency), module); + } + + public void importDependencies(@NotNull Iterable dependencies, @NotNull Module module) { + final List moduleDependencies = new ArrayList(); + final List libraryDependencies = new ArrayList(); + GradleEntityVisitor visitor = new GradleEntityVisitorAdapter() { + @Override + public void visit(@NotNull GradleModuleDependency dependency) { + moduleDependencies.add(dependency); + } + + @Override + public void visit(@NotNull GradleLibraryDependency dependency) { + libraryDependencies.add(dependency); + } + }; + for (GradleDependency dependency : dependencies) { + dependency.invite(visitor); + } + importLibraryDependencies(libraryDependencies, module); + importModuleDependencies(moduleDependencies, module); + } + + public void importModuleDependencies(@NotNull Iterable dependencies, @NotNull Module module) { + // TODO den implement + } + + public void importLibraryDependencies(@NotNull final Iterable dependencies, @NotNull final Module module) { + // TODO den make non-EDT agnostic + final LibraryTable libraryTable = myPlatformFacade.getProjectLibraryTable(module.getProject()); + final Map gradle2intellij = new HashMap(); + final Set librariesToCreate = new HashSet(); + for (final GradleLibraryDependency dependency : dependencies) { + // Try to find existing library in project libraries. + Library library = libraryTable.getLibraryByName(dependency.getName()); + if (library == null) { + librariesToCreate.add(dependency.getTarget()); + } + else { + gradle2intellij.put(dependency.getTarget(), library); + } + } + + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + // Create all necessary libraries. + if (!librariesToCreate.isEmpty()) { + final LibraryTable.ModifiableModel projectLibraryModel = libraryTable.getModifiableModel(); + try { + for (GradleLibrary library : librariesToCreate) { + final Library intellijLibrary = projectLibraryModel.createLibrary(library.getName()); + gradle2intellij.put(library, intellijLibrary); + final Library.ModifiableModel libraryModel = intellijLibrary.getModifiableModel(); + try { + registerPaths(library, libraryModel); + } + finally { + libraryModel.commit(); + } + } + } + finally { + projectLibraryModel.commit(); + } + } + + // Register library dependencies. + ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module); + final ModifiableRootModel moduleRootModel = moduleRootManager.getModifiableModel(); + try { + for (GradleLibraryDependency dependency : dependencies) { + LibraryOrderEntry orderEntry = moduleRootModel.addLibraryEntry(gradle2intellij.get(dependency.getTarget())); + orderEntry.setExported(dependency.isExported()); + orderEntry.setScope(dependency.getScope()); + } + } + finally { + moduleRootModel.commit(); + } + // TODO den refresh gradle project tree + } + }); + } + + private static void registerPaths(@NotNull GradleLibrary gradleLibrary, @NotNull Library.ModifiableModel model) { + for (LibraryPathType pathType : LibraryPathType.values()) { + for (String path : gradleLibrary.getPaths(pathType)) { + VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByIoFile(new File(path)); + if (virtualFile == null) { + GradleLog.LOG.warn(String.format("Can't find %s of the library '%s' at path '%s'", pathType, gradleLibrary.getName(), path)); + continue; + } + if (virtualFile.isDirectory()) { + model.addRoot(virtualFile, LIBRARY_ROOT_MAPPINGS.get(pathType)); + } + else { + VirtualFile jarRoot = JarFileSystem.getInstance().getJarRootForLocalFile(virtualFile); + if (jarRoot == null) { + GradleLog.LOG.warn(String.format( + "Can't parse contents of the jar file at path '%s' for the library '%s''", path, gradleLibrary.getName() + )); + continue; + } + model.addRoot(jarRoot, LIBRARY_ROOT_MAPPINGS.get(pathType)); + } + } + } + } + +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModuleImporter.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModuleImporter.java new file mode 100644 index 000000000000..7ee3a1eac434 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModuleImporter.java @@ -0,0 +1,125 @@ +package org.jetbrains.plugins.gradle.importing; + +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.module.StdModuleTypes; +import com.intellij.openapi.project.Project; +import com.intellij.util.Alarm; +import com.intellij.util.containers.hash.HashMap; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.model.GradleModule; +import org.jetbrains.plugins.gradle.util.GradleLog; + +import java.io.File; +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * Encapsulates functionality of importing gradle module to the intellij project. + * + * @author Denis Zhdanov + * @since 2/7/12 2:49 PM + */ +public class GradleModuleImporter { + + /** + * We can't modify project modules (add/remove) until it's initialised, so, we delay that activity. Current constant + * holds number of milliseconds to wait between 'after project initialisation' processing attempts. + */ + private static final int PROJECT_INITIALISATION_DELAY_MS = (int)TimeUnit.SECONDS.toMillis(1); + + private final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD); + + @NotNull private final GradleContentRootImporter myContentRootImporter; + @NotNull private final GradleModuleDependencyImporter myDependencyImporter; + + public GradleModuleImporter(@NotNull GradleContentRootImporter contentRootImporter, + @NotNull GradleModuleDependencyImporter dependencyImporter) + { + myContentRootImporter = contentRootImporter; + myDependencyImporter = dependencyImporter; + } + + public void importModule(@NotNull GradleModule module, @NotNull Project project) { + importModules(Collections.singleton(module), project, false); + } + + public void importModules(@NotNull final Iterable modules, @NotNull final Project project, final boolean recursive) { + if (!project.isInitialized()) { + myAlarm.addRequest(new ImportModulesTask(project, modules, recursive), PROJECT_INITIALISATION_DELAY_MS); + return; + } + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + removeExistingModulesConfigs(modules); + Application application = ApplicationManager.getApplication(); + final Map moduleMappings = new HashMap(); + application.runWriteAction(new Runnable() { + @Override + public void run() { + final ModuleManager moduleManager = ModuleManager.getInstance(project); + for (GradleModule module : modules) { + final Module created = moduleManager.newModule(module.getModuleFilePath(), StdModuleTypes.JAVA); + moduleMappings.put(module, created); + } + } + }); + if (!recursive) { + return; + } + for (GradleModule gradleModule : modules) { + final Module intellijModule = moduleMappings.get(gradleModule); + myContentRootImporter.importContentRoots(gradleModule.getContentRoots(), intellijModule); + myDependencyImporter.importDependencies(gradleModule.getDependencies(), intellijModule); + } + } + }); + } + + private static void removeExistingModulesConfigs(@NotNull Iterable modules) { + for (GradleModule module : modules) { + // Remove existing '*.iml' file if necessary. + final String moduleFilePath = module.getModuleFilePath(); + File file = new File(moduleFilePath); + if (file.isFile()) { + boolean success = file.delete(); + if (!success) { + GradleLog.LOG.warn("Can't remove existing module file at '" + moduleFilePath + "'"); + } + } + } + } + + private class ImportModulesTask implements Runnable { + + private final Project myProject; + private final Iterable myModules; + private final boolean myRecursive; + + ImportModulesTask(@NotNull Project project, @NotNull Iterable modules, boolean recursive) { + myProject = project; + myModules = modules; + myRecursive = recursive; + } + + @Override + public void run() { + myAlarm.cancelAllRequests(); + if (!myProject.isInitialized()) { + myAlarm.addRequest( + new ImportModulesTask(myProject, myModules, myRecursive), + PROJECT_INITIALISATION_DELAY_MS + ); + return; + } + + importModules(myModules, myProject, myRecursive); + } + } + +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModulesImporter.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModulesImporter.java index 0753b80c148f..5a6de37bf1d0 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModulesImporter.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModulesImporter.java @@ -40,6 +40,7 @@ import java.util.concurrent.TimeUnit; * @author Denis Zhdanov * @since 8/26/11 10:01 AM */ +// TODO den remove public class GradleModulesImporter { private static final Map LIBRARY_ROOT_MAPPINGS diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/wizard/adjust/GradleAdjustImportSettingsStep.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/wizard/adjust/GradleAdjustImportSettingsStep.java index e504101aa38a..f9bd8e7d8f6f 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/wizard/adjust/GradleAdjustImportSettingsStep.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/wizard/adjust/GradleAdjustImportSettingsStep.java @@ -260,7 +260,7 @@ public class GradleAdjustImportSettingsStep extends AbstractImportFromGradleWiza // We build tree node, its settings control and map them altogether. The only trick here is that nodes can reuse the same // settings control (e.g. more than one node may have the same library as a dependency, so, library dependency node for // every control will use the same settings control). - GradleProjectStructureNode result = new GradleProjectStructureNode(myFactory.buildDescriptor(entity)); + GradleProjectStructureNode result = new GradleProjectStructureNode(myFactory.buildDescriptor(entity), GradleEntityType.SYNTHETIC); Pair> pair = processed.get(entity); if (pair == null) { String cardName = String.valueOf(counter); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/wizard/adjust/GradleProjectStructureFactory.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/wizard/adjust/GradleProjectStructureFactory.java index a488a328071b..fef410ddc578 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/wizard/adjust/GradleProjectStructureFactory.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/wizard/adjust/GradleProjectStructureFactory.java @@ -30,9 +30,9 @@ public class GradleProjectStructureFactory { /** Shared instance of the current (stateless) class. */ public static final GradleProjectStructureFactory INSTANCE = new GradleProjectStructureFactory(); - @SuppressWarnings("MethodMayBeStatic") + @SuppressWarnings({"MethodMayBeStatic", "unchecked"}) @NotNull - public GradleProjectStructureNodeDescriptor buildDescriptor(@NotNull T entity) { + public GradleProjectStructureNodeDescriptor buildDescriptor(@NotNull T entity) { final Ref> result = new Ref>(); entity.invite(new GradleEntityVisitor() { @Override @@ -70,7 +70,7 @@ public class GradleProjectStructureFactory { visit(dependency.getTarget()); } }); - return result.get(); + return (GradleProjectStructureNodeDescriptor)result.get(); } @SuppressWarnings("MethodMayBeStatic") diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleDependency.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleDependency.java index cc6558f17909..a20b775c2a06 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleDependency.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleDependency.java @@ -15,6 +15,9 @@ public interface GradleDependency extends GradleEntity { @NotNull DependencyScope getScope(); + + @NotNull + GradleModule getOwnerModule(); @NotNull GradleDependency clone(@NotNull GradleEntityCloneContext context); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleEntityType.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleEntityType.java new file mode 100644 index 000000000000..948903544476 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleEntityType.java @@ -0,0 +1,9 @@ +package org.jetbrains.plugins.gradle.model; + +/** + * @author Denis Zhdanov + * @since 2/7/12 11:18 AM + */ +public enum GradleEntityType { + PROJECT, MODULE, LIBRARY_DEPENDENCY, SYNTHETIC +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleLibrary.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleLibrary.java index 55f39878e9e9..cfd267d41064 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleLibrary.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleLibrary.java @@ -39,6 +39,10 @@ public class GradleLibrary extends AbstractNamedGradleEntity implements Named { paths.add(GradleUtil.toCanonicalPath(path)); } + public void forgetAllPaths() { + myPaths.clear(); + } + @Override public void invite(@NotNull GradleEntityVisitor visitor) { visitor.visit(this); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleLibraryDependencyId.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleLibraryDependencyId.java new file mode 100644 index 000000000000..e42cc70130de --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleLibraryDependencyId.java @@ -0,0 +1,78 @@ +package org.jetbrains.plugins.gradle.model; + +import com.intellij.openapi.roots.LibraryOrderEntry; +import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * This class serves as an id for any library dependency. We can't use library object itself because its hashCode()/equals() may + * be changed over time (e.g. source root is added). + *

+ * Thread-safe. + * + * @author Denis Zhdanov + * @since 2/6/12 12:09 PM + */ +public class GradleLibraryDependencyId { + + private final String myLibraryName; + private final String myModuleName; + + public GradleLibraryDependencyId(@NotNull String libraryName, @NotNull String moduleName) { + myLibraryName = libraryName; + myModuleName = moduleName; + } + + @Nullable + public static GradleLibraryDependencyId of(@Nullable GradleLibraryDependency dependency) { + return dependency == null ? null : new GradleLibraryDependencyId(dependency.getName(), dependency.getOwnerModule().getName()); + } + + @Nullable + public static GradleLibraryDependencyId of(@Nullable LibraryOrderEntry dependency) { + if (dependency == null) { + return null; + } + final String libraryName = dependency.getLibraryName(); + if (libraryName == null || StringUtil.isEmpty(libraryName)) { + return null; + } + return new GradleLibraryDependencyId(libraryName, dependency.getOwnerModule().getName()); + } + + @NotNull + public String getLibraryName() { + return myLibraryName; + } + + @NotNull + public String getModuleName() { + return myModuleName; + } + + @Override + public int hashCode() { + int result = myLibraryName.hashCode(); + result = 31 * result + myModuleName.hashCode(); + return result; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + GradleLibraryDependencyId id = (GradleLibraryDependencyId)o; + + if (!myLibraryName.equals(id.myLibraryName)) return false; + if (!myModuleName.equals(id.myModuleName)) return false; + + return true; + } + + @Override + public String toString() { + return String.format("library dependency: library='%s', module='%s'", myLibraryName, myModuleName); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModel.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModel.java index f1ee0022e65d..66934ce49864 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModel.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModel.java @@ -3,6 +3,7 @@ package org.jetbrains.plugins.gradle.sync; import com.intellij.openapi.components.AbstractProjectComponent; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.diff.GradleProjectStructureChange; import org.jetbrains.plugins.gradle.diff.GradleStructureChangesCalculator; import org.jetbrains.plugins.gradle.model.GradleProject; @@ -13,7 +14,7 @@ import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.atomic.AtomicReference; /** - * // TODO den add doc + * Manages information about the changes between the gradle and intellij project structures. *

* Thread-safe. * @@ -25,7 +26,9 @@ public class GradleProjectStructureChangesModel extends AbstractProjectComponent private final Set myListeners = new CopyOnWriteArraySet(); private final AtomicReference> myChanges = new AtomicReference>(new HashSet()); - + + private final AtomicReference myGradleProject = new AtomicReference(); + private final GradleStructureChangesCalculator myChangesCalculator; public GradleProjectStructureChangesModel(@NotNull Project project, @@ -54,6 +57,7 @@ public class GradleProjectStructureChangesModel extends AbstractProjectComponent * @param gradleProject gradle project to sync with */ public void update(@NotNull GradleProject gradleProject) { + myGradleProject.set(gradleProject); Set knownChanges = new HashSet(myChanges.get()); Set currentChanges = new HashSet(); myChangesCalculator.calculate(gradleProject, myProject, knownChanges, currentChanges); @@ -66,6 +70,14 @@ public class GradleProjectStructureChangesModel extends AbstractProjectComponent } } + /** + * @return last known gradle project state + */ + @Nullable + public GradleProject getGradleProject() { + return myGradleProject.get(); + } + /** * Registers given listener within the current model. * diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java index d2bc50a5ff41..ee03292076d2 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java @@ -1,18 +1,27 @@ package org.jetbrains.plugins.gradle.sync; +import com.intellij.ide.ui.customization.CustomizationUtil; import com.intellij.openapi.project.Project; import com.intellij.ui.treeStructure.Tree; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.config.GradleToolWindowPanel; import org.jetbrains.plugins.gradle.diff.GradleProjectStructureChange; import org.jetbrains.plugins.gradle.diff.PlatformFacade; +import org.jetbrains.plugins.gradle.ui.GradleDataKeys; +import org.jetbrains.plugins.gradle.ui.GradleProjectStructureNode; import org.jetbrains.plugins.gradle.util.GradleConstants; import javax.swing.*; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreePath; import java.awt.*; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; /** * UI control for showing difference between the gradle and intellij project structure. @@ -22,14 +31,16 @@ import java.util.Collection; */ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel { + private Tree myTree; private GradleProjectStructureTreeModel myTreeModel; private JPanel myContent; public GradleProjectStructureChangesPanel(@NotNull Project project, @NotNull GradleProjectStructureChangesModel model, - @NotNull PlatformFacade projectStructureHelper) + @NotNull PlatformFacade platformFacade, + @NotNull GradleProjectStructureHelper projectStructureHelper) { - super(project, projectStructureHelper, GradleConstants.TOOL_WINDOW_TOOLBAR_PLACE); + super(project, platformFacade, projectStructureHelper, GradleConstants.TOOL_WINDOW_TOOLBAR_PLACE); model.addListener(new GradleProjectStructureChangeListener() { @Override public void onChanges(@NotNull final Collection oldChanges, @@ -39,7 +50,7 @@ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel { @Override public void run() { myTreeModel.update(currentChanges); - myTreeModel.pruneObsoleteNodes(ContainerUtil.subtract(oldChanges, currentChanges)); + myTreeModel.processObsoleteChanges(ContainerUtil.subtract(oldChanges, currentChanges)); } }); } @@ -48,14 +59,17 @@ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel { private void init() { myContent = new JPanel(new GridBagLayout()); - myTreeModel = new GradleProjectStructureTreeModel(getProject(), getProjectStructureHelper()); - Tree tree = new Tree(myTreeModel); + myTreeModel = new GradleProjectStructureTreeModel(getProject(), getProjectFacade(), getProjectStructureHelper()); + myTree = new Tree(myTreeModel); + applyInitialAppearance(myTree, (DefaultMutableTreeNode)myTreeModel.getRoot()); GridBagConstraints constraints = new GridBagConstraints(); constraints.fill = GridBagConstraints.BOTH; constraints.weightx = constraints.weighty = 1; - myContent.add(tree, constraints); - myContent.setBackground(tree.getBackground()); + myContent.add(myTree, constraints); + myContent.setBackground(myTree.getBackground()); + + CustomizationUtil.installPopupHandler(myTree, GradleConstants.ACTION_GROUP_SYNC_TREE, GradleConstants.SYNC_TREE_PLACE); } @NotNull @@ -71,4 +85,33 @@ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel { int i = 1; } + @Nullable + @Override + public Object getData(@NonNls String dataId) { + if (GradleDataKeys.SYNC_TREE_NODE.is(dataId)) { + TreePath[] paths = myTree.getSelectionPaths(); + if (paths == null) { + return null; + } + List> result = new ArrayList>(); + for (TreePath path : paths) { + result.add((GradleProjectStructureNode)path.getLastPathComponent()); + } + return result; + } + else { + return super.getData(dataId); + } + } + + private static void applyInitialAppearance(@NotNull Tree tree, @NotNull DefaultMutableTreeNode node) { + if (node.getUserObject() == GradleProjectStructureTreeModel.DEPENDENCIES_NODE_DESCRIPTOR) { + tree.expandPath(new TreePath(node.getPath())); + return; + } + + for (int i = 0; i < node.getChildCount(); i++) { + applyInitialAppearance(tree, (DefaultMutableTreeNode)node.getChildAt(i)); + } + } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureHelper.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureHelper.java new file mode 100644 index 000000000000..8fba1b558e74 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureHelper.java @@ -0,0 +1,119 @@ +package org.jetbrains.plugins.gradle.sync; + +import com.intellij.openapi.components.AbstractProjectComponent; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.LibraryOrderEntry; +import com.intellij.openapi.roots.OrderEntry; +import com.intellij.openapi.roots.RootPolicy; +import com.intellij.openapi.util.Ref; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.gradle.diff.PlatformFacade; +import org.jetbrains.plugins.gradle.model.*; + +/** + * @author Denis Zhdanov + * @since 2/6/12 3:28 PM + */ +public class GradleProjectStructureHelper extends AbstractProjectComponent { + + private final GradleProjectStructureChangesModel myModel; + private final PlatformFacade myFacade; + + public GradleProjectStructureHelper(@NotNull Project project, + @NotNull GradleProjectStructureChangesModel model, + @NotNull PlatformFacade facade) + { + super(project); + myModel = model; + myFacade = facade; + } + + /** + * Allows to answer if target library dependency is still available at the target project. + * + * @param id target library id + * @return true if target library dependency is still available at the target project; + * false otherwise + */ + public boolean isIntellijLibraryDependencyExist(@NotNull final GradleLibraryDependencyId id) { + final Module module = findIntellijModuleByName(id.getModuleName()); + if (module == null) { + return false; + } + + RootPolicy visitor = new RootPolicy() { + @Override + public Boolean visitLibraryOrderEntry(LibraryOrderEntry libraryOrderEntry, Boolean value) { + return id.getLibraryName().equals(libraryOrderEntry.getLibraryName()); + } + }; + for (OrderEntry entry : myFacade.getOrderEntries(module)) { + if (entry.accept(visitor, false)) { + return true; + } + } + return false; + } + + /** + * Allows to answer if target library dependency is still available at the target project. + * + * @param id target library id + * @return true if target library dependency is still available at the target project; + * false otherwise + */ + public boolean isGradleLibraryDependencyExist(@NotNull final GradleLibraryDependencyId id) { + return findLibraryDependency(id) != null; + } + + @Nullable + public Module findIntellijModuleByName(@NotNull String name) { + for (Module module : myFacade.getModules(myProject)) { + if (name.equals(module.getName())) { + return module; + } + } + return null; + } + + @Nullable + public GradleModule findGradleModuleByName(@NotNull String name) { + final GradleProject project = myModel.getGradleProject(); + if (project == null) { + return null; + } + for (GradleModule module : project.getModules()) { + if (name.equals(module.getName())) { + return module; + } + } + return null; + } + + @Nullable + public GradleLibraryDependency findLibraryDependency(@NotNull final GradleLibraryDependencyId id) { + final GradleModule module = findGradleModuleByName(id.getModuleName()); + if (module == null) { + return null; + } + final Ref ref = new Ref(); + GradleEntityVisitor visitor = new GradleEntityVisitorAdapter() { + @Override + public void visit(@NotNull GradleLibraryDependency dependency) { + if (id.getLibraryName().equals(dependency.getName())) { + ref.set(dependency); + } + } + }; + for (GradleDependency dependency : module.getDependencies()) { + dependency.invite(visitor); + final GradleLibraryDependency result = ref.get(); + if (result != null) { + return result; + } + } + return null; + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java index 5327468b119c..9a32b95e3338 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java @@ -1,26 +1,24 @@ package org.jetbrains.plugins.gradle.sync; +import com.intellij.openapi.editor.colors.TextAttributesKey; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.LibraryOrderEntry; import com.intellij.openapi.roots.OrderEntry; import com.intellij.openapi.roots.RootPolicy; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.containers.hash.HashMap; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.config.GradleTextAttributes; import org.jetbrains.plugins.gradle.diff.*; -import org.jetbrains.plugins.gradle.model.GradleLibraryDependency; -import org.jetbrains.plugins.gradle.model.Named; +import org.jetbrains.plugins.gradle.model.GradleEntityType; +import org.jetbrains.plugins.gradle.model.GradleLibraryDependencyId; import org.jetbrains.plugins.gradle.ui.GradleIcons; +import org.jetbrains.plugins.gradle.ui.GradleProjectStructureNode; import org.jetbrains.plugins.gradle.ui.GradleProjectStructureNodeDescriptor; import org.jetbrains.plugins.gradle.util.GradleBundle; import javax.swing.*; -import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.MutableTreeNode; import javax.swing.tree.TreeNode; import java.util.ArrayList; import java.util.Collection; @@ -36,7 +34,14 @@ import java.util.Map; * @since 1/30/12 4:20 PM */ public class GradleProjectStructureTreeModel extends DefaultTreeModel { - + + public static final GradleProjectStructureNodeDescriptor DEPENDENCIES_NODE_DESCRIPTOR + = new GradleProjectStructureNodeDescriptor( + GradleBundle.message("gradle.project.structure.tree.node.dependencies"), + GradleBundle.message("gradle.project.structure.tree.node.dependencies"), + null + ); + /** *

    *     ...
@@ -47,27 +52,34 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel {
    *                  |_dependency2
    * 
*/ - private final Map myModuleDependencies = new HashMap(); - private final Map myModules = new HashMap(); + private final Map> myModuleDependencies + = new HashMap>(); + private final Map> myModules + = new HashMap>(); private final TreeNode[] myNodeHolder = new TreeNode[1]; private final int[] myIndexHolder = new int[1]; - private final Project myProject; - private final PlatformFacade myPlatformFacade; + private final Project myProject; + private final PlatformFacade myPlatformFacade; + private final GradleProjectStructureHelper myProjectStructureHelper; - public GradleProjectStructureTreeModel(@NotNull Project project, @NotNull PlatformFacade platformFacade) { + public GradleProjectStructureTreeModel(@NotNull Project project, + @NotNull PlatformFacade platformFacade, + @NotNull GradleProjectStructureHelper projectStructureHelper) { super(null); myProject = project; myPlatformFacade = platformFacade; + myProjectStructureHelper = projectStructureHelper; rebuild(); } public void rebuild() { myModuleDependencies.clear(); myModules.clear(); - - DefaultMutableTreeNode root = new DefaultMutableTreeNode(buildDescriptor(getProject())); + + GradleProjectStructureNode root + = buildNode(getProject(), GradleEntityType.PROJECT, getProject().getName(), myPlatformFacade.getProjectIcon()); final Collection modules = myPlatformFacade.getModules(getProject()); RootPolicy policy = new RootPolicy() { @Override @@ -76,19 +88,21 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { } }; for (Module module : modules) { - final DefaultMutableTreeNode moduleNode = new DefaultMutableTreeNode(buildDescriptor(module)); + final GradleProjectStructureNode moduleNode = buildNode(GradleEntityType.MODULE, module.getName(), GradleIcons.MODULE_ICON); myModules.put(module.getName(), moduleNode); // Assuming that module names are unique. List libraryDependencies = new ArrayList(); for (OrderEntry orderEntry : myPlatformFacade.getOrderEntries(module)) { final LibraryOrderEntry libraryDependency = orderEntry.accept(policy, null); - if (libraryDependency != null && !StringUtil.isEmpty(libraryDependency.getLibraryName())) { - libraryDependencies.add(libraryDependency); - } + libraryDependencies.add(libraryDependency); } if (!libraryDependencies.isEmpty()) { - DefaultMutableTreeNode dependenciesNode = getDependenciesNode(module.getName()); + GradleProjectStructureNode dependenciesNode = getDependenciesNode(module.getName()); for (LibraryOrderEntry dependency : libraryDependencies) { - dependenciesNode.add(new DefaultMutableTreeNode(buildDescriptor(dependency))); + GradleLibraryDependencyId id = GradleLibraryDependencyId.of(dependency); + if (id == null) { + continue; + } + dependenciesNode.add(buildNode(id, GradleEntityType.LIBRARY_DEPENDENCY, id.getLibraryName(), GradleIcons.LIB_ICON)); } moduleNode.add(dependenciesNode); } @@ -103,45 +117,37 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { return myProject; } - private static GradleProjectStructureNodeDescriptor buildDescriptor(@NotNull String name, @Nullable Icon icon) { - return new GradleProjectStructureNodeDescriptor(new Object(), name, icon); + private static GradleProjectStructureNodeDescriptor buildDescriptor(@NotNull T entity, @NotNull String name, @NotNull Icon icon) { + return new GradleProjectStructureNodeDescriptor(entity, name, icon); } - private static GradleProjectStructureNodeDescriptor buildDescriptor(@NotNull Named entity, @NotNull Icon icon) { - return new GradleProjectStructureNodeDescriptor(entity, entity.getName(), icon); + private static GradleProjectStructureNode buildNode(@NotNull GradleEntityType type, @NotNull String name, @NotNull Icon icon) { + return buildNode(name, type, name, icon); } - private GradleProjectStructureNodeDescriptor buildDescriptor(@NotNull Project project) { - return new GradleProjectStructureNodeDescriptor(project, project.getName(), myPlatformFacade.getProjectIcon()); + private static GradleProjectStructureNode buildNode(@NotNull T entity, + @NotNull GradleEntityType type, + @NotNull String name, + @NotNull Icon icon) + { + return new GradleProjectStructureNode(buildDescriptor(entity, name, icon), type); } - private static GradleProjectStructureNodeDescriptor buildDescriptor(@NotNull Module module) { - return new GradleProjectStructureNodeDescriptor(module, module.getName(), GradleIcons.MODULE_ICON); - } - - private static GradleProjectStructureNodeDescriptor buildDescriptor(@NotNull LibraryOrderEntry library) { - final String name = library.getLibraryName(); - assert name != null; - return new GradleProjectStructureNodeDescriptor(library, name, GradleIcons.LIB_ICON); - } - - private DefaultMutableTreeNode getDependenciesNode(@NotNull String moduleName) { - final DefaultMutableTreeNode cached = myModuleDependencies.get(moduleName); + private GradleProjectStructureNode getDependenciesNode(@NotNull String moduleName) { + final GradleProjectStructureNode cached = myModuleDependencies.get(moduleName); if (cached != null) { return cached; } - DefaultMutableTreeNode moduleNode = myModules.get(moduleName); + GradleProjectStructureNode moduleNode = myModules.get(moduleName); if (moduleNode == null) { - moduleNode = new DefaultMutableTreeNode(buildDescriptor(moduleName, GradleIcons.MODULE_ICON)); + moduleNode = buildNode(GradleEntityType.MODULE, moduleName, GradleIcons.MODULE_ICON); myModules.put(moduleName, moduleNode); } - DefaultMutableTreeNode result = new DefaultMutableTreeNode(buildDescriptor( - GradleBundle.message("gradle.project.structure.tree.node.dependencies"), - null - )); + GradleProjectStructureNode result = new GradleProjectStructureNode(DEPENDENCIES_NODE_DESCRIPTOR, GradleEntityType.SYNTHETIC); moduleNode.add(result); myModuleDependencies.put(moduleName, result); + return result; } @@ -152,61 +158,41 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { */ public void update(@NotNull Collection changes) { for (GradleProjectStructureChange change : changes) { - change.invite(new GradleProjectStructureChangeVisitor() { + change.invite(new GradleProjectStructureChangeVisitorAdapter() { @Override - public void visit(@NotNull GradleRenameChange change) { - // TODO den implement - } - - @Override - public void visit(@NotNull GradleProjectStructureChange change) { - // TODO den implement - } - - @Override - public void visit(@NotNull GradleModulePresenceChange change) { - // TODO den implement + public void visit(@NotNull GradleMismatchedLibraryPathChange change) { + for (GradleProjectStructureNode holder : myModuleDependencies.values()) { + for (GradleProjectStructureNode dependencyNode : holder.getChildren(GradleLibraryDependencyId.class)) { + final GradleLibraryDependencyId id = dependencyNode.getDescriptor().getElement(); + if (change.getLibraryName().equals(id.getLibraryName())) { + dependencyNode.addConflictChange(change); + break; + } + } + } } @Override public void visit(@NotNull GradleLibraryDependencyPresenceChange change) { - String moduleName; - GradleProjectStructureNodeDescriptor descriptor; - final GradleLibraryDependency gradleEntity = change.getGradleEntity(); - final LibraryOrderEntry intellijEntity = change.getIntellijEntity(); - final Object missingEntity; - if (gradleEntity == null && intellijEntity == null) { - // Never expect to be here. - assert false; + GradleLibraryDependencyId id = change.getGradleEntity(); + TextAttributesKey attributes = GradleTextAttributes.GRADLE_LOCAL_CHANGE; + if (id == null) { + id = change.getIntellijEntity(); + attributes = GradleTextAttributes.INTELLIJ_LOCAL_CHANGE; } - - if (gradleEntity == null) { - // Particular library dependency is added at the intellij side. - moduleName = intellijEntity.getOwnerModule().getName(); - if (intellijEntity.getLibraryName() == null) { - return; - } - descriptor = buildDescriptor(intellijEntity); - descriptor.setAttributes(GradleTextAttributes.INTELLIJ_LOCAL_CHANGE); - missingEntity = intellijEntity; - } - else { - // Particular library dependency is added at the gradle side. - moduleName = gradleEntity.getOwnerModule().getName(); - descriptor = buildDescriptor(gradleEntity, GradleIcons.LIB_ICON); - descriptor.setAttributes(GradleTextAttributes.GRADLE_LOCAL_CHANGE); - missingEntity = gradleEntity; - } - final DefaultMutableTreeNode dependenciesNode = getDependenciesNode(moduleName); - for (int i = 0, max = dependenciesNode.getChildCount(); i < max; i++) { - final DefaultMutableTreeNode child = (DefaultMutableTreeNode)dependenciesNode.getChildAt(i); - GradleProjectStructureNodeDescriptor d = (GradleProjectStructureNodeDescriptor)child.getUserObject(); - if (missingEntity.equals(d.getElement())) { - d.setAttributes(descriptor.getAttributes()); + assert id != null; + final GradleProjectStructureNode dependenciesNode = getDependenciesNode(id.getModuleName()); + for (GradleProjectStructureNode node : dependenciesNode.getChildren(GradleLibraryDependencyId.class)) { + GradleProjectStructureNodeDescriptor d = node.getDescriptor(); + if (id.equals(d.getElement())) { + d.setAttributes(attributes); + nodeStructureChanged(node); return; } } - DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(descriptor); + GradleProjectStructureNode newNode + = buildNode(id, GradleEntityType.LIBRARY_DEPENDENCY, id.getLibraryName(), GradleIcons.LIB_ICON); + newNode.getDescriptor().setAttributes(attributes); dependenciesNode.add(newNode); nodeStructureChanged(dependenciesNode); } @@ -215,7 +201,7 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { } /** - * Asks current model to remove all obsolete nodes for the considering that the given changes are obsolete. + * Asks current model to process given changes assuming that they are obsolete. *

* Example: *

@@ -227,63 +213,72 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel {
    * 
    * 
*/ - public void pruneObsoleteNodes(Collection changes) { + public void processObsoleteChanges(Collection changes) { for (GradleProjectStructureChange change : changes) { - change.invite(new GradleProjectStructureChangeVisitor() { + change.invite(new GradleProjectStructureChangeVisitorAdapter() { @Override - public void visit(@NotNull GradleRenameChange change) { - // TODO den implement - } - - @Override - public void visit(@NotNull GradleProjectStructureChange change) { - // TODO den implement - } - - @Override - public void visit(@NotNull GradleModulePresenceChange change) { - // TODO den implement + public void visit(@NotNull GradleMismatchedLibraryPathChange change) { + for (GradleProjectStructureNode holder : myModuleDependencies.values()) { + for (GradleProjectStructureNode node : holder.getChildren(GradleLibraryDependencyId.class)) { + final GradleLibraryDependencyId id = node.getDescriptor().getElement(); + if (id.getLibraryName().equals(change.getLibraryName())) { + node.removeConflictChange(change); + nodeChanged(node); + break; + } + } + } } @Override public void visit(@NotNull GradleLibraryDependencyPresenceChange change) { // We need to remove the corresponding node then. - String moduleName; - Object library; - final GradleLibraryDependency gradleEntity = change.getGradleEntity(); - final LibraryOrderEntry intellijEntity = change.getIntellijEntity(); - assert gradleEntity != null || intellijEntity != null; - if (gradleEntity == null) { - moduleName = intellijEntity.getOwnerModule().getName(); - library = intellijEntity; + GradleLibraryDependencyId id = change.getGradleEntity(); + boolean removeNode; + if (id == null) { + id = change.getIntellijEntity(); + assert id != null; + removeNode = !myProjectStructureHelper.isIntellijLibraryDependencyExist(id); } else { - moduleName = gradleEntity.getOwnerModule().getName(); - library = gradleEntity; + removeNode = !myProjectStructureHelper.isGradleLibraryDependencyExist(id); } - final DefaultMutableTreeNode holder = myModuleDependencies.get(moduleName); + final GradleProjectStructureNode holder = myModuleDependencies.get(id.getModuleName()); if (holder == null) { return; } - for (DefaultMutableTreeNode node = holder.getFirstLeaf(); node != null; node = node.getNextSibling()) { - GradleProjectStructureNodeDescriptor descriptor = (GradleProjectStructureNodeDescriptor)node.getUserObject(); - if (descriptor.getElement().equals(library)) { - removeNode(node); - return; + + // There are two possible cases why 'local library dependency' change is obsolete: + // 1. Corresponding dependency has been added at the counterparty; + // 2. The 'local dependency' has been removed; + // We should distinguish between those situations because we need to mark the node as 'synced' at one case and + // completely removed at another one. + + for (GradleProjectStructureNode node : holder.getChildren(GradleLibraryDependencyId.class)) { + GradleProjectStructureNodeDescriptor descriptor = node.getDescriptor(); + if (!id.equals(descriptor.getElement())) { + continue; } + if (removeNode) { + removeNode(node); + } + else { + descriptor.setAttributes(GradleTextAttributes.GRADLE_NO_CHANGE); + } + return; } } }); } } - private void removeNode(@NotNull TreeNode node) { - final MutableTreeNode parent = (MutableTreeNode)node.getParent(); + private void removeNode(@NotNull GradleProjectStructureNode node) { + final GradleProjectStructureNode parent = node.getParent(); if (parent == null) { return; } int i = parent.getIndex(node); - if (i <= 0) { + if (i < 0) { assert false : node; return; } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleDataKeys.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleDataKeys.java new file mode 100644 index 000000000000..134db91a6efc --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleDataKeys.java @@ -0,0 +1,18 @@ +package org.jetbrains.plugins.gradle.ui; + +import com.intellij.openapi.actionSystem.DataKey; + +import java.util.Collection; + +/** + * @author Denis Zhdanov + * @since 2/7/12 11:19 AM + */ +public class GradleDataKeys { + + /** Key for obtaining currently selected nodes at the gradle 'sync project structure' tree. */ + public static final DataKey>> SYNC_TREE_NODE = DataKey.create("gradle.sync.tree.node"); + + private GradleDataKeys() { + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectStructureNode.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectStructureNode.java index 06e7285d2861..e009d1a88b19 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectStructureNode.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectStructureNode.java @@ -1,24 +1,149 @@ package org.jetbrains.plugins.gradle.ui; import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.config.GradleTextAttributes; +import org.jetbrains.plugins.gradle.diff.GradleProjectStructureChange; +import org.jetbrains.plugins.gradle.model.GradleEntityType; import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.MutableTreeNode; +import java.util.*; /** * @author Denis Zhdanov * @since 8/23/11 3:50 PM + * @param type of the target entity {@link GradleProjectStructureNodeDescriptor#getElement() associated} with the current node */ -public class GradleProjectStructureNode extends DefaultMutableTreeNode { - - private final GradleProjectStructureNodeDescriptor myDescriptor; +public class GradleProjectStructureNode extends DefaultMutableTreeNode implements Iterable> { - public GradleProjectStructureNode(@NotNull GradleProjectStructureNodeDescriptor descriptor) { + private final Set myConflictChanges = new HashSet(); + + private final GradleProjectStructureNodeDescriptor myDescriptor; + private final GradleEntityType myType; + + public GradleProjectStructureNode(@NotNull GradleProjectStructureNodeDescriptor descriptor, @NotNull GradleEntityType type) { super(descriptor); myDescriptor = descriptor; + myType = type; } @NotNull - public GradleProjectStructureNodeDescriptor getDescriptor() { + public GradleProjectStructureNodeDescriptor getDescriptor() { return myDescriptor; } + + @NotNull + public GradleEntityType getType() { + return myType; + } + + @Override + public GradleProjectStructureNode getChildAt(int index) { + return (GradleProjectStructureNode)super.getChildAt(index); + } + + @Override + public GradleProjectStructureNode getParent() { + return (GradleProjectStructureNode)super.getParent(); + } + + @Override + public void add(MutableTreeNode newChild) { + GradleProjectStructureNode child = (GradleProjectStructureNode)newChild; + final String newName = child.getDescriptor().getName(); + for (int i = 0; i < getChildCount(); i++) { + GradleProjectStructureNode node = getChildAt(i); + if (newName.compareTo(node.getDescriptor().getName()) < 0) { + insert(newChild, i); + return; + } + } + super.add(newChild); + } + + /** + * Registers given change within the given node assuming that it is + * {@link GradleTextAttributes#GRADLE_CHANGE_CONFLICT 'conflict change'}. We need to track number of such changes per-node because + * of the following possible situation: + *
+   * 
    + *
  1. There are two 'conflict changes' for particular node;
  2. + *
  3. + * One of those changes is resolved but the node still should be marked as 'conflict' because there is still one conflict change; + *
  4. + *
  5. The second conflict change is removed. The node should be marked as 'no change' now;
  6. + *
+ *
+ * + * @param change conflict change to register for the current node + */ + public void addConflictChange(@NotNull GradleProjectStructureChange change) { + myConflictChanges.add(change); + myDescriptor.setAttributes(GradleTextAttributes.GRADLE_CHANGE_CONFLICT); + } + + /** + * Performs reverse operation to {@link #addConflictChange(GradleProjectStructureChange)}. + * + * @param change conflict change to de-register from the current node + */ + public void removeConflictChange(@NotNull GradleProjectStructureChange change) { + myConflictChanges.remove(change); + if (myConflictChanges.isEmpty()) { + myDescriptor.setAttributes(GradleTextAttributes.GRADLE_NO_CHANGE); + } + } + + /** + * Allows to query current node for all children that are associated with the entity of the given type. + * + * @param clazz target entity type + * @param target entity type + * @return all children nodes that are associated with the entity of the given type if any; + * empty collection otherwise + */ + @SuppressWarnings("unchecked") + @NotNull + public Collection> getChildren(@NotNull Class clazz) { + List> result = null; + for (int i = 0; i < getChildCount(); i++) { + final GradleProjectStructureNode child = getChildAt(i); + final Object element = child.getDescriptor().getElement(); + if (!clazz.isInstance(element)) { + continue; + } + if (result == null) { + result = new ArrayList>(); + } + result.add((GradleProjectStructureNode)child); + } + if (result == null) { + result = Collections.emptyList(); + } + return result; + } + + @NotNull + @Override + public Iterator> iterator() { + return new Iterator>() { + + private int i; + + @Override + public boolean hasNext() { + return i < getChildCount(); + } + + @Override + public GradleProjectStructureNode next() { + return getChildAt(i++); + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectStructureNodeDescriptor.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectStructureNodeDescriptor.java index f68a833439fe..031e5077fa2e 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectStructureNodeDescriptor.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectStructureNodeDescriptor.java @@ -40,6 +40,7 @@ public class GradleProjectStructureNodeDescriptor extends PresentableNodeDesc presentation.setClosedIcon(myClosedIcon); } + @NotNull @Override public T getElement() { return myData; diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleToolWindowFactory.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleToolWindowFactory.java new file mode 100644 index 000000000000..7fe40ad3f877 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleToolWindowFactory.java @@ -0,0 +1,25 @@ +package org.jetbrains.plugins.gradle.ui; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.wm.ToolWindow; +import com.intellij.openapi.wm.ToolWindowFactory; +import com.intellij.ui.content.impl.ContentImpl; +import org.jetbrains.plugins.gradle.diff.PlatformFacade; +import org.jetbrains.plugins.gradle.sync.GradleProjectStructureChangesModel; +import org.jetbrains.plugins.gradle.sync.GradleProjectStructureChangesPanel; +import org.jetbrains.plugins.gradle.sync.GradleProjectStructureHelper; +import org.jetbrains.plugins.gradle.util.GradleBundle; + +public class GradleToolWindowFactory implements ToolWindowFactory { + @Override + public void createToolWindowContent(final Project project, final ToolWindow toolWindow) { + final GradleProjectStructureChangesModel model = project.getComponent(GradleProjectStructureChangesModel.class); + final PlatformFacade facade = ServiceManager.getService(PlatformFacade.class); + final GradleProjectStructureHelper helper = project.getComponent(GradleProjectStructureHelper.class); + + final GradleProjectStructureChangesPanel panel = new GradleProjectStructureChangesPanel(project, model, facade, helper); + final String syncTitle = GradleBundle.message("gradle.sync.title.tab"); + toolWindow.getContentManager().addContent(new ContentImpl(panel, syncTitle, true)); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleConstants.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleConstants.java index 49f441744592..acc24a256475 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleConstants.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleConstants.java @@ -1,10 +1,7 @@ package org.jetbrains.plugins.gradle.util; -import com.intellij.openapi.util.IconLoader; import org.jetbrains.annotations.NonNls; -import javax.swing.*; - /** * Holds object representation of icons used at the Gradle plugin. * @@ -13,9 +10,13 @@ import javax.swing.*; */ public class GradleConstants { - @NonNls public static final String EXTENSION = "gradle"; - @NonNls public static final String DEFAULT_SCRIPT_NAME = "build.gradle"; + @NonNls public static final String EXTENSION = "gradle"; + @NonNls public static final String DEFAULT_SCRIPT_NAME = "build.gradle"; + @NonNls public static final String TOOL_WINDOW_TOOLBAR_PLACE = "GRADLE_SYNC_CHANGES_TOOLBAR"; + @NonNls public static final String SYNC_TREE_PLACE = "GRADLE_SYNC_TREE_PLACE"; + + @NonNls public static final String ACTION_GROUP_SYNC_TREE = "Gradle.SyncTreeGroup"; private GradleConstants() { } diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModelTest.groovy b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModelTest.groovy index a1028db5d50c..178bd46bf6b2 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModelTest.groovy +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModelTest.groovy @@ -1,16 +1,13 @@ package org.jetbrains.plugins.gradle.sync; -import com.intellij.openapi.Disposable import com.intellij.openapi.project.Project -import com.intellij.openapi.util.Disposer import com.intellij.testFramework.SkipInHeadlessEnvironment import com.intellij.util.containers.ContainerUtil import org.jetbrains.plugins.gradle.testutil.ChangeBuilder import org.jetbrains.plugins.gradle.testutil.GradleProjectBuilder import org.jetbrains.plugins.gradle.testutil.IntellijProjectBuilder import org.jetbrains.plugins.gradle.testutil.ProjectStructureChecker -import org.junit.After import org.junit.Before import org.junit.Test import org.picocontainer.defaults.DefaultPicoContainer @@ -31,7 +28,6 @@ public class GradleProjectStructureChangesModelTest { def changes def treeChecker def container - Disposable disposable = [dispose: { }] as Disposable @Before public void setUp() { @@ -46,18 +42,15 @@ public class GradleProjectStructureChangesModelTest { container.registerComponentImplementation(GradleStructureChangesCalculator, GradleProjectStructureChangesCalculator) container.registerComponentImplementation(GradleModuleStructureChangesCalculator) container.registerComponentImplementation(GradleLibraryDependencyStructureChangesCalculator) + container.registerComponentImplementation(GradleLibraryStructureChangesCalculator) container.registerComponentImplementation(GradleProjectStructureTreeModel) + container.registerComponentImplementation(GradleProjectStructureHelper) changesModel = container.getComponentInstance(GradleProjectStructureChangesModel) as GradleProjectStructureChangesModel } - @After - public void tearDown() { - Disposer.dispose(disposable) - } - @Test - public void mergeGradleLocalToIntellij() { + public void processObsoleteGradleLocalChange() { // Configure initial projects state. init( gradle { @@ -65,6 +58,7 @@ public class GradleProjectStructureChangesModelTest { dependencies { lib(name: "lib1") lib(name: "lib2") + lib(name: "lib3") } } }, intellij { @@ -78,46 +72,157 @@ public class GradleProjectStructureChangesModelTest { checkChanges { presence { lib(gradle: gradle.modules.dependencies.flatten().findAll { it.name == "lib2" }) + lib(gradle: gradle.modules.dependencies.flatten().findAll { it.name == "lib3" }) } } checkTree { project { - module("xxx") { + module() { dependencies { lib1() lib2('gradle') + lib3('gradle') } } } } - // Define changed project state. + // Add the same library at intellij side. Expecting to have the only change now. + intellij { + module { + dependencies { + lib(name: "lib1") + lib(name: "lib2") + } } } + changesModel.update(gradle.project) + checkChanges { + presence { + lib(gradle: gradle.modules.dependencies.flatten().findAll { it.name == "lib3" }) + } } + checkTree { + project { + module() { + dependencies { + lib1() + lib2() + lib3('gradle') + } } } } + + // Remove the 'gradle local' dependency. gradle { module { dependencies { lib(name: "lib1") + lib(name: "lib2") } } } // Apply the changed project state and check if it's correctly parsed. changesModel.update(gradle.project) + checkChanges { } // no changes. assertEquals([].toSet(), changesModel.changes) checkTree { project { module { dependencies { lib1() + lib2() } } } } } - + + @Test + public void libraryDependenciesWithDifferentPaths() { + // Let the model has two differences in a library setup initially. + init( + gradle { + module { + dependencies { + lib(name: "lib1") + lib(name: "lib2", bin: ['1', '2']) + } } }, + intellij { + module { + dependencies { + lib(name: "lib1") + lib(name: "lib2", bin: ['2', '3']) + }}} + ) + + checkChanges { + libraryConflict(entity: intellij.libraries['lib2']) { + binaryPath(gradle: '1', intellij: null) + binaryPath(gradle: null, intellij: '3') + } } + checkTree { + project { + module { + dependencies { + lib1() + lib2('conflict') + } } } } + + // Remove one difference from the library setup and check that the corresponding node is still marked as conflicted + gradle { + module { + dependencies { + lib(name: "lib1") + lib(name: "lib2", bin: ['2']) + } } } + intellij { + module { + dependencies { + lib(name: "lib1") + lib(name: "lib2", bin: ['2', '3']) + }}} + changesModel.update(gradle.project) + checkChanges { + libraryConflict(entity: intellij.dependencies.values().flatten().find {it.library.name == 'lib2' }.library) { + binaryPath(gradle: null, intellij: '3') + } } + checkTree { + project { + module { + dependencies { + lib1() + lib2('conflict') + } } } } + + // Match the remaining change and check that the corresponding node is not marked as conflicted anymore. + gradle { + module { + dependencies { + lib(name: "lib1") + lib(name: "lib2", bin: ['2', '3']) + } } } + intellij { + module { + dependencies { + lib(name: "lib1") + lib(name: "lib2", bin: ['2', '3']) + }}} + changesModel.update(gradle.project) + checkChanges { } // No changes + checkTree { + project { + module { + dependencies { + lib1() + lib2() + } } } } + } + @SuppressWarnings("GroovyAssignabilityCheck") private def init(gradleProjectInit, intellijProjectInit) { treeModel = container.getComponentInstance(GradleProjectStructureTreeModel) as GradleProjectStructureTreeModel changesModel.addListener({ old, current -> treeModel.update(current) - treeModel.pruneObsoleteNodes(ContainerUtil.subtract(old, current)); + treeModel.processObsoleteChanges(ContainerUtil.subtract(old, current)); } as GradleProjectStructureChangeListener) changesModel.update(gradle.project) } private def checkChanges(c) { c.delegate = changes - assertEquals(c(), changesModel.changes) + def expected = c() + if (!expected) { + expected = [].toSet() + } + assertEquals(expected, changesModel.changes) } private def checkTree(c) { diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/AbstractProjectBuilder.groovy b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/AbstractProjectBuilder.groovy index 6e4d1f3fd140..a42abe160332 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/AbstractProjectBuilder.groovy +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/AbstractProjectBuilder.groovy @@ -1,19 +1,26 @@ package org.jetbrains.plugins.gradle.testutil -import com.intellij.pom.java.LanguageLevel; +import com.intellij.pom.java.LanguageLevel /** * @author Denis Zhdanov * @since 1/25/12 4:06 PM */ -public abstract class AbstractProjectBuilder extends BuilderSupport { +public abstract class AbstractProjectBuilder extends BuilderSupport { - private static final def SAME_TOKEN = "same" + public static final def SAME_TOKEN = "same" private static int COUNTER def project def modules = [] - def libraries = [:].withDefault { createLibrary(it.name?: same, it.paths?: [:]) } + /** Holds (library name; library) pairs for the active configuration. */ + def libraries = [:] + /** + * Holds (library name; library) pairs for the whole test. I.e. there is a possible case that we define particular configuration + * initially and the adjust it. We need to use the same library instance then in order to pass hashCode()/equals() checks then. + * This map works as a test-wide storage. + */ + def librariesCache = [:] def dependencies = [:].withDefault {[]} @Override @@ -43,7 +50,7 @@ public abstract class AbstractProjectBuilder extends BuilderSupport { case "module": def module = createModule(attributes.name?: same); modules << module; return module case "lib": def module = getCurrent() - def dep = createLibraryDependency(module, libraries[attributes]) + def dep = createLibraryDependency(module, getLibrary(attributes)) dependencies[module] << dep return dep } @@ -57,10 +64,27 @@ public abstract class AbstractProjectBuilder extends BuilderSupport { protected abstract def createProject(String name, LanguageLevel languageLevel) protected abstract def createModule(String name) protected abstract def createLibrary(String name, Map paths) + protected abstract def applyLibraryPaths(library, Map paths) protected abstract def createLibraryDependency(module, library) protected String getUnique() { "./${COUNTER++}" } protected String getSame() { SAME_TOKEN } + + private def getLibrary(Map attributes) { + def name = attributes.name?: same + def result = libraries[name] + if (result) return result + result = librariesCache[name] + if (result) { + applyLibraryPaths(result, attributes) + } + else { + result = createLibrary(name, attributes.withDefault { /* empty paths*/ [] }) + librariesCache[name] = result + } + libraries[name] = result + result + } private def reset() { [modules, dependencies, libraries]*.clear() diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/ChangeBuilder.groovy b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/ChangeBuilder.groovy index 700bcac3111a..b8ebd3b713d0 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/ChangeBuilder.groovy +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/ChangeBuilder.groovy @@ -2,6 +2,9 @@ package org.jetbrains.plugins.gradle.testutil; import org.jetbrains.plugins.gradle.diff.GradleLibraryDependencyPresenceChange +import org.jetbrains.plugins.gradle.diff.GradleMismatchedLibraryPathChange +import com.intellij.openapi.roots.libraries.Library +import org.jetbrains.plugins.gradle.util.GradleUtil /** * @author Denis Zhdanov @@ -17,10 +20,7 @@ public class ChangeBuilder extends BuilderSupport { @Override protected Object createNode(Object name) { - if (current == null) { - changes = [] - } - changes + createNode(name, [:]) } @Override @@ -28,13 +28,31 @@ public class ChangeBuilder extends BuilderSupport { @Override protected Object createNode(Object name, Map attributes) { + if (current == null) { + changes = [] + } switch (name) { case "presence": return changes case "lib": changes.addAll attributes.gradle.collect { new GradleLibraryDependencyPresenceChange(it, null)} changes.addAll attributes.intellij.collect { new GradleLibraryDependencyPresenceChange(null, it)} - return + return changes + case "libraryConflict": + def library = attributes.entity + if (!library) { + throw new IllegalArgumentException("No entity is defined for the library conflict change. Known attributes: $attributes") + } + if (attributes.gradle) { + return register(new GradleMismatchedLibraryPathChange(library, attributes.gradle, attributes.intellij)) + } + return library + case "binaryPath": + // Assuming that we're processing library binary path conflict here + register(new GradleMismatchedLibraryPathChange( + current as Library, toCanonicalPath(attributes.gradle), toCanonicalPath(attributes.intellij) + )) } + changes } @Override @@ -44,4 +62,13 @@ public class ChangeBuilder extends BuilderSupport { protected Object postNodeCompletion(Object parent, Object node) { parent == null ? changes.toSet() : node } + + protected def register(change) { + changes << change + change + } + + private def toCanonicalPath(String path) { + path ? GradleUtil.toCanonicalPath(path) : path + } } diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/GradleProjectBuilder.groovy b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/GradleProjectBuilder.groovy index e889543406fa..348e0842c973 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/GradleProjectBuilder.groovy +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/GradleProjectBuilder.groovy @@ -31,9 +31,7 @@ class GradleProjectBuilder extends AbstractProjectBuilder { @Override protected createLibrary(String name, Map paths) { def result = new GradleLibrary(name) - (paths.bin?: [same]).each { result.addPath(LibraryPathType.BINARY, it) } - (paths.src?: [same]).each { result.addPath(LibraryPathType.SOURCE, it) } - (paths.doc?: [same]).each { result.addPath(LibraryPathType.DOC, it) } + applyLibraryPaths(result, paths) result } @@ -43,4 +41,12 @@ class GradleProjectBuilder extends AbstractProjectBuilder { module.addDependency(result) result } + + @Override + protected applyLibraryPaths(library, Map paths) { + library.forgetAllPaths() + ['bin': LibraryPathType.BINARY, 'src': LibraryPathType.SOURCE, 'doc': LibraryPathType.DOC].each { + key, type -> paths[key]?.each { library.addPath(type, it) } + } + } } diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/IntellijProjectBuilder.groovy b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/IntellijProjectBuilder.groovy index 4948c10dd0cb..d8ff3e8436e3 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/IntellijProjectBuilder.groovy +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/IntellijProjectBuilder.groovy @@ -9,19 +9,29 @@ import com.intellij.openapi.roots.LibraryOrderEntry import com.intellij.openapi.project.Project import com.intellij.openapi.util.IconLoader +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.roots.OrderRootType +import org.jetbrains.plugins.gradle.util.GradleUtil + /** * @author Denis Zhdanov * @since 1/25/12 3:09 PM */ class IntellijProjectBuilder extends AbstractProjectBuilder { + + static def LIBRARY_ENTRY_TYPES = [(OrderRootType.CLASSES) : "bin"] + static VirtualFile[] DUMMY_VIRTUAL_FILE_ARRAY = new VirtualFile[0] def projectStub = [:] def project = projectStub as Project def platformFacade = [ getModules: { modules }, getOrderEntries: { dependencies[it] }, - getProjectIcon: { IconLoader.getIcon("/nodes/ideaProject.png") } + getProjectIcon: { IconLoader.getIcon("/nodes/ideaProject.png") }, + getLocalFileSystemPath: { it.path } ] + /** (library name - (library root type - paths)). */ + def libraryPaths = [:].withDefault { [:] } @Override protected createProject(String name, LanguageLevel languageLevel) { @@ -37,7 +47,17 @@ class IntellijProjectBuilder extends AbstractProjectBuilder { @Override protected createLibrary(String name, Map paths) { - [ getName: { name }, getPresentableName: { name } ] as Library + libraryPaths[name] = paths + [ + getName: { name }, + getPresentableName: { name }, + getFiles: { + type -> (libraryPaths[name])[LIBRARY_ENTRY_TYPES[type]].findAll { it }.collect { + String path = it + [getPath: { GradleUtil.toCanonicalPath(path) }] as VirtualFile + }.toArray(DUMMY_VIRTUAL_FILE_ARRAY) + } + ] as Library } @Override @@ -46,6 +66,13 @@ class IntellijProjectBuilder extends AbstractProjectBuilder { def result = stub as LibraryOrderEntry stub.accept = { policy, defaultValue -> policy.visitLibraryOrderEntry(result, defaultValue) } stub.getLibraryName = { library.name } + stub.getLibrary = { library } + stub.getOwnerModule = { module } result } + + @Override + protected applyLibraryPaths(library, Map paths) { + libraryPaths[library.name] = paths + } } diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/ProjectStructureChecker.groovy b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/ProjectStructureChecker.groovy index 88decefa8a00..62d8ed0c9191 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/ProjectStructureChecker.groovy +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/ProjectStructureChecker.groovy @@ -35,6 +35,9 @@ class ProjectStructureChecker { check it as Node, actual.getChildAt(childIndex++) as DefaultMutableTreeNode } for (it in expected.children().findAll { it instanceof Node}) { + if (childIndex >= actual.childCount) { + fail "Expected node is not matched: $expected" + } check it as Node, actual.getChildAt(childIndex++) as DefaultMutableTreeNode } if (childIndex < actual.childCount) { @@ -43,7 +46,7 @@ class ProjectStructureChecker { } private void checkName(Node expected, GradleProjectStructureNodeDescriptor actual) { - if (expected.name() == actual.toString()) { + if (AbstractProjectBuilder.SAME_TOKEN == actual.toString() || expected.name() == actual.toString()) { return } def clazz = BUILT_IN[expected.name()] diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyFileType.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyFileType.java index 8e9a333abfd1..69a1382f00e0 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyFileType.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyFileType.java @@ -16,15 +16,15 @@ package org.jetbrains.plugins.groovy; +import com.intellij.lang.Language; +import com.intellij.openapi.editor.colors.EditorColorsScheme; +import com.intellij.openapi.editor.highlighter.EditorHighlighter; import com.intellij.openapi.fileTypes.EditorHighlighterProvider; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypeEditorHighlighterProviders; import com.intellij.openapi.fileTypes.LanguageFileType; -import com.intellij.openapi.editor.highlighter.EditorHighlighter; -import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.lang.Language; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -50,7 +50,7 @@ public class GroovyFileType extends LanguageFileType { public EditorHighlighter getEditorHighlighter(@Nullable Project project, @NotNull FileType fileType, @Nullable VirtualFile virtualFile, @NotNull EditorColorsScheme colors) { - return new GroovyEditorHighlighter(colors, project, virtualFile); + return new GroovyEditorHighlighter(colors); } }); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyCodeFragmentFactory.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyCodeFragmentFactory.java index 3f85a1e6649b..17c9260260f6 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyCodeFragmentFactory.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyCodeFragmentFactory.java @@ -55,7 +55,7 @@ import java.util.regex.Pattern; /** * @author ven */ -public class GroovyCodeFragmentFactory implements CodeFragmentFactory { +public class GroovyCodeFragmentFactory extends CodeFragmentFactory { private static final String EVAL_NAME = "_JETGROOVY_EVAL_"; private static final String IMPORTS = "___$$IMPORTS$$___"; private static final String TEXT = "___$$TEXT$$___"; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovyIndentProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovyIndentProcessor.java index 1ae7a5e18634..3272fd5d8b92 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovyIndentProcessor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovyIndentProcessor.java @@ -22,10 +22,10 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.GroovyFileType; import org.jetbrains.plugins.groovy.formatter.GroovyBlock; -import org.jetbrains.plugins.groovy.lang.editor.actions.GroovyEditorActionUtil; import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocComment; import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocTag; import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; @@ -50,6 +50,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMe */ public abstract class GroovyIndentProcessor implements GroovyElementTypes { public static final int GDOC_COMMENT_INDENT = 1; + private static TokenSet GSTRING_TOKENS_INNER = TokenSet.create(mGSTRING_BEGIN,mGSTRING_CONTENT,mGSTRING_END,mDOLLAR); /** * Calculates indent, based on code style, between parent block and child node @@ -72,14 +73,12 @@ public abstract class GroovyIndentProcessor implements GroovyElementTypes { return Indent.getContinuationIndent(); } - if (GroovyEditorActionUtil.GSTRING_TOKENS_INNER.contains(child.getElementType()) && - mGSTRING_BEGIN != child.getElementType()) { + if (GSTRING_TOKENS_INNER.contains(child.getElementType()) && mGSTRING_BEGIN != child.getElementType()) { return Indent.getAbsoluteNoneIndent(); } if (psiParent instanceof GrListOrMap) { - if (mLBRACK.equals(child.getElementType()) || - mRBRACK.equals(child.getElementType())) { + if (mLBRACK.equals(child.getElementType()) || mRBRACK.equals(child.getElementType())) { return Indent.getNoneIndent(); } else { return Indent.getContinuationWithoutFirstIndent(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovyEditorHighlighter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovyEditorHighlighter.java index abdc14186e73..c0a235eb0211 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovyEditorHighlighter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovyEditorHighlighter.java @@ -20,8 +20,6 @@ import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.ex.util.LayerDescriptor; import com.intellij.openapi.editor.ex.util.LayeredLexerEditorHighlighter; import com.intellij.openapi.fileTypes.SyntaxHighlighter; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.plugins.groovy.lang.groovydoc.highlighter.GroovyDocSyntaxHighlighter; import org.jetbrains.plugins.groovy.lang.groovydoc.parser.GroovyDocElementTypes; @@ -30,7 +28,7 @@ import org.jetbrains.plugins.groovy.lang.groovydoc.parser.GroovyDocElementTypes; */ public class GroovyEditorHighlighter extends LayeredLexerEditorHighlighter { - public GroovyEditorHighlighter(EditorColorsScheme scheme, Project project, VirtualFile virtualFile) { + public GroovyEditorHighlighter(EditorColorsScheme scheme) { super(new GroovySyntaxHighlighter(), scheme); registerGroovydocHighlighter(); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovyTodoIndexer.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovyTodoIndexer.java index 0ebf01cbb7c6..c9daf9280738 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovyTodoIndexer.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovyTodoIndexer.java @@ -15,13 +15,11 @@ */ package org.jetbrains.plugins.groovy.highlighter; -import com.intellij.lexer.FilterLexer; import com.intellij.lexer.Lexer; import com.intellij.psi.impl.cache.impl.OccurrenceConsumer; import com.intellij.psi.impl.cache.impl.todo.LexerBasedTodoIndexer; import org.jetbrains.plugins.groovy.lang.lexer.GroovyFilterLexer; import org.jetbrains.plugins.groovy.lang.lexer.GroovyLexer; -import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; /** * @author Maxim.Medvedev @@ -29,7 +27,6 @@ import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; public class GroovyTodoIndexer extends LexerBasedTodoIndexer { @Override public Lexer createLexer(OccurrenceConsumer consumer) { - final GroovyFilterLexer groovyFilterLexer = new GroovyFilterLexer(new GroovyLexer(), consumer); - return new FilterLexer(groovyFilterLexer, new FilterLexer.SetFilter(TokenSets.WHITE_SPACES_OR_COMMENTS)); + return new GroovyFilterLexer(new GroovyLexer(), consumer); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java index 0b133fffb90b..56b61fa3179e 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java @@ -45,6 +45,7 @@ import com.intellij.util.PairConsumer; import com.intellij.util.ProcessingContext; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.GroovyBundle; import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; @@ -64,18 +65,18 @@ import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatem import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeParameterList; +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.CompleteReferenceExpression; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.refactoring.DefaultGroovyVariableNameValidator; import org.jetbrains.plugins.groovy.refactoring.GroovyNameSuggestionUtil; import org.jetbrains.plugins.groovy.refactoring.inline.InlineMethodConflictSolver; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import static com.intellij.patterns.PlatformPatterns.psiElement; import static com.intellij.patterns.PsiJavaPatterns.elementType; +import static com.intellij.util.containers.CollectionFactory.arrayList; import static com.intellij.util.containers.CollectionFactory.hashMap; import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.*; import static org.jetbrains.plugins.groovy.lang.lexer.TokenSets.SEPARATORS; @@ -176,18 +177,20 @@ public class GroovyCompletionContributor extends CompletionContributor { private static void addAllClasses(CompletionParameters parameters, final CompletionResultSet result, final InheritorsHolder inheritors) { - addAllClasses(parameters, result, new Consumer() { + addAllClasses(parameters, new Consumer() { @Override public void consume(LookupElement element) { result.addElement(element); } - }, inheritors); + }, inheritors, result.getPrefixMatcher()); } - public static void addAllClasses(CompletionParameters parameters, CompletionResultSet result, final Consumer consumer, final InheritorsHolder inheritors) { + public static void addAllClasses(CompletionParameters parameters, + final Consumer consumer, + final InheritorsHolder inheritors, final PrefixMatcher matcher) { final PsiElement position = parameters.getPosition(); final ElementFilter filter = getClassFilter(position); - AllClassesGetter.processJavaClasses(parameters, result.getPrefixMatcher(), parameters.getInvocationCount() <= 1, + AllClassesGetter.processJavaClasses(parameters, matcher, parameters.getInvocationCount() <= 1, new Consumer() { @Override public void consume(PsiClass psiClass) { @@ -310,21 +313,21 @@ public class GroovyCompletionContributor extends CompletionContributor { addUnfinishedMethodTypeParameters(position, result); - final PsiElement parent = position.getParent(); - GrReferenceElement reference; - if (parent instanceof GrReferenceElement) { - reference = (GrReferenceElement)parent; - if (reference.getParent() instanceof GrImportStatement && reference.getQualifier() != null) { - result.addElement(LookupElementBuilder.create("*")); - } - } else if (couldContainReference(position)) { - reference = GroovyPsiElementFactory.getInstance(position.getProject()).createReferenceElementFromText("Foo", position); - } else { + GrReferenceElement reference = findGroovyReference(position); + if (reference == null) { return; } + if (reference.getParent() instanceof GrImportStatement && reference.getQualifier() != null) { + result.addElement(LookupElementBuilder.create("*")); + } + InheritorsHolder inheritors = new InheritorsHolder(position, result); - completeReference(parameters, result, reference, inheritors); + if (GroovySmartCompletionContributor.AFTER_NEW.accepts(position)) { + GroovySmartCompletionContributor.generateInheritorVariants(parameters, result.getPrefixMatcher(), inheritors); + } + + result.addAllElements(completeReference(parameters, reference, inheritors, result.getPrefixMatcher())); if (reference.getQualifier() == null) { GroovySmartCompletionContributor.addExpectedClassMembers(parameters, result); @@ -361,6 +364,17 @@ public class GroovyCompletionContributor extends CompletionContributor { } + @Nullable private static GrReferenceElement findGroovyReference(PsiElement position) { + final PsiElement parent = position.getParent(); + if (parent instanceof GrReferenceElement) { + return (GrReferenceElement)parent; + } + if (couldContainReference(position)) { + return GroovyPsiElementFactory.getInstance(position.getProject()).createReferenceElementFromText("Foo", position); + } + return null; + } + private static boolean couldContainReference(PsiElement position) { return IN_CATCH_TYPE.accepts(position) || AFTER_AT.accepts(position) || @@ -408,31 +422,31 @@ public class GroovyCompletionContributor extends CompletionContributor { super.fillCompletionVariants(parameters, result); } - private static void completeReference(final CompletionParameters parameters, - final CompletionResultSet result, - GrReferenceElement reference, final InheritorsHolder inheritorsHolder) { + static LinkedHashSet completeReference(final CompletionParameters parameters, + GrReferenceElement reference, final InheritorsHolder inheritorsHolder, final PrefixMatcher matcher) { final PsiElement position = parameters.getPosition(); - if (GroovySmartCompletionContributor.AFTER_NEW.accepts(position)) { - GroovySmartCompletionContributor.generateInheritorVariants(parameters, result.getPrefixMatcher(), inheritorsHolder); - } - - final int invocationCount = parameters.getInvocationCount(); - final boolean firstCompletionInvoked = invocationCount < 2; - - final String prefix = result.getPrefixMatcher().getPrefix(); - final boolean skipAccessors = firstCompletionInvoked && !prefix.startsWith("g") && !prefix.startsWith("s") && !prefix.startsWith("i"); - result.restartCompletionOnPrefixChange("g"); - result.restartCompletionOnPrefixChange("i"); - result.restartCompletionOnPrefixChange("s"); - final Map staticMembers = hashMap(); final PsiElement qualifier = reference.getQualifier(); final PsiType qualifierType = qualifier instanceof GrExpression ? ((GrExpression)qualifier).getType() : null; + LinkedHashSet result = new LinkedHashSet(); + if (reference instanceof GrReferenceExpression && (qualifier instanceof GrExpression || qualifier == null)) { + for (String string : CompleteReferenceExpression.getVariantsWithSameQualifier(matcher, (GrExpression)qualifier, (GrReferenceExpression)reference)) { + result.add(GroovyCompletionUtil.getLookupElement(string)); + } + if (parameters.getInvocationCount() < 2 && qualifier != null && qualifierType == null) { + if (parameters.getInvocationCount() == 1) { + showInfo(); + } + return result; + } + } + final ElementFilter classFilter = getClassFilter(position); - reference.processVariants(result.getPrefixMatcher(), parameters, new Consumer() { + final List items = arrayList(); + reference.processVariants(matcher, parameters, new Consumer() { public void consume(Object element) { if (element instanceof PsiClass && inheritorsHolder.alreadyProcessed((PsiClass)element)) { return; @@ -445,15 +459,11 @@ public class GroovyCompletionContributor extends CompletionContributor { element = ((LookupElement)element).getObject(); } - final LookupElement lookupElement = element instanceof PsiClass - ? GroovyCompletionUtil.createClassLookupItem(CompletionUtil.getOriginalOrSelf((PsiClass)element)) - : GroovyCompletionUtil.getLookupElement(element); + LookupElement lookupElement = element instanceof PsiClass + ? GroovyCompletionUtil.createClassLookupItem(CompletionUtil.getOriginalOrSelf((PsiClass)element)) + : GroovyCompletionUtil.getLookupElement(element); Object object = lookupElement.getObject(); - PsiSubstitutor substitutor = null; - GroovyResolveResult resolveResult = null; if (object instanceof GroovyResolveResult) { - resolveResult = (GroovyResolveResult)object; - substitutor = resolveResult.getSubstitutor(); object = ((GroovyResolveResult)object).getElement(); } @@ -461,44 +471,9 @@ public class GroovyCompletionContributor extends CompletionContributor { return; } - final boolean autopopup = parameters.getInvocationCount() == 0; - //skip default groovy methods - if (firstCompletionInvoked && - object instanceof GrGdkMethod && - GroovyCompletionUtil.skipDefGroovyMethod((GrGdkMethod)object, substitutor, qualifierType)) { - if (!autopopup) { - showInfo(); - } - return; - } - - //skip operator methods - if (firstCompletionInvoked && - object instanceof PsiMethod && - GroovyCompletionUtil.OPERATOR_METHOD_NAMES.contains(((PsiMethod)object).getName())) { - if (!checkForIterator((PsiMethod)object)) { - if (!autopopup) { - showInfo(); - } - return; - } - } - - //skip accessors if there is no get, set, is prefix - if (skipAccessors && object instanceof PsiMethod && GroovyPropertyUtils.isSimplePropertyAccessor((PsiMethod)object)) { - if (!autopopup) { - showInfo(); - } - return; - } - - //skip inaccessible elements - if (firstCompletionInvoked && resolveResult != null && !resolveResult.isAccessible()) { - if (!autopopup) { - showInfo(); - } - return; - } + int priority = assignPriority(lookupElement, qualifierType); + lookupElement = JavaCompletionUtil.highlightIfNeeded(qualifierType, + PrioritizedLookupElement.withPriority(lookupElement, priority), object); if ((object instanceof PsiMethod || object instanceof PsiField) && ((PsiModifierListOwner)object).hasModifierProperty(PsiModifier.STATIC)) { @@ -510,7 +485,8 @@ public class GroovyCompletionContributor extends CompletionContributor { if (object instanceof PsiClass && !classFilter.isAcceptable(object, position)) { return; } - result.addElement(JavaCompletionUtil.highlightIfNeeded(qualifierType, lookupElement, object)); + + items.add(lookupElement); } }); @@ -522,7 +498,7 @@ public class GroovyCompletionContributor extends CompletionContributor { member = ((GrAccessorMethod)member).getProperty(); } final String name = member.getName(); - if (name == null || !result.getPrefixMatcher().prefixMatches(name)) { + if (name == null || !matcher.prefixMatches(name)) { staticMembers.remove(member); return; } @@ -532,7 +508,26 @@ public class GroovyCompletionContributor extends CompletionContributor { }); } - result.addAllElements(staticMembers.values()); + items.addAll(staticMembers.values()); + + for (Iterator iterator = items.iterator(); iterator.hasNext(); ) { + LookupElement element = iterator.next(); + PrioritizedLookupElement prio = element.as(PrioritizedLookupElement.CLASS_CONDITION_KEY); + if (prio == null || prio.getPriority() >= 0) { + result.add(element); + iterator.remove(); + } + } + result.addAll(items); + + return result; + } + + private static void showInfo() { + if (StringUtil.isEmpty(CompletionService.getCompletionService().getAdvertisementText())) { + CompletionService.getCompletionService() + .setAdvertisementText(GroovyBundle.message("invoke.completion.second.time.to.show.skipped.methods")); + } } private static boolean checkForIterator(PsiMethod method) { @@ -545,11 +540,39 @@ public class GroovyCompletionContributor extends CompletionContributor { return InheritanceUtil.isInheritorOrSelf(containingClass, iterator, true); } - private static void showInfo() { - if (StringUtil.isEmpty(CompletionService.getCompletionService().getAdvertisementText())) { - CompletionService.getCompletionService() - .setAdvertisementText(GroovyBundle.message("invoke.completion.second.time.to.show.skipped.methods")); + + private static int assignPriority(LookupElement lookupElement, PsiType qualifierType) { + Object object = lookupElement.getObject(); + PsiSubstitutor substitutor = null; + GroovyResolveResult resolveResult = null; + if (object instanceof GroovyResolveResult) { + resolveResult = (GroovyResolveResult)object; + substitutor = resolveResult.getSubstitutor(); + object = ((GroovyResolveResult)object).getElement(); } + + // default groovy methods + if (object instanceof GrGdkMethod && + GroovyCompletionUtil.skipDefGroovyMethod((GrGdkMethod)object, substitutor, qualifierType)) { + return -1; + } + + // operator methods + if (object instanceof PsiMethod && + GroovyCompletionUtil.OPERATOR_METHOD_NAMES.contains(((PsiMethod)object).getName()) && !checkForIterator((PsiMethod)object)) { + return -3; + } + + // accessors if there is no get, set, is prefix + if (object instanceof PsiMethod && GroovyPropertyUtils.isSimplePropertyAccessor((PsiMethod)object)) { + return -1; + } + + // inaccessible elements + if (resolveResult != null && !resolveResult.isAccessible()) { + return -2; + } + return 0; } static StaticMemberProcessor completeStaticMembers(CompletionParameters parameters) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java index e9188299ceee..2ea9dd45cc24 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java @@ -446,7 +446,7 @@ public class GroovyCompletionUtil { public static final Set OPERATOR_METHOD_NAMES = CollectionFactory.newSet( "plus", "minus", "multiply", "power", "div", "mod", "or", "and", "xor", "next", "previous", "getAt", "putAt", "leftShift", "rightShift", - "isCase", "bitwiseNegate", "negative", "positive" + "isCase", "bitwiseNegate", "negative", "positive", "call" ); public static boolean skipDefGroovyMethod(GrGdkMethod gdkMethod, PsiSubstitutor substitutor, @Nullable PsiType type) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyNoVariantsDelegator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyNoVariantsDelegator.java index 957e080bd9f0..55a8f20a93e5 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyNoVariantsDelegator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyNoVariantsDelegator.java @@ -16,9 +16,21 @@ package org.jetbrains.plugins.groovy.lang.completion; import com.intellij.codeInsight.completion.*; +import com.intellij.codeInsight.completion.impl.CamelHumpMatcher; import com.intellij.codeInsight.lookup.AutoCompletionPolicy; import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiType; import com.intellij.util.Consumer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; + +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Set; /** * @author peter @@ -27,27 +39,114 @@ public class GroovyNoVariantsDelegator extends NoVariantsDelegator { @Override protected void delegate(CompletionParameters parameters, CompletionResultSet result, Consumer passResult) { - if (parameters.getCompletionType() == CompletionType.BASIC && - parameters.getInvocationCount() <= 1 && - JavaCompletionContributor.mayStartClassName(result, false) && - GroovyCompletionContributor.isClassNamePossible(parameters.getPosition()) && - !MapArgumentCompletionProvider.isMapKeyCompletion(parameters)) { - final ClassByNameMerger merger = new ClassByNameMerger(parameters.getInvocationCount() == 0, result); - - GroovyCompletionContributor.addAllClasses(parameters, result, - new Consumer() { - @Override - public void consume(LookupElement element) { - JavaPsiClassReferenceElement classElement = element.as(JavaPsiClassReferenceElement.CLASS_CONDITION_KEY); - if (classElement != null) { - classElement.setAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE); - } - merger.consume(classElement); - } - }, new InheritorsHolder(parameters.getPosition(), result)); - - merger.finishedClassProcessing(); + if (parameters.getCompletionType() == CompletionType.BASIC) { + if (parameters.getInvocationCount() <= 1 && + JavaCompletionContributor.mayStartClassName(result, false) && + GroovyCompletionContributor.isClassNamePossible(parameters.getPosition()) && + !MapArgumentCompletionProvider.isMapKeyCompletion(parameters)) { + suggestNonImportedClasses(parameters, result); + } + suggestChainedCalls(parameters, result); } } + + private static void suggestNonImportedClasses(CompletionParameters parameters, CompletionResultSet result) { + final ClassByNameMerger merger = new ClassByNameMerger(parameters.getInvocationCount() == 0, result); + + GroovyCompletionContributor.addAllClasses(parameters, new Consumer() { + @Override + public void consume(LookupElement element) { + JavaPsiClassReferenceElement classElement = + element.as(JavaPsiClassReferenceElement.CLASS_CONDITION_KEY); + if (classElement != null) { + classElement.setAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE); + } + merger.consume(classElement); + } + }, new InheritorsHolder(parameters.getPosition(), result), result.getPrefixMatcher()); + + merger.finishedClassProcessing(); + } + + private static void suggestChainedCalls(CompletionParameters parameters, CompletionResultSet result) { + PsiElement position = parameters.getPosition(); + PsiElement parent = position.getParent(); + if (!(parent instanceof GrReferenceElement)) { + return; + } + PsiElement qualifier = ((GrReferenceElement)parent).getQualifier(); + if (!(qualifier instanceof GrReferenceElement) || + ((GrReferenceElement)qualifier).getQualifier() != null || + ((GrReferenceElement)qualifier).resolve() != null) { + return; + } + + String fullPrefix = position.getContainingFile().getText().substring(parent.getTextRange().getStartOffset(), parameters.getOffset()); + final CompletionResultSet qualifiedCollector = result.withPrefixMatcher(fullPrefix); + InheritorsHolder inheritors = new InheritorsHolder(position, result); + for (final LookupElement base : suggestQualifierItems(parameters, (GrReferenceElement)qualifier, inheritors)) { + final PsiType type = JavaCompletionUtil.getLookupElementType(base); + if (type != null && !PsiType.VOID.equals(type)) { + GrReferenceElement ref = createMockReference(position, type, base); + PsiElement refName = ref.getReferenceNameElement(); + assert refName != null; + for (LookupElement element : GroovyCompletionContributor.completeReference( + parameters.withPosition(refName, refName.getTextRange().getStartOffset()), ref, inheritors, result.getPrefixMatcher())) { + qualifiedCollector.addElement(new JavaChainLookupElement(base, element) { + @Override + protected boolean shouldParenthesizeQualifier(PsiFile file, int startOffset, int endOffset) { + return false; + } + }); + } + } + } + } + + private static GrReferenceElement createMockReference(final PsiElement place, @NotNull PsiType qualifierType, LookupElement qualifierItem) { + GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(place.getProject()); + if (qualifierItem.getObject() instanceof PsiClass) { + return factory + .createReferenceExpressionFromText(((PsiClass)qualifierItem.getObject()).getQualifiedName() + ".xxx", place); + } + + return factory.createReferenceExpressionFromText("xxx.xxx", + ReferenceExpressionCompletionContributor + .createContextWithXxxVariable(place, qualifierType)); + } + + + private static Set suggestQualifierItems(CompletionParameters _parameters, + GrReferenceElement qualifier, + InheritorsHolder inheritors) { + CompletionParameters parameters = + _parameters.withPosition(qualifier.getReferenceNameElement(), qualifier.getTextRange().getEndOffset()); + String referenceName = qualifier.getReferenceName(); + if (referenceName == null) { + return Collections.emptySet(); + } + + final PrefixMatcher qMatcher = new CamelHumpMatcher(referenceName); + final Set variants = new LinkedHashSet(); + for (LookupElement element : GroovyCompletionContributor.completeReference(parameters, qualifier, inheritors, qMatcher)) { + if (qMatcher.prefixMatches(element)) { + variants.add(element); + } + } + + if (variants.isEmpty()) { + GroovyCompletionContributor.addAllClasses(parameters, new Consumer() { + @Override + public void consume(LookupElement element) { + if (qMatcher.prefixMatches(element)) { + variants.add(element); + } + } + }, inheritors, qMatcher); + } + return variants; + } + + } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyReferenceCharFilter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyReferenceCharFilter.java index 998d1ac5a3fb..185e62caa2c5 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyReferenceCharFilter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyReferenceCharFilter.java @@ -72,6 +72,9 @@ public class GroovyReferenceCharFilter extends CharFilter { if (c == '[') return CharFilter.Result.SELECT_ITEM_AND_FINISH_LOOKUP; if (c == '<' && item.getObject() instanceof PsiClass) return Result.SELECT_ITEM_AND_FINISH_LOOKUP; + if (c == '(' && PsiKeyword.RETURN.equals(item.getLookupString())) { + return Result.HIDE_LOOKUP; + } return null; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/smartEnter/fixers/GrMethodBodyFixer.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/smartEnter/fixers/GrMethodBodyFixer.java index 5af20679a58b..eddfea2a46d3 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/smartEnter/fixers/GrMethodBodyFixer.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/smartEnter/fixers/GrMethodBodyFixer.java @@ -15,16 +15,17 @@ */ package org.jetbrains.plugins.groovy.lang.completion.smartEnter.fixers; -import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.IncorrectOperationException; +import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiModifier; +import com.intellij.util.IncorrectOperationException; import org.jetbrains.plugins.groovy.lang.completion.smartEnter.GroovySmartEnterProcessor; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrCodeBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrCodeBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; /** * User: Dmitry.Krasilschikov @@ -34,13 +35,14 @@ public class GrMethodBodyFixer implements GrFixer { public void apply(Editor editor, GroovySmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException { if (!(psiElement instanceof GrMethod)) return; GrMethod method = (GrMethod) psiElement; - if (method.getContainingClass().isInterface() || method.hasModifierProperty(PsiModifier.ABSTRACT)) return; + final PsiClass aClass = method.getContainingClass(); + if (aClass != null && aClass.isInterface() || method.hasModifierProperty(PsiModifier.ABSTRACT)) return; final GrCodeBlock body = method.getBlock(); final Document doc = editor.getDocument(); if (body != null) { // See IDEADEV-1093. This is quite hacky heuristic but it seem to be best we can do. String bodyText = body.getText(); - if (bodyText.startsWith("{")) { + if (StringUtil.startsWithChar(bodyText, '{')) { final GrStatement[] statements = body.getStatements(); if (statements.length > 0) { // [todo] diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/smartEnter/processors/GroovyPlainEnterProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/smartEnter/processors/GroovyPlainEnterProcessor.java index 8ddab9bcce21..c8068ea98a05 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/smartEnter/processors/GroovyPlainEnterProcessor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/smartEnter/processors/GroovyPlainEnterProcessor.java @@ -15,14 +15,16 @@ */ package org.jetbrains.plugins.groovy.lang.completion.smartEnter.processors; -import com.intellij.psi.PsiElement; import com.intellij.codeInsight.editorActions.smartEnter.EnterProcessor; +import com.intellij.openapi.actionSystem.IdeActions; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.actionSystem.EditorActionManager; import com.intellij.openapi.editor.ex.EditorEx; -import com.intellij.openapi.actionSystem.IdeActions; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrCodeBlock; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.*; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrCodeBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; /** * User: Dmitry.Krasilschikov @@ -45,19 +47,30 @@ public class GroovyPlainEnterProcessor implements EnterProcessor { return true; } + @Nullable private static GrCodeBlock getControlStatementBlock(int caret, PsiElement element) { GrStatement body = null; + + if (element instanceof GrMethod) return ((GrMethod)element).getBlock(); + if (element instanceof GrIfStatement) { - body = ((GrIfStatement) element).getThenBranch(); - if (caret > body.getTextRange().getEndOffset()) { - body = ((GrIfStatement) element).getElseBranch(); + body = ((GrIfStatement)element).getThenBranch(); + if (body != null && caret > body.getTextRange().getEndOffset()) { + body = ((GrIfStatement)element).getElseBranch(); } - } else if (element instanceof GrWhileStatement) { - body = ((GrWhileStatement) element).getBody(); - } else if (element instanceof GrForStatement) { - body = ((GrForStatement) element).getBody(); + } + else if (element instanceof GrWhileStatement) { + body = ((GrWhileStatement)element).getBody(); + } + else if (element instanceof GrForStatement) { + body = ((GrForStatement)element).getBody(); } - return body instanceof GrBlockStatement ? ((GrBlockStatement) body).getBlock() : null; + if (body instanceof GrBlockStatement) { + return ((GrBlockStatement)body).getBlock(); + } + + + return null; } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyEditorActionUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyEditorActionUtil.java index 0af2055bc353..9cb94a190826 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyEditorActionUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyEditorActionUtil.java @@ -23,12 +23,13 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; -import com.intellij.psi.tree.TokenSet; import org.jetbrains.plugins.groovy.GroovyFileType; -import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrString; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mGSTRING_LITERAL; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mSTRING_LITERAL; + /** * @author ilyas */ @@ -66,7 +67,7 @@ public class GroovyEditorActionUtil { if (child != null && child.getNode() != null) { ASTNode node = child.getNode(); assert node != null; - return node.getElementType() == GroovyTokenTypes.mSTRING_LITERAL; + return node.getElementType() == mSTRING_LITERAL; } return false; } @@ -76,23 +77,8 @@ public class GroovyEditorActionUtil { if (child != null && child.getNode() != null) { ASTNode node = child.getNode(); assert node != null; - return node.getElementType() == GroovyTokenTypes.mGSTRING_LITERAL; + return node.getElementType() == mGSTRING_LITERAL; } return false; } - - public static TokenSet GSTRING_TOKENS = TokenSet.create( - GroovyTokenTypes.mGSTRING_BEGIN, - GroovyTokenTypes.mGSTRING_CONTENT, - GroovyTokenTypes.mGSTRING_END, - GroovyTokenTypes.mGSTRING_LITERAL, - GroovyTokenTypes.mDOLLAR - ); - - public static TokenSet GSTRING_TOKENS_INNER = TokenSet.create( - GroovyTokenTypes.mGSTRING_BEGIN, - GroovyTokenTypes.mGSTRING_CONTENT, - GroovyTokenTypes.mGSTRING_END, - GroovyTokenTypes.mDOLLAR - ); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyEnterHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyEnterHandler.java index 8e3748d4d660..d615a8774470 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyEnterHandler.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyEnterHandler.java @@ -33,28 +33,81 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; +import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.formatter.GeeseUtil; import org.jetbrains.plugins.groovy.formatter.GroovyCodeStyleSettings; import org.jetbrains.plugins.groovy.lang.editor.HandlerUtils; -import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; +import org.jetbrains.plugins.groovy.lang.lexer.GroovyLexer; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrStringInjection; -import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.*; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mCLOSABLE_BLOCK_OP; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mDOLLAR; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mDOLLAR_SLASH_REGEX_BEGIN; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mDOLLAR_SLASH_REGEX_CONTENT; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mDOLLAR_SLASH_REGEX_END; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mDOLLAR_SLASH_REGEX_LITERAL; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mGSTRING_BEGIN; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mGSTRING_CONTENT; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mGSTRING_END; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mGSTRING_LITERAL; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mIDENT; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mLBRACK; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mLCURLY; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mNLS; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mRBRACK; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mRCURLY; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mREGEX_BEGIN; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mREGEX_CONTENT; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mREGEX_END; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mREGEX_LITERAL; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mSTRING_LITERAL; +import static org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes.*; /** * @author ilyas */ public class GroovyEnterHandler extends EnterHandlerDelegateAdapter { + private static final TokenSet GSTRING_TOKENS = TokenSet.create(mGSTRING_BEGIN, mGSTRING_CONTENT, mGSTRING_END, mGSTRING_LITERAL); + + private static final TokenSet REGEX_TOKENS = TokenSet.create(mREGEX_BEGIN, mREGEX_CONTENT, mREGEX_END, mDOLLAR_SLASH_REGEX_BEGIN, + mDOLLAR_SLASH_REGEX_CONTENT, mDOLLAR_SLASH_REGEX_END); + + private static final TokenSet AFTER_DOLLAR = TokenSet.create(mLCURLY, mIDENT, mGSTRING_CONTENT, mDOLLAR, mGSTRING_END, mREGEX_CONTENT, + mDOLLAR_SLASH_REGEX_CONTENT, mREGEX_END, mDOLLAR_SLASH_REGEX_END); + + private static final TokenSet ALL_STRINGS = TokenSet.create(mSTRING_LITERAL, mGSTRING_LITERAL, mGSTRING_BEGIN, mGSTRING_END, + mGSTRING_CONTENT, mRCURLY, mIDENT, mDOLLAR, mREGEX_BEGIN, mREGEX_CONTENT, + mREGEX_END, mDOLLAR_SLASH_REGEX_BEGIN, mDOLLAR_SLASH_REGEX_CONTENT, + mDOLLAR_SLASH_REGEX_END, mREGEX_LITERAL, mDOLLAR_SLASH_REGEX_LITERAL); + + private static final TokenSet BEFORE_DOLLAR =TokenSet.create(mGSTRING_BEGIN, mGSTRING_CONTENT, mREGEX_BEGIN, mREGEX_CONTENT, + mDOLLAR_SLASH_REGEX_BEGIN, mDOLLAR_SLASH_REGEX_CONTENT); + + private static final TokenSet EXPR_END = TokenSet.create(mRCURLY, mIDENT); + + private static final TokenSet AFTER_EXPR_END = TokenSet.create(mGSTRING_END, mGSTRING_CONTENT, mDOLLAR, mREGEX_END, mREGEX_CONTENT, + mDOLLAR_SLASH_REGEX_END, mDOLLAR_SLASH_REGEX_CONTENT); + + private static final TokenSet STRING_END = TokenSet.create(mSTRING_LITERAL, mGSTRING_LITERAL, mGSTRING_END, mREGEX_END, + mDOLLAR_SLASH_REGEX_END, mREGEX_LITERAL, mDOLLAR_SLASH_REGEX_LITERAL); + + private static final TokenSet INNER_STRING_TOKENS = TokenSet.create(mGSTRING_BEGIN, mGSTRING_CONTENT, mGSTRING_END, mREGEX_BEGIN, + mREGEX_CONTENT, mREGEX_END, mDOLLAR_SLASH_REGEX_BEGIN, + mDOLLAR_SLASH_REGEX_CONTENT, mDOLLAR_SLASH_REGEX_END, + GSTRING_INJECTION); + + public Result preprocessEnter(@NotNull PsiFile file, @NotNull Editor editor, @NotNull Ref caretOffset, @@ -152,9 +205,7 @@ public class GroovyEnterHandler extends EnterHandlerDelegateAdapter { if (element == null || !GeeseUtil.isClosureRBrace(element)) return false; element = GeeseUtil.getNextNonWhitespaceToken(element); - if (element == null || - element.getNode().getElementType() != GroovyTokenTypes.mNLS || - StringUtil.countChars(element.getText(), '\n') > 1) { + if (element == null || element.getNode().getElementType() != mNLS || StringUtil.countChars(element.getText(), '\n') > 1) { return false; } @@ -204,25 +255,13 @@ public class GroovyEnterHandler extends EnterHandlerDelegateAdapter { return false; } - private static final TokenSet AFTER_DOLLAR = TokenSet.create(mLCURLY, mIDENT, mGSTRING_CONTENT, mDOLLAR, mGSTRING_END); - - private static final TokenSet ALL_STRINGS = - TokenSet.create(mSTRING_LITERAL, mGSTRING_LITERAL, mGSTRING_BEGIN, mGSTRING_END, mGSTRING_CONTENT, mRCURLY, mIDENT, mDOLLAR); - - private static final TokenSet BEFORE_DOLLAR = TokenSet.create(mGSTRING_BEGIN, mGSTRING_CONTENT); - - private static final TokenSet EXPR_END = TokenSet.create(mRCURLY, mIDENT); - - private static final TokenSet AFTER_EXPR_END = TokenSet.create(mGSTRING_END, mGSTRING_CONTENT, mDOLLAR); - - private static final TokenSet STRING_END = TokenSet.create(mSTRING_LITERAL, mGSTRING_LITERAL, mGSTRING_END); - - private static boolean handleInString(Editor editor, int caretOffset, DataContext dataContext, EditorActionHandler originalHandler) { Project project = PlatformDataKeys.PROJECT.getData(dataContext); if (project == null) return false; - PsiFile file = PsiManager.getInstance(project).findFile(FileDocumentManager.getInstance().getFile(editor.getDocument())); + final VirtualFile vfile = FileDocumentManager.getInstance().getFile(editor.getDocument()); + assert vfile != null; + PsiFile file = PsiManager.getInstance(project).findFile(vfile); Document document = editor.getDocument(); String fileText = document.getText(); @@ -237,30 +276,40 @@ public class GroovyEnterHandler extends EnterHandlerDelegateAdapter { ASTNode node = stringElement.getNode(); if (node == null) return false; - // For simple String literals like 'abcdef' - if (mSTRING_LITERAL == node.getElementType()) { - if (GroovyEditorActionUtil.isPlainStringLiteral(node)) { - TextRange literalRange = stringElement.getTextRange(); - document.insertString(literalRange.getEndOffset(), "''"); - document.insertString(literalRange.getStartOffset(), "''"); - editor.getCaretModel().moveToOffset(caretOffset + 2); - EditorModificationUtil.insertStringAtCaret(editor, "\n"); - } - else { - originalHandler.execute(editor, dataContext); - } - return true; - } - // For expression injection in GString like "abc ${} abc" - if (!GroovyEditorActionUtil.GSTRING_TOKENS.contains(node.getElementType()) && checkGStringInnerExpression(stringElement)) { + if (!INNER_STRING_TOKENS.contains(node.getElementType()) && checkGStringInjection(stringElement)) { stringElement = stringElement.getParent().getParent().getNextSibling(); if (stringElement == null) return false; node = stringElement.getNode(); if (node == null) return false; } - if (GroovyEditorActionUtil.GSTRING_TOKENS.contains(node.getElementType())) { + boolean isInsertIndent = isInsertIndent(caretOffset, stringElement.getTextRange().getStartOffset(), fileText); + + // For simple String literals like 'abcdef' + if (mSTRING_LITERAL == node.getElementType()) { + if (GroovyEditorActionUtil.isPlainStringLiteral(node)) { + TextRange literalRange = stringElement.getTextRange(); + + //the case of print '\' + if (fileText.charAt(caretOffset) == '\'' && caretOffset > 0 && fileText.charAt(caretOffset - 1) == '\\') { + convertEndToMultiline(caretOffset, document, fileText); + } + else { + convertEndToMultiline(literalRange.getEndOffset(), document, fileText); + } + document.insertString(literalRange.getStartOffset(), "''"); + editor.getCaretModel().moveToOffset(caretOffset + 2); + EditorModificationUtil.insertStringAtCaret(editor, "\n"); + } + else { + insertLineFeedInString(editor, dataContext, originalHandler, isInsertIndent); + } + return true; + } + + if (GSTRING_TOKENS.contains(node.getElementType()) || + node.getElementType() == mDOLLAR && node.getTreeParent().getTreeParent().getElementType() == GSTRING) { PsiElement parent = stringElement.getParent(); if (node.getElementType() == mGSTRING_LITERAL) { parent = stringElement; @@ -285,49 +334,98 @@ public class GroovyEnterHandler extends EnterHandlerDelegateAdapter { } } else { - originalHandler.execute(editor, dataContext); + insertLineFeedInString(editor, dataContext, originalHandler, isInsertIndent); } return true; } + + if (REGEX_TOKENS.contains(node.getElementType()) || + node.getElementType() == mDOLLAR && node.getTreeParent().getTreeParent().getElementType() == REGEX) { + PsiElement parent = stringElement.getParent(); + if (node.getElementType() == mREGEX_LITERAL || node.getElementType() == mDOLLAR_SLASH_REGEX_LITERAL) { + parent = stringElement; + } + else { + while (parent != null && !(parent instanceof GrLiteral)) { + parent = parent.getParent(); + } + } + if (parent == null || parent.getLastChild() instanceof PsiErrorElement) return false; + PsiElement exprSibling = stringElement.getNextSibling(); + boolean rightFromDollar = exprSibling instanceof GrExpression && exprSibling.getTextRange().getStartOffset() == caretOffset; + if (rightFromDollar) { + editor.getCaretModel().moveToOffset(caretOffset - 1); + } + insertLineFeedInString(editor, dataContext, originalHandler, isInsertIndent); + if (rightFromDollar) { + editor.getCaretModel().moveCaretRelatively(1, 0, false, false, true); + } + return true; + } + return false; } - private static boolean checkStringApplicable(Editor editor, int caret) { - final EditorHighlighter highlighter = ((EditorEx)editor).getHighlighter(); - HighlighterIterator iteratorLeft = highlighter.createIterator(caret - 1); - HighlighterIterator iteratorRight = highlighter.createIterator(caret); + private static void insertLineFeedInString(Editor editor, + DataContext dataContext, + EditorActionHandler originalHandler, + boolean isInsertIndent) { + if (isInsertIndent) { + originalHandler.execute(editor, dataContext); + } + else { + EditorModificationUtil.insertStringAtCaret(editor, "\n"); + } + } - if (iteratorLeft != null && !(ALL_STRINGS.contains(iteratorLeft.getTokenType()))) { + private static boolean isInsertIndent(int caret, int stringOffset, String text) { + final int i = text.indexOf('\n', stringOffset); + return stringOffset < i && i < caret; + } + + private static void convertEndToMultiline(int caretOffset, Document document, String fileText) { + if (caretOffset < fileText.length() && fileText.charAt(caretOffset) == '\'' || + caretOffset > 0 && fileText.charAt(caretOffset - 1) == '\'') { + document.insertString(caretOffset, "''"); + } + else { + document.insertString(caretOffset, "'''"); + } + } + + private static boolean checkStringApplicable(Editor editor, int caret) { + final GroovyLexer lexer = new GroovyLexer(); + lexer.start(editor.getDocument().getText()); + + while (lexer.getTokenEnd() < caret) { + lexer.advance(); + } + final IElementType leftToken = lexer.getTokenType(); + if (lexer.getTokenEnd() <= caret) lexer.advance(); + final IElementType rightToken = lexer.getTokenType(); + + if (!(ALL_STRINGS.contains(leftToken))) { return false; } - if (iteratorLeft != null && - BEFORE_DOLLAR.contains(iteratorLeft.getTokenType()) && - iteratorRight != null && - !AFTER_DOLLAR.contains(iteratorRight.getTokenType())) { + if (BEFORE_DOLLAR.contains(leftToken) && !AFTER_DOLLAR.contains(rightToken)) { return false; } - if (iteratorLeft != null && - EXPR_END.contains(iteratorLeft.getTokenType()) && - iteratorRight != null && - !AFTER_EXPR_END.contains(iteratorRight.getTokenType())) { + if (EXPR_END.contains(leftToken) && !AFTER_EXPR_END.contains(rightToken)) { return false; } - if (iteratorLeft != null && - STRING_END.contains(iteratorLeft.getTokenType()) && - iteratorRight != null && - !STRING_END.contains(iteratorRight.getTokenType())) { + if (STRING_END.contains(leftToken) && !STRING_END.contains(rightToken)) { return false; } return true; } - private static boolean checkGStringInnerExpression(PsiElement element) { + private static boolean checkGStringInjection(PsiElement element) { if (element != null && (element.getParent() instanceof GrReferenceExpression || element.getParent() instanceof GrClosableBlock)) { final PsiElement parent = element.getParent().getParent(); if (!(parent instanceof GrStringInjection)) return false; PsiElement nextSibling = parent.getNextSibling(); if (nextSibling == null) return false; - return GroovyEditorActionUtil.GSTRING_TOKENS_INNER.contains(nextSibling.getNode().getElementType()); + return INNER_STRING_TOKENS.contains(nextSibling.getNode().getElementType()); } return false; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/folding/GroovyFoldingBuilder.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/folding/GroovyFoldingBuilder.java index 38f77425389c..574c5c9d4e1b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/folding/GroovyFoldingBuilder.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/folding/GroovyFoldingBuilder.java @@ -18,7 +18,7 @@ package org.jetbrains.plugins.groovy.lang.folding; import com.intellij.codeInsight.folding.JavaCodeFoldingSettings; import com.intellij.lang.ASTNode; -import com.intellij.lang.folding.FoldingBuilder; +import com.intellij.lang.folding.CustomFoldingBuilder; import com.intellij.lang.folding.FoldingDescriptor; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.FoldingGroup; @@ -33,6 +33,7 @@ import com.intellij.psi.tree.IElementType; import com.intellij.util.containers.hash.HashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; @@ -43,23 +44,23 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefini import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement; import org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil; -import java.util.ArrayList; import java.util.List; import java.util.Set; /** * @author ilyas */ -public class GroovyFoldingBuilder implements FoldingBuilder, GroovyElementTypes, DumbAware { +public class GroovyFoldingBuilder extends CustomFoldingBuilder implements GroovyElementTypes, DumbAware { - @NotNull - public FoldingDescriptor[] buildFoldRegions(@NotNull ASTNode node, @NotNull Document document) { - List descriptors = new ArrayList(); - appendDescriptors(node.getPsi(), descriptors, new HashSet()); - return descriptors.toArray(new FoldingDescriptor[descriptors.size()]); + @Override + protected void buildLanguageFoldRegions(@NotNull List descriptors, + @NotNull PsiElement root, + @NotNull Document document, + boolean quick) { + appendDescriptors(root, descriptors, new HashSet()); } - private static void appendDescriptors(PsiElement element, List descriptors, Set usedComments) { + private void appendDescriptors(PsiElement element, List descriptors, Set usedComments) { ASTNode node = element.getNode(); if (node == null) return; IElementType type = node.getElementType(); @@ -70,13 +71,13 @@ public class GroovyFoldingBuilder implements FoldingBuilder, GroovyElementTypes, } } // comments - if ((type.equals(mML_COMMENT) || type.equals(GROOVY_DOC_COMMENT)) && + if (((type.equals(mML_COMMENT) && !isCustomRegionStart(node)) || type.equals(GROOVY_DOC_COMMENT)) && isMultiline(element) && isWellEndedComment(element)) { descriptors.add(new FoldingDescriptor(node, node.getTextRange())); } - if (type.equals(mSL_COMMENT) && !usedComments.contains(element)) { + if (type.equals(mSL_COMMENT) && !isCustomRegionStart(node) && !usedComments.contains(element)) { usedComments.add(element); PsiElement end = null; for (PsiElement current = element.getNextSibling(); current != null; current = current.getNextSibling()) { @@ -209,31 +210,13 @@ public class GroovyFoldingBuilder implements FoldingBuilder, GroovyElementTypes, return element.getText().endsWith("*/"); } - private static boolean isWellEndedString(PsiElement element) { - final String text = element.getText(); - - if (!text.endsWith("'''") && !text.endsWith("\"\"\"") && !text.endsWith("/") && !text.endsWith("/$")) return false; - - - final IElementType type = element.getNode().getElementType(); - if (TokenSets.STRING_LITERAL_SET.contains(type)) return true; - - final PsiElement lastChild = element.getLastChild(); - if (lastChild == null) return false; - - final IElementType lastType = lastChild.getNode().getElementType(); - if (type == GSTRING) return lastType == mGSTRING_END; - if (type == REGEX) return lastType == mREGEX_END || lastType == mDOLLAR_SLASH_REGEX_END; - - return false; - } - private static boolean isMultiline(PsiElement element) { String text = element.getText(); return text.contains("\n") || text.contains("\r") || text.contains("\r\n"); } - public String getPlaceholderText(@NotNull ASTNode node) { + @Override + protected String getLanguagePlaceholderText(@NotNull ASTNode node, @NotNull TextRange range) { final IElementType elemType = node.getElementType(); if (BLOCK_SET.contains(elemType) || elemType == CLOSABLE_BLOCK) { return "{...}"; @@ -255,7 +238,8 @@ public class GroovyFoldingBuilder implements FoldingBuilder, GroovyElementTypes, return null; } - public boolean isCollapsedByDefault(@NotNull ASTNode node) { + @Override + protected boolean isRegionCollapsedByDefault(@NotNull ASTNode node) { final JavaCodeFoldingSettings settings = JavaCodeFoldingSettings.getInstance(); if ( node.getElementType() == IMPORT_STATEMENT ){ return settings.isCollapseImports(); @@ -297,6 +281,17 @@ public class GroovyFoldingBuilder implements FoldingBuilder, GroovyElementTypes, node.getElementType().equals(GSTRING) || node.getElementType().equals(REGEX)) && isMultiline(node.getPsi()) && - isWellEndedString(node.getPsi()); + GrStringUtil.isWellEndedString(node.getPsi()); + } + + @Override + protected boolean isCustomFoldingCandidate(ASTNode node) { + return node.getElementType() == GroovyTokenTypes.mSL_COMMENT; + } + + @Override + protected boolean isCustomFoldingRoot(ASTNode node) { + IElementType nodeType = node.getElementType(); + return nodeType == GroovyElementTypes.CLASS_DEFINITION || nodeType == GroovyElementTypes.OPEN_BLOCK; } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java index 54bdbe6af25b..2c4a6af49cfb 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java @@ -25,7 +25,6 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.TypeConversionUtil; -import com.intellij.util.ArrayUtil; import com.intellij.util.Consumer; import com.intellij.util.containers.hash.HashSet; import org.jetbrains.annotations.NotNull; @@ -48,7 +47,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrRe import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; -import org.jetbrains.plugins.groovy.lang.psi.util.GrClassImplUtil; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ClosureMissingMethodContributor; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; @@ -88,7 +86,6 @@ public class CompleteReferenceExpression { private static void getVariantsImpl(PrefixMatcher matcher, GrReferenceExpression refExpr, CompleteReferenceProcessor processor) { GrExpression qualifier = refExpr.getQualifierExpression(); - getVariantsWithSameQualifier(matcher, qualifier, refExpr, processor); if (qualifier == null) { ResolveUtil.treeWalkUp(refExpr, processor, true); @@ -228,7 +225,8 @@ public class CompleteReferenceExpression { return; } } - getVariantsFromQualifierType(refExpr, processor, GrClassImplUtil.getGroovyObjectType(refExpr), project); + getVariantsFromQualifierType(refExpr, processor, + PsiType.getJavaLangObject(refExpr.getManager(), qualifier.getResolveScope()), project); } else if (qualifierType instanceof PsiIntersectionType) { for (PsiType conjunct : ((PsiIntersectionType)qualifierType).getConjuncts()) { @@ -256,20 +254,19 @@ public class CompleteReferenceExpression { } } - private static String[] getVariantsWithSameQualifier(PrefixMatcher matcher,GrExpression qualifier, GrReferenceExpression refExpr, CompleteReferenceProcessor processor) { - if (qualifier != null && qualifier.getType() != null) return ArrayUtil.EMPTY_STRING_ARRAY; + public static Set getVariantsWithSameQualifier(PrefixMatcher matcher, @Nullable GrExpression qualifier, GrReferenceExpression refExpr) { + if (qualifier != null && qualifier.getType() != null) return Collections.emptySet(); final PsiElement scope = PsiTreeUtil.getParentOfType(refExpr, GrMember.class, PsiFile.class); Set result = new LinkedHashSet(); - addVariantsWithSameQualifier(matcher, scope, refExpr, qualifier, result, processor); - return ArrayUtil.toStringArray(result); + addVariantsWithSameQualifier(matcher, scope, refExpr, qualifier, result); + return result; } private static void addVariantsWithSameQualifier(PrefixMatcher matcher, PsiElement element, GrReferenceExpression patternExpression, GrExpression patternQualifier, - Set result, - CompleteReferenceProcessor processor) { + Set result) { if (element instanceof GrReferenceExpression && element != patternExpression && !PsiUtil.isLValue((GroovyPsiElement)element)) { final GrReferenceExpression refExpr = (GrReferenceExpression)element; final String refName = refExpr.getReferenceName(); @@ -279,21 +276,19 @@ public class CompleteReferenceExpression { if (PsiEquivalenceUtil.areElementsEquivalent(hisQualifier, patternQualifier)) { if (refExpr.resolve() == null) { result.add(refName); - processor.consume(refName); } } } else if (hisQualifier == null && patternQualifier == null) { if (refExpr.resolve() == null) { result.add(refName); - processor.consume(refName); } } } } for (PsiElement child = element.getFirstChild(); child != null; child = child.getNextSibling()) { - addVariantsWithSameQualifier(matcher, child, patternExpression, patternQualifier, result, processor); + addVariantsWithSameQualifier(matcher, child, patternExpression, patternQualifier, result); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrStringUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrStringUtil.java index b340263d6b7e..edb3b8798b1f 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrStringUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrStringUtil.java @@ -8,6 +8,8 @@ import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; +import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; @@ -801,4 +803,23 @@ public class GrStringUtil { final IElementType elementType = literal.getFirstChild().getNode().getElementType(); return elementType == mREGEX_LITERAL || elementType == mDOLLAR_SLASH_REGEX_LITERAL; } + + public static boolean isWellEndedString(PsiElement element) { + final String text = element.getText(); + + if (!text.endsWith("'''") && !text.endsWith("\"\"\"") && !text.endsWith("/") && !text.endsWith("/$")) return false; + + + final IElementType type = element.getNode().getElementType(); + if (TokenSets.STRING_LITERAL_SET.contains(type)) return true; + + final PsiElement lastChild = element.getLastChild(); + if (lastChild == null) return false; + + final IElementType lastType = lastChild.getNode().getElementType(); + if (type == GroovyElementTypes.GSTRING) return lastType == mGSTRING_END; + if (type == GroovyElementTypes.REGEX) return lastType == mREGEX_END || lastType == mDOLLAR_SLASH_REGEX_END; + + return false; + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcFramework.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcFramework.java index d18ad53521ba..c92d5b61b675 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcFramework.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcFramework.java @@ -102,6 +102,10 @@ public abstract class MvcFramework { return module.getName().endsWith(getCommonPluginSuffix()); } + public List reorderModulesForMvcView(List modules) { + return modules; + } + public abstract String getApplicationDirectoryName(); public void syncSdkAndLibrariesInPluginsModule(@NotNull Module module) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/projectView/MvcProjectNode.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/projectView/MvcProjectNode.java index e43430267187..8159c2993e8a 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/projectView/MvcProjectNode.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/projectView/MvcProjectNode.java @@ -43,7 +43,10 @@ public class MvcProjectNode extends AbstractProjectNode { @NotNull public Collection getChildren() { - final List modules = MvcModuleStructureUtil.getAllModulesWithSupport(myProject, myDescriptor.getFramework()); + List modules = MvcModuleStructureUtil.getAllModulesWithSupport(myProject, myDescriptor.getFramework()); + + modules = myDescriptor.getFramework().reorderModulesForMvcView(modules); + final ArrayList nodes = new ArrayList(); for (Module module : modules) { nodes.add(new MvcModuleNode(module, getSettings(), myDescriptor)); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/spock/SpockMemberContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/spock/SpockMemberContributor.java index 3cad6a8569de..9061beb5ff0b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/spock/SpockMemberContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/spock/SpockMemberContributor.java @@ -8,6 +8,7 @@ import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; +import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightMethodBuilder; import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint; @@ -26,25 +27,33 @@ public class SpockMemberContributor extends NonCodeMembersContributor { GroovyPsiElement place, ResolveState state) { ClassHint classHint = processor.getHint(ClassHint.KEY); - if (classHint != null && !classHint.shouldProcess(ClassHint.ResolveKind.PROPERTY)) return; + if (classHint == null || classHint.shouldProcess(ClassHint.ResolveKind.PROPERTY)) { + GrMethod method = PsiTreeUtil.getParentOfType(place, GrMethod.class); + if (method == null) return; - GrMethod method = PsiTreeUtil.getParentOfType(place, GrMethod.class); - if (method == null) return; + if (aClass != method.getContainingClass()) return; - if (aClass != method.getContainingClass()) return; + Map cachedValue = SpockUtils.getVariableMap(method); - Map cachedValue = SpockUtils.getVariableMap(method); - - String nameHint = ResolveUtil.getNameHint(processor); - if (nameHint == null) { - for (SpockVariableDescriptor spockVar : cachedValue.values()) { - if (!processor.execute(spockVar.getVariable(), state)) return; + String nameHint = ResolveUtil.getNameHint(processor); + if (nameHint == null) { + for (SpockVariableDescriptor spockVar : cachedValue.values()) { + if (!processor.execute(spockVar.getVariable(), state)) return; + } + } + else { + SpockVariableDescriptor spockVar = cachedValue.get(nameHint); + if (spockVar != null && spockVar.getNavigationElement() != place) { + if (!processor.execute(spockVar.getVariable(), state)) return; + } } } - else { - SpockVariableDescriptor spockVar = cachedValue.get(nameHint); - if (spockVar != null && spockVar.getNavigationElement() != place) { - if (!processor.execute(spockVar.getVariable(), state)) return; + + if (classHint == null || classHint.shouldProcess(ClassHint.ResolveKind.METHOD)) { + if ("get_".equals(ResolveUtil.getNameHint(processor))) { + GrLightMethodBuilder m = new GrLightMethodBuilder(aClass.getManager(), "get_"); + m.setReturnType(null); + if (!processor.execute(m, state)) return; } } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GrCompletionWithLibraryTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GrCompletionWithLibraryTest.groovy index fbdb4e312da7..1c6f897345d6 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GrCompletionWithLibraryTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GrCompletionWithLibraryTest.groovy @@ -170,7 +170,67 @@ toString wait wait wait -with\ +with +getThisProp +setThisProp +getSuperProp +setSuperProp +addShutdownHook +any +any +asBoolean +asType +collect +collect +dump +each +eachWithIndex +every +every +find +findAll +findIndexOf +findIndexOf +findIndexValues +findIndexValues +findLastIndexOf +findLastIndexOf +getAt +getClass +getMetaClass +getMetaPropertyValues +getProperties +grep +hasPerInstanceMetaClass +hasProperty +identity +inject +inspect +is +isCase +iterator +metaClass +primitiveArrayGet +primitiveArrayGet +primitiveArrayGet +primitiveArrayPut +print +print +printf +printf +println +println +println +putAt +respondsTo +respondsTo +setMetaClass +split +sprintf +sprintf +use +use +use\ """.split('\n') } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy index 5cb4306414a9..e47e50a569e7 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy @@ -56,7 +56,7 @@ class GroovyAutoPopupTest extends CompletionAutoPopupTestCase { public void testNoLookupFocusOnUnresolvedQualifier() { myFixture.configureByText("a.groovy", """xxx.""") type 'h' //hashCode - assert !lookup.focused + assert !lookup } public void testNoLookupFocusOnUntypedQualifier() { @@ -65,7 +65,7 @@ class GroovyAutoPopupTest extends CompletionAutoPopupTestCase { xxx. }""") type 'h' - assert !lookup.focused + assert !lookup } public void testPossibleClosureParameter() { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy index 94794bebd83b..fe133175c2fb 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy @@ -891,16 +891,6 @@ class B extends A { checkCompletion "assex", ' ', 'assert x' } - public void testDontShowAccessors() { - assertNull doContainsTest("getFoo", """ -class MyClass { - def foo -} - -def a = new MyClass() -a.""") - } - public void testPreferInstanceof() { caseSensitiveNone() @@ -1072,7 +1062,7 @@ class X { } public void testSortOrder0() { - doVariantableTest 'se', 'setMetaClass', 'setProperty', 'setSe' + doVariantableTest 'se', 'setProperty', 'setMetaClass', 'setSe' } public void testPrimitiveCastOverwrite() { @@ -1118,9 +1108,29 @@ public class KeyVO { checkSingleItemCompletion 'class Foo impl {}', 'class Foo implements {}' } + public void testAmbiguousClassQualifier() { + myFixture.addClass("package foo; public class Util { public static void foo() {} }") + myFixture.addClass("package bar; public class Util { public static void bar() {} }") + myFixture.configureByText 'a.groovy', 'Util.' + myFixture.completeBasic() + assert myFixture.lookupElementStrings[0..1] == ['Util.bar', 'Util.foo'] + + def presentation = LookupElementPresentation.renderElement(myFixture.lookupElements[0]) + assert 'Util.bar' == presentation.itemText + assert '() (bar)' == presentation.tailText + assert !presentation.tailGrayed + + myFixture.type 'f\n' + myFixture.checkResult '''import foo.Util + +Util.foo()''' + } + public void testPreferInterfacesInImplements() { myFixture.addClass('interface FooIntf {}') myFixture.addClass('class FooClass {}') doVariantableTest('FooIntf', 'FooClass') } + + public void testPropertyChain() { doBasicTest() } } \ No newline at end of file diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/dsl/GroovyTransformationsTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/dsl/GroovyTransformationsTest.groovy index a46a38e51faa..0228220fa5ea 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/dsl/GroovyTransformationsTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/dsl/GroovyTransformationsTest.groovy @@ -50,7 +50,7 @@ class GroovyTransformationsTest extends LightCodeInsightFixtureTestCase { public void testVetoableTransform() throws Throwable { doPlainTest() } - public void testNewifyTransform1() throws Throwable { doVariantsTest('newInstance', 'new', 'new', 'newInstance') } + public void testNewifyTransform1() throws Throwable { doVariantsTest('newInstance', 'new', 'new', 'newInstance', 'negative', 'next') } public void testNewifyTransform2() throws Throwable { doVariantsTest('Leaf', 'Leaf', 'Leaf') } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/formatter/EnterActionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/formatter/EnterActionTest.groovy index 1de81cbf2f45..7403202ad786 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/formatter/EnterActionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/formatter/EnterActionTest.groovy @@ -69,6 +69,9 @@ public class EnterActionTest extends GroovyFormatterTestCase { public void testGstring11() throws Throwable { doTest(); } public void testGstring12() throws Throwable { doTest(); } public void testGstring13() throws Throwable { doTest(); } + public void testGstring14() throws Throwable { doTest(); } + public void testGstring15() throws Throwable { doTest(); } + public void testGstring16() throws Throwable { doTest(); } public void testGstring2() throws Throwable { doTest(); } public void testGstring3() throws Throwable { doTest(); } public void testGstring4() throws Throwable { doTest(); } @@ -78,6 +81,7 @@ public class EnterActionTest extends GroovyFormatterTestCase { public void testGstring8() throws Throwable { doTest(); } public void testGstring9() throws Throwable { doTest(); } public void testMultilineIndent() throws Throwable { doTest(); } + public void testMultilineIndent2() throws Throwable { doTest(); } public void testSpaces1() throws Throwable { doTest(); } public void testString1() throws Throwable { doTest(); } public void testString2() throws Throwable { doTest(); } @@ -85,6 +89,20 @@ public class EnterActionTest extends GroovyFormatterTestCase { public void testString4() throws Throwable { doTest(); } public void testString5() throws Throwable { doTest(); } public void testString6() throws Throwable { doTest(); } + public void testString7() throws Throwable { doTest(); } + public void testString8() throws Throwable { doTest(); } + public void testString9() throws Throwable { doTest(); } + public void testString10() throws Throwable { doTest(); } + public void testRegex1() {doTest()} + public void testRegex2() {doTest()} + public void testRegex3() {doTest()} + public void testRegex4() {doTest()} + public void testRegex5() {doTest()} + public void testRegex6() {doTest()} + public void testRegex7() {doTest()} + public void testRegex8() {doTest()} + public void testRegex9() {doTest()} + public void testRegex10() {doTest()} def doTest(String before, String after) { myFixture.configureByText("a.groovy", before) @@ -287,7 +305,6 @@ foo { } } ''' - } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/smartEnter/SmartEnterTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/smartEnter/SmartEnterTest.java index c0636a8c06b6..d7e9e97d4412 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/smartEnter/SmartEnterTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/smartEnter/SmartEnterTest.java @@ -1,6 +1,8 @@ package org.jetbrains.plugins.groovy.lang.smartEnter; import com.intellij.openapi.actionSystem.IdeActions; +import com.intellij.psi.codeStyle.CodeStyleSettingsManager; +import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; import org.jetbrains.plugins.groovy.GroovyFileType; import org.jetbrains.plugins.groovy.util.TestUtils; @@ -37,8 +39,12 @@ public class SmartEnterTest extends LightCodeInsightFixtureTestCase { public void testListFixer() throws Throwable {doTest();} public void testSwitchBraces() throws Throwable {doTest();} public void testCatchClause() throws Throwable {doTest();} + public void testMethodBodyAtNextLine() { + CodeStyleSettingsManager.getSettings(myFixture.getProject()).getCommonSettings(GroovyFileType.GROOVY_LANGUAGE).METHOD_BRACE_STYLE = CommonCodeStyleSettings.NEXT_LINE; + doTest(); + } - public void doTest() throws Exception { + public void doTest() { final List data = TestUtils.readInput(getTestDataPath() + getTestName(true) + ".test"); myFixture.configureByText(GroovyFileType.GROOVY_FILE_TYPE, data.get(0)); diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/spock/SpockTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/spock/SpockTest.groovy index af6500eb819d..526c9ba3825c 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/spock/SpockTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/spock/SpockTest.groovy @@ -7,6 +7,8 @@ import com.intellij.psi.PsiFile import com.intellij.psi.PsiVariable import com.intellij.psi.CommonClassNames +import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection +import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GroovyUnresolvedAccessInspection /** * @author Sergey Evdokimov @@ -198,5 +200,35 @@ class FooSpec extends spock.lang.Specification { assertEmpty("Some completion variants are missed", missedVariants); } + public void testVariable_resolved() { + myFixture.enableInspections(GroovyAssignabilityCheckInspection, GroovyUnresolvedAccessInspection) + + myFixture.configureByText("FooSpec.groovy", """ +class FooSpec extends spock.lang.Specification { + def "foo test"() { + String subscriber = Mock() + then: (0.._) * subscriber.concat(_) + subscriber.concat(asdasdasd) + subscriber.concat(23) + } +} +""") + + myFixture.checkHighlighting(true, false, true) + } + + public void testVariable_NotExistingInCompletion() { + myFixture.configureByText("FooSpec.groovy", """ +class FooSpec extends spock.lang.Specification { + def "foo test"() { + String subscriber = Mock() + then: (0.._) * subscriber.concat() + } +} +""") + myFixture.completeBasic() + def elements = myFixture.getLookupElementStrings() + assert !elements.contains("_") + } } diff --git a/plugins/groovy/testdata/groovy/actions/smartEnter/methodBodyAtNextLine.test b/plugins/groovy/testdata/groovy/actions/smartEnter/methodBodyAtNextLine.test new file mode 100644 index 000000000000..c2560671ba12 --- /dev/null +++ b/plugins/groovy/testdata/groovy/actions/smartEnter/methodBodyAtNextLine.test @@ -0,0 +1,6 @@ +def foo() +------ +def foo() +{ + +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/completion/PropertyChain.groovy b/plugins/groovy/testdata/groovy/completion/PropertyChain.groovy new file mode 100644 index 000000000000..cc24bcc939bc --- /dev/null +++ b/plugins/groovy/testdata/groovy/completion/PropertyChain.groovy @@ -0,0 +1,8 @@ +class A { + File myFile; + + def foo() { + myf.cap + } + +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/completion/PropertyChain_after.groovy b/plugins/groovy/testdata/groovy/completion/PropertyChain_after.groovy new file mode 100644 index 000000000000..84c0be7c409a --- /dev/null +++ b/plugins/groovy/testdata/groovy/completion/PropertyChain_after.groovy @@ -0,0 +1,8 @@ +class A { + File myFile; + + def foo() { + myFile.canonicalPath + } + +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/gstring14.test b/plugins/groovy/testdata/groovy/enterAction/gstring14.test new file mode 100644 index 000000000000..8a40d015ca8e --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/gstring14.test @@ -0,0 +1,4 @@ +"p\nreved $id medved" +----- +"""p +\nreved $id medved""" \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/gstring15.test b/plugins/groovy/testdata/groovy/enterAction/gstring15.test new file mode 100644 index 000000000000..7be49c36622a --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/gstring15.test @@ -0,0 +1,4 @@ +"p\nreved $id medved" +----- +"""p\ +nreved $id medved""" \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/gstring16.test b/plugins/groovy/testdata/groovy/enterAction/gstring16.test new file mode 100644 index 000000000000..077cf356371e --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/gstring16.test @@ -0,0 +1,4 @@ +"p\nreved $id medved" +----- +"""p\n +reved $id medved""" \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/multilineIndent2.test b/plugins/groovy/testdata/groovy/enterAction/multilineIndent2.test new file mode 100644 index 000000000000..e4504d8a5828 --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/multilineIndent2.test @@ -0,0 +1,16 @@ +def foo() { + ''' +class Foo { + void foo() {} +} +''' +} +----- +def foo() { + ''' + +class Foo { + void foo() {} +} +''' +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/regex1.test b/plugins/groovy/testdata/groovy/enterAction/regex1.test new file mode 100644 index 000000000000..ce149fef825a --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/regex1.test @@ -0,0 +1,8 @@ +cl { + /abc/ +} +----- +cl { + /a +bc/ +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/regex10.test b/plugins/groovy/testdata/groovy/enterAction/regex10.test new file mode 100644 index 000000000000..20bd1f184d11 --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/regex10.test @@ -0,0 +1,8 @@ +cl { + $/a${}bc/$ +} +----- +cl { + $/a +${}bc/$ +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/regex2.test b/plugins/groovy/testdata/groovy/enterAction/regex2.test new file mode 100644 index 000000000000..582ae04d4943 --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/regex2.test @@ -0,0 +1,10 @@ +cl { + /a + bbc/ +} +----- +cl { + /a + b + bc/ +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/regex3.test b/plugins/groovy/testdata/groovy/enterAction/regex3.test new file mode 100644 index 000000000000..8229dff4652c --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/regex3.test @@ -0,0 +1,8 @@ +cl { + /a${}bc/ +} +----- +cl { + /a${} +bc/ +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/regex4.test b/plugins/groovy/testdata/groovy/enterAction/regex4.test new file mode 100644 index 000000000000..639854265834 --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/regex4.test @@ -0,0 +1,8 @@ +cl { + /a${}bc/ +} +----- +cl { + /a +${}bc/ +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/regex5.test b/plugins/groovy/testdata/groovy/enterAction/regex5.test new file mode 100644 index 000000000000..858a5220a76c --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/regex5.test @@ -0,0 +1,8 @@ +cl { + /a${}bc/ +} +----- +cl { + /a +${}bc/ +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/regex6.test b/plugins/groovy/testdata/groovy/enterAction/regex6.test new file mode 100644 index 000000000000..cc1d0448e268 --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/regex6.test @@ -0,0 +1,8 @@ +cl { + $/abc/$ +} +----- +cl { + $/a +bc/$ +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/regex7.test b/plugins/groovy/testdata/groovy/enterAction/regex7.test new file mode 100644 index 000000000000..5697e7e7a742 --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/regex7.test @@ -0,0 +1,10 @@ +cl { + $/a + bbc/$ +} +----- +cl { + $/a + b + bc/$ +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/regex8.test b/plugins/groovy/testdata/groovy/enterAction/regex8.test new file mode 100644 index 000000000000..5b2bfc9de036 --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/regex8.test @@ -0,0 +1,8 @@ +cl { + $/a${}bc/$ +} +----- +cl { + $/a${} +bc/$ +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/regex9.test b/plugins/groovy/testdata/groovy/enterAction/regex9.test new file mode 100644 index 000000000000..7c61b1a3a30f --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/regex9.test @@ -0,0 +1,8 @@ +cl { + $/a${}bc/$ +} +----- +cl { + $/a +${}bc/$ +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/string10.test b/plugins/groovy/testdata/groovy/enterAction/string10.test new file mode 100644 index 000000000000..62ac00930273 --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/string10.test @@ -0,0 +1,8 @@ +def cl = { + print ('foo\n') +} +----- +def cl = { + print ('''foo +\n''') +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/string7.test b/plugins/groovy/testdata/groovy/enterAction/string7.test new file mode 100644 index 000000000000..ef77526f024f --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/string7.test @@ -0,0 +1,8 @@ +def cl = { + print ('foo\') +} +----- +def cl = { + print ('''foo\ +''') +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/string8.test b/plugins/groovy/testdata/groovy/enterAction/string8.test new file mode 100644 index 000000000000..6ba93cb02352 --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/string8.test @@ -0,0 +1,8 @@ +def cl = { + print ('foo\') +} +----- +def cl = { + print ('''foo +\')''' +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/string9.test b/plugins/groovy/testdata/groovy/enterAction/string9.test new file mode 100644 index 000000000000..cd1288e6a2c0 --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/string9.test @@ -0,0 +1,8 @@ +def cl = { + print ('foo\n') +} +----- +def cl = { + print ('''foo\ +n''') +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/oldCompletion/reference/tupleObjCompl.test b/plugins/groovy/testdata/groovy/oldCompletion/reference/tupleObjCompl.test index dc46468034b5..3da80cb6eb56 100644 --- a/plugins/groovy/testdata/groovy/oldCompletion/reference/tupleObjCompl.test +++ b/plugins/groovy/testdata/groovy/oldCompletion/reference/tupleObjCompl.test @@ -1,4 +1,3 @@ def (street, home, postCode) def s = street.toS ------ -toString \ No newline at end of file +----- \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/oldCompletion/reference/untyped.test b/plugins/groovy/testdata/groovy/oldCompletion/reference/untyped.test index 62a56f8f57b3..369b6e64961c 100644 --- a/plugins/groovy/testdata/groovy/oldCompletion/reference/untyped.test +++ b/plugins/groovy/testdata/groovy/oldCompletion/reference/untyped.test @@ -1,3 +1,2 @@ unknown.metaCl ------ -metaClass \ No newline at end of file +----- \ No newline at end of file diff --git a/plugins/groovy/testdata/highlighting/GloballyUnusedSymbols.groovy b/plugins/groovy/testdata/highlighting/GloballyUnusedSymbols.groovy index 06a58af451d1..210f013905b7 100644 --- a/plugins/groovy/testdata/highlighting/GloballyUnusedSymbols.groovy +++ b/plugins/groovy/testdata/highlighting/GloballyUnusedSymbols.groovy @@ -9,6 +9,9 @@ class BarUnused> { Bar usedMethod() { this } Object getAt(int key) {} + Object call() {} + Object call(String param) {} + Bar getUsedPropertyGetter() {} public static void main(String[] args) { usedPrivately() } diff --git a/plugins/junit/src/com/intellij/execution/junit2/info/PsiClassLocator.java b/plugins/junit/src/com/intellij/execution/junit2/info/PsiClassLocator.java index 2e140a29dc6f..2be74bcef64c 100644 --- a/plugins/junit/src/com/intellij/execution/junit2/info/PsiClassLocator.java +++ b/plugins/junit/src/com/intellij/execution/junit2/info/PsiClassLocator.java @@ -35,7 +35,7 @@ public class PsiClassLocator implements PsiLocator { public static PsiClassLocator fromQualifiedName(final String name) { final int lastDot = name.lastIndexOf('.'); - if (lastDot == -1 || lastDot == name.length()) + if (lastDot == -1 || lastDot == name.length() || (name.endsWith("]") && name.contains("["))) return new PsiClassLocator(name, ""); else return new PsiClassLocator(name.substring(lastDot + 1), name.substring(0, lastDot)); diff --git a/plugins/junit_rt/src/com/intellij/junit4/JUnit46ClassesRequestBuilder.java b/plugins/junit_rt/src/com/intellij/junit4/JUnit46ClassesRequestBuilder.java index 4dfe3ac733fa..697620d242e1 100644 --- a/plugins/junit_rt/src/com/intellij/junit4/JUnit46ClassesRequestBuilder.java +++ b/plugins/junit_rt/src/com/intellij/junit4/JUnit46ClassesRequestBuilder.java @@ -25,12 +25,17 @@ import org.junit.runner.Request; import org.junit.runner.Runner; import org.junit.runners.model.InitializationError; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + public class JUnit46ClassesRequestBuilder { private JUnit46ClassesRequestBuilder() {} - public static Request getClassesRequest(final String suiteName, Class[] classes) { + public static Request getClassesRequest(final String suiteName, Class[] classes, Map classMethods) { + boolean canUseSuiteMethod = canUseSuiteMethod(classMethods); try { - final AllDefaultPossibilitiesBuilder builder = new AllDefaultPossibilitiesBuilder(true); + final AllDefaultPossibilitiesBuilder builder = new AllDefaultPossibilitiesBuilder(canUseSuiteMethod); final Runner suite = new IdeaSuite(builder, classes, suiteName); return Request.runner(suite); } @@ -39,4 +44,20 @@ public class JUnit46ClassesRequestBuilder { } } + private static boolean canUseSuiteMethod(Map classMethods) { + for (Iterator iterator = classMethods.keySet().iterator(); iterator.hasNext(); ) { + Object className = iterator.next(); + Set methods = (Set) classMethods.get(className); + if (methods == null) { + return true; + } + for (Iterator iterator1 = methods.iterator(); iterator1.hasNext(); ) { + String methodName = (String)iterator1.next(); + if ("suite".equals(methodName)) { + return true; + } + } + } + return classMethods.isEmpty(); + } } \ No newline at end of file diff --git a/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestResultsSender.java b/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestResultsSender.java index c427e578a122..bfb590a18a02 100644 --- a/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestResultsSender.java +++ b/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestResultsSender.java @@ -99,10 +99,10 @@ public class JUnit4TestResultsSender extends RunListener { Matcher matcher = Pattern.compile("\nExpected: (.*)\n\\s*got: (.*)", Pattern.DOTALL).matcher(message); if (!matcher.matches()) { - matcher = Pattern.compile("expected same:<(.*)> was not:<(.*)>", Pattern.DOTALL).matcher(message); + matcher = Pattern.compile("\\s*expected same:<(.*)> was not:<(.*)>", Pattern.DOTALL).matcher(message); } if (!matcher.matches()) { - matcher = Pattern.compile("expected:<(.*)> but was:<(.*)>", Pattern.DOTALL).matcher(message); + matcher = Pattern.compile("\\s*expected:<(.*)> but was:<(.*)>", Pattern.DOTALL).matcher(message); } if (!matcher.matches()) { matcher = Pattern.compile("\nExpected: \"(.*)\"\n\\s*but: was \"(.*)\"", Pattern.DOTALL).matcher(message); diff --git a/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestRunnerUtil.java b/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestRunnerUtil.java index 864e51a87373..fc75268f3598 100644 --- a/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestRunnerUtil.java +++ b/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestRunnerUtil.java @@ -79,7 +79,7 @@ public class JUnit4TestRunnerUtil { Request allClasses; try { Class.forName("org.junit.runner.Computer"); - allClasses = JUnit46ClassesRequestBuilder.getClassesRequest(suiteName, classes); + allClasses = JUnit46ClassesRequestBuilder.getClassesRequest(suiteName, classes, classMethods); } catch (ClassNotFoundException e) { allClasses = getClassRequestsUsing44API(suiteName, classes); diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java index f6dbfa657089..767438724e2a 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java @@ -891,7 +891,7 @@ public class MavenProject { volatile List myUnresolvedPluginsCache; volatile List myUnresolvedExtensionsCache; - ConcurrentHashMap myCache = new ConcurrentHashMap(); + transient ConcurrentHashMap myCache = new ConcurrentHashMap(); @Override public State clone() { @@ -940,5 +940,10 @@ public class MavenProject { return result; } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + myCache = new ConcurrentHashMap(); + } } } diff --git a/plugins/properties/src/com/intellij/psi/impl/cache/impl/idCache/PropertiesIdIndexer.java b/plugins/properties/src/com/intellij/psi/impl/cache/impl/idCache/PropertiesIdIndexer.java index 112c77d3a7fc..4224983fc769 100644 --- a/plugins/properties/src/com/intellij/psi/impl/cache/impl/idCache/PropertiesIdIndexer.java +++ b/plugins/properties/src/com/intellij/psi/impl/cache/impl/idCache/PropertiesIdIndexer.java @@ -16,26 +16,19 @@ package com.intellij.psi.impl.cache.impl.idCache; import com.intellij.lang.properties.parsing.PropertiesLexer; -import com.intellij.lexer.FilterLexer; import com.intellij.lexer.Lexer; -import com.intellij.psi.TokenType; import com.intellij.psi.impl.cache.impl.OccurrenceConsumer; import com.intellij.psi.impl.cache.impl.id.LexerBasedIdIndexer; -import com.intellij.psi.tree.TokenSet; /** * @author Maxim.Mossienko */ public class PropertiesIdIndexer extends LexerBasedIdIndexer { - private static TokenSet WHITE_SPACE_SET = TokenSet.create(TokenType.WHITE_SPACE); - public Lexer createLexer(final OccurrenceConsumer consumer) { return createIndexingLexer(consumer); } static Lexer createIndexingLexer(OccurrenceConsumer consumer) { - final PropertiesFilterLexer propsLexer = - new PropertiesFilterLexer(new PropertiesLexer(), consumer); - return new FilterLexer(propsLexer, new FilterLexer.SetFilter(WHITE_SPACE_SET)); + return new PropertiesFilterLexer(new PropertiesLexer(), consumer); } } diff --git a/plugins/spellchecker/src/META-INF/SpellCheckerPlugin.xml b/plugins/spellchecker/src/META-INF/SpellCheckerPlugin.xml index 7f4abf63d633..5a4a66dfba5f 100644 --- a/plugins/spellchecker/src/META-INF/SpellCheckerPlugin.xml +++ b/plugins/spellchecker/src/META-INF/SpellCheckerPlugin.xml @@ -28,7 +28,7 @@ key="spellchecking.inspection.name" groupKey="spelling" enabledByDefault="true" level="TYPO" implementationClass="com.intellij.spellchecker.inspections.SpellCheckingInspection"/> - + diff --git a/plugins/spellchecker/src/com/intellij/spellchecker/quickfixes/DictionarySuggestionProvider.java b/plugins/spellchecker/src/com/intellij/spellchecker/quickfixes/DictionarySuggestionProvider.java index 08978686773c..c0d1551251fd 100644 --- a/plugins/spellchecker/src/com/intellij/spellchecker/quickfixes/DictionarySuggestionProvider.java +++ b/plugins/spellchecker/src/com/intellij/spellchecker/quickfixes/DictionarySuggestionProvider.java @@ -18,14 +18,14 @@ package com.intellij.spellchecker.quickfixes; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiNamedElement; import com.intellij.psi.codeStyle.SuggestedNameInfo; -import com.intellij.refactoring.rename.NameSuggestionProvider; +import com.intellij.refactoring.rename.PreferrableNameSuggestionProvider; import com.intellij.spellchecker.SpellCheckerManager; import java.util.Set; import java.util.TreeSet; -public class DictionarySuggestionProvider implements NameSuggestionProvider { +public class DictionarySuggestionProvider extends PreferrableNameSuggestionProvider { private boolean active; @@ -33,6 +33,11 @@ public class DictionarySuggestionProvider implements NameSuggestionProvider { this.active = active; } + @Override + public boolean shouldCheckOthers() { + return !active; + } + public SuggestedNameInfo getSuggestedNames(PsiElement element, PsiElement nameSuggestionContext, Set result) { assert result != null; if (!active || nameSuggestionContext==null) { diff --git a/plugins/svn4idea/lib/svnkit-javahl.jar b/plugins/svn4idea/lib/svnkit-javahl.jar index 01ecf37bb43c..d7eb592d28f6 100644 Binary files a/plugins/svn4idea/lib/svnkit-javahl.jar and b/plugins/svn4idea/lib/svnkit-javahl.jar differ diff --git a/plugins/svn4idea/lib/svnkit-javahl16.zip b/plugins/svn4idea/lib/svnkit-javahl16.zip index fbe729c06c7e..00c4886fd4f6 100644 Binary files a/plugins/svn4idea/lib/svnkit-javahl16.zip and b/plugins/svn4idea/lib/svnkit-javahl16.zip differ diff --git a/plugins/svn4idea/lib/svnkit.jar b/plugins/svn4idea/lib/svnkit.jar index 37d118155a25..0087d15e25dd 100644 Binary files a/plugins/svn4idea/lib/svnkit.jar and b/plugins/svn4idea/lib/svnkit.jar differ diff --git a/plugins/svn4idea/lib/svnkitsrc.zip b/plugins/svn4idea/lib/svnkitsrc.zip index 0d48d754443e..1bc2a1918888 100644 Binary files a/plugins/svn4idea/lib/svnkitsrc.zip and b/plugins/svn4idea/lib/svnkitsrc.zip differ diff --git a/plugins/svn4idea/src/META-INF/plugin.xml b/plugins/svn4idea/src/META-INF/plugin.xml index 64653a3b78f4..5d762cdd1cc5 100644 --- a/plugins/svn4idea/src/META-INF/plugin.xml +++ b/plugins/svn4idea/src/META-INF/plugin.xml @@ -3,7 +3,7 @@ Subversion 1.7 1.0.1 VCS Integration - + Version 1.0.1 - Added an option for a status operation to be executed with command line client. (for performance reasons) This plugin provides only basic support for Subversion 1.7. Some operations are not implemented. diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn17/ProxySvnAuthentication.java b/plugins/svn4idea/src/org/jetbrains/idea/svn17/ProxySvnAuthentication.java index 74b0a9e3bf31..25d49e231fa4 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn17/ProxySvnAuthentication.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn17/ProxySvnAuthentication.java @@ -26,9 +26,15 @@ public class ProxySvnAuthentication { private ProxySvnAuthentication() { } - public static SVNAuthentication proxy(final SVNAuthentication in, final boolean storeAuth) { - if (in.isStorageAllowed() == storeAuth || (! in.isStorageAllowed())) return in; + public static SVNAuthentication proxy(final SVNAuthentication in, final boolean storeAuth, boolean forceSaving) { + if (forceSaving && storeAuth) { + return putPassedValueAsSave(in, forceSaving); + } + if (in.isStorageAllowed() == storeAuth || ( ! in.isStorageAllowed())) return in; + return putPassedValueAsSave(in, storeAuth); + } + private static SVNAuthentication putPassedValueAsSave(SVNAuthentication in, boolean storeAuth) { final String userName = in.getUserName(); if (in instanceof SVNPasswordAuthentication) { return new SVNPasswordAuthentication(userName, ((SVNPasswordAuthentication)in).getPassword(), diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn17/RootsToWorkingCopies.java b/plugins/svn4idea/src/org/jetbrains/idea/svn17/RootsToWorkingCopies.java index 6282ab342321..3a2ccdb3677d 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn17/RootsToWorkingCopies.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn17/RootsToWorkingCopies.java @@ -73,6 +73,7 @@ public class RootsToWorkingCopies implements VcsListener { @CalledInBackground public WorkingCopy getMatchingCopy(final SVNURL url) { assert ! ApplicationManager.getApplication().isDispatchThread(); + if (url == null) return null; final VirtualFile[] roots = ProjectLevelVcsManager.getInstance(myProject).getRootsUnderVcs(SvnVcs17.getInstance(myProject)); synchronized (myLock) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn17/SvnAuthenticationManager.java b/plugins/svn4idea/src/org/jetbrains/idea/svn17/SvnAuthenticationManager.java index f14dc7d2c1d0..71d7bd24a02d 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn17/SvnAuthenticationManager.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn17/SvnAuthenticationManager.java @@ -18,6 +18,7 @@ package org.jetbrains.idea.svn17; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; @@ -67,6 +68,7 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im private IdeaSVNHostOptionsProvider myLocalHostOptionsProvider; private final ThreadLocalSavePermissions mySavePermissions; private final Map myKeyAlgorithm; + private boolean myArtificialSaving; public SvnAuthenticationManager(final Project project, final File configDirectory) { super(configDirectory, true, null, null); @@ -82,6 +84,10 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im myInteraction = new MySvnAuthenticationInteraction(myProject); } + public void setArtificialSaving(boolean artificialSaving) { + myArtificialSaving = artificialSaving; + } + private void ensureListenerCreated() { if (myListener == null) { myListener = EventDispatcher.create(SvnAuthenticationListener.class); @@ -115,6 +121,11 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im myListener.getMulticaster().saveAttemptFinished(type, url, realm, kind); } + @Override + public void acknowledge(boolean accepted, String kind, String realm, SVNErrorMessage message, SVNAuthentication authentication) { + myListener.getMulticaster().acknowledge(accepted, kind, realm, message, authentication); + } + @Override public void requested(ProviderType type, SVNURL url, String realm, String kind, boolean canceled) { if (ProviderType.interactive.equals(type) && (! canceled)) { @@ -137,12 +148,18 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im String realm, SVNErrorMessage errorMessage, SVNAuthentication authentication) throws SVNException { + boolean successSaving = false; + myListener.getMulticaster().acknowledge(accepted, kind, realm, errorMessage, authentication); try { final boolean authStorageEnabled = getHostOptionsProvider().getHostOptions(authentication.getURL()).isAuthStorageEnabled(); - final SVNAuthentication proxy = ProxySvnAuthentication.proxy(authentication, authStorageEnabled); + final SVNAuthentication proxy = ProxySvnAuthentication.proxy(authentication, authStorageEnabled, myArtificialSaving); super.acknowledgeAuthentication(accepted, kind, realm, errorMessage, proxy); + successSaving = true; } finally { mySavePermissions.remove(); + if (myArtificialSaving) { + throw new CredentialsSavedException(successSaving); + } } } @@ -229,11 +246,10 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im public void saveAuthentication(final SVNAuthentication auth, final String kind, final String realm) throws SVNException { final Boolean fromInteractive = ourJustEntered.get(); ourJustEntered.set(null); - if (! Boolean.TRUE.equals(fromInteractive)) { + if (! myArtificialSaving && ! Boolean.TRUE.equals(fromInteractive)) { // not what user entered return; } - myListener.getMulticaster().saveAttemptStarted(ProviderType.persistent, auth.getURL(), realm, auth.getKind()); ((ISVNPersistentAuthenticationProvider) myDelegate).saveAuthentication(auth, kind, realm); myListener.getMulticaster().saveAttemptFinished(ProviderType.persistent, auth.getURL(), realm, auth.getKind()); @@ -822,4 +838,16 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im return s[0]; } } + + public static class CredentialsSavedException extends RuntimeException { + private final boolean mySuccess; + + public CredentialsSavedException(boolean success) { + mySuccess = success; + } + + public boolean isSuccess() { + return mySuccess; + } + } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn17/SvnAuthenticationNotifier.java b/plugins/svn4idea/src/org/jetbrains/idea/svn17/SvnAuthenticationNotifier.java index a494e24a237b..ffc2d4002b47 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn17/SvnAuthenticationNotifier.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn17/SvnAuthenticationNotifier.java @@ -178,7 +178,7 @@ public class SvnAuthenticationNotifier extends GenericNotifierImpl { return myOptions; } + public static SvnAuthenticationManager createForTmpDir(final Project project, final File dir) { + final SvnVcs17 vcs = SvnVcs17.getInstance(project); + //final SvnAuthenticationManager manager = new SvnAuthenticationManager(project, dir); + + final SvnAuthenticationManager interactive = new SvnAuthenticationManager(project, dir); + interactive.setRuntimeStorage(RUNTIME_AUTH_CACHE); + final SvnInteractiveAuthenticationProvider interactiveProvider = new SvnInteractiveAuthenticationProvider(vcs, interactive); + interactive.setAuthenticationProvider(interactiveProvider); + + //manager.setAuthenticationProvider(new SvnAuthenticationProvider(vcs, interactiveProvider, RUNTIME_AUTH_CACHE)); + //manager.setRuntimeStorage(RUNTIME_AUTH_CACHE); + return interactive; + } + public SvnAuthenticationManager getAuthenticationManager(final SvnVcs17 svnVcs) { if (myAuthManager == null) { // reloaded when configuration directory changes diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn17/actions/MarkResolvedAction.java b/plugins/svn4idea/src/org/jetbrains/idea/svn17/actions/MarkResolvedAction.java index a8fb65a03d36..14c7e6ccd36a 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn17/actions/MarkResolvedAction.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn17/actions/MarkResolvedAction.java @@ -33,6 +33,7 @@ import org.jetbrains.idea.svn17.SvnBundle; import org.jetbrains.idea.svn17.SvnStatusUtil; import org.jetbrains.idea.svn17.SvnVcs17; import org.jetbrains.idea.svn17.dialogs.SelectFilesDialog; +import org.tmatesoft.svn.core.SVNDepth; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.wc.*; @@ -90,7 +91,7 @@ public class MarkResolvedAction extends BasicAction { SVNWCClient wcClient = vcs.createWCClient(); for (String path : pathsArray) { File ioFile = new File(path); - wcClient.doResolve(ioFile, false); + wcClient.doResolve(ioFile, SVNDepth.EMPTY, SVNConflictChoice.MERGED); } } catch (SVNException e) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn17/auth/SvnAuthenticationInteraction.java b/plugins/svn4idea/src/org/jetbrains/idea/svn17/auth/SvnAuthenticationInteraction.java index 568a72ff41d9..2d43bddd06a8 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn17/auth/SvnAuthenticationInteraction.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn17/auth/SvnAuthenticationInteraction.java @@ -15,7 +15,9 @@ */ package org.jetbrains.idea.svn17.auth; +import org.tmatesoft.svn.core.SVNErrorMessage; import org.tmatesoft.svn.core.SVNURL; +import org.tmatesoft.svn.core.auth.SVNAuthentication; import java.io.File; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn17/auth/SvnAuthenticationListener.java b/plugins/svn4idea/src/org/jetbrains/idea/svn17/auth/SvnAuthenticationListener.java index dc556ec452e1..7f3558494b91 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn17/auth/SvnAuthenticationListener.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn17/auth/SvnAuthenticationListener.java @@ -15,7 +15,9 @@ */ package org.jetbrains.idea.svn17.auth; +import org.tmatesoft.svn.core.SVNErrorMessage; import org.tmatesoft.svn.core.SVNURL; +import org.tmatesoft.svn.core.auth.SVNAuthentication; import java.util.EventListener; @@ -24,4 +26,5 @@ public interface SvnAuthenticationListener extends EventListener { void actualSaveWillBeTried(final ProviderType type, final SVNURL url, String realm, String kind); void saveAttemptStarted(final ProviderType type, final SVNURL url, String realm, String kind); void saveAttemptFinished(final ProviderType type, final SVNURL url, String realm, String kind); + void acknowledge(boolean accepted, String kind, String realm, SVNErrorMessage message, SVNAuthentication authentication); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/CommandLineAuthenticator.java b/plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/CommandLineAuthenticator.java new file mode 100644 index 000000000000..1cffdfb64c79 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/CommandLineAuthenticator.java @@ -0,0 +1,200 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.idea.svn17.commandLine; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.MessageType; +import com.intellij.openapi.util.Trinity; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier; +import org.jetbrains.idea.svn17.SvnAuthenticationManager; +import org.jetbrains.idea.svn17.SvnConfiguration17; +import org.jetbrains.idea.svn17.SvnVcs17; +import org.jetbrains.idea.svn17.auth.ProviderType; +import org.jetbrains.idea.svn17.auth.SvnAuthenticationListener; +import org.tmatesoft.svn.core.SVNErrorCode; +import org.tmatesoft.svn.core.SVNErrorMessage; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNURL; +import org.tmatesoft.svn.core.auth.SVNAuthentication; +import org.tmatesoft.svn.core.wc.SVNRevision; +import org.tmatesoft.svn.core.wc.SVNWCClient; + +import java.io.File; +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 2/1/12 + * Time: 12:28 PM + */ +public class CommandLineAuthenticator { + private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn17.commandLine.CommandLineAuthenticator"); + private final Project myProject; + private final AuthenticationRequiringCommand myCommand; + private final SvnConfiguration17 myConfiguration17; + private final File myConfigDir; + + public CommandLineAuthenticator(Project project, AuthenticationRequiringCommand command) { + myProject = project; + myCommand = command; + myConfiguration17 = SvnConfiguration17.getInstance(project); + final String configurationDirectory = myConfiguration17.getConfigurationDirectory(); + myConfigDir = new File(configurationDirectory); + } + + public void doWithAuthentication() throws SVNException { + try { + myCommand.run(myConfigDir); + return; + } catch (SVNException e) { + if (! e.getErrorMessage().getErrorCode().isAuthentication()) throw e; + } + File tempDirectory = null; + try { + tempDirectory = FileUtil.createTempDirectory("tmp", "Subversion"); + final SvnAuthenticationManager authenticationManager = SvnConfiguration17.createForTmpDir(myProject, tempDirectory); + //authenticationManager.setAuthenticationForced(true); + authenticationManager.setArtificialSaving(true); + myCommand.cleanup(); + tryGetCredentials(authenticationManager, tempDirectory); + + myCommand.cleanup(); + myCommand.run(tempDirectory); + } + catch (IOException e) { + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e); + } finally { + if (tempDirectory != null) { + FileUtil.delete(tempDirectory); + } + } + } + + private void tryGetCredentials(SvnAuthenticationManager manager, final File tempDirectory) throws SVNException { + final StoreListener storeListener = new StoreListener(); + manager.addListener(storeListener); + final SVNURL svnurl = myCommand.sampleUrl(); + try { + myCommand.runWithSvnkitClient(tempDirectory, manager); + LOG.assertTrue(false, "Credentials not asked"); // todo? + } catch (SvnAuthenticationManager.CredentialsSavedException e) { + // ok, check result? + if (e.isSuccess()) { + final SvnAuthenticationManager realManager = myConfiguration17.getAuthenticationManager(SvnVcs17.getInstance(myProject)); + storeListener.reStore(myProject, realManager, svnurl); + } + } + //final SVNWCClient client = new SVNWCClient(manager, myConfiguration17.getOptions(myProject)); + //client.doInfo(svnurl, SVNRevision.UNDEFINED, SVNRevision.UNDEFINED); + } + + public interface AuthenticationRequiringCommand { + void run(final File configDir) throws SVNException; + void runWithSvnkitClient(final File configDir, SvnAuthenticationManager manager) throws SVNException; + SVNURL sampleUrl(); + void cleanup() throws SVNException; + } + + private static class StoreListener implements SvnAuthenticationListener { + private final Set myData; + private final Set> myAuthRequested; + + private StoreListener() { + myData = new HashSet(); + myAuthRequested = new HashSet>(); + } + + @Override + public void requested(ProviderType type, SVNURL url, String realm, String kind, boolean canceled) { + if (ProviderType.interactive.equals(type)) { + myAuthRequested.add(create(kind, realm, url)); + } + } + + private Trinity create(String kind, String realm, SVNURL url) { + return new Trinity(kind, realm, url); + } + + @Override + public void actualSaveWillBeTried(ProviderType type, SVNURL url, String realm, String kind) { + } + @Override + public void saveAttemptStarted(ProviderType type, SVNURL url, String realm, String kind) { + } + @Override + public void saveAttemptFinished(ProviderType type, SVNURL url, String realm, String kind) { + } + @Override + public void acknowledge(boolean accepted, String kind, String realm, SVNErrorMessage message, SVNAuthentication authentication) { + if (accepted && authentication.isStorageAllowed()) { + final Trinity trinity = create(kind, realm, authentication.getURL()); + if (myAuthRequested.contains(trinity)) { + myData.add(new StoreData(kind, realm, authentication)); + } + } + } + + public void reStore(final Project project, final SvnAuthenticationManager realManager, final SVNURL svnurl) { + for (StoreData data : myData) { + if (data.myAuthentication == null) continue; + realManager.requested(ProviderType.interactive, svnurl, data.myRealm, data.myKind, false); + try { + realManager.acknowledgeAuthentication(true, data.myKind, data.myRealm, null, data.myAuthentication); + } + catch (SVNException e) { + VcsBalloonProblemNotifier.showOverChangesView(project, "Wasn't able to store credentials: " + e.getMessage(), MessageType.ERROR); + } + } + } + } + + private static class StoreData { + public String myKind; + public String myRealm; + public SVNAuthentication myAuthentication; + + private StoreData(String kind, String realm, SVNAuthentication authentication) { + myKind = kind; + myRealm = realm; + myAuthentication = authentication; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + StoreData data = (StoreData)o; + + if (myKind != null ? !myKind.equals(data.myKind) : data.myKind != null) return false; + if (myRealm != null ? !myRealm.equals(data.myRealm) : data.myRealm != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = myKind != null ? myKind.hashCode() : 0; + result = 31 * result + (myRealm != null ? myRealm.hashCode() : 0); + return result; + } + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/SvnCommandLineUpdateClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/SvnCommandLineUpdateClient.java new file mode 100644 index 000000000000..87f54e9b53eb --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/SvnCommandLineUpdateClient.java @@ -0,0 +1,270 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.idea.svn17.commandLine; + +import com.intellij.execution.process.ProcessOutputTypes; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.vcs.LineProcessEventListener; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.concurrency.Semaphore; +import org.jetbrains.idea.svn17.SvnAuthenticationManager; +import org.jetbrains.idea.svn17.SvnConfiguration17; +import org.jetbrains.idea.svn17.SvnVcs17; +import org.jetbrains.idea.svn17.portable.SvnExceptionWrapper; +import org.jetbrains.idea.svn17.portable.SvnSvnkitUpdateClient; +import org.tmatesoft.svn.core.*; +import org.tmatesoft.svn.core.wc.*; + +import java.io.File; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 2/1/12 + * Time: 12:13 PM + */ +public class SvnCommandLineUpdateClient extends SvnSvnkitUpdateClient { + private static final Pattern ourExceptionPattern = Pattern.compile("svn: E(\\d{6}): .+"); + private static final String ourAuthenticationRealm = "Authentication realm:"; + private final Project myProject; + private final VirtualFile myCommonAncestor; + + public SvnCommandLineUpdateClient(final Project project, VirtualFile commonAncestor) { + super(SvnVcs17.getInstance(project).createUpdateClient()); + myProject = project; + myCommonAncestor = commonAncestor; + } + + @Override + public long doUpdate(File file, SVNRevision revision, boolean recursive) throws SVNException { + final long[] longs = doUpdate(new File[]{file}, revision, SVNDepth.fromRecurse(recursive), false, false, false); + return longs[0]; + } + + @Override + public long doUpdate(File file, SVNRevision revision, boolean recursive, boolean force) throws SVNException { + final long[] longs = doUpdate(new File[]{file}, revision, SVNDepth.fromRecurse(recursive), force, false, false); + return longs[0]; + } + + @Override + public long[] doUpdate(File[] paths, SVNRevision revision, SVNDepth depth, boolean allowUnversionedObstructions, boolean depthIsSticky) + throws SVNException { + return doUpdate(paths, revision, depth, allowUnversionedObstructions, depthIsSticky, false); + } + + @Override + public long[] doUpdate(final File[] paths, final SVNRevision revision, final SVNDepth depth, final boolean allowUnversionedObstructions, + final boolean depthIsSticky, final boolean makeParents) throws SVNException { + // since one revision is passed -> I assume same repository here + final SvnCommandLineInfoClient infoClient = new SvnCommandLineInfoClient(myProject); + final SVNInfo info = infoClient.doInfo(paths[0], SVNRevision.UNDEFINED); + if (info == null || info.getURL() == null) { + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.WC_NOT_WORKING_COPY, paths[0].getPath())); + } + final long[] result = new long[paths.length]; + + new CommandLineAuthenticator(myProject, new CommandLineAuthenticator.AuthenticationRequiringCommand() { + @Override + public void run(File configDir) throws SVNException { + final File base = myCommonAncestor == null ? paths[0] : new File(myCommonAncestor.getPath()); + final SvnLineCommand command = new SvnLineCommand(myProject, base, SvnCommandName.up); + if (revision != null && ! SVNRevision.UNDEFINED.equals(revision) && ! SVNRevision.WORKING.equals(revision)) { + command.addParameters("-r", revision.toString()); + } + // unknown depth is not used any more for 1.7 -> why? + if (depth != null && ! SVNDepth.UNKNOWN.equals(depth)) { + command.addParameters("--depth", depth.toString()); + } + if (allowUnversionedObstructions) { + command.addParameters("--force"); + } + if (depthIsSticky && depth != null) {// !!! not sure, but not used + command.addParameters("--set-depth", depth.toString()); + } + if (makeParents) { + command.addParameters("--parents"); + } + command.addParameters("--accept", "postpone"); + command.addParameters("--config-dir", configDir.getPath()); + + for (File path : paths) { + command.addParameters(path.getPath()); + } + + final StringBuffer sbError = new StringBuffer(); + final Semaphore semaphore = new Semaphore(); + semaphore.down(); + final ISVNEventHandler handler = getEventHandler(); + final UpdateOutputLineConverter converter = new UpdateOutputLineConverter(base); + final SVNException[] innerException = new SVNException[1]; + command.addListener(new LineProcessEventListener() { + @Override + public void onLineAvailable(String line, Key outputType) { + if (ProcessOutputTypes.STDOUT.equals(outputType)) { + final SVNEvent event = converter.convert(line); + if (event != null) { + checkForUpdateCompleted(event); + try { + handler.handleEvent(event, 0.5); + } + catch (SVNException e) { + command.cancel(); + semaphore.up(); + innerException[0] = e; + } + } + } else if (ProcessOutputTypes.STDERR.equals(outputType)) { + sbError.append(line); + if (line.contains(ourAuthenticationRealm)) { + command.cancel(); + semaphore.up(); + } + } + } + + @Override + public void processTerminated(int exitCode) { + semaphore.up(); + } + + @Override + public void startFailed(Throwable exception) { + semaphore.up(); + } + }); + try { + command.start(); + semaphore.waitFor(); + + checkForException(sbError); + } catch (SvnExceptionWrapper e){ + throw (SVNException) e.getCause(); + } + } + + @Override + public void runWithSvnkitClient(File configDir, SvnAuthenticationManager manager) throws SVNException { + final SVNUpdateClient client = new SVNUpdateClient(manager, SvnConfiguration17.getInstance(myProject).getOptions(myProject)); + client.doUpdate(paths, revision, depth, allowUnversionedObstructions, depthIsSticky, makeParents); + } + + private void checkForUpdateCompleted(SVNEvent event) { + if (SVNEventAction.UPDATE_COMPLETED.equals(event.getAction())) { + final long eventRevision = event.getRevision(); + for (int i = 0; i < paths.length; i++) { + final File path = paths[i]; + if (path.equals(event.getFile())) { + result[i] = eventRevision; + break; + } + } + } + } + + @Override + public SVNURL sampleUrl() { + return info.getURL(); + } + + @Override + public void cleanup() throws SVNException { + final SvnVcs17 vcs17 = SvnVcs17.getInstance(myProject); + final SVNWCClient client = vcs17.createWCClient(); + for (File path : paths) { + client.doCleanup(path); + } + } + }).doWithAuthentication(); + return result; + } + + private void checkForException(final StringBuffer sbError) throws SVNException { + if (sbError.length() == 0) return; + final String message = sbError.toString(); + final Matcher matcher = ourExceptionPattern.matcher(message); + if (matcher.matches()) { + final String group = matcher.group(1); + if (group != null) { + try { + final int code = Integer.parseInt(group); + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.getErrorCode(code), message)); + } catch (NumberFormatException e) { + // + } + } + } + if (message.contains(ourAuthenticationRealm)) { + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.AUTHN_CREDS_UNAVAILABLE, message)); + } + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.UNKNOWN, message)); + } + + @Override + public long doUpdate(File path, SVNRevision revision, SVNDepth depth, boolean allowUnversionedObstructions, boolean depthIsSticky) + throws SVNException { + final long[] longs = doUpdate(new File[]{path}, revision, depth, allowUnversionedObstructions, depthIsSticky, false); + return longs[0]; + } + + @Override + public long doSwitch(File file, SVNURL url, SVNRevision revision, boolean recursive) throws SVNException { + throw new UnsupportedOperationException(); + //return super.doSwitch(file, url, revision, recursive); + } + + @Override + public long doSwitch(File file, SVNURL url, SVNRevision pegRevision, SVNRevision revision, boolean recursive) throws SVNException { + throw new UnsupportedOperationException(); + //return super.doSwitch(file, url, pegRevision, revision, recursive); + } + + @Override + public long doSwitch(File file, SVNURL url, SVNRevision pegRevision, SVNRevision revision, boolean recursive, boolean force) + throws SVNException { + throw new UnsupportedOperationException(); + //return super.doSwitch(file, url, pegRevision, revision, recursive, force); + } + + @Override + public long doSwitch(File path, + SVNURL url, + SVNRevision pegRevision, + SVNRevision revision, + SVNDepth depth, + boolean allowUnversionedObstructions, + boolean depthIsSticky) throws SVNException { + throw new UnsupportedOperationException(); + //return super.doSwitch(path, url, pegRevision, revision, depth, allowUnversionedObstructions, depthIsSticky); + } + + @Override + public long doSwitch(File path, + SVNURL url, + SVNRevision pegRevision, + SVNRevision revision, + SVNDepth depth, + boolean allowUnversionedObstructions, + boolean depthIsSticky, + boolean ignoreAncestry) throws SVNException { + throw new UnsupportedOperationException(); + // todo MAIN + //return super.doSwitch(path, url, pegRevision, revision, depth, allowUnversionedObstructions, depthIsSticky, ignoreAncestry); + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/SvnStatusHandler.java b/plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/SvnStatusHandler.java index 3ff4c027b40c..65fe6819bae3 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/SvnStatusHandler.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/SvnStatusHandler.java @@ -339,6 +339,12 @@ public class SvnStatusHandler extends DefaultHandler { super(new String[]{"commit"}, new String[]{}); } + /**/ + @Override protected void updateStatus(Attributes attributes, PortableStatus status) throws SAXException { final String props = attributes.getValue("props"); @@ -355,6 +361,10 @@ public class SvnStatusHandler extends DefaultHandler { } // optional + final String locked = attributes.getValue("wc-locked"); + if (locked != null && Boolean.parseBoolean(locked)) { + status.setIsLocked(true); + } final String copied = attributes.getValue("copied"); if (copied != null && Boolean.parseBoolean(copied)) { status.setIsCopied(true); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/UpdateOutputLineConverter.java b/plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/UpdateOutputLineConverter.java new file mode 100644 index 000000000000..80c50ea9c7dc --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn17/commandLine/UpdateOutputLineConverter.java @@ -0,0 +1,199 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.idea.svn17.commandLine; + +import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.Nullable; +import org.tmatesoft.svn.core.SVNErrorCode; +import org.tmatesoft.svn.core.SVNErrorMessage; +import org.tmatesoft.svn.core.SVNNodeKind; +import org.tmatesoft.svn.core.wc.SVNEvent; +import org.tmatesoft.svn.core.wc.SVNEventAction; +import org.tmatesoft.svn.core.wc.SVNStatusType; + +import java.io.File; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 2/1/12 + * Time: 5:13 PM + */ +public class UpdateOutputLineConverter { + private final static String UPDATING = "Updating"; + private final static String AT_REVISION = "At revision (\\d+)\\."; + private final static String UPDATED_TO_REVISION = "Updated to revision (\\d+)\\."; + private final static String SKIPPED = "Skipped"; + private final static String RESTORED = "Restored"; + + private final static String FETCHING_EXTERNAL = "Fetching external"; + private final static String EXTERNAL = "External at (\\d+)\\."; + private final static String UPDATED_EXTERNAL = "Updated external to revision (\\d+)\\."; + + private final static Pattern ourAtRevision = Pattern.compile(AT_REVISION); + private final static Pattern ourUpdatedToRevision = Pattern.compile(UPDATED_TO_REVISION); + + private final static Pattern ourExternal = Pattern.compile(EXTERNAL); + private final static Pattern ourUpdatedExternal = Pattern.compile(UPDATED_EXTERNAL); + + private final static Pattern[] ourCompletePatterns = new Pattern[] {ourAtRevision, ourUpdatedToRevision, ourExternal, ourUpdatedExternal}; + + private final File myBase; + private File myCurrentFile; + + public UpdateOutputLineConverter(File base) { + myBase = base; + } + + public SVNEvent convert(final String line) { + if (StringUtil.isEmptyOrSpaces(line)) return null; + + if (line.startsWith(UPDATING)) { + myCurrentFile = parseForPath(line); + return new SVNEvent(myCurrentFile, myCurrentFile == null ? null : (myCurrentFile.isDirectory() ? SVNNodeKind.DIR : SVNNodeKind.FILE), + null, -1, null, null, null, null, SVNEventAction.UPDATE_NONE, SVNEventAction.UPDATE_NONE, null, null, null, null, null); + } else if (line.startsWith(RESTORED)) { + myCurrentFile = parseForPath(line); + return new SVNEvent(myCurrentFile, myCurrentFile == null ? null : (myCurrentFile.isDirectory() ? SVNNodeKind.DIR : SVNNodeKind.FILE), + null, -1, null, null, null, null, SVNEventAction.RESTORE, SVNEventAction.RESTORE, null, null, null, null, null); + } else if (line.startsWith(SKIPPED)) { + myCurrentFile = parseForPath(line); + final String comment = parseComment(line); + return new SVNEvent(myCurrentFile, myCurrentFile == null ? null : (myCurrentFile.isDirectory() ? SVNNodeKind.DIR : SVNNodeKind.FILE), + null, -1, null, null, null, null, SVNEventAction.SKIP, SVNEventAction.SKIP, + comment == null ? null : SVNErrorMessage.create(SVNErrorCode.WC_OBSTRUCTED_UPDATE, comment), null, null, null, null); + } else if (line.startsWith(FETCHING_EXTERNAL)) { + myCurrentFile = parseForPath(line); + return new SVNEvent(myCurrentFile, myCurrentFile == null ? null : (myCurrentFile.isDirectory() ? SVNNodeKind.DIR : SVNNodeKind.FILE), + null, -1, null, null, null, null, SVNEventAction.UPDATE_EXTERNAL, SVNEventAction.UPDATE_EXTERNAL, null, null, null, null, null); + } + + for (int i = 0; i < ourCompletePatterns.length; i++) { + final Pattern pattern = ourCompletePatterns[i]; + final long revision = matchAndGetRevision(pattern, line); + if (revision != -1) { + return new SVNEvent(myCurrentFile, myCurrentFile == null ? null : (myCurrentFile.isDirectory() ? SVNNodeKind.DIR : SVNNodeKind.FILE), + null, revision, null, null, null, null, SVNEventAction.UPDATE_COMPLETED, SVNEventAction.UPDATE_COMPLETED, null, null, null, null, null); + } + } + + return parseNormalString(line); + } + + private final static Set ourActions = new HashSet(Arrays.asList(new Character[] {'A', 'D', 'U', 'C', 'G', 'E', 'R'})); + + @Nullable + private SVNEvent parseNormalString(final String line) { + if (line.length() < 5) return null; + final char first = line.charAt(0); + if (' ' != first && ! ourActions.contains(first)) return null; + final SVNStatusType contentsStatus = getStatusType(first); + final char second = line.charAt(1); + final SVNStatusType propertiesStatus = getStatusType(second); + final char lock = line.charAt(2); // dont know what to do with stolen lock info + if (' ' != lock && 'B' != lock) return null; + final char treeConflict = line.charAt(3); + if (' ' != treeConflict && 'C' != treeConflict) return null; + final boolean haveTreeConflict = 'C' == treeConflict; + + final String path = line.substring(4).trim(); + if (StringUtil.isEmptyOrSpaces(path)) return null; + final File file = new File(myBase, path); + if (SVNStatusType.STATUS_OBSTRUCTED.equals(contentsStatus)) { + // obstructed + return new SVNEvent(file, file.isDirectory() ? SVNNodeKind.DIR : SVNNodeKind.FILE, + null, -1, contentsStatus, propertiesStatus, null, null, SVNEventAction.UPDATE_SKIP_OBSTRUCTION, SVNEventAction.UPDATE_ADD, + null, null, null, null, null); + } + + SVNEventAction action; + SVNEventAction expectedAction; + if (SVNStatusType.STATUS_ADDED.equals(contentsStatus)) { + expectedAction = SVNEventAction.UPDATE_ADD; + } else if (SVNStatusType.STATUS_DELETED.equals(contentsStatus)) { + expectedAction = SVNEventAction.UPDATE_DELETE; + } else { + expectedAction = SVNEventAction.UPDATE_UPDATE; + } + action = expectedAction; + if (haveTreeConflict) { + action = SVNEventAction.TREE_CONFLICT; + } + + return new SVNEvent(file, file.isDirectory() ? SVNNodeKind.DIR : SVNNodeKind.FILE, null, -1, contentsStatus, propertiesStatus, null, + null, action, expectedAction, null, null, null, null, null); + } + + private SVNStatusType getStatusType(char first) { + final SVNStatusType contentsStatus; + if ('A' == first) { + contentsStatus = SVNStatusType.STATUS_ADDED; + } else if ('D' == first) { + contentsStatus = SVNStatusType.STATUS_DELETED; + } else if ('U' == first) { + contentsStatus = SVNStatusType.CHANGED; + } else if ('C' == first) { + contentsStatus = SVNStatusType.CONFLICTED; + } else if ('G' == first) { + contentsStatus = SVNStatusType.MERGED; + } else if ('R' == first) { + contentsStatus = SVNStatusType.STATUS_REPLACED; + } else if ('E' == first) { + contentsStatus = SVNStatusType.STATUS_OBSTRUCTED; + } else { + contentsStatus = SVNStatusType.STATUS_NORMAL; + } + return contentsStatus; + } + + @Nullable + private long matchAndGetRevision(final Pattern pattern, final String line) { + final Matcher matcher = pattern.matcher(line); + if (matcher.matches()) { + final String group = matcher.group(1); + if (group == null) return -1; + try { + return Long.parseLong(group); + } catch (NumberFormatException e) { + // + } + } + return -1; + } + + @Nullable + private String parseComment(final String line) { + final int idx = line.lastIndexOf("--"); + if (idx != -1 && idx < (line.length() - 2)) { + return line.substring(idx + 2).trim(); + } + return null; + } + + @Nullable + private File parseForPath(final String line) { + final int idx1 = line.indexOf('\''); + if (idx1 == -1) return null; + final int idx2 = line.indexOf('\'', idx1 + 1); + if (idx2 == -1) return null; + final String substring = line.substring(idx1 + 1, idx2); + if (".".equals(substring)) return myBase; + return new File(myBase, substring); + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn17/dialogs/SvnAuthenticationProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn17/dialogs/SvnAuthenticationProvider.java index 44a35487ccee..93a5383534d6 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn17/dialogs/SvnAuthenticationProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn17/dialogs/SvnAuthenticationProvider.java @@ -17,11 +17,14 @@ package org.jetbrains.idea.svn17.dialogs; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.util.SystemProperties; import org.jetbrains.idea.svn17.SvnAuthenticationNotifier; +import org.jetbrains.idea.svn17.SvnConfiguration17; import org.jetbrains.idea.svn17.SvnVcs17; import org.tmatesoft.svn.core.SVNErrorMessage; +import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager; import org.tmatesoft.svn.core.auth.ISVNAuthenticationProvider; @@ -40,11 +43,13 @@ public class SvnAuthenticationProvider implements ISVNAuthenticationProvider { private final Project myProject; private final SvnAuthenticationNotifier myAuthenticationNotifier; private final ISVNAuthenticationProvider mySvnInteractiveAuthenticationProvider; + private final SvnVcs17 mySvnVcs; private final ISVNAuthenticationStorage myAuthenticationStorage; private static final Set ourForceInteractive = new HashSet(); public SvnAuthenticationProvider(final SvnVcs17 svnVcs, final ISVNAuthenticationProvider provider, final ISVNAuthenticationStorage authenticationStorage) { + mySvnVcs = svnVcs; myAuthenticationStorage = authenticationStorage; myProject = svnVcs.getProject(); myAuthenticationNotifier = svnVcs.getAuthNotifier(); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn17/dialogs/SvnInteractiveAuthenticationProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn17/dialogs/SvnInteractiveAuthenticationProvider.java index 7323a2ae2628..34cb4dff294c 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn17/dialogs/SvnInteractiveAuthenticationProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn17/dialogs/SvnInteractiveAuthenticationProvider.java @@ -17,6 +17,8 @@ package org.jetbrains.idea.svn17.dialogs; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier; @@ -31,7 +33,9 @@ import org.tmatesoft.svn.core.SVNErrorMessage; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.auth.*; +import javax.swing.*; import java.io.File; +import java.lang.reflect.InvocationTargetException; import java.security.cert.X509Certificate; public class SvnInteractiveAuthenticationProvider implements ISVNAuthenticationProvider { @@ -200,7 +204,20 @@ public class SvnInteractiveAuthenticationProvider implements ISVNAuthenticationP MessageType.ERROR); return REJECTED; } - WaitForProgressToShow.runOrInvokeAndWaitAboveProgress(command); + final ProgressIndicator pi = ProgressManager.getInstance().getProgressIndicator(); + if (pi != null) { + WaitForProgressToShow.runOrInvokeAndWaitAboveProgress(command, pi.getModalityState()); + } else { + try { + SwingUtilities.invokeAndWait(command); + } + catch (InterruptedException e) { + // + } + catch (InvocationTargetException e) { + // + } + } return result[0]; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn17/history/SvnRevisionsNavigationMediator.java b/plugins/svn4idea/src/org/jetbrains/idea/svn17/history/SvnRevisionsNavigationMediator.java index 677ef50f7cc8..8f3d687be18a 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn17/history/SvnRevisionsNavigationMediator.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn17/history/SvnRevisionsNavigationMediator.java @@ -15,7 +15,10 @@ */ package org.jetbrains.idea.svn17.history; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.openapi.vcs.RepositoryLocation; @@ -53,21 +56,35 @@ public class SvnRevisionsNavigationMediator implements CommittedChangesNavigatio myChunks = new LinkedList>(); - SVNRepository repository = null; - final SVNURL repositoryRoot; - final long youngRevision; - try { - repository = vcs.createRepository(location.getURL()); - youngRevision = repository.getLatestRevision(); - repositoryRoot = repository.getRepositoryRoot(false); - } - catch (SVNException e) { - throw new VcsException(e); - } - finally { - if (repository != null) { - repository.closeSession(); + final SVNURL[] repositoryRoot = new SVNURL[1]; + final long[] youngRevision = new long[1]; + final SVNException[] exception = new SVNException[1]; + + final boolean succeeded = ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() { + @Override + public void run() { + SVNRepository repository = null; + try { + repository = vcs.createRepository(location.getURL()); + youngRevision[0] = repository.getLatestRevision(); + repositoryRoot[0] = repository.getRepositoryRoot(false); + } + catch (SVNException e) { + exception[0] = e; + } + finally { + if (repository != null) { + repository.closeSession(); + } + } } + }, "Getting latest repository revision", true, myProject); + + if (exception[0] != null) { + throw new VcsException(exception[0]); + } + if (! succeeded) { + throw new ProcessCanceledException(); } final Iterator visualIterator = project.isDefault() ? null : @@ -78,7 +95,7 @@ public class SvnRevisionsNavigationMediator implements CommittedChangesNavigatio myVisuallyCached = (visualIterator == null) ? null : new VisuallyCachedProvider(visualIterator, myProject, location); myChunkFactory = new BunchFactory(myInternallyCached, myVisuallyCached, - new LiveProvider(vcs, location, youngRevision, new SvnLogUtil(myProject, vcs, location, repositoryRoot))); + new LiveProvider(vcs, location, youngRevision[0], new SvnLogUtil(myProject, vcs, location, repositoryRoot[0]))); myCurrentIdx = -1; // init first screen diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn17/portable/SvnSvnkitUpdateClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn17/portable/SvnSvnkitUpdateClient.java new file mode 100644 index 000000000000..dfc26591277b --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn17/portable/SvnSvnkitUpdateClient.java @@ -0,0 +1,206 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.idea.svn17.portable; + +import org.tmatesoft.svn.core.SVNDepth; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNURL; +import org.tmatesoft.svn.core.wc.ISVNEventHandler; +import org.tmatesoft.svn.core.wc.SVNRevision; +import org.tmatesoft.svn.core.wc.SVNUpdateClient; + +import java.io.File; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 2/1/12 + * Time: 12:11 PM + */ +public class SvnSvnkitUpdateClient implements SvnUpdateClientI { + private final SVNUpdateClient myClient; + private ISVNEventHandler myDispatcher; + + public SvnSvnkitUpdateClient(SVNUpdateClient client) { + myClient = client; + } + + @Override + public long doUpdate(File file, SVNRevision revision, boolean recursive) throws SVNException { + return myClient.doUpdate(file, revision, recursive); + } + + @Override + public long doUpdate(File file, SVNRevision revision, boolean recursive, boolean force) throws SVNException { + return myClient.doUpdate(file, revision, recursive, force); + } + + @Override + public long[] doUpdate(File[] paths, + SVNRevision revision, + SVNDepth depth, + boolean allowUnversionedObstructions, + boolean depthIsSticky) throws SVNException { + return myClient.doUpdate(paths, revision, depth, allowUnversionedObstructions, depthIsSticky); + } + + @Override + public long[] doUpdate(File[] paths, + SVNRevision revision, + SVNDepth depth, + boolean allowUnversionedObstructions, + boolean depthIsSticky, + boolean makeParents) throws SVNException { + return myClient.doUpdate(paths, revision, depth, allowUnversionedObstructions, depthIsSticky, makeParents); + } + + @Override + public long doUpdate(File path, SVNRevision revision, SVNDepth depth, boolean allowUnversionedObstructions, boolean depthIsSticky) + throws SVNException { + return myClient.doUpdate(path, revision, depth, allowUnversionedObstructions, depthIsSticky); + } + + @Override + public void setUpdateLocksOnDemand(boolean locksOnDemand) { + myClient.setUpdateLocksOnDemand(locksOnDemand); + } + + @Override + public long doSwitch(File file, SVNURL url, SVNRevision revision, boolean recursive) throws SVNException { + return myClient.doSwitch(file, url, revision, recursive); + } + + @Override + public long doSwitch(File file, SVNURL url, SVNRevision pegRevision, SVNRevision revision, boolean recursive) throws SVNException { + return myClient.doSwitch(file, url, pegRevision, revision, recursive); + } + + @Override + public long doSwitch(File file, SVNURL url, SVNRevision pegRevision, SVNRevision revision, boolean recursive, boolean force) + throws SVNException { + return myClient.doSwitch(file, url, pegRevision, revision, recursive, force); + } + + @Override + public long doSwitch(File path, + SVNURL url, + SVNRevision pegRevision, + SVNRevision revision, + SVNDepth depth, + boolean allowUnversionedObstructions, boolean depthIsSticky) throws SVNException { + return myClient.doSwitch(path, url, pegRevision, revision, depth, allowUnversionedObstructions, depthIsSticky); + } + + @Override + public long doSwitch(File path, + SVNURL url, + SVNRevision pegRevision, + SVNRevision revision, + SVNDepth depth, + boolean allowUnversionedObstructions, boolean depthIsSticky, boolean ignoreAncestry) throws SVNException { + return myClient.doSwitch(path, url, pegRevision, revision, depth, allowUnversionedObstructions, depthIsSticky, ignoreAncestry); + } + + @Override + public long doCheckout(SVNURL url, File dstPath, SVNRevision pegRevision, SVNRevision revision, boolean recursive) throws SVNException { + return myClient.doCheckout(url, dstPath, pegRevision, revision, recursive); + } + + @Override + public long doCheckout(SVNURL url, File dstPath, SVNRevision pegRevision, SVNRevision revision, boolean recursive, boolean force) + throws SVNException { + return myClient.doCheckout(url, dstPath, pegRevision, revision, recursive, force); + } + + @Override + public long doCheckout(SVNURL url, + File dstPath, + SVNRevision pegRevision, + SVNRevision revision, + SVNDepth depth, + boolean allowUnversionedObstructions) throws SVNException { + return myClient.doCheckout(url, dstPath, pegRevision, revision, depth, allowUnversionedObstructions); + } + + @Override + public long doExport(SVNURL url, + File dstPath, + SVNRevision pegRevision, + SVNRevision revision, + String eolStyle, + boolean force, + boolean recursive) throws SVNException { + return myClient.doExport(url, dstPath, pegRevision, revision, eolStyle, force, recursive); + } + + @Override + public long doExport(SVNURL url, + File dstPath, + SVNRevision pegRevision, + SVNRevision revision, + String eolStyle, + boolean overwrite, + SVNDepth depth) throws SVNException { + return myClient.doExport(url, dstPath, pegRevision, revision, eolStyle, overwrite, depth); + } + + @Override + public long doExport(File srcPath, + File dstPath, + SVNRevision pegRevision, + SVNRevision revision, + String eolStyle, + boolean force, + boolean recursive) throws SVNException { + return myClient.doExport(srcPath, dstPath, pegRevision, revision, eolStyle, force, recursive); + } + + @Override + public long doExport(File srcPath, + File dstPath, + SVNRevision pegRevision, + SVNRevision revision, + String eolStyle, + boolean overwrite, + SVNDepth depth) throws SVNException { + return myClient.doExport(srcPath, dstPath, pegRevision, revision, eolStyle, overwrite, depth); + } + + @Override + public void doRelocate(File dst, SVNURL oldURL, SVNURL newURL, boolean recursive) throws SVNException { + myClient.doRelocate(dst, oldURL, newURL, recursive); + } + + @Override + public void doCanonicalizeURLs(File dst, boolean omitDefaultPort, boolean recursive) throws SVNException { + myClient.doCanonicalizeURLs(dst, omitDefaultPort, recursive); + } + + @Override + public void setExportExpandsKeywords(boolean expand) { + myClient.setExportExpandsKeywords(expand); + } + + @Override + public void setEventHandler(ISVNEventHandler dispatcher) { + myDispatcher = dispatcher; + myClient.setEventHandler(dispatcher); + } + + public ISVNEventHandler getEventHandler() { + return myDispatcher; + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn17/portable/SvnUpdateClientI.java b/plugins/svn4idea/src/org/jetbrains/idea/svn17/portable/SvnUpdateClientI.java new file mode 100644 index 000000000000..434f657d61b9 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn17/portable/SvnUpdateClientI.java @@ -0,0 +1,75 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.idea.svn17.portable; + +import org.tmatesoft.svn.core.SVNDepth; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNURL; +import org.tmatesoft.svn.core.wc.ISVNEventHandler; +import org.tmatesoft.svn.core.wc.SVNRevision; + +import java.io.File; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 2/1/12 + * Time: 11:59 AM + */ +public interface SvnUpdateClientI { + long doUpdate(File file, SVNRevision revision, boolean recursive) throws SVNException; + + long doUpdate(File file, SVNRevision revision, boolean recursive, boolean force) throws SVNException; + + long[] doUpdate(File[] paths, SVNRevision revision, SVNDepth depth, boolean allowUnversionedObstructions, boolean depthIsSticky) throws SVNException; + + long[] doUpdate(File[] paths, SVNRevision revision, SVNDepth depth, boolean allowUnversionedObstructions, boolean depthIsSticky, boolean makeParents) throws SVNException; + + long doUpdate(File path, SVNRevision revision, SVNDepth depth, boolean allowUnversionedObstructions, boolean depthIsSticky) throws SVNException; + + void setUpdateLocksOnDemand(boolean locksOnDemand); + + long doSwitch(File file, SVNURL url, SVNRevision revision, boolean recursive) throws SVNException; + + long doSwitch(File file, SVNURL url, SVNRevision pegRevision, SVNRevision revision, boolean recursive) throws SVNException; + + long doSwitch(File file, SVNURL url, SVNRevision pegRevision, SVNRevision revision, boolean recursive, boolean force) throws SVNException; + + long doSwitch(File path, SVNURL url, SVNRevision pegRevision, SVNRevision revision, SVNDepth depth, boolean allowUnversionedObstructions, boolean depthIsSticky) throws SVNException; + + long doSwitch(File path, SVNURL url, SVNRevision pegRevision, SVNRevision revision, SVNDepth depth, boolean allowUnversionedObstructions, boolean depthIsSticky, boolean ignoreAncestry) throws SVNException; + + long doCheckout(SVNURL url, File dstPath, SVNRevision pegRevision, SVNRevision revision, boolean recursive) throws SVNException; + + long doCheckout(SVNURL url, File dstPath, SVNRevision pegRevision, SVNRevision revision, boolean recursive, boolean force) throws SVNException; + + long doCheckout(SVNURL url, File dstPath, SVNRevision pegRevision, SVNRevision revision, SVNDepth depth, boolean allowUnversionedObstructions) throws SVNException; + + long doExport(SVNURL url, File dstPath, SVNRevision pegRevision, SVNRevision revision, String eolStyle, boolean force, boolean recursive) throws SVNException; + + long doExport(SVNURL url, File dstPath, SVNRevision pegRevision, SVNRevision revision, String eolStyle, boolean overwrite, SVNDepth depth) throws SVNException; + + long doExport(File srcPath, File dstPath, SVNRevision pegRevision, SVNRevision revision, String eolStyle, boolean force, boolean recursive) throws SVNException; + + long doExport(File srcPath, File dstPath, SVNRevision pegRevision, SVNRevision revision, String eolStyle, boolean overwrite, SVNDepth depth) throws SVNException; + + void doRelocate(File dst, SVNURL oldURL, SVNURL newURL, boolean recursive) throws SVNException; + + void doCanonicalizeURLs(File dst, boolean omitDefaultPort, boolean recursive) throws SVNException; + + void setExportExpandsKeywords(boolean expand); + void setEventHandler(ISVNEventHandler dispatcher); +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn17/update/SvnUpdateEnvironment17.java b/plugins/svn4idea/src/org/jetbrains/idea/svn17/update/SvnUpdateEnvironment17.java index 1f9155c6719c..db44c0a19478 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn17/update/SvnUpdateEnvironment17.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn17/update/SvnUpdateEnvironment17.java @@ -23,10 +23,10 @@ import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.update.UpdatedFiles; import org.jetbrains.annotations.Nullable; -import org.jetbrains.idea.svn17.SvnBundle; -import org.jetbrains.idea.svn17.SvnConfiguration17; -import org.jetbrains.idea.svn17.SvnRevisionNumber; -import org.jetbrains.idea.svn17.SvnVcs17; +import org.jetbrains.idea.svn17.*; +import org.jetbrains.idea.svn17.commandLine.SvnCommandLineUpdateClient; +import org.jetbrains.idea.svn17.portable.SvnSvnkitUpdateClient; +import org.jetbrains.idea.svn17.portable.SvnUpdateClientI; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.io.SVNRepository; @@ -82,25 +82,16 @@ public class SvnUpdateEnvironment17 extends AbstractSvnUpdateIntegrateEnvironmen final SvnConfiguration17 configuration = SvnConfiguration17.getInstance(myVcs.getProject()); final UpdateRootInfo rootInfo = configuration.getUpdateRootInfo(root, myVcs); - final SVNUpdateClient updateClient = myVcs.createUpdateClient(); - updateClient.setEventHandler(myHandler); - updateClient.setUpdateLocksOnDemand(configuration.UPDATE_LOCK_ON_DEMAND); - if (rootInfo != null) { - final SVNURL url = rootInfo.getUrl(); - if (url != null && url.equals(getSourceUrl(myVcs, root))) { - if (rootInfo.isUpdateToRevision()) { - rev = updateClient.doUpdate(root, rootInfo.getRevision(), configuration.UPDATE_DEPTH, configuration.FORCE_UPDATE, false); - } else { - rev = updateClient.doUpdate(root, SVNRevision.HEAD, configuration.UPDATE_DEPTH, configuration.FORCE_UPDATE, false); - } + final SVNURL sourceUrl = getSourceUrl(myVcs, root); + final boolean isSwitch = rootInfo != null && rootInfo.getUrl() != null && ! rootInfo.getUrl().equals(sourceUrl); + final SVNRevision updateTo = rootInfo != null && rootInfo.isUpdateToRevision() ? rootInfo.getRevision() : SVNRevision.HEAD; - } else if (url != null) { - rev = updateClient.doSwitch(root, url, SVNRevision.UNDEFINED, rootInfo.getRevision(), configuration.UPDATE_DEPTH, configuration.FORCE_UPDATE, false); - } else { - rev = updateClient.doUpdate(root, SVNRevision.HEAD, configuration.UPDATE_DEPTH, configuration.FORCE_UPDATE, false); - } + if (isSwitch) { + final SvnUpdateClientI updateClient = createUpdateClient(configuration, root, true, sourceUrl); + rev = updateClient.doSwitch(root, rootInfo.getUrl(), SVNRevision.UNDEFINED, rootInfo.getRevision(), configuration.UPDATE_DEPTH, configuration.FORCE_UPDATE, false); } else { - rev = updateClient.doUpdate(root, SVNRevision.HEAD, configuration.UPDATE_DEPTH, configuration.FORCE_UPDATE, false); + final SvnUpdateClientI updateClient = createUpdateClient(configuration, root, false, sourceUrl); + rev = updateClient.doUpdate(root, updateTo, configuration.UPDATE_DEPTH, configuration.FORCE_UPDATE, false); } myPostUpdateFiles.setRevisions(root.getAbsolutePath(), myVcs, new SvnRevisionNumber(SVNRevision.create(rev))); @@ -108,6 +99,20 @@ public class SvnUpdateEnvironment17 extends AbstractSvnUpdateIntegrateEnvironmen return rev; } + private SvnUpdateClientI createUpdateClient(SvnConfiguration17 configuration, File root, boolean isSwitch, SVNURL sourceUrl) { + final SvnUpdateClientI updateClient; + // do not do from command line for switch now + if (! isSwitch && SvnConfiguration17.UseAcceleration.commandLine.equals(configuration.myUseAcceleration) && + Svn17Detector.is17(myVcs.getProject(), root) && SvnAuthenticationManager.HTTP.equals(sourceUrl.getProtocol())) { + updateClient = new SvnCommandLineUpdateClient(myVcs.getProject(), null); + } else { + updateClient = new SvnSvnkitUpdateClient(myVcs.createUpdateClient()); + } + updateClient.setEventHandler(myHandler); + updateClient.setUpdateLocksOnDemand(configuration.UPDATE_LOCK_ON_DEMAND); + return updateClient; + } + protected boolean isMerge() { return false; } diff --git a/plugins/svn4idea/testSource/org/jetbrains/idea/svn17/SvnAuthenticationTest.java b/plugins/svn4idea/testSource/org/jetbrains/idea/svn17/SvnAuthenticationTest.java index 86bc1b019921..3e4d91df96bf 100644 --- a/plugins/svn4idea/testSource/org/jetbrains/idea/svn17/SvnAuthenticationTest.java +++ b/plugins/svn4idea/testSource/org/jetbrains/idea/svn17/SvnAuthenticationTest.java @@ -1054,6 +1054,10 @@ public class SvnAuthenticationTest extends PlatformTestCase { return myCnt; } + @Override + public void acknowledge(boolean accepted, String kind, String realm, SVNErrorMessage message, SVNAuthentication authentication) { + } + @Override public void saveAttemptStarted(ProviderType type, SVNURL url, String realm, String kind) { mySaved = false; @@ -1119,6 +1123,10 @@ public class SvnAuthenticationTest extends PlatformTestCase { mySaved = new HashSet>(); } + @Override + public void acknowledge(boolean accepted, String kind, String realm, SVNErrorMessage message, SVNAuthentication authentication) { + } + public void reset() { mySaved.clear(); myClientRequested.clear(); diff --git a/plugins/svn4ideaOld/svn4idea-testsOld.iml b/plugins/svn4ideaOld/svn4idea-testsOld.iml index 0408c596ec62..1135812c57d2 100644 --- a/plugins/svn4ideaOld/svn4idea-testsOld.iml +++ b/plugins/svn4ideaOld/svn4idea-testsOld.iml @@ -34,6 +34,8 @@ + + diff --git a/plugins/svn4ideaOld/testSource/org/jetbrains/idea/svn/SvnChangesCorrectlyRefreshedTest.java b/plugins/svn4ideaOld/testSource/org/jetbrains/idea/svn/SvnChangesCorrectlyRefreshedTest.java index 08c6f77a4828..d49a3e711301 100644 --- a/plugins/svn4ideaOld/testSource/org/jetbrains/idea/svn/SvnChangesCorrectlyRefreshedTest.java +++ b/plugins/svn4ideaOld/testSource/org/jetbrains/idea/svn/SvnChangesCorrectlyRefreshedTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.jetbrains.idea.svn; import com.intellij.openapi.fileEditor.impl.LoadTextUtil; @@ -12,6 +27,7 @@ import com.intellij.openapi.vcs.changes.ui.RollbackWorker; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.Nullable; import org.junit.Assert; import org.junit.Test; @@ -61,9 +77,9 @@ public class SvnChangesCorrectlyRefreshedTest extends SvnTestCase { } } - private static void sleep300() { + private static void sleep(final int millis) { try { - Thread.sleep(300); + Thread.sleep(millis); } catch (InterruptedException ignore) { } } @@ -73,14 +89,14 @@ public class SvnChangesCorrectlyRefreshedTest extends SvnTestCase { //ChangeListManagerImpl.DEBUG = true; final SubTree subTree = new SubTree(myWorkingCopyDir); checkin(); - sleep300(); + sleep(1000); editFileInCommand(myProject, subTree.myS1File, "new"); final CharSequence text1 = LoadTextUtil.loadText(subTree.myS1File); Assert.assertEquals("new", text1.toString()); - sleep300(); + sleep(1000); LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(subTree.myS1File.getPath())); VcsDirtyScopeManager.getInstance(myProject).markEverythingDirty(); clManager.ensureUpToDate(false); @@ -115,7 +131,7 @@ public class SvnChangesCorrectlyRefreshedTest extends SvnTestCase { assertVF(subTree.mySourceDir, newName); - sleep300(); + sleep(300); VcsDirtyScopeManager.getInstance(myProject).markEverythingDirty(); clManager.ensureUpToDate(false); DuringChangeListManagerUpdateTestScheme.checkFilesAreInList(new VirtualFile[] {subTree.myS1File}, clManager.getDefaultListName(), clManager); @@ -140,7 +156,7 @@ public class SvnChangesCorrectlyRefreshedTest extends SvnTestCase { assertVF(subTree.myTargetDir, "s1.txt"); - sleep300(); + sleep(300); VcsDirtyScopeManager.getInstance(myProject).markEverythingDirty(); clManager.ensureUpToDate(false); DuringChangeListManagerUpdateTestScheme.checkFilesAreInList(new VirtualFile[] {subTree.myS1File}, clManager.getDefaultListName(), clManager); @@ -168,7 +184,7 @@ public class SvnChangesCorrectlyRefreshedTest extends SvnTestCase { assertVF(subTree.mySourceDir, "s1.txt"); assertVF(subTree.mySourceDir, "s2.txt"); - sleep300(); + sleep(300); VcsDirtyScopeManager.getInstance(myProject).markEverythingDirty(); clManager.ensureUpToDate(false); DuringChangeListManagerUpdateTestScheme.checkFilesAreInList(new VirtualFile[] {subTree.mySourceDir, subTree.myS1File, subTree.myS2File}, @@ -201,7 +217,7 @@ public class SvnChangesCorrectlyRefreshedTest extends SvnTestCase { final CharSequence text1 = LoadTextUtil.loadText(subTree.myS1File); Assert.assertEquals("new", text1.toString()); - sleep300(); + sleep(300); VcsDirtyScopeManager.getInstance(myProject).markEverythingDirty(); clManager.ensureUpToDate(false); DuringChangeListManagerUpdateTestScheme.checkFilesAreInList(new VirtualFile[] {subTree.mySourceDir, subTree.myS1File, subTree.myS2File}, @@ -264,7 +280,7 @@ public class SvnChangesCorrectlyRefreshedTest extends SvnTestCase { checkin(); deleteFileInCommand(subTree.myRootDir); - sleep300(); + sleep(300); VcsDirtyScopeManager.getInstance(myProject).markEverythingDirty(); clManager.ensureUpToDate(false); @@ -290,11 +306,12 @@ public class SvnChangesCorrectlyRefreshedTest extends SvnTestCase { DuringChangeListManagerUpdateTestScheme.checkFilesAreInList(new VirtualFile[] {}, clManager.getDefaultListName(), clManager); } - private VirtualFile assertVF(final VirtualFile parent, final String name) { + @Nullable + private static VirtualFile assertVF(final VirtualFile parent, final String name) { final VirtualFile[] files = parent.getChildren(); - final StringBuilder sb = new StringBuilder("Files: "); + //final StringBuilder sb = new StringBuilder("Files: "); for (VirtualFile file : files) { - sb.append(file.getName()).append(' '); + //sb.append(file.getName()).append(' '); if (name.equals(file.getName())) return file; } System.out.println("not found as child"); diff --git a/plugins/swing-designer/src/META-INF/plugin.xml b/plugins/swing-designer/src/META-INF/plugin.xml new file mode 100644 index 000000000000..48e8a04476fe --- /dev/null +++ b/plugins/swing-designer/src/META-INF/plugin.xml @@ -0,0 +1,9 @@ + + Swing Designer + com.intellij.swing-designer + JetBrains + messages.SwingDesignerBundle + com.intellij.java-i18n + com.intellij.properties + com.intellij.ui-designer-new + diff --git a/plugins/swing-designer/src/messages/SwingDesignerBundle.properties b/plugins/swing-designer/src/messages/SwingDesignerBundle.properties new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/plugins/swing-designer/swing-designer.iml b/plugins/swing-designer/swing-designer.iml new file mode 100644 index 000000000000..8c4b67627078 --- /dev/null +++ b/plugins/swing-designer/swing-designer.iml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/ui-designer/ui-designer-new/src/META-INF/plugin.xml b/plugins/ui-designer/ui-designer-new/src/META-INF/plugin.xml new file mode 100644 index 000000000000..f17e6122d390 --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/META-INF/plugin.xml @@ -0,0 +1,17 @@ + + UI Designer (Core) + com.intellij.ui-designer-new + JetBrains + + messages.UIDesignerBundle + + com.intellij.java-i18n + com.intellij.properties + + + + com.intellij.uiDesigner.UIDesignerToolWindowManager + + + + diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/DesignerEditor.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/DesignerEditor.java new file mode 100644 index 000000000000..9612ef06c6c3 --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/DesignerEditor.java @@ -0,0 +1,97 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.uiDesigner; + +import com.intellij.codeHighlighting.BackgroundEditorHighlighter; +import com.intellij.ide.structureView.StructureViewBuilder; +import com.intellij.openapi.fileEditor.FileEditor; +import com.intellij.openapi.fileEditor.FileEditorLocation; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleUtil; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.UserDataHolderBase; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.testFramework.LightVirtualFile; +import com.intellij.uiDesigner.designSurface.DesignerEditorPanel; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.beans.PropertyChangeListener; + +/** + * @author Alexander Lobas + */ +public abstract class DesignerEditor extends UserDataHolderBase implements FileEditor { + private final DesignerEditorPanel myDesignerPanel; + + public DesignerEditor(Project project, VirtualFile file) { + if (file instanceof LightVirtualFile) { + file = ((LightVirtualFile)file).getOriginalFile(); + } + Module module = ModuleUtil.findModuleForFile(file, project); + if (module == null) { + throw new IllegalArgumentException("No module for file " + file + " in project " + project); + } + myDesignerPanel = new DesignerEditorPanel(module, file); + } + + @NotNull + @Override + public JComponent getComponent() { + return myDesignerPanel; + } + + @Override + public JComponent getPreferredFocusedComponent() { + return myDesignerPanel.getPreferredFocusedComponent(); + } + + @Override + public void dispose() { + myDesignerPanel.dispose(); + } + + @Override + public void selectNotify() { + } + + @Override + public void deselectNotify() { + } + + @Override + public void addPropertyChangeListener(@NotNull PropertyChangeListener listener) { + } + + @Override + public void removePropertyChangeListener(@NotNull PropertyChangeListener listener) { + } + + @Override + public BackgroundEditorHighlighter getBackgroundHighlighter() { + return null; + } + + @Override + public FileEditorLocation getCurrentLocation() { + return null; + } + + @Override + public StructureViewBuilder getStructureViewBuilder() { + return null; + } +} \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/UIDesignerBundle.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/UIDesignerBundle.java new file mode 100644 index 000000000000..ec46f725d320 --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/UIDesignerBundle.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.uiDesigner; + +import com.intellij.CommonBundle; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.PropertyKey; + +import java.lang.ref.Reference; +import java.lang.ref.SoftReference; +import java.util.ResourceBundle; + +/** + * @author yole + */ +public class UIDesignerBundle { + private static Reference ourBundle; + + @NonNls private static final String BUNDLE = "messages.UIDesignerBundle"; + + private UIDesignerBundle() { + } + + public static String message(@PropertyKey(resourceBundle = BUNDLE) String key, Object... params) { + return CommonBundle.message(getBundle(), key, params); + } + + private static ResourceBundle getBundle() { + ResourceBundle bundle = null; + if (ourBundle != null) bundle = ourBundle.get(); + if (bundle == null) { + bundle = ResourceBundle.getBundle(BUNDLE); + ourBundle = new SoftReference(bundle); + } + return bundle; + } +} \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/UIDesignerToolWindowManager.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/UIDesignerToolWindowManager.java new file mode 100644 index 000000000000..03f0171f0aaa --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/UIDesignerToolWindowManager.java @@ -0,0 +1,52 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.uiDesigner; + +import com.intellij.openapi.components.ProjectComponent; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +/** + * @author Alexander Lobas + */ +public final class UIDesignerToolWindowManager implements ProjectComponent { + @Override + public void projectOpened() { + // TODO: Auto-generated method stub + } + + @Override + public void projectClosed() { + // TODO: Auto-generated method stub + } + + @Override + public void initComponent() { + // TODO: Auto-generated method stub + } + + @Override + public void disposeComponent() { + // TODO: Auto-generated method stub + } + + @NotNull + @NonNls + @Override + public String getComponentName() { + return "UIDesignerToolWindowManager2"; + } +} \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/componentTree/ComponentTree.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/componentTree/ComponentTree.java new file mode 100644 index 000000000000..25e524e08173 --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/componentTree/ComponentTree.java @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.uiDesigner.componentTree; + +import com.intellij.openapi.actionSystem.DataProvider; +import com.intellij.ui.treeStructure.Tree; +import org.jetbrains.annotations.NonNls; + +/** + * @author Alexander Lobas + */ +public final class ComponentTree extends Tree implements DataProvider { + @Override + public Object getData(@NonNls String dataId) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } +} \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/designSurface/DesignerEditorPanel.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/designSurface/DesignerEditorPanel.java new file mode 100644 index 000000000000..da8039a5f012 --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/designSurface/DesignerEditorPanel.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.uiDesigner.designSurface; + +import com.intellij.openapi.actionSystem.DataProvider; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; + +/** + * @author Alexander Lobas + */ +public final class DesignerEditorPanel extends JPanel implements DataProvider { + public DesignerEditorPanel(@NotNull Module module, @NotNull VirtualFile file) { + setLayout(new BorderLayout()); + add(new JLabel("Design Surface"), BorderLayout.CENTER); + } + + @Override + public Object getData(@NonNls String dataId) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public void dispose() { + // TODO: Auto-generated method stub + } + + public JComponent getPreferredFocusedComponent() { + return null; // TODO: Auto-generated method stub + } +} \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/model/RadComponent.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/model/RadComponent.java new file mode 100644 index 000000000000..23225a438671 --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/model/RadComponent.java @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.uiDesigner.model; + +import com.intellij.uiDesigner.propertyTable.Property; + +import java.util.List; + +/** + * @author Alexander Lobas + */ +public abstract class RadComponent { + private RadComponent myParent; + + public RadComponent getRoot() { + return myParent == null ? this : myParent.getRoot(); + } + + public final RadComponent getParent() { + return myParent; + } + + public final void setParent(RadComponent parent) { + myParent = parent; + } + + public List getChildren() { + return null; + } + + public List getProperties() { + return null; + } +} \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/propertyTable/Property.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/propertyTable/Property.java new file mode 100644 index 000000000000..f2b8bfd4171b --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/propertyTable/Property.java @@ -0,0 +1,60 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.uiDesigner.propertyTable; + +import com.intellij.uiDesigner.model.RadComponent; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * @author Alexander Lobas + */ +public abstract class Property { + private final Property myParent; + @NotNull private final String myName; + + public Property(Property parent, @NotNull @NonNls String name) { + + myParent = parent; + myName = name; + } + + public final Property getParent() { + return myParent; + } + + @NotNull + public final String getName() { + return myName; + } + + public List getChildren(RadComponent component) { + return null; + } + + public Object getValue(RadComponent component) { + return null; + } + + @NotNull + public abstract PropertyRenderer getRenderer(); + + @Nullable + public abstract PropertyEditor getEditor(); +} \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/propertyTable/PropertyEditor.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/propertyTable/PropertyEditor.java new file mode 100644 index 000000000000..91029fa37dbd --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/propertyTable/PropertyEditor.java @@ -0,0 +1,29 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.uiDesigner.propertyTable; + +import com.intellij.uiDesigner.model.RadComponent; + +import javax.swing.*; + +/** + * @author Alexander Lobas + */ +public interface PropertyEditor { + JComponent getComponent(RadComponent component, Object value); + + Object getValue(); +} \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/propertyTable/PropertyRenderer.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/propertyTable/PropertyRenderer.java new file mode 100644 index 000000000000..5b63bf8b66ac --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/propertyTable/PropertyRenderer.java @@ -0,0 +1,41 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.uiDesigner.propertyTable; + +import com.intellij.uiDesigner.model.RadComponent; + +import javax.swing.*; + +/** + * @author Alexander Lobas + */ +public interface PropertyRenderer { + /** + * @return JComponent to represent the value + * somewhere in UI (for example in the JList of in the JTree). To be + * consistent with other UI additional parameter abount selection and + * focus are also passed. + */ + JComponent getComponent(RadComponent component, Object value, boolean selected, boolean hasFocus); + + /** + * Renderer should update UI of all its internal components to fit current + * IDEA Look And Feel. We cannot directly update UI of the component + * that is returned by {@link #getComponent } method + * because hidden component that are not in the Swing tree can exist. + */ + void updateUI(); +} \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/propertyTable/PropertyTable.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/propertyTable/PropertyTable.java new file mode 100644 index 000000000000..0e79e343a095 --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/propertyTable/PropertyTable.java @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.uiDesigner.propertyTable; + +import com.intellij.openapi.actionSystem.DataProvider; +import com.intellij.ui.table.JBTable; +import org.jetbrains.annotations.NonNls; + +/** + * @author Alexander Lobas + */ +public final class PropertyTable extends JBTable implements DataProvider { + @Override + public Object getData(@NonNls String dataId) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } +} \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/propertyTable/PropertyTablePanel.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/propertyTable/PropertyTablePanel.java new file mode 100644 index 000000000000..b6f6e9ee00a2 --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/uiDesigner/propertyTable/PropertyTablePanel.java @@ -0,0 +1,29 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.uiDesigner.propertyTable; + +import javax.swing.*; +import java.awt.*; + +/** + * @author Alexander Lobas + */ +public final class PropertyTablePanel extends JPanel { + public PropertyTablePanel() { + setLayout(new BorderLayout()); + add(new JLabel("Design Surface"), BorderLayout.CENTER); + } +} \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/messages/UIDesignerBundle.properties b/plugins/ui-designer/ui-designer-new/src/messages/UIDesignerBundle.properties new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/plugins/ui-designer/ui-designer-new/ui-designer-new.iml b/plugins/ui-designer/ui-designer-new/ui-designer-new.iml new file mode 100644 index 000000000000..9503087bf8c9 --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/ui-designer-new.iml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/context/XsltVariableContext.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/context/XsltVariableContext.java index 120fd516d802..ff860ddc2e87 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/context/XsltVariableContext.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/context/XsltVariableContext.java @@ -61,6 +61,7 @@ public class XsltVariableContext implements VariableContext { final VariantsProcessor processor = new VariantsProcessor(context); ResolveUtil.treeWalkUp(processor, context); + processForwardGlobals(context, processor); return processor.getResult(); } @@ -75,19 +76,32 @@ public class XsltVariableContext implements VariableContext { final ResolveProcessor processor = new ResolveProcessor(reference.getReferencedName(), context); final XPathVariable variable = (XPathVariable)ResolveUtil.treeWalkUp(processor, context); - if (variable == null) { - final XmlFile file = PsiTreeUtil.getParentOfType(context, XmlFile.class, true); - if (file != null) { - XsltIncludeIndex.processBackwardDependencies(file, new Processor() { - public boolean process(XmlFile xmlFile) { - processor.processExternalFile(xmlFile, context); - return processor.shouldContinue(); - } - }); - return (XPathVariable)processor.getResult(); - } + if (variable != null) { + return variable; } - return variable; + if (!processForwardGlobals(context, processor)) { + final XmlFile file = PsiTreeUtil.getParentOfType(context, XmlFile.class, true); + if (file != null) { + XsltIncludeIndex.processBackwardDependencies(file, new Processor() { + public boolean process(XmlFile xmlFile) { + processor.processExternalFile(xmlFile, context); + return processor.shouldContinue(); + } + }); + } + } + return (XPathVariable)processor.getResult(); + } + + private static boolean processForwardGlobals(XmlTag context, VariableProcessor processor) { + while (context != null && !XsltSupport.isTopLevelElement(context)) { + context = context.getParentTag(); + } + while (context != null && processor.shouldContinue()) { + processor.process(context); + context = PsiTreeUtil.getNextSiblingOfType(context, XmlTag.class); + } + return !processor.shouldContinue(); } @Nullable @@ -141,6 +155,8 @@ public class XsltVariableContext implements VariableContext { processVarOrParamImpl(tag); } } + + protected abstract boolean shouldContinue(); } static class VariantsProcessor extends VariableProcessor { diff --git a/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltResolveTest.java b/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltResolveTest.java index e0234af216c8..08f6041879b4 100644 --- a/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltResolveTest.java +++ b/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltResolveTest.java @@ -40,6 +40,10 @@ public class XsltResolveTest extends TestBase { doVariableResolveTest(true); } + public void testResolveForwardVariable() throws Throwable { + doVariableResolveTest(true); + } + public void testResolveSingleVariable() throws Throwable { doVariableResolveTest(false); } diff --git a/plugins/xpath/xpath-lang/testData/xslt/highlighting/XsltFreeze.xsl b/plugins/xpath/xpath-lang/testData/xslt/highlighting/xsltFreeze.xsl similarity index 100% rename from plugins/xpath/xpath-lang/testData/xslt/highlighting/XsltFreeze.xsl rename to plugins/xpath/xpath-lang/testData/xslt/highlighting/xsltFreeze.xsl diff --git a/plugins/xpath/xpath-lang/testData/xslt/resolve/resolveForwardVariable.xsl b/plugins/xpath/xpath-lang/testData/xslt/resolve/resolveForwardVariable.xsl new file mode 100644 index 000000000000..2ccc54fdc968 --- /dev/null +++ b/plugins/xpath/xpath-lang/testData/xslt/resolve/resolveForwardVariable.xsl @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/resources-en/src/messages/DebuggerBundle.properties b/resources-en/src/messages/DebuggerBundle.properties index 1e872a490d1e..dfa2fa8b5b58 100644 --- a/resources-en/src/messages/DebuggerBundle.properties +++ b/resources-en/src/messages/DebuggerBundle.properties @@ -183,6 +183,7 @@ label.base.renderer.configurable.show.static.final.fields=Static &final fields label.base.renderer.configurable.show.declared.type=Declared &type label.base.renderer.configurable.show.fq.names=Fully &qualified names label.base.renderer.configurable.show.object.id=Object &id +label.base.renderer.configurable.auto.expressions=Enable auto expressions in Variables view label.base.renderer.configurable.alternate.view=Enable alternative view for Coll&ections classes label.base.renderer.configurable.enable.tostring=Enable 't&oString()' object view: label.base.renderer.configurable.all.overridding=For all classes that override 'toString()' method diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index 472fdda42908..bdef3c17b07e 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -213,10 +213,12 @@ + + order="before javaMemberName, before javaLegacy, after liveTemplates"/> + order="after xml"/> + + diff --git a/resources/src/idea/RichPlatformPlugin.xml b/resources/src/idea/RichPlatformPlugin.xml index 4d0722c1aa5b..2d976d81609a 100644 --- a/resources/src/idea/RichPlatformPlugin.xml +++ b/resources/src/idea/RichPlatformPlugin.xml @@ -72,6 +72,7 @@ + @@ -86,6 +87,9 @@ + + diff --git a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/XmlHighlightVisitor.java b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/XmlHighlightVisitor.java index 30465e7a79ca..669b0d42c469 100644 --- a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/XmlHighlightVisitor.java +++ b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/XmlHighlightVisitor.java @@ -136,21 +136,23 @@ public class XmlHighlightVisitor extends XmlElementVisitor implements HighlightV } } else if (tokenType == XmlTokenType.XML_DATA_CHARACTERS && token.getParent() instanceof XmlText) { if (token.textContains(']') && token.textContains('>')) { + String s = token.getText(); String marker = "]]>"; int i = s.indexOf(marker); - - if (i != -1) { // TODO: fix - TextRange textRange = token.getTextRange(); - int start = textRange.getStartOffset() + i; - HighlightInfoType type = PsiTreeUtil.getParentOfType(token, XmlTag.class) instanceof HtmlTag ? - HighlightInfoType.WARNING : HighlightInfoType.ERROR; - HighlightInfo info = HighlightInfo.createHighlightInfo( - type, - start, start + marker.length(), - XmlErrorMessages.message("cdata.end.should.not.appear.in.content.unless.to.mark.end.of.cdata.section") - ); - addToResults(info); + + if (i != -1 ) { // TODO: fix + XmlTag tag = PsiTreeUtil.getParentOfType(token, XmlTag.class); + if (tag != null && XmlExtension.getExtensionByElement(tag).shouldBeHighlightedAsTag(tag) && !skipValidation(tag)) { + TextRange textRange = token.getTextRange(); + int start = textRange.getStartOffset() + i; + HighlightInfo info = HighlightInfo.createHighlightInfo( + tag instanceof HtmlTag ? HighlightInfoType.WARNING : HighlightInfoType.ERROR, + start, start + marker.length(), + XmlErrorMessages.message("cdata.end.should.not.appear.in.content.unless.to.mark.end.of.cdata.section") + ); + addToResults(info); + } } } } diff --git a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/XmlUnusedNamespaceInspection.java b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/XmlUnusedNamespaceInspection.java index c49be1b8653f..ca59bb366f21 100644 --- a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/XmlUnusedNamespaceInspection.java +++ b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/XmlUnusedNamespaceInspection.java @@ -127,9 +127,11 @@ public class XmlUnusedNamespaceInspection extends XmlSuppressableInspectionTool private static void checkUnusedLocations(XmlAttribute attribute, ProblemsHolder holder) { if (XmlUtil.XML_SCHEMA_INSTANCE_URI.equals(attribute.getNamespace())) { + XmlRefCountHolder refCountHolder = XmlRefCountHolder.getRefCountHolder(attribute); + if (refCountHolder == null) return; + if (XmlUtil.NO_NAMESPACE_SCHEMA_LOCATION_ATT.equals(attribute.getLocalName())) { - XmlRefCountHolder refCountHolder = XmlRefCountHolder.getRefCountHolder(attribute); - if (refCountHolder == null || refCountHolder.isInUse("")) return; + if (refCountHolder.isInUse("")) return; holder.registerProblem(attribute, NAMESPACE_LOCATION_IS_NEVER_USED, ProblemHighlightType.LIKE_UNUSED_SYMBOL, new RemoveNamespaceLocationFix("")); } @@ -141,7 +143,7 @@ public class XmlUnusedNamespaceInspection extends XmlSuppressableInspectionTool PsiReference reference = references[i]; if (reference instanceof URLReference) { String ns = getNamespaceFromReference(reference); - if (ArrayUtil.indexOf(attribute.getParent().knownNamespaces(), ns) == -1) { + if (ArrayUtil.indexOf(attribute.getParent().knownNamespaces(), ns) == -1 && !refCountHolder.isUsedNamespace(ns)) { if (!XmlHighlightVisitor.hasBadResolve(reference, false)) { holder.registerProblemForReference(reference, ProblemHighlightType.LIKE_UNUSED_SYMBOL, NAMESPACE_LOCATION_IS_NEVER_USED, new RemoveNamespaceLocationFix(ns)); diff --git a/xml/impl/src/com/intellij/ide/browsers/BrowsersConfiguration.java b/xml/impl/src/com/intellij/ide/browsers/BrowsersConfiguration.java index fdb43c9d78a3..95f0884d0f54 100644 --- a/xml/impl/src/com/intellij/ide/browsers/BrowsersConfiguration.java +++ b/xml/impl/src/com/intellij/ide/browsers/BrowsersConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -66,7 +66,7 @@ public class BrowsersConfiguration implements PersistentStateComponent return new FirefoxSettings(); } }, - CHROME(XmlBundle.message("browsers.chrome"), getWindowsPathToChrome(), "google-chrome", null, IconLoader.getIcon("/xml/browsers/chrome16.png")) { + CHROME(XmlBundle.message("browsers.chrome"), getWindowsPathToChrome(), "google-chrome", "Google Chrome", IconLoader.getIcon("/xml/browsers/chrome16.png")) { @Override public BrowserSpecificSettings createBrowserSpecificSettings() { return new ChromeSettings(); diff --git a/xml/impl/src/com/intellij/psi/impl/cache/impl/idCache/XHtmlFilterLexer.java b/xml/impl/src/com/intellij/psi/impl/cache/impl/idCache/XHtmlFilterLexer.java index d25652c781b3..075c8b9bbc2b 100644 --- a/xml/impl/src/com/intellij/psi/impl/cache/impl/idCache/XHtmlFilterLexer.java +++ b/xml/impl/src/com/intellij/psi/impl/cache/impl/idCache/XHtmlFilterLexer.java @@ -32,7 +32,7 @@ public class XHtmlFilterLexer extends BaseFilterLexer { } public void advance() { - final IElementType tokenType = getDelegate().getTokenType(); + final IElementType tokenType = myDelegate.getTokenType(); if (tokenType == XmlElementType.XML_COMMENT_CHARACTERS) { scanWordsInToken(UsageSearchContext.IN_COMMENTS, false, false); @@ -51,11 +51,12 @@ public class XHtmlFilterLexer extends BaseFilterLexer { false); if (inComments) advanceTodoItemCountsInToken(); - } else { + } + else if (!XmlFilterLexer.ourNoWordsTokenSet.contains(tokenType)) { scanWordsInToken(UsageSearchContext.IN_PLAIN_TEXT, false, false); } - getDelegate().advance(); + myDelegate.advance(); } } diff --git a/xml/impl/src/com/intellij/psi/impl/cache/impl/idCache/XmlFilterLexer.java b/xml/impl/src/com/intellij/psi/impl/cache/impl/idCache/XmlFilterLexer.java index 8809d088d223..e8e75da3c8bc 100644 --- a/xml/impl/src/com/intellij/psi/impl/cache/impl/idCache/XmlFilterLexer.java +++ b/xml/impl/src/com/intellij/psi/impl/cache/impl/idCache/XmlFilterLexer.java @@ -16,20 +16,41 @@ package com.intellij.psi.impl.cache.impl.idCache; import com.intellij.lexer.Lexer; +import com.intellij.psi.TokenType; import com.intellij.psi.impl.cache.impl.BaseFilterLexer; import com.intellij.psi.impl.cache.impl.OccurrenceConsumer; import com.intellij.psi.search.UsageSearchContext; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; import com.intellij.psi.xml.XmlElementType; +import com.intellij.psi.xml.XmlTokenType; public class XmlFilterLexer extends BaseFilterLexer { + static final TokenSet ourNoWordsTokenSet = TokenSet.create( + XmlTokenType.TAG_WHITE_SPACE, + TokenType.WHITE_SPACE, + XmlTokenType.XML_REAL_WHITE_SPACE, + XmlTokenType.XML_EQ, + XmlTokenType.XML_ATTRIBUTE_VALUE_START_DELIMITER, + XmlTokenType.XML_ATTRIBUTE_VALUE_END_DELIMITER, + XmlTokenType.XML_START_TAG_START, + XmlTokenType.XML_EMPTY_ELEMENT_END, + XmlTokenType.XML_END_TAG_START, + XmlTokenType.XML_TAG_END, + XmlTokenType.XML_DOCTYPE_END, + XmlTokenType.XML_COMMENT_START, + XmlTokenType.XML_COMMENT_END, + XmlTokenType.XML_PI_START, + XmlTokenType.XML_PI_END, + XmlTokenType.XML_CDATA_END + ); public XmlFilterLexer(Lexer originalLexer, OccurrenceConsumer table) { super(originalLexer, table); } public void advance() { - final IElementType tokenType = getDelegate().getTokenType(); + final IElementType tokenType = myDelegate.getTokenType(); if (tokenType == XmlElementType.XML_COMMENT_CHARACTERS) { scanWordsInToken(UsageSearchContext.IN_COMMENTS, false, false); @@ -48,10 +69,10 @@ public class XmlFilterLexer extends BaseFilterLexer { else if (tokenType == XmlElementType.XML_TEXT) { scanWordsInToken(UsageSearchContext.IN_PLAIN_TEXT | UsageSearchContext.IN_FOREIGN_LANGUAGES, false, false); } - else { + else if (!ourNoWordsTokenSet.contains(tokenType)) { scanWordsInToken(UsageSearchContext.IN_PLAIN_TEXT, false, false); } - getDelegate().advance(); + myDelegate.advance(); } } diff --git a/xml/impl/src/com/intellij/xml/XmlExtension.java b/xml/impl/src/com/intellij/xml/XmlExtension.java index 7dcc882d230b..cddc55479e31 100644 --- a/xml/impl/src/com/intellij/xml/XmlExtension.java +++ b/xml/impl/src/com/intellij/xml/XmlExtension.java @@ -59,7 +59,7 @@ public abstract class XmlExtension { return DEFAULT_EXTENSION; } - @Nullable + @SuppressWarnings("ConstantConditions") public static XmlExtension getExtensionByElement(PsiElement element) { final PsiFile psiFile = element.getContainingFile(); if (psiFile != null) { diff --git a/xml/impl/src/com/intellij/xml/util/XmlRefCountHolder.java b/xml/impl/src/com/intellij/xml/util/XmlRefCountHolder.java index abc213158bb1..0a43ad190e36 100644 --- a/xml/impl/src/com/intellij/xml/util/XmlRefCountHolder.java +++ b/xml/impl/src/com/intellij/xml/util/XmlRefCountHolder.java @@ -68,6 +68,7 @@ public class XmlRefCountHolder { private final Set myAdditionallyDeclaredIds = new HashSet(); private final Set myDoNotValidateParentsList = new HashSet(); private final Set myUsedPrefixes = new HashSet(); + private final Set myUsedNamespaces = new HashSet(); @Nullable public static XmlRefCountHolder getRefCountHolder(final XmlElement element) { @@ -140,6 +141,10 @@ public class XmlRefCountHolder { return myUsedPrefixes.contains(prefix); } + public boolean isUsedNamespace(String ns) { + return myUsedNamespaces.contains(ns); + } + private static class IdGatheringRecursiveVisitor extends XmlRecursiveElementVisitor { private final XmlRefCountHolder myHolder; @@ -192,6 +197,7 @@ public class XmlRefCountHolder { @Override public void visitXmlTag(XmlTag tag) { myHolder.addUsedPrefix(tag.getNamespacePrefix()); + myHolder.addUsedNamespace(tag.getNamespace()); String text = tag.getValue().getTrimmedText(); detectPrefix(text); super.visitXmlTag(tag); @@ -202,6 +208,7 @@ public class XmlRefCountHolder { if (!attribute.isNamespaceDeclaration()) { myHolder.addUsedPrefix(attribute.getNamespacePrefix()); } + myHolder.addUsedNamespace(attribute.getNamespace()); super.visitXmlAttribute(attribute); } @@ -269,4 +276,8 @@ public class XmlRefCountHolder { private void addUsedPrefix(String prefix) { myUsedPrefixes.add(prefix); } + + private void addUsedNamespace(String ns) { + myUsedNamespaces.add(ns); + } }