diff --git a/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java b/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java index f7ed9c255bf8..8369bb136d1a 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java @@ -53,6 +53,8 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.packaging.artifacts.Artifact; +import com.intellij.packaging.impl.artifacts.ArtifactBySourceFileFinder; import com.intellij.util.ArrayUtil; import com.intellij.util.messages.MessageBusConnection; import org.apache.oro.text.regex.*; @@ -978,7 +980,15 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements } return extensionsString.toString(); } - + + public boolean isCompilableResourceFile(final Project project, final VirtualFile file) { + if (!isResourceFile(file)) { + return false; + } + final Collection artifacts = ArtifactBySourceFileFinder.getInstance(project).findArtifacts(file); + return artifacts.isEmpty(); + } + private static class CompiledPattern { @NotNull final Pattern fileName; @Nullable final Pattern dir; diff --git a/java/compiler/impl/src/com/intellij/compiler/actions/CompileAction.java b/java/compiler/impl/src/com/intellij/compiler/actions/CompileAction.java index 800adaa1b5f6..38f230f92997 100644 --- a/java/compiler/impl/src/com/intellij/compiler/actions/CompileAction.java +++ b/java/compiler/impl/src/com/intellij/compiler/actions/CompileAction.java @@ -26,14 +26,11 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.packaging.artifacts.Artifact; -import com.intellij.packaging.impl.artifacts.ArtifactBySourceFileFinder; import com.intellij.psi.*; import java.util.ArrayList; -import java.util.Collection; import java.util.List; public class CompileAction extends CompileActionBase { @@ -108,7 +105,8 @@ public class CompileAction extends CompileActionBase { else if (files.length == 1) { final VirtualFile file = files[0]; FileType fileType = file.getFileType(); - if (CompilerManager.getInstance(project).isCompilableFileType(fileType) || isCompilableResourceFile(project, compilerConfiguration, file)) { + if (CompilerManager.getInstance(project).isCompilableFileType(fileType) || compilerConfiguration + .isCompilableResourceFile(project, file)) { elementDescription = "'" + file.getName() + "'"; } else { @@ -135,7 +133,7 @@ public class CompileAction extends CompileActionBase { } private static String createPresentationText(String elementDescription) { - StringBuffer buffer = new StringBuffer(40); + StringBuilder buffer = new StringBuilder(40); buffer.append(ActionsBundle.actionText(IdeActions.ACTION_COMPILE)).append(" "); int length = elementDescription.length(); if (length > 23) { @@ -175,20 +173,12 @@ public class CompileAction extends CompileActionBase { } else { FileType fileType = file.getFileType(); - if (!(compilerManager.isCompilableFileType(fileType) || isCompilableResourceFile(project, compilerConfiguration, file))) { + if (!(compilerManager.isCompilableFileType(fileType) || compilerConfiguration.isCompilableResourceFile(project, file))) { continue; } } filesToCompile.add(file); } - return VfsUtil.toVirtualFileArray(filesToCompile); - } - - private static boolean isCompilableResourceFile(final Project project, final CompilerConfiguration compilerConfiguration, final VirtualFile file) { - if (!compilerConfiguration.isResourceFile(file)) { - return false; - } - final Collection artifacts = ArtifactBySourceFileFinder.getInstance(project).findArtifacts(file); - return artifacts.isEmpty(); + return VfsUtilCore.toVirtualFileArray(filesToCompile); } } \ No newline at end of file diff --git a/java/compiler/impl/src/com/intellij/compiler/progress/CompilerTask.java b/java/compiler/impl/src/com/intellij/compiler/progress/CompilerTask.java index c4497e09827c..710baf36f29b 100644 --- a/java/compiler/impl/src/com/intellij/compiler/progress/CompilerTask.java +++ b/java/compiler/impl/src/com/intellij/compiler/progress/CompilerTask.java @@ -198,14 +198,15 @@ public class CompilerTask extends Task.Backgroundable { ApplicationManager.getApplication().invokeLater(new Runnable() { public void run() { - if (myProject.isDisposed()) { + final Project project = myProject; + if (project == null || project.isDisposed()) { return; } synchronized (myMessageViewLock) { // clear messages from the previous compilation if (myErrorTreeView == null) { // if message view != null, the contents has already been cleared - removeAllContents(myProject, null); + removeAllContents(project, null); } } } @@ -454,7 +455,12 @@ public class CompilerTask extends Task.Backgroundable { if (content == notRemove) { continue; } - if (CONTENT_ID_KEY.get(content) == myContentId || SESSION_ID_KEY.get(content) != mySessionId) { // the content was added by previous compilation + boolean toRemove = CONTENT_ID_KEY.get(content) == myContentId; + if (!toRemove) { + final Object contentSessionId = SESSION_ID_KEY.get(content); + toRemove = contentSessionId != null && contentSessionId != mySessionId; // the content was added by previous compilation + } + if (toRemove) { messageView.getContentManager().removeContent(content, true); } } diff --git a/java/compiler/openapi/src/com/intellij/compiler/CompilerConfiguration.java b/java/compiler/openapi/src/com/intellij/compiler/CompilerConfiguration.java index 9aa97cf0e089..364379490852 100644 --- a/java/compiler/openapi/src/com/intellij/compiler/CompilerConfiguration.java +++ b/java/compiler/openapi/src/com/intellij/compiler/CompilerConfiguration.java @@ -54,6 +54,8 @@ public abstract class CompilerConfiguration { public abstract boolean isResourceFile(String path); + public abstract boolean isCompilableResourceFile(Project project, VirtualFile file); + public abstract void addResourceFilePattern(String namePattern) throws MalformedPatternException; public abstract boolean isAddNotNullAssertions(); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/OrderEntryFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/OrderEntryFix.java index 6b4a4721b4f0..97249280bb4e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/OrderEntryFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/OrderEntryFix.java @@ -124,19 +124,7 @@ public abstract class OrderEntryFix implements IntentionAction, LocalQuickFix { final VirtualFile location = PsiUtilCore.getVirtualFile(reference != null ? reference.getElement() : null); boolean inTests = location != null && ModuleRootManager.getInstance(currentModule).getFileIndex().isInTestSourceContent(location); try { - final String[] junit4Paths = {JavaSdkUtil.getJunit4JarPath(), - PathUtil.getJarPathForClass(Class.forName("org.hamcrest.Matcher")), - PathUtil.getJarPathForClass(Class.forName("org.hamcrest.Matchers"))}; - ModuleRootModificationUtil.addModuleLibrary(currentModule, - "JUnit4", - ContainerUtil.map(junit4Paths, - new Function() { - @Override - public String fun(String libPath) { - return convertToLibraryRoot(libPath).getUrl(); - } - }), - Collections.emptyList(), inTests ? DependencyScope.TEST : DependencyScope.COMPILE); + addJUnit4Library(inTests, currentModule); final GlobalSearchScope scope = GlobalSearchScope.moduleWithLibrariesScope(currentModule); final PsiClass aClass = JavaPsiFacade.getInstance(project).findClass(className, scope); if (aClass != null && editor != null && reference != null) { @@ -276,6 +264,22 @@ public abstract class OrderEntryFix implements IntentionAction, LocalQuickFix { return result; } + public static void addJUnit4Library(boolean inTests, Module currentModule) throws ClassNotFoundException { + final String[] junit4Paths = {JavaSdkUtil.getJunit4JarPath(), + PathUtil.getJarPathForClass(Class.forName("org.hamcrest.Matcher")), + PathUtil.getJarPathForClass(Class.forName("org.hamcrest.Matchers"))}; + ModuleRootModificationUtil.addModuleLibrary(currentModule, + "JUnit4", + ContainerUtil.map(junit4Paths, + new Function() { + @Override + public String fun(String libPath) { + return convertToLibraryRoot(libPath).getUrl(); + } + }), + Collections.emptyList(), inTests ? DependencyScope.TEST : DependencyScope.COMPILE); + } + private static List filterAllowedDependencies(PsiElement element, PsiClass[] classes) { DependencyValidationManager dependencyValidationManager = DependencyValidationManager.getInstance(element.getProject()); PsiFile fromFile = element.getContainingFile(); diff --git a/java/java-impl/src/com/intellij/testIntegration/JavaTestFramework.java b/java/java-impl/src/com/intellij/testIntegration/JavaTestFramework.java index 400648016cba..6dfb54116bbb 100644 --- a/java/java-impl/src/com/intellij/testIntegration/JavaTestFramework.java +++ b/java/java-impl/src/com/intellij/testIntegration/JavaTestFramework.java @@ -15,6 +15,7 @@ */ package com.intellij.testIntegration; +import com.intellij.codeInsight.daemon.impl.quickfix.OrderEntryFix; import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.ide.fileTemplates.FileTemplateDescriptor; import com.intellij.ide.fileTemplates.FileTemplateManager; @@ -119,4 +120,8 @@ public abstract class JavaTestFramework implements TestFramework { public FileTemplateDescriptor getTestClassFileTemplateDescriptor() { return null; } + + public void setupLibrary(Module module) { + OrderEntryFix.addJarToRoots(getLibraryPath(), module, null); + } } diff --git a/java/java-impl/src/com/intellij/testIntegration/createTest/CreateTestDialog.java b/java/java-impl/src/com/intellij/testIntegration/createTest/CreateTestDialog.java index fe2b896499b3..cf4c67911208 100644 --- a/java/java-impl/src/com/intellij/testIntegration/createTest/CreateTestDialog.java +++ b/java/java-impl/src/com/intellij/testIntegration/createTest/CreateTestDialog.java @@ -126,10 +126,7 @@ public class CreateTestDialog extends DialogWrapper { for (final TestFramework descriptor : Extensions.getExtensions(TestFramework.EXTENSION_NAME)) { final JRadioButton b = new JRadioButton(descriptor.getName()); if (descriptor instanceof JavaTestFramework) { - final char mnemonic = ((JavaTestFramework)descriptor).getMnemonic(); - if (mnemonic > -1) { - b.setMnemonic(mnemonic); - } + b.setMnemonic(((JavaTestFramework)descriptor).getMnemonic()); } myLibraryButtons.add(b); group.add(b); @@ -173,7 +170,11 @@ public class CreateTestDialog extends DialogWrapper { public void actionPerformed(ActionEvent e) { ApplicationManager.getApplication().runWriteAction(new Runnable() { public void run() { - OrderEntryFix.addJarToRoots(mySelectedFramework.getLibraryPath(), myTargetModule, null); + if (mySelectedFramework instanceof JavaTestFramework) { + ((JavaTestFramework)mySelectedFramework).setupLibrary(myTargetModule); + } else { + OrderEntryFix.addJarToRoots(mySelectedFramework.getLibraryPath(), myTargetModule, null); + } } }); myFixLibraryPanel.setVisible(false); diff --git a/java/java-tests/testData/inspection/deprecation/DeprecatedDefaultConstructorFromTypeParameter/expected.xml b/java/java-tests/testData/inspection/deprecation/deprecatedDefaultConstructorTypeParameter/expected.xml similarity index 100% rename from java/java-tests/testData/inspection/deprecation/DeprecatedDefaultConstructorFromTypeParameter/expected.xml rename to java/java-tests/testData/inspection/deprecation/deprecatedDefaultConstructorTypeParameter/expected.xml diff --git a/java/java-tests/testData/inspection/deprecation/DeprecatedDefaultConstructorFromTypeParameter/src/Test.java b/java/java-tests/testData/inspection/deprecation/deprecatedDefaultConstructorTypeParameter/src/Test.java similarity index 100% rename from java/java-tests/testData/inspection/deprecation/DeprecatedDefaultConstructorFromTypeParameter/src/Test.java rename to java/java-tests/testData/inspection/deprecation/deprecatedDefaultConstructorTypeParameter/src/Test.java diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/actions/AbstractLayoutCodeProcessorTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/actions/AbstractLayoutCodeProcessorTest.java index f6327b780569..efc85b5805b5 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/actions/AbstractLayoutCodeProcessorTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/actions/AbstractLayoutCodeProcessorTest.java @@ -97,8 +97,8 @@ public abstract class AbstractLayoutCodeProcessorTest extends PsiTestCase { @Override public void tearDown() throws Exception { - super.tearDown(); delete(myWorkingDirectory.getVirtualFile()); + super.tearDown(); } @NotNull @@ -277,45 +277,6 @@ public abstract class AbstractLayoutCodeProcessorTest extends PsiTestCase { PsiTestUtil.addSourceRoot(module, src.getVirtualFile()); return module; } - - class TestFileStructure { - private int myLevel; - @NotNull private PsiDirectory myRoot; - @NotNull private PsiDirectory myCurrentLevelDirectory; - private List> myFilesForLevel = new ArrayList>(); - - TestFileStructure(@NotNull PsiDirectory root) { - myRoot = root; - myCurrentLevelDirectory = root; - myFilesForLevel.add(new ArrayList()); - myLevel = 0; - } - - TestFileStructure addTestFilesToCurrentDirectory(String[] names) throws IOException { - getFilesAtLevel(myLevel).addAll(createTestFiles(myCurrentLevelDirectory, names)); - return this; - } - - TestFileStructure createDirectoryAndMakeItCurrent(String name) { - myLevel++; - myFilesForLevel.add(new ArrayList()); - myCurrentLevelDirectory = createDirectory(myCurrentLevelDirectory.getVirtualFile(), name); - return this; - } - - List getFilesAtLevel(int level) { - assert (myLevel >= level); - return myFilesForLevel.get(level); - } - - List getAllFiles() { - List all = new ArrayList(); - for (List files: myFilesForLevel) { - all.addAll(files); - } - return all; - } - } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/actions/ReformatCodeActionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/actions/ReformatCodeActionTest.java index fa0a4c1f2d80..f2cd858132db 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/actions/ReformatCodeActionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/actions/ReformatCodeActionTest.java @@ -32,14 +32,6 @@ public class ReformatCodeActionTest extends AbstractLayoutCodeProcessorTest { private static String[] classNames = {"Vasya", "Main", "Oiie", "Ololo"}; - private TestFileStructure getThreeLevelDirectoryStructure() throws IOException { - TestFileStructure fileStructure = new TestFileStructure(getTempRootDirectory()); - fileStructure.createDirectoryAndMakeItCurrent("dir").addTestFilesToCurrentDirectory(classNames) - .createDirectoryAndMakeItCurrent("innerDir").addTestFilesToCurrentDirectory(classNames) - .createDirectoryAndMakeItCurrent("innerInnerDir").addTestFilesToCurrentDirectory(classNames); - return fileStructure; - } - public void testReformatAndOptimizeMultipleFiles() throws IOException { List files = createTestFiles(getTempRootDirectory(), classNames); injectMockDialogFlags(new MockReformatFileSettings().setOptimizeImports(true)); @@ -118,4 +110,25 @@ public class ReformatCodeActionTest extends AbstractLayoutCodeProcessorTest { checkFormationAndImportsOptimizationFor(files); } + private TestFileStructure getThreeLevelDirectoryStructure() throws IOException { + TestFileStructure fileStructure = new TestFileStructure(getModule(), getTempRootDirectory()); + + fileStructure.createDirectoryAndMakeItCurrent("dir"); + addFilesToCurrentDirectory(fileStructure); + + fileStructure.createDirectoryAndMakeItCurrent("innerDir"); + addFilesToCurrentDirectory(fileStructure); + + fileStructure.createDirectoryAndMakeItCurrent("innerInnerDir"); + addFilesToCurrentDirectory(fileStructure); + + return fileStructure; + } + + private void addFilesToCurrentDirectory(TestFileStructure fileStructure) throws IOException { + for (int i = 0; i < 5; i++) { + String className = "Test" + i; + fileStructure.addTestFile("Test" + i + ".java", getUntouchedJavaSourceForTotalProcessing(className)); + } + } } diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DeprecationInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DeprecationInspectionTest.java index 2cd737e5ed78..15b82e9382b0 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DeprecationInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DeprecationInspectionTest.java @@ -49,7 +49,7 @@ public class DeprecationInspectionTest extends InspectionTestCase { doTest(); } - public void testDeprecatedDefaultConstructorFromTypeParameter() throws Exception { + public void testDeprecatedDefaultConstructorTypeParameter() throws Exception { doTest(); } diff --git a/lib/libpty/win/xp/libwinpty.dll b/lib/libpty/win/xp/libwinpty.dll new file mode 100644 index 000000000000..f7eef719e72a Binary files /dev/null and b/lib/libpty/win/xp/libwinpty.dll differ diff --git a/lib/libpty/win/xp/winpty-agent.exe b/lib/libpty/win/xp/winpty-agent.exe new file mode 100644 index 000000000000..5abeecdd25e3 Binary files /dev/null and b/lib/libpty/win/xp/winpty-agent.exe differ diff --git a/lib/pty4j-0.3.jar b/lib/pty4j-0.3.jar index 8ffcc9c0d67b..d1345bc70264 100644 Binary files a/lib/pty4j-0.3.jar and b/lib/pty4j-0.3.jar differ diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/CharTableImpl.java b/platform/core-impl/src/com/intellij/psi/impl/source/CharTableImpl.java index 179d344711ae..01f1d17eab93 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/CharTableImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/CharTableImpl.java @@ -16,13 +16,12 @@ package com.intellij.psi.impl.source; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.CommonClassNames; import com.intellij.util.CharTable; -import com.intellij.util.containers.OpenTHashSet; import com.intellij.util.text.CharArrayUtil; -import com.intellij.util.text.CharSequenceHashingStrategy; -import com.intellij.util.text.CharSequenceSubSequence; import com.intellij.util.text.StringFactory; +import gnu.trove.TIntObjectHashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -34,55 +33,62 @@ import java.lang.reflect.Modifier; */ public class CharTableImpl implements CharTable { private static final int INTERN_THRESHOLD = 40; // 40 or more characters long tokens won't be interned. - private static final CharSequenceHashingStrategy HASHER = CharSequenceHashingStrategy.CASE_SENSITIVE; - private static final OpenTHashSet STATIC_ENTRIES = newStaticSet(); - private final OpenTHashSet entries = new OpenTHashSet(10, 0.9f, HASHER); + private static final StringHashToCharSequencesMap STATIC_ENTRIES = newStaticSet(); + private final StringHashToCharSequencesMap entries = new StringHashToCharSequencesMap(10, 0.9f); @NotNull @Override public CharSequence intern(@NotNull final CharSequence text) { - if (text.length() > INTERN_THRESHOLD) return createSequence(text); + CharSequence result; + if (text.length() > INTERN_THRESHOLD) result = createSequence(text); + else result = doIntern(text); - return doIntern(text); + return result; } @NotNull - public CharSequence doIntern(@NotNull CharSequence text) { - CharSequence interned = getStaticInterned(text); + private CharSequence doIntern(@NotNull CharSequence text, int startOffset, int endOffset) { + int hashCode = subSequenceHashCode(text, startOffset, endOffset); + CharSequence interned = STATIC_ENTRIES.getSubSequenceWithHashCode(hashCode, text, startOffset, endOffset); if (interned != null) { return interned; } synchronized(entries) { - interned = entries.get(text); - if (interned != null) { - return interned; - } - // We need to create separate string just to prevent referencing all character data when original is string or char sequence over string - final CharSequence entry = createSequence(text); - boolean added = entries.add(entry); - assert added; - - return entry; + return entries.getOrAddSubSequenceWithHashCode(hashCode, text, startOffset, endOffset); } } + @NotNull + public CharSequence doIntern(@NotNull CharSequence text) { + return doIntern(text, 0, text.length()); + } + @NotNull @Override public CharSequence intern(@NotNull final CharSequence baseText, final int startOffset, final int endOffset) { - if (endOffset - startOffset == baseText.length()) return intern(baseText); - return intern(new CharSequenceSubSequence(baseText, startOffset, endOffset)); + CharSequence result; + if (endOffset - startOffset == baseText.length()) result = intern(baseText); + else if (endOffset - startOffset > INTERN_THRESHOLD) result = createSequence(baseText, startOffset, endOffset); + else result = doIntern(baseText, startOffset, endOffset); + + return result; } @NotNull private static String createSequence(@NotNull CharSequence text) { + return createSequence(text, 0, text.length()); + } + + @NotNull + private static String createSequence(@NotNull CharSequence text, int startOffset, int endOffset) { if (text instanceof String) { - return (String)text; + return ((String)text).substring(startOffset, endOffset); } - char[] buf = new char[text.length()]; - CharArrayUtil.getChars(text, buf, 0); + char[] buf = new char[endOffset - startOffset]; + CharArrayUtil.getChars(text, buf, startOffset, 0, buf.length); return StringFactory.createShared(buf); // this way the .toString() doesn't create another instance (as opposed to new CharArrayCharSequence()) } @@ -96,9 +102,9 @@ public class CharTableImpl implements CharTable { STATIC_ENTRIES.add(text); } } - - private static OpenTHashSet newStaticSet() { - final OpenTHashSet r = new OpenTHashSet(10, 0.9f, HASHER); + + private static StringHashToCharSequencesMap newStaticSet() { + final StringHashToCharSequencesMap r = new StringHashToCharSequencesMap(10, 0.9f); r.add("==" ); r.add("!=" ); r.add("||" ); @@ -214,4 +220,95 @@ public class CharTableImpl implements CharTable { staticIntern(typeName); } } + + private static class StringHashToCharSequencesMap extends TIntObjectHashMap { + StringHashToCharSequencesMap(int capacity, float loadFactor) { + super(capacity, loadFactor); + } + + CharSequence get(CharSequence sequence, int startOffset, int endOffset) { + return getSubSequenceWithHashCode(subSequenceHashCode(sequence, startOffset, endOffset), sequence, startOffset, endOffset); + } + + CharSequence getSubSequenceWithHashCode(int hashCode, CharSequence sequence, int startOffset, int endOffset) { + Object o = get(hashCode); + if (o == null) return null; + if (o instanceof CharSequence) { + if (charSequenceSubSequenceEquals((CharSequence)o, sequence, startOffset, endOffset)) { + return (CharSequence)o; + } + return null; + } else if (o instanceof CharSequence[]) { + for(CharSequence cs:(CharSequence[])o) { + if (charSequenceSubSequenceEquals(cs, sequence, startOffset, endOffset)) { + return cs; + } + } + } else { + assert false:o.getClass(); + } + return null; + } + + private static boolean charSequenceSubSequenceEquals(CharSequence cs, CharSequence baseSequence, int startOffset, int endOffset) { + if (cs.length() != endOffset - startOffset) return false; + if (cs == baseSequence && startOffset == 0) return true; + for(int i = 0, len = cs.length(); i < len; ++i) { + if (cs.charAt(i) != baseSequence.charAt(startOffset + i)) return false; + } + return true; + } + + CharSequence get(CharSequence sequence) { + return get(sequence, 0, sequence.length()); + } + + CharSequence add(CharSequence sequence) { + return add(sequence, 0, sequence.length()); + } + + CharSequence add(CharSequence sequence, int startOffset, int endOffset) { + int hashCode = subSequenceHashCode(sequence, startOffset, endOffset); + return getOrAddSubSequenceWithHashCode(hashCode, sequence, startOffset, endOffset); + } + + private CharSequence getOrAddSubSequenceWithHashCode(int hashCode, CharSequence sequence, int startOffset, int endOffset) { + int index = index(hashCode); + String addedSequence = null; + + if (index < 0) { + put(hashCode, addedSequence = createSequence(sequence, startOffset, endOffset)); + } else { + Object value = _values[index]; + if (value instanceof CharSequence) { + CharSequence existingSequence = (CharSequence)value; + if (charSequenceSubSequenceEquals(existingSequence, sequence, startOffset, endOffset)) { + return existingSequence; + } + put(hashCode, new CharSequence[] {existingSequence, addedSequence = createSequence(sequence, startOffset, endOffset)}); + } else if (value instanceof CharSequence[]) { + CharSequence[] existingSequenceArray = (CharSequence[])value; + for(CharSequence cs:existingSequenceArray) { + if (charSequenceSubSequenceEquals(cs, sequence, startOffset, endOffset)) { + return cs; + } + } + CharSequence[] newSequenceArray = new CharSequence[existingSequenceArray.length + 1]; + System.arraycopy(existingSequenceArray, 0, newSequenceArray, 0, existingSequenceArray.length); + newSequenceArray[existingSequenceArray.length] = addedSequence = createSequence(sequence, startOffset, endOffset); + put(hashCode, newSequenceArray); + } else { + assert false:value.getClass(); + } + } + return addedSequence; + } + } + + private static int subSequenceHashCode(CharSequence sequence, int startOffset, int endOffset) { + if (startOffset == 0 && endOffset == sequence.length()) { + return StringUtil.stringHashCode(sequence); + } + return StringUtil.stringHashCode(sequence, startOffset, endOffset); + } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/AbstractLayoutCodeProcessor.java b/platform/lang-impl/src/com/intellij/codeInsight/actions/AbstractLayoutCodeProcessor.java index b024ef473d03..b524697e42c1 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/actions/AbstractLayoutCodeProcessor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/actions/AbstractLayoutCodeProcessor.java @@ -25,7 +25,6 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; @@ -34,18 +33,23 @@ import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectCoreUtil; import com.intellij.openapi.roots.GeneratedSourcesFilter; -import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.ex.MessagesEx; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.*; +import com.intellij.psi.PsiBundle; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiFile; import com.intellij.util.IncorrectOperationException; import com.intellij.util.SequentialModalProgressTask; import com.intellij.util.SequentialTask; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; @@ -205,7 +209,14 @@ public abstract class AbstractLayoutCodeProcessor { return; } - FileTreeIterator iterator = buildFileTreeIterator(); + FileTreeIterator iterator; + if (myFiles != null) { + iterator = new FileTreeIterator(myFiles); + } + else { + iterator = myProcessChangedTextOnly ? buildChangedFilesIterator() + : buildFileTreeIterator(); + } runProcessFiles(iterator); } @@ -226,6 +237,35 @@ public abstract class AbstractLayoutCodeProcessor { return new FileTreeIterator(Collections.emptyList()); } + @NotNull + private FileTreeIterator buildChangedFilesIterator() { + List files = getChangedFilesFromContext(); + return new FileTreeIterator(files); + } + + @NotNull + private List getChangedFilesFromContext() { + List dirs = getAllSearchableDirsFromContext(); + return FormatChangedTextUtil.getChangedFilesFromDirs(myProject, dirs); + } + + private List getAllSearchableDirsFromContext() { + List dirs = ContainerUtil.newArrayList(); + if (myDirectory != null) { + dirs.add(myDirectory); + } + else if (myModule != null) { + List allModuleDirs = FileTreeIterator.collectModuleDirectories(myModule); + dirs.addAll(allModuleDirs); + } + else if (myProject != null) { + List allProjectDirs = FileTreeIterator.collectProjectDirectories(myProject); + dirs.addAll(allProjectDirs); + } + return dirs; + } + + private void runProcessFile(@NotNull final PsiFile file) { Document document = PsiDocumentManager.getInstance(myProject).getDocument(file); @@ -493,72 +533,4 @@ public abstract class AbstractLayoutCodeProcessor { myCompositeTask = compositeTask; } } - - private static class FileTreeIterator { - private Queue myCurrentFiles = new LinkedList(); - private Queue myCurrentDirectories = new LinkedList(); - - public FileTreeIterator(@NotNull List files) { - myCurrentFiles.addAll(files); - } - - public FileTreeIterator(@NotNull Module module) { - addDirectoriesFrom(module); - expandDirectoriesUntilFilesNotEmpty(); - } - - public FileTreeIterator(@NotNull Project project) { - Module[] modules = ModuleManager.getInstance(project).getModules(); - for (Module module : modules) { - addDirectoriesFrom(module); - } - expandDirectoriesUntilFilesNotEmpty(); - } - - public FileTreeIterator(@NotNull PsiDirectory directory) { - myCurrentDirectories.add(directory); - expandDirectoriesUntilFilesNotEmpty(); - } - - public FileTreeIterator(@NotNull FileTreeIterator fileTreeIterator) { - myCurrentFiles = new LinkedList(fileTreeIterator.myCurrentFiles); - myCurrentDirectories = new LinkedList(fileTreeIterator.myCurrentDirectories); - } - - @NotNull - public PsiFile next() { - if (myCurrentFiles.isEmpty()) { - throw new NoSuchElementException(); - } - PsiFile current = myCurrentFiles.poll(); - expandDirectoriesUntilFilesNotEmpty(); - return current; - } - - public boolean hasNext() { - return !myCurrentFiles.isEmpty(); - } - - private void expandDirectoriesUntilFilesNotEmpty() { - while (myCurrentFiles.isEmpty() && !myCurrentDirectories.isEmpty()) { - PsiDirectory dir = myCurrentDirectories.poll(); - expandDirectory(dir); - } - } - - private void expandDirectory(@NotNull PsiDirectory dir) { - Collections.addAll(myCurrentFiles, dir.getFiles()); - Collections.addAll(myCurrentDirectories, dir.getSubdirectories()); - } - - private void addDirectoriesFrom(Module module) { - VirtualFile[] contentRoots = ModuleRootManager.getInstance(module).getContentRoots(); - for (VirtualFile root : contentRoots) { - PsiDirectory dir = PsiManager.getInstance(module.getProject()).findDirectory(root); - if (dir != null) { - myCurrentDirectories.add(dir); - } - } - } - } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/FileTreeIterator.java b/platform/lang-impl/src/com/intellij/codeInsight/actions/FileTreeIterator.java new file mode 100644 index 000000000000..af629e9c02f1 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/actions/FileTreeIterator.java @@ -0,0 +1,111 @@ +/* + * Copyright 2000-2014 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.codeInsight.actions; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.*; + +public class FileTreeIterator { + private Queue myCurrentFiles = new LinkedList(); + private Queue myCurrentDirectories = new LinkedList(); + + public FileTreeIterator(@NotNull List files) { + myCurrentFiles.addAll(files); + } + + public FileTreeIterator(@NotNull Module module) { + myCurrentDirectories.addAll(collectModuleDirectories(module)); + expandDirectoriesUntilFilesNotEmpty(); + } + + public FileTreeIterator(@NotNull Project project) { + myCurrentDirectories.addAll(collectProjectDirectories(project)); + expandDirectoriesUntilFilesNotEmpty(); + } + + @NotNull + public static List collectProjectDirectories(@NotNull Project project) { + List directories = ContainerUtil.newArrayList(); + + Module[] modules = ModuleManager.getInstance(project).getModules(); + for (Module module : modules) { + directories.addAll(collectModuleDirectories(module)); + } + + return directories; + } + + public FileTreeIterator(@NotNull PsiDirectory directory) { + myCurrentDirectories.add(directory); + expandDirectoriesUntilFilesNotEmpty(); + } + + public FileTreeIterator(@NotNull FileTreeIterator fileTreeIterator) { + myCurrentFiles = new LinkedList(fileTreeIterator.myCurrentFiles); + myCurrentDirectories = new LinkedList(fileTreeIterator.myCurrentDirectories); + } + + @NotNull + public PsiFile next() { + if (myCurrentFiles.isEmpty()) { + throw new NoSuchElementException(); + } + PsiFile current = myCurrentFiles.poll(); + expandDirectoriesUntilFilesNotEmpty(); + return current; + } + + public boolean hasNext() { + return !myCurrentFiles.isEmpty(); + } + + private void expandDirectoriesUntilFilesNotEmpty() { + while (myCurrentFiles.isEmpty() && !myCurrentDirectories.isEmpty()) { + PsiDirectory dir = myCurrentDirectories.poll(); + expandDirectory(dir); + } + } + + private void expandDirectory(@NotNull PsiDirectory dir) { + Collections.addAll(myCurrentFiles, dir.getFiles()); + Collections.addAll(myCurrentDirectories, dir.getSubdirectories()); + } + + @NotNull + public static List collectModuleDirectories(Module module) { + List dirs = ContainerUtil.newArrayList(); + + VirtualFile[] contentRoots = ModuleRootManager.getInstance(module).getContentRoots(); + for (VirtualFile root : contentRoots) { + PsiDirectory dir = PsiManager.getInstance(module.getProject()).findDirectory(root); + if (dir != null) { + dirs.add(dir); + } + } + + return dirs; + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/FormatChangedTextUtil.java b/platform/lang-impl/src/com/intellij/codeInsight/actions/FormatChangedTextUtil.java index e51deaed6de7..bf77a3022a0e 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/actions/FormatChangedTextUtil.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/actions/FormatChangedTextUtil.java @@ -17,7 +17,9 @@ package com.intellij.codeInsight.actions; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.application.Result; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.EditorFactory; import com.intellij.openapi.editor.markup.RangeHighlighter; import com.intellij.openapi.module.ModifiableModuleModel; import com.intellij.openapi.module.Module; @@ -25,27 +27,30 @@ import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.ChangeListManager; +import com.intellij.openapi.vcs.changes.ContentRevision; import com.intellij.openapi.vcs.ex.LineStatusTracker; import com.intellij.openapi.vcs.ex.Range; +import com.intellij.openapi.vcs.ex.RangesBuilder; import com.intellij.openapi.vcs.impl.LineStatusTrackerManager; import com.intellij.openapi.vcs.impl.LineStatusTrackerManagerI; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.ContainerUtilRt; +import com.intellij.util.diff.FilesTooBigForDiffException; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.*; -/** - * Contains utility methods for 'format only changed text' (in terms of VCS changes). - * - * @author Denis Zhdanov - * @since 12/19/11 10:55 AM - */ public class FormatChangedTextUtil { + private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.actions.FormatChangedTextUtil"); private FormatChangedTextUtil() { } @@ -120,6 +125,14 @@ public class FormatChangedTextUtil { return false; } + public static boolean hasChanges(@NotNull VirtualFile[] files, @NotNull Project project) { + for (VirtualFile file : files) { + if (hasChanges(file, project)) + return true; + } + return false; + } + /** * Allows to answer if any file that belongs to the given module has changes in comparison with VCS. * @@ -209,4 +222,96 @@ public class FormatChangedTextUtil { } return result; } + + @NotNull + public static List getChangedFilesFromDirs(@NotNull Project project, @NotNull List dirs) { + ChangeListManager changeListManager = ChangeListManager.getInstance(project); + Collection changes = ContainerUtil.newArrayList(); + + for (PsiDirectory dir : dirs) { + changes.addAll(changeListManager.getChangesIn(dir.getVirtualFile())); + } + + return getChangedFiles(project, changes); + } + + @NotNull + public static List getChangedFiles(@NotNull Project project, @NotNull Collection changes) { + List files = ContainerUtil.newArrayList(); + for (Change change : changes) { + VirtualFile vFile = change.getVirtualFile(); + if (vFile != null) { + PsiFile file = PsiManager.getInstance(project).findFile(vFile); + if (file != null) files.add(file); + } + } + return files; + } + + @NotNull + public static List getChangedTextRanges(@NotNull Project project, @NotNull PsiFile file) { + Change change = ChangeListManager.getInstance(project).getChange(file.getVirtualFile()); + if (change == null) { + return ContainerUtilRt.emptyList(); + } + if (change.getType() == Change.Type.NEW) { + return ContainerUtil.newArrayList(file.getTextRange()); + } + + String contentFromVcs = getRevisionedContentFrom(change); + return contentFromVcs != null ? calculateChangedTextRanges(project, file, contentFromVcs) + : ContainerUtil.emptyList(); + } + + @Nullable + private static String getRevisionedContentFrom(@NotNull Change change) { + ContentRevision revision = change.getBeforeRevision(); + if (revision == null) { + return null; + } + + try { + return revision.getContent(); + } + catch (VcsException e) { + LOG.error("Can't get content for: " + change.getVirtualFile(), e); + return null; + } + } + + @NotNull + private static List calculateChangedTextRanges(@NotNull Project project, @NotNull PsiFile file, @NotNull String contentFromVcs) { + Document documentFromVcs = EditorFactory.getInstance().createDocument(contentFromVcs); + Document document = PsiDocumentManager.getInstance(project).getDocument(file); + + if (document == null) { + return ContainerUtil.emptyList(); + } + + try { + List changedRanges = new RangesBuilder(document, documentFromVcs).getRanges(); + return getChangedTextRanges(document, changedRanges); + } + catch (FilesTooBigForDiffException e) { + LOG.error("Error while calculating changed ranges for: " + file.getVirtualFile(), e); + return ContainerUtil.emptyList(); + } + } + + @NotNull + private static List getChangedTextRanges(@NotNull Document document, @NotNull List changedRanges) { + List ranges = ContainerUtil.newArrayList(); + for (Range range : changedRanges) { + if (range.getType() != Range.DELETED) { + int changeStartLine = range.getOffset1(); + int changeEndLine = range.getOffset2(); + + int lineStartOffset = document.getLineStartOffset(changeStartLine); + int lineEndOffset = document.getLineEndOffset(changeEndLine - 1); + + ranges.add(new TextRange(lineStartOffset, lineEndOffset)); + } + } + return ranges; + } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeDialog.java b/platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeDialog.java index 41977e2e7015..cbf36e1f4b33 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeDialog.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeDialog.java @@ -187,8 +187,7 @@ public class LayoutCodeDialog extends DialogWrapper implements LayoutCodeOptions myCbArrangeEntries.setEnabled(true); myCbArrangeEntries.setSelected(myRearrangeEntriesSelected); - //TODO enable it when getting changed ranges will be fixed - myCbOnlyVcsChangedRegions.setEnabled(false); + myCbOnlyVcsChangedRegions.setEnabled(myDirectory != null && FormatChangedTextUtil.hasChanges(myDirectory)); myCbOnlyVcsChangedRegions.setSelected(false); myDoNotAskMeCheckBox.setEnabled(false); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutProjectCodeDialog.java b/platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutProjectCodeDialog.java index 7c581c5220dc..aa4aadc9a083 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutProjectCodeDialog.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutProjectCodeDialog.java @@ -34,11 +34,13 @@ public class LayoutProjectCodeDialog extends DialogWrapper implements ReformatFi private static @NonNls final String HELP_ID = "editing.codeReformatting"; private final String myText; + private final boolean myEnableOnlyVCSChangedTextCb; private final boolean mySuggestOptimizeImports; private final Project myProject; private JCheckBox myCbOptimizeImports; + private JCheckBox myCbOnlyVcsChangedRegions; private JCheckBox myCbRearrangeEntries; public LayoutProjectCodeDialog(@NotNull Project project, @@ -51,6 +53,7 @@ public class LayoutProjectCodeDialog extends DialogWrapper implements ReformatFi myText = text; mySuggestOptimizeImports = suggestOptimizeImports; myProject = project; + myEnableOnlyVCSChangedTextCb = enableOnlyVCSChangedTextCb; setOKButtonText(CodeInsightBundle.message("reformat.code.accept.button.text")); setTitle(title); @@ -63,16 +66,22 @@ public class LayoutProjectCodeDialog extends DialogWrapper implements ReformatFi return new JLabel(myText); } - JPanel panel = new JPanel(new GridLayout(3, 1)); + JPanel panel = new JPanel(new GridLayout(4, 1)); myCbOptimizeImports = new JCheckBox(CodeInsightBundle.message("reformat.option.optimize.imports")); myCbRearrangeEntries = new JCheckBox(CodeInsightBundle.message("reformat.option.rearrange.entries")); + myCbOnlyVcsChangedRegions = new JCheckBox(CodeInsightBundle.message("reformat.option.vcs.changed.region")); panel.add(new JLabel(myText)); panel.add(myCbOptimizeImports); panel.add(myCbRearrangeEntries); + panel.add(myCbOnlyVcsChangedRegions); myCbOptimizeImports.setSelected(PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.OPTIMIZE_IMPORTS_KEY, false)); myCbRearrangeEntries.setSelected(LayoutCodeSettingsStorage.getLastSavedRearrangeEntriesCbStateFor(myProject)); + myCbOnlyVcsChangedRegions.setEnabled(myEnableOnlyVCSChangedTextCb); + myCbOnlyVcsChangedRegions.setSelected( + myEnableOnlyVCSChangedTextCb && PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, false) + ); return panel; } @@ -99,6 +108,9 @@ public class LayoutProjectCodeDialog extends DialogWrapper implements ReformatFi if (mySuggestOptimizeImports) { PropertiesComponent.getInstance().setValue(LayoutCodeConstants.OPTIMIZE_IMPORTS_KEY, Boolean.toString(isOptimizeImports())); LayoutCodeSettingsStorage.saveRearrangeEntriesOptionFor(myProject, isRearrangeEntries()); + if (myEnableOnlyVCSChangedTextCb) { + PropertiesComponent.getInstance().setValue(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, Boolean.toString(myCbOnlyVcsChangedRegions.isSelected())); + } } } @@ -107,7 +119,7 @@ public class LayoutProjectCodeDialog extends DialogWrapper implements ReformatFi } public boolean isProcessOnlyChangedText() { - return false; + return myCbOnlyVcsChangedRegions.isEnabled() && myCbOnlyVcsChangedRegions.isSelected(); } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeProcessor.java b/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeProcessor.java index 9bd23c30f5dc..ff032c22747b 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeProcessor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeProcessor.java @@ -26,6 +26,7 @@ import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -62,14 +63,14 @@ public class ReformatCodeProcessor extends AbstractLayoutCodeProcessor { } } - public ReformatCodeProcessor(Project project, PsiFile[] files, Runnable postRunnable, boolean processChangedTextOnly) { + public ReformatCodeProcessor(Project project, PsiFile[] files, @Nullable Runnable postRunnable, boolean processChangedTextOnly) { this(project, files, COMMAND_NAME, postRunnable, processChangedTextOnly); } public ReformatCodeProcessor(Project project, PsiFile[] files, String commandName, - Runnable postRunnable, + @Nullable Runnable postRunnable, boolean processChangedTextOnly) { super(project, files, PROGRESS_TEXT, commandName, postRunnable, processChangedTextOnly); @@ -85,13 +86,8 @@ public class ReformatCodeProcessor extends AbstractLayoutCodeProcessor { public Boolean call() throws Exception { FormattingProgressTask.FORMATTING_CANCELLED_FLAG.set(false); try { - if (myRanges.isEmpty() && processChangedTextOnly) { - myRanges.addAll(FormatChangedTextUtil.getChanges(file)); - } - if (myRanges.isEmpty()) { - myRanges.add(file.getTextRange()); - } - CodeStyleManager.getInstance(myProject).reformatText(file, myRanges); + Collection ranges = getRangesToFormat(processChangedTextOnly, file); + CodeStyleManager.getInstance(myProject).reformatText(file, ranges); return !FormattingProgressTask.FORMATTING_CANCELLED_FLAG.get(); } catch (IncorrectOperationException e) { @@ -104,4 +100,13 @@ public class ReformatCodeProcessor extends AbstractLayoutCodeProcessor { } }); } -} + + @NotNull + private Collection getRangesToFormat(boolean processChangedTextOnly, PsiFile file) { + if (processChangedTextOnly) { + return FormatChangedTextUtil.getChangedTextRanges(myProject, file); + } + + return !myRanges.isEmpty() ? myRanges : ContainerUtil.newArrayList(file.getTextRange()); + } +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatFilesDialog.form b/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatFilesDialog.form index 4a2cb037cb1f..97a3afccbb10 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatFilesDialog.form +++ b/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatFilesDialog.form @@ -3,12 +3,12 @@ - + - + @@ -32,9 +32,17 @@ + + + + + + + + - + diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatFilesDialog.java b/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatFilesDialog.java index 0ed05536303b..26a158e027f4 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatFilesDialog.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatFilesDialog.java @@ -29,6 +29,7 @@ public class ReformatFilesDialog extends DialogWrapper implements ReformatFilesO @NotNull private Project myProject; private JPanel myPanel; private JCheckBox myOptimizeImports; + private JCheckBox myOnlyChangedText; private JCheckBox myRearrangeEntriesCb; public ReformatFilesDialog(@NotNull Project project, @NotNull VirtualFile[] files) { @@ -36,6 +37,11 @@ public class ReformatFilesDialog extends DialogWrapper implements ReformatFilesO myProject = project; setTitle(CodeInsightBundle.message("dialog.reformat.files.title")); myOptimizeImports.setSelected(isOptmizeImportsOptionOn()); + boolean canTargetVcsChanges = FormatChangedTextUtil.hasChanges(files, project); + myOnlyChangedText.setEnabled(canTargetVcsChanges); + myOnlyChangedText.setSelected( + canTargetVcsChanges && PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, false) + ); myOptimizeImports.setSelected(isOptmizeImportsOptionOn()); myRearrangeEntriesCb.setSelected(LayoutCodeSettingsStorage.getLastSavedRearrangeEntriesCbStateFor(myProject)); init(); @@ -53,7 +59,7 @@ public class ReformatFilesDialog extends DialogWrapper implements ReformatFilesO @Override public boolean isProcessOnlyChangedText() { - return false; + return myOnlyChangedText.isEnabled() && myOnlyChangedText.isSelected(); } @Override @@ -65,6 +71,7 @@ public class ReformatFilesDialog extends DialogWrapper implements ReformatFilesO protected void doOKAction() { super.doOKAction(); PropertiesComponent.getInstance().setValue(LayoutCodeConstants.OPTIMIZE_IMPORTS_KEY, Boolean.toString(myOptimizeImports.isSelected())); + PropertiesComponent.getInstance().setValue(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, Boolean.toString(myOnlyChangedText.isSelected())); LayoutCodeSettingsStorage.saveRearrangeEntriesOptionFor(myProject, isRearrangeEntries()); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hint/actions/ShowImplementationsAction.java b/platform/lang-impl/src/com/intellij/codeInsight/hint/actions/ShowImplementationsAction.java index 77995ac6fd2a..1f6f1347f16d 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/hint/actions/ShowImplementationsAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/hint/actions/ShowImplementationsAction.java @@ -33,9 +33,11 @@ import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.TextEditor; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.ui.popup.LightweightWindowEvent; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Ref; import com.intellij.openapi.vfs.VirtualFile; @@ -285,10 +287,21 @@ public class ShowImplementationsAction extends AnAction implements PopupAction { @Override public boolean process(JBPopup popup) { usageView.set(component.showInUsageView()); + myTaskRef = new WeakReference(null); popup.cancel(); return false; } }) + .setCancelCallback(new Computable() { + @Override + public Boolean compute() { + final BackgroundUpdaterTask task = myTaskRef.get(); + if (task != null) { + task.setCanceled(); + } + return Boolean.TRUE; + } + }) .createPopup(); updateInBackground(editor, element, component, title, (AbstractPopup)popup, usageView); @@ -315,7 +328,12 @@ public class ShowImplementationsAction extends AnAction implements PopupAction { task.init(popup, component, usageView); myTaskRef = new WeakReference(task); - ProgressManager.getInstance().run(task); + ProgressManager.getInstance().runProcessWithProgressAsynchronously(task, new BackgroundableProcessIndicator(task) { + @Override + public boolean isCanceled() { + return super.isCanceled() || task.isCanceled(); + } + }); } protected boolean isIncludeAlwaysSelf() { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/BackgroundUpdaterTask.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/BackgroundUpdaterTask.java index 539a54ca9126..4fb9dc21fb06 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/BackgroundUpdaterTask.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/BackgroundUpdaterTask.java @@ -73,12 +73,6 @@ public abstract class BackgroundUpdaterTask extends Task.Backgroundable { myComponent = component; myUsageView = usageView; - myPopup.addPopupListener(new JBPopupAdapter() { - @Override - public void onClosed(LightweightWindowEvent event) { - setCanceled(); - } - }); } public abstract String getCaption(int size); @@ -91,6 +85,10 @@ public abstract class BackgroundUpdaterTask extends Task.Backgroundable { return canceled; } + public boolean isCanceled() { + return myCanceled; + } + public boolean updateComponent(final PsiElement element, @Nullable final Comparator comparator) { final UsageView view = myUsageView.get(); if (view != null && !((UsageViewImpl)view).isDisposed()) { diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java index ace169021f27..30e1bac9316d 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -152,10 +152,8 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA private Component myContextComponent; private CalcThread myCalcThread; private static AtomicBoolean ourShiftIsPressed = new AtomicBoolean(false); - private static AtomicBoolean shift1Pressed = new AtomicBoolean(false); - private static AtomicBoolean shift1Released = new AtomicBoolean(false); - private static AtomicBoolean shift2Pressed = new AtomicBoolean(false); - private static AtomicBoolean shift2Released = new AtomicBoolean(false); + private final static Couple ourPressed = Couple.newOne(new AtomicBoolean(false), new AtomicBoolean(false)); + private final static Couple ourReleased = Couple.newOne(new AtomicBoolean(false), new AtomicBoolean(false)); private static AtomicBoolean ourOtherKeyWasPressed = new AtomicBoolean(false); private static AtomicLong ourLastTimePressed = new AtomicLong(0); private static AtomicBoolean showAll = new AtomicBoolean(false); @@ -185,7 +183,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA return false; } ourOtherKeyWasPressed.set(false); - if (shift1Pressed.get() && System.currentTimeMillis() - ourLastTimePressed.get() > 500) { + if (ourPressed.first.get() && System.currentTimeMillis() - ourLastTimePressed.get() > 500) { resetState(); } handleShift((KeyEvent)event); @@ -203,37 +201,37 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } private void resetState() { - shift1Pressed.set(false); - shift1Released.set(false); - shift2Pressed.set(false); - shift2Released.set(false); + ourPressed.first.set(false); + ourPressed.second.set(false); + ourReleased.first.set(false); + ourReleased.second.set(false); } private void handleShift(KeyEvent event) { - if (shift1Pressed.get() && System.currentTimeMillis() - ourLastTimePressed.get() > 300) { + if (ourPressed.first.get() && System.currentTimeMillis() - ourLastTimePressed.get() > 300) { resetState(); return; } if (event.getID() == KeyEvent.KEY_PRESSED) { - if (!shift1Pressed.get()) { + if (!ourPressed.first.get()) { resetState(); - shift1Pressed.set(true); + ourPressed.first.set(true); ourLastTimePressed.set(System.currentTimeMillis()); return; } else { - if (shift1Pressed.get() && shift1Released.get()) { - shift2Pressed.set(true); + if (ourPressed.first.get() && ourReleased.first.get()) { + ourPressed.second.set(true); ourLastTimePressed.set(System.currentTimeMillis()); return; } } } else if (event.getID() == KeyEvent.KEY_RELEASED) { - if (shift1Pressed.get() && !shift1Released.get()) { - shift1Released.set(true); + if (ourPressed.first.get() && !ourReleased.first.get()) { + ourReleased.first.set(true); ourLastTimePressed.set(System.currentTimeMillis()); return; - } else if (shift1Pressed.get() && shift1Released.get() && shift2Pressed.get()) { + } else if (ourPressed.first.get() && ourReleased.first.get() && ourPressed.second.get()) { resetState(); run(event); return; @@ -426,16 +424,9 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA @Override protected void textChanged(DocumentEvent e) { final String pattern = editor.getText(); - final int len = pattern.trim().length(); - myAlarm.cancelAllRequests(); - myAlarm.addRequest(new Runnable() { - @Override - public void run() { - if (editor.hasFocus()) { - rebuildList(pattern); - } - } - }, len == 1 ? 400 : len == 2 ? 300 : len == 3 ? 250 : 30); + if (editor.hasFocus()) { + rebuildList(pattern); + } } }); editor.addFocusListener(new FocusAdapter() { @@ -1021,7 +1012,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA final int width = myMainPanel.getPreferredSize().width; if (width > myPopupActualWidth) { myPopupActualWidth = width; - schedulePopupUpdate(); + //schedulePopupUpdate(); } return myMainPanel; } diff --git a/platform/platform-api/src/com/intellij/openapi/editor/LazyRangeMarkerFactory.java b/platform/platform-api/src/com/intellij/openapi/editor/LazyRangeMarkerFactory.java index e99e06527878..2dca4e6c88a8 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/LazyRangeMarkerFactory.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/LazyRangeMarkerFactory.java @@ -45,6 +45,15 @@ public class LazyRangeMarkerFactory { EditorFactory.getInstance().getEventMulticaster().addDocumentListener(new DocumentAdapter() { @Override public void beforeDocumentChange(DocumentEvent e) { + transformRangeMarkers(e); + } + + @Override + public void documentChanged(DocumentEvent e) { + transformRangeMarkers(e); + } + + private void transformRangeMarkers(DocumentEvent e) { VirtualFile file = fileDocumentManager.getFile(e.getDocument()); if (file == null) { return; @@ -58,8 +67,7 @@ public class LazyRangeMarkerFactory { List markers = lazyMarkers.toStrongList(); List markersToRemove = null; for (LazyMarker marker : markers) { - if (file.equals(marker.getFile())) { - marker.getOrCreateDelegate(); + if (file.equals(marker.getFile()) && marker.documentChanged(e.getDocument()) != null) { if (markersToRemove == null) { markersToRemove = new SmartList(); } @@ -143,13 +151,26 @@ public class LazyRangeMarkerFactory { return myDelegate; } - @NotNull + @Nullable + protected final RangeMarker documentChanged(@NotNull Document document) { + if (myDelegate == null) { + myDelegate = createDelegate(myFile, document); + } + return myDelegate; + } + + @Nullable protected abstract RangeMarker createDelegate(@NotNull VirtualFile file, @NotNull Document document); @Override @NotNull public Document getDocument() { - return getOrCreateDelegate().getDocument(); + RangeMarker delegate = getOrCreateDelegate(); + if (delegate == null) { + //noinspection ConstantConditions + return FileDocumentManager.getInstance().getDocument(myFile); + } + return delegate.getDocument(); } @Override @@ -222,10 +243,13 @@ public class LazyRangeMarkerFactory { } @Override - @NotNull - public RangeMarker createDelegate(@NotNull VirtualFile file, @NotNull final Document document) { - int offset = calculateOffset(myProject, file, document, myLine, myColumn); + @Nullable + public RangeMarker createDelegate(@NotNull VirtualFile file, @NotNull Document document) { + if (document.getTextLength() == 0 && !(myLine == 0 && myColumn == 0)) { + return null; + } + int offset = calculateOffset(myProject, file, document, myLine, myColumn); return document.createRangeMarker(offset, offset); } diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java index bce1a97ccdae..456e7fcfd19b 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java @@ -69,6 +69,7 @@ import javax.xml.parsers.SAXParserFactory; import java.awt.*; import java.awt.event.MouseEvent; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; import java.net.URL; import java.util.*; @@ -329,6 +330,9 @@ public abstract class PluginManagerMain implements Disposable { } catch (ProcessCanceledException ignore) { } + catch (FileNotFoundException e) { + LOG.info(e); + } catch (Exception e) { LOG.info(e); errorMessages.add(e.getMessage()); diff --git a/platform/platform-impl/src/com/intellij/ide/startupWizardV2/FeaturedPluginsPage.java b/platform/platform-impl/src/com/intellij/ide/startupWizardV2/FeaturedPluginsPage.java deleted file mode 100644 index 12aac3dd61e4..000000000000 --- a/platform/platform-impl/src/com/intellij/ide/startupWizardV2/FeaturedPluginsPage.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2000-2014 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.ide.startupWizardV2; - -import com.intellij.CommonBundle; -import org.jetbrains.annotations.NotNull; - -public class FeaturedPluginsPage extends AbstractWizardPage{ - @NotNull - @Override - String getID() { - return "Featured plugins"; - } - - @NotNull - @Override - String getTitle() { - return "Download featured plugins"; - } - - @NotNull - @Override - String getHeader() { - return "We have a few plugins in our web repository that most users like to download. Perhaps, you need them too?"; - } - - @NotNull - @Override - String getFooter() { - return "New plugins can be also downloaded in " + CommonBundle.settingsTitle() +" | Plugins"; - } -} diff --git a/platform/platform-impl/src/com/intellij/ide/startupWizardV2/LafPage.java b/platform/platform-impl/src/com/intellij/ide/startupWizardV2/LafPage.java deleted file mode 100644 index bee68fb93411..000000000000 --- a/platform/platform-impl/src/com/intellij/ide/startupWizardV2/LafPage.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2000-2014 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.ide.startupWizardV2; - -import com.intellij.CommonBundle; -import com.intellij.ide.ui.laf.IntelliJLookAndFeelInfo; -import com.intellij.ide.ui.laf.darcula.DarculaLookAndFeelInfo; -import com.intellij.openapi.util.IconLoader; -import com.intellij.openapi.util.SystemInfo; -import com.intellij.util.IconUtil; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; -import java.awt.*; -import java.util.LinkedHashMap; -import java.util.Map; - -public class LafPage extends AbstractWizardPage { - private static final String AQUA = "Default"; - private static final String DARCULA = "Darcula"; - private static final String ALLOY = "Alloy. IDEA Theme"; - private static final String INTELLIJ = "IntelliJ"; - private static final String GTK = "GTK+"; - - private Map myLafs = new LinkedHashMap(); - private final JLabel myPreviewLabel = new JLabel(); - private final boolean myVertical; - - public LafPage() { - boolean isAlloyAvailable = false; - boolean isGTKAvailable = false; - for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { - if (ALLOY.equals(info.getName())) { - isAlloyAvailable = true; - } - if (GTK.equals(info.getName())) { - isGTKAvailable = true; - } - } - final String osPrefix = SystemInfo.isMac ? "OSX" : SystemInfo.isWindows ? "Windows" : "Linux"; - - if (SystemInfo.isMac) { - myLafs.put(new UIManager.LookAndFeelInfo(AQUA, "com.apple.laf.AquaLookAndFeel"), IconLoader.getIcon("/lafs/OSXAqua.png")); - } - else { - if (isAlloyAvailable) { - myLafs.put(new UIManager.LookAndFeelInfo(ALLOY, "com.incors.plaf.alloy.AlloyIdea"), - IconLoader.getIcon("/lafs/" + osPrefix + "Alloy.png")); - } - else { - myLafs.put(new IntelliJLookAndFeelInfo(), IconLoader.getIcon("/lafs/" + osPrefix + "IntelliJ.png")); - } - } - - myLafs.put(new DarculaLookAndFeelInfo(), IconLoader.getIcon("/lafs/" + osPrefix + "Darcula.png")); - - if (SystemInfo.isLinux && isGTKAvailable) { - myLafs.put(new UIManager.LookAndFeelInfo(GTK, "com.sun.java.swing.plaf.gtk.GTKLookAndFeel"), - IconLoader.getIcon("/lafs/" + osPrefix + "GTK.png")); - } - - myVertical = myLafs.size() > 2; - JPanel buttonPanel = new JPanel(myVertical ? new GridLayout(myLafs.size(), 1, 5, 5) : new GridLayout(1, myLafs.size(), 5, 5)); - ButtonGroup group = new ButtonGroup(); - boolean isFirst = true; - for (Map.Entry entry : myLafs.entrySet()) { - JPanel p = new JPanel(new BorderLayout()); - JRadioButton radioButton = new JRadioButton(entry.getKey().getName(), isFirst); - isFirst = false; - group.add(radioButton); - p.add(radioButton, BorderLayout.NORTH); - Icon icon = entry.getValue(); - buttonPanel.add(new JLabel(myVertical ? - new ImageIcon(IconUtil.toImage(icon) - .getScaledInstance(icon.getIconWidth() / 3, icon.getIconHeight() / 3, Image.SCALE_AREA_AVERAGING)) - : icon)); - } - setLayout(new BorderLayout()); - add(buttonPanel, BorderLayout.CENTER); - if (myVertical) { - add(myPreviewLabel, BorderLayout.EAST); - } - } - - @NotNull - @Override - String getTitle() { - return "Set UI Theme"; - } - - @NotNull - @Override - String getID() { - return "UI Themes"; - } - - @NotNull - @Override - String getFooter() { - return "UI theme can be changed later in " + CommonBundle.settingsTitle() + " | Appearance."; - } -} diff --git a/platform/platform-impl/src/com/intellij/ide/startupWizardV2/PluginsPage.java b/platform/platform-impl/src/com/intellij/ide/startupWizardV2/PluginsPage.java deleted file mode 100644 index 1e27ad49ea7a..000000000000 --- a/platform/platform-impl/src/com/intellij/ide/startupWizardV2/PluginsPage.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2000-2014 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.ide.startupWizardV2; - -import com.intellij.openapi.application.ApplicationNamesInfo; -import org.jetbrains.annotations.NotNull; - -public class PluginsPage extends AbstractWizardPage { - @NotNull - @Override - String getID() { - return "Default plugins"; - } - - @NotNull - @Override - String getTitle() { - return "Tune " + ApplicationNamesInfo.getInstance().getProductName() + " to your tasks"; - } - - @NotNull - @Override - String getHeader() { - return ApplicationNamesInfo.getInstance().getProductName() + " has a lot of tools enabled by default. You can set only the ones you need or leave them all."; - } -} diff --git a/platform/platform-impl/src/com/intellij/ide/startupWizardV2/StartupWizard2.java b/platform/platform-impl/src/com/intellij/ide/startupWizardV2/StartupWizard2.java deleted file mode 100644 index 89cbfbf71fbc..000000000000 --- a/platform/platform-impl/src/com/intellij/ide/startupWizardV2/StartupWizard2.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2000-2014 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.ide.startupWizardV2; - -import com.intellij.openapi.application.ApplicationNamesInfo; -import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.ui.VerticalFlowLayout; -import com.intellij.openapi.util.IconLoader; -import com.intellij.ui.JBCardLayout; -import com.intellij.ui.components.JBScrollPane; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import javax.swing.border.EmptyBorder; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.Arrays; -import java.util.List; - -public class StartupWizard2 extends DialogWrapper implements ActionListener { - - private final JLabel myNavLabel = new JLabel(); - private final JLabel myHeaderLabel = new JLabel(); - private final JLabel myFooterLabel = new JLabel(); - private final JBCardLayout myCardLayout = new JBCardLayout(); - private final JPanel myContentPanel = new JPanel(myCardLayout); - - private final JButton mySkipButton = new JButton(); - private final JButton myBackwardButton = new JButton(); - private final JButton myForwardButton = new JButton(); - - private List myPages = Arrays.asList(new LafPage(), new KeymapPage(), new PluginsPage(), new FeaturedPluginsPage()); - private int myIndex = -1; - - public StartupWizard2() { - super(null, true, true); - IconLoader.activate(); - getPeer().setAppIcons(); - setResizable(false); - setTitle("Customize" + ApplicationNamesInfo.getInstance().getProductName()); - init(); - showPage(0); - } - - @Override - protected void dispose() { - super.dispose(); - IconLoader.deactivate(); - } - - @Override - public Dimension getPreferredSize() { - return new Dimension(700, 700); - } - - @Override - public void actionPerformed(ActionEvent event) { - if (event.getSource() == mySkipButton) { - doOKAction(); - } - if (event.getSource() == myBackwardButton) { - showPage(myIndex - 1); - } - if (event.getSource() == myForwardButton) { - if (myIndex == myPages.size() - 1) { - doOKAction(); - } - else { - showPage(myIndex + 1); - } - } - } - - private void showPage(int index) { - myIndex = index; - AbstractWizardPage page = myPages.get(index); - myCardLayout.swipe(myContentPanel, page.getID(), JBCardLayout.SwipeDirection.AUTO); - updateNavLabel(); - myHeaderLabel.setText("

" + page.getTitle() + "

" + page.getHeader() + ""); - myFooterLabel.setText("" + page.getFooter() + ""); - mySkipButton.setText(myIndex>0?"Skip All and Set Defaults" : "Skip Remaining and Set Defaults"); - myBackwardButton.setVisible(myIndex>0); - if (myIndex > 0) { - myBackwardButton.setText("Back to " + myPages.get(myIndex-1).getID()); - } - myForwardButton.setText(myIndex < myPages.size() - 1 ? "Next: " + myPages.get(myIndex+1).getID() : "Start using " + ApplicationNamesInfo - .getInstance().getFullProductName()); - } - - private void updateNavLabel() { - StringBuilder sb = new StringBuilder(""); - for (int i = 0; i < myPages.size(); i++) { - AbstractWizardPage wizardPage = myPages.get(i); - if (i > 0 && i < myPages.size() - 1) sb.append(" → "); - if (i == myIndex) sb.append(""); - sb.append(wizardPage.getID()); - if (i == myIndex) sb.append(""); - } - sb.append(""); - myNavLabel.setText(sb.toString()); - } - - - @Nullable - @Override - protected JComponent createCenterPanel() { - for (AbstractWizardPage page : myPages) { - myContentPanel.add(page, page.getID()); - } - JPanel mainPanel = new JPanel(new VerticalFlowLayout()); - mainPanel.add(myNavLabel); - mainPanel.add(myHeaderLabel); - mainPanel.add( - new JBScrollPane(myContentPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER)); - mainPanel.add(myFooterLabel); - return mainPanel; - } - - @Nullable - @Override - protected JComponent createSouthPanel() { - JPanel result = new JPanel(new GridBagLayout()); - result.setBorder(new EmptyBorder(5, 5, 5, 5)); - GridBagConstraints gbc = new GridBagConstraints(); - gbc.gridy = 0; - result.add(mySkipButton, gbc); - result.add(myBackwardButton, gbc); - gbc.weightx = 1; - result.add(Box.createHorizontalGlue(), gbc); - gbc.weightx = 0; - result.add(myForwardButton, gbc); - - mySkipButton.addActionListener(this); - myBackwardButton.addActionListener(this); - myForwardButton.addActionListener(this); - - return result; - } -} diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarFileSystemImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarFileSystemImpl.java index e86ea895cd9b..6c7f26d6ecea 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarFileSystemImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarFileSystemImpl.java @@ -18,7 +18,6 @@ package com.intellij.openapi.vfs.impl.jar; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.application.PathManager; -import com.intellij.openapi.components.ApplicationComponent; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileAttributes; import com.intellij.openapi.util.io.FileUtil; @@ -44,7 +43,7 @@ import java.util.List; import java.util.Map; import java.util.Set; -public class JarFileSystemImpl extends JarFileSystem implements ApplicationComponent { +public class JarFileSystemImpl extends JarFileSystem { private static final class JarFileSystemImplLock { } private static final JarFileSystemImplLock LOCK = new JarFileSystemImplLock(); @@ -125,18 +124,6 @@ public class JarFileSystemImpl extends JarFileSystem implements ApplicationCompo return null; } - @Override - @NotNull - public String getComponentName() { - return "JarFileSystem"; - } - - @Override - public void initComponent() { } - - @Override - public void disposeComponent() { } - @Override public void setNoCopyJarForPath(String pathInJar) { if (myNoCopyJarPaths == null || pathInJar == null) return; diff --git a/platform/platform-impl/src/com/intellij/util/io/socketConnection/ConnectionStatus.java b/platform/platform-impl/src/com/intellij/util/io/socketConnection/ConnectionStatus.java index cad91b35802d..1c4fd2a664e6 100644 --- a/platform/platform-impl/src/com/intellij/util/io/socketConnection/ConnectionStatus.java +++ b/platform/platform-impl/src/com/intellij/util/io/socketConnection/ConnectionStatus.java @@ -3,11 +3,16 @@ package com.intellij.util.io.socketConnection; import org.jetbrains.annotations.NotNull; public enum ConnectionStatus { - NOT_CONNECTED("Not connected"), WAITING_FOR_CONNECTION("Waiting for connection"), CONNECTED("Connected"), DISCONNECTED("Disconnected"), - CONNECTION_FAILED("Connection failed"); + NOT_CONNECTED("Not connected"), + WAITING_FOR_CONNECTION("Waiting for connection"), + CONNECTED("Connected"), + DISCONNECTED("Disconnected"), + CONNECTION_FAILED("Connection failed"), + DETACHED("Detached"); + private final String myStatusText; - ConnectionStatus(String statusText) { + ConnectionStatus(@NotNull String statusText) { myStatusText = statusText; } diff --git a/platform/platform-resources-en/src/messages/ExecutionBundle.properties b/platform/platform-resources-en/src/messages/ExecutionBundle.properties index 5776b6b664b2..407e5176c629 100644 --- a/platform/platform-resources-en/src/messages/ExecutionBundle.properties +++ b/platform/platform-resources-en/src/messages/ExecutionBundle.properties @@ -16,7 +16,7 @@ home.directory.not.specified.for.jdk.error.message=Home directory is not specifi run.configuration.pause.output.action.name=Pause Output main.class.is.not.specified.error.message=Main class is not specified close.tab.action.name=Close -run.configuration.show.command.line.action.name=Show command line +run.configuration.show.command.line.action.name=Show Python Prompt #--- create.run.configuration.action.name=Create Run Configuration diff --git a/platform/platform-impl/src/com/intellij/ide/startupWizardV2/KeymapPage.java b/platform/platform-tests/testSrc/com/intellij/codeInsight/actions/ChangedLines.java similarity index 58% rename from platform/platform-impl/src/com/intellij/ide/startupWizardV2/KeymapPage.java rename to platform/platform-tests/testSrc/com/intellij/codeInsight/actions/ChangedLines.java index 2bcf1a091c5e..35c02e5bb904 100644 --- a/platform/platform-impl/src/com/intellij/ide/startupWizardV2/KeymapPage.java +++ b/platform/platform-tests/testSrc/com/intellij/codeInsight/actions/ChangedLines.java @@ -13,27 +13,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.ide.startupWizardV2; +package com.intellij.codeInsight.actions; -import com.intellij.CommonBundle; -import org.jetbrains.annotations.NotNull; +public class ChangedLines { + public final int from; + public final int to; -public class KeymapPage extends AbstractWizardPage { - @NotNull - @Override - String getID() { - return "Keymaps"; + ChangedLines(int from, int to) { + this.from = from; + this.to = to; } - @NotNull @Override - String getTitle() { - return "Select keymap scheme"; + public String toString() { + return "(" + from + ", " + to + ")"; } - @NotNull @Override - String getFooter() { - return "Keymap scheme can be later changed in " + CommonBundle.settingsTitle() + " | Keymap"; + public boolean equals(Object obj) { + if (obj instanceof ChangedLines) { + ChangedLines line = (ChangedLines)obj; + return from == line.from && to == line.to; + } + + return false; } } diff --git a/platform/platform-tests/testSrc/com/intellij/codeInsight/actions/MockCodeStyleManager.java b/platform/platform-tests/testSrc/com/intellij/codeInsight/actions/MockCodeStyleManager.java new file mode 100644 index 000000000000..1b3771fe3c10 --- /dev/null +++ b/platform/platform-tests/testSrc/com/intellij/codeInsight/actions/MockCodeStyleManager.java @@ -0,0 +1,172 @@ +/* + * Copyright 2000-2014 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.codeInsight.actions; + +import com.intellij.lang.ASTNode; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.psi.codeStyle.Indent; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.ThrowableRunnable; +import com.intellij.util.containers.HashMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Map; + +public class MockCodeStyleManager extends CodeStyleManager { + private Map myFormattedLinesForFile = new HashMap(); + + @NotNull + public ChangedLines[] getFormattedLinesFor(@NotNull PsiFile file) { + ChangedLines[] changedLines = myFormattedLinesForFile.get(file); + return changedLines != null ? changedLines : new ChangedLines[0]; + } + + @Override + public void reformatText(@NotNull PsiFile file, @NotNull Collection ranges) throws IncorrectOperationException { + Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file); + assert(document != null); + + ChangedLines[] formattedLines = new ChangedLines[ranges.size()]; + int i = 0; + for (TextRange range : ranges) { + int lineStart = document.getLineNumber(range.getStartOffset()); + int lineEnd = document.getLineNumber(range.getEndOffset()); + formattedLines[i++] = new ChangedLines(lineStart, lineEnd); + } + + myFormattedLinesForFile.put(file, formattedLines); + } + + @NotNull + @Override + public Project getProject() { + throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.getProject(...)"); + } + + @NotNull + @Override + public PsiElement reformat(@NotNull PsiElement element) throws IncorrectOperationException { + throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.reformat(...)"); + } + + @NotNull + @Override + public PsiElement reformat(@NotNull PsiElement element, boolean canChangeWhiteSpacesOnly) throws IncorrectOperationException { + throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.reformat(...)"); + } + + @Override + public PsiElement reformatRange(@NotNull PsiElement element, int startOffset, int endOffset) throws IncorrectOperationException { + throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.reformatRange(...)"); + } + + @Override + public PsiElement reformatRange(@NotNull PsiElement element, int startOffset, int endOffset, boolean canChangeWhiteSpacesOnly) + throws IncorrectOperationException { + throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.reformatRange(...)"); + } + + @Override + public void reformatText(@NotNull PsiFile file, int startOffset, int endOffset) throws IncorrectOperationException { + throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.reformatText(...)"); + } + + @Override + public void adjustLineIndent(@NotNull PsiFile file, TextRange rangeToAdjust) throws IncorrectOperationException { + throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.adjustLineIndent(...)"); + } + + @Override + public int adjustLineIndent(@NotNull PsiFile file, int offset) throws IncorrectOperationException { + throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.adjustLineIndent(...)"); + } + + @Override + public int adjustLineIndent(@NotNull Document document, int offset) { + throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.adjustLineIndent(...)"); + } + + @Override + public boolean isLineToBeIndented(@NotNull PsiFile file, int offset) { + throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.isLineToBeIndented(...)"); + } + + @Nullable + @Override + public String getLineIndent(@NotNull PsiFile file, int offset) { + throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.getLineIndent(...)"); + } + + @Nullable + @Override + public String getLineIndent(@NotNull Document document, int offset) { + throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.getLineIndent(...)"); + } + + @Override + public Indent getIndent(String text, FileType fileType) { + throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.getIndent(...)"); + } + + @Override + public String fillIndent(Indent indent, FileType fileType) { + throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.fillIndent(...)"); + } + + @Override + public Indent zeroIndent() { + throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.zeroIndent(...)"); + } + + @Override + public void reformatNewlyAddedElement(@NotNull ASTNode block, @NotNull ASTNode addedElement) + throws IncorrectOperationException { + throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.reformatNewlyAddedElement(...)"); + } + + @Override + public boolean isSequentialProcessingAllowed() { + throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockCodeStyleManager.isSequentialProcessingAllowed(...)"); + } + + @Override + public void performActionWithFormatterDisabled(Runnable r) { + throw new UnsupportedOperationException( + "com.intellij.codeInsight.actions.MockCodeStyleManager.performActionWithFormatterDisabled(...)"); + } + + @Override + public void performActionWithFormatterDisabled(ThrowableRunnable r) throws T { + throw new UnsupportedOperationException( + "com.intellij.codeInsight.actions.MockCodeStyleManager.performActionWithFormatterDisabled(...)"); + } + + @Override + public T performActionWithFormatterDisabled(Computable r) { + throw new UnsupportedOperationException( + "com.intellij.codeInsight.actions.MockCodeStyleManager.performActionWithFormatterDisabled(...)"); + } +} diff --git a/platform/platform-tests/testSrc/com/intellij/codeInsight/actions/MockPlainTextFormattingModelBuilder.java b/platform/platform-tests/testSrc/com/intellij/codeInsight/actions/MockPlainTextFormattingModelBuilder.java new file mode 100644 index 000000000000..fb98cb52f52e --- /dev/null +++ b/platform/platform-tests/testSrc/com/intellij/codeInsight/actions/MockPlainTextFormattingModelBuilder.java @@ -0,0 +1,46 @@ +/* + * Copyright 2000-2014 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.codeInsight.actions; + +import com.intellij.formatting.CustomFormattingModelBuilder; +import com.intellij.formatting.FormattingModel; +import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.codeStyle.CodeStyleSettings; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class MockPlainTextFormattingModelBuilder implements CustomFormattingModelBuilder { + + @Override + public boolean isEngagedToFormat(PsiElement context) { + return true; + } + + @NotNull + @Override + public FormattingModel createModel(PsiElement element, CodeStyleSettings settings) { + throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockPlainTextFormattingModelBuilder.createModel(...)"); + } + + @Nullable + @Override + public TextRange getRangeAffectingIndent(PsiFile file, int offset, ASTNode elementAtOffset) { + throw new UnsupportedOperationException("com.intellij.codeInsight.actions.MockPlainTextFormattingModelBuilder.getRangeAffectingIndent(...)"); + } +} diff --git a/platform/platform-tests/testSrc/com/intellij/codeInsight/actions/ReformatOnlyVcsChangedTextTest.java b/platform/platform-tests/testSrc/com/intellij/codeInsight/actions/ReformatOnlyVcsChangedTextTest.java new file mode 100644 index 000000000000..476bd66ddde4 --- /dev/null +++ b/platform/platform-tests/testSrc/com/intellij/codeInsight/actions/ReformatOnlyVcsChangedTextTest.java @@ -0,0 +1,339 @@ +/* + * Copyright 2000-2014 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.codeInsight.actions; + +import com.intellij.lang.LanguageFormatting; +import com.intellij.openapi.components.impl.ComponentManagerImpl; +import com.intellij.openapi.fileTypes.PlainTextLanguage; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.FilePathImpl; +import com.intellij.openapi.vcs.changes.Change; +import com.intellij.openapi.vcs.changes.ChangeListManager; +import com.intellij.openapi.vcs.changes.ContentRevision; +import com.intellij.openapi.vcs.changes.SimpleContentRevision; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiFile; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.testFramework.LightPlatformTestCase; +import com.intellij.testFramework.PlatformTestCase; +import com.intellij.testFramework.vcs.MockChangeListManager; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.picocontainer.MutablePicoContainer; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; + +public class ReformatOnlyVcsChangedTextTest extends LightPlatformTestCase { + private static final String TEMP_DIR_NAME = "dir"; + private PsiDirectory myWorkingDirectory; + + private MockChangeListManager myMockChangeListManager; + private MockCodeStyleManager myMockCodeStyleManager; + private MockPlainTextFormattingModelBuilder myMockPlainTextFormattingModelBuilder; + + private ChangeListManager myRealChangeListManager; + private CodeStyleManager myRealCodeStyleManger; + + private final static String COMMITTED = + "class Test {\n" + + " int a = 22;\n" + + " public String getName() { return \"Test\"; }\n" + + "}"; + + private final static String MODIFIED = + "class Test {\n" + + " int a = 22;\n" + + " long l;\n" + + " double d;\n" + + " int i;\n" + + " public String getName() { return \"Test\"; }\n" + + " String test1;\n" + + " String test2;\n" + + "}"; + + private final static ChangedLines[] CHANGED_LINES = new ChangedLines[] { line(2, 4), line(6, 7) }; + private final static ChangedLines[] NO_CHANGED_LINES = new ChangedLines[0]; + + @Override + public void setUp() throws Exception { + PlatformTestCase.initPlatformLangPrefix(); + super.setUp(); + myWorkingDirectory = TestFileStructure.createDirectory(getProject(), getSourceRoot(), TEMP_DIR_NAME); + + myRealChangeListManager = ChangeListManager.getInstance(getProject()); + myMockChangeListManager = new MockChangeListManager(); + registerChangeListManager(myMockChangeListManager); + + myRealCodeStyleManger = CodeStyleManager.getInstance(getProject()); + myMockCodeStyleManager = new MockCodeStyleManager(); + registerCodeStyleManager(myMockCodeStyleManager); + + myMockPlainTextFormattingModelBuilder = new MockPlainTextFormattingModelBuilder(); + LanguageFormatting.INSTANCE.addExplicitExtension(PlainTextLanguage.INSTANCE, myMockPlainTextFormattingModelBuilder); + } + + @Override + public void tearDown() throws Exception { + registerChangeListManager(myRealChangeListManager); + registerCodeStyleManager(myRealCodeStyleManger); + LanguageFormatting.INSTANCE.removeExplicitExtension(PlainTextLanguage.INSTANCE, myMockPlainTextFormattingModelBuilder); + + TestFileStructure.delete(myWorkingDirectory.getVirtualFile()); + super.tearDown(); + } + + public void testInsertion() throws IOException { + doTest( + "public class B {\n" + + " int a = 3;\n" + + " String text;\n" + + " Object last = null;\n" + + "}", + + "public class B {\n" + + " int a = 3;\n" + + " int toIndent1 = 1;\n" + + " String text;\n" + + " int toIndent2\n" + + " Object last = null;\n" + + "}", + + line(2, 2), line(4, 4) + ); + } + + private static ChangedLines line(int from, int to) { + return new ChangedLines(from, to); + } + + public void testDeletion() throws IOException { + doTest( + "public class B {\n" + + " int a = 3;\n" + + " String text;\n" + + " Object last = null;\n" + + " Object first = null;\n" + + " Object second = null;\n" + + "}", + + "public class B {\n" + + " int newInt = 1;\n" + + " Object last = null;\n" + + "}", + + line(1, 1) + ); + } + + public void testModification() throws IOException { + doTest( + "public class B {\n" + + " int a = 3;\n" + + " String text;\n" + + " Object last = null;\n" + + " Object first = null;\n" + + " Object second = null;\n" + + "}", + + "public class B {\n" + + " int a = 33;\n" + + " String text;\n" + + " Object last = new Object();\n" + + " Object first = null;\n" + + " Object second = new Object();\n" + + "}", + + line(1, 1), line(3,3), line(5,5) + ); + } + + public void testReformatFiles() throws IOException { + ChangedFilesStructure fs = new ChangedFilesStructure(myWorkingDirectory); + + PsiFile m1 = fs.createFile("Test1.java", COMMITTED, MODIFIED); + PsiFile u1 = fs.createFile("Test2.java", COMMITTED, COMMITTED); + + fs.createDirectoryAndMakeItCurrent(); + PsiFile m2 = fs.createFile("Test3.java", COMMITTED, MODIFIED); + PsiFile u2 = fs.createFile("Test4.java", COMMITTED, COMMITTED); + + new ReformatCodeProcessor(getProject(), new PsiFile[] {m1, m2, u1, u2}, null, true).run(); + + assertFormattedLines(CHANGED_LINES, m1, m2); + assertFormattedLines(NO_CHANGED_LINES, u1, u2); + } + + public void testNoChangesNoFormatting() throws IOException { + ChangedFilesStructure fs = new ChangedFilesStructure(myWorkingDirectory); + + PsiFile u1 = fs.createFile("Test1.java", COMMITTED, COMMITTED); + PsiFile u2 = fs.createFile("Test2.java", COMMITTED, COMMITTED); + + reformatDirectory(fs.getCurrentDirectory()); + + assertFormattedLines(NO_CHANGED_LINES, u1, u2); + } + + + public void testReformatOnlyChanged() throws IOException { + ChangedFilesStructure fs = new ChangedFilesStructure(myWorkingDirectory); + + PsiFile untouched1 = fs.createFile("Test1.java", COMMITTED, COMMITTED); + PsiFile untouched2 = fs.createFile("Test2.java", COMMITTED, COMMITTED); + + PsiFile modified1 = fs.createFile("Test4.java", COMMITTED, MODIFIED); + PsiFile modified2 = fs.createFile("Test5.java", COMMITTED, MODIFIED); + PsiFile modified3 = fs.createFile("Test6.java", COMMITTED, MODIFIED); + + reformatDirectory(fs.getCurrentDirectory()); + + + assertFormattedLines(CHANGED_LINES, modified1, modified2, modified3); + assertFormattedLines(NO_CHANGED_LINES, untouched1, untouched2); + } + + public void testReformatInAllSubtree() throws IOException { + ChangedFilesStructure fs = new ChangedFilesStructure(myWorkingDirectory); + PsiFile modified11 = fs.createFile("Test4.java", COMMITTED, MODIFIED); + PsiFile modified12 = fs.createFile("Test5.java", COMMITTED, MODIFIED); + + fs.createDirectoryAndMakeItCurrent(); + PsiDirectory dirToReformat = fs.getCurrentDirectory(); + PsiFile modified21 = fs.createFile("Test6.java", COMMITTED, MODIFIED); + PsiFile modified22 = fs.createFile("Test7.java", COMMITTED, MODIFIED); + + fs.createDirectoryAndMakeItCurrent(); + PsiFile modified31 = fs.createFile("Test8.java", COMMITTED, MODIFIED); + PsiFile modified32 = fs.createFile("Test9.java", COMMITTED, MODIFIED); + + reformatDirectory(dirToReformat); + + assertFormattedLines(CHANGED_LINES, modified21, modified22, modified31, modified32); + assertFormattedLines(NO_CHANGED_LINES, modified11, modified12); + } + + private static void registerChangeListManager(@NotNull ChangeListManager manager) { + Project project = getProject(); + assert (project instanceof ComponentManagerImpl); + ComponentManagerImpl projectComponentManager = (ComponentManagerImpl)project; + projectComponentManager.registerComponentInstance(ChangeListManager.class, manager); + } + + private static void registerCodeStyleManager(@NotNull CodeStyleManager manager) { + String componentKey = CodeStyleManager.class.getName(); + MutablePicoContainer container = (MutablePicoContainer)getProject().getPicoContainer(); + container.unregisterComponent(componentKey); + container.registerComponentInstance(componentKey, manager); + } + + private void doTest(@NotNull String committed, @NotNull String modified, @NotNull ChangedLines... lines) throws IOException { + ChangedFilesStructure fs = new ChangedFilesStructure(myWorkingDirectory); + PsiFile file = fs.createFile("Test.java", committed, modified); + reformatDirectory(myWorkingDirectory); + assertFormattedRangesEqualsTo(file, lines); + } + + private void assertFormattedLines(@NotNull ChangedLines[] expectedLines, @NotNull PsiFile... files) { + for (PsiFile file : files) + assertFormattedRangesEqualsTo(file, expectedLines); + } + + private void assertFormattedRangesEqualsTo(@NotNull PsiFile file, ChangedLines... expected) { + ChangedLines[] formatted = myMockCodeStyleManager.getFormattedLinesFor(file); + + Comparator cmp = new Comparator() { + @Override + public int compare(ChangedLines o1, ChangedLines o2) { + return o1.from < o2.from ? -1 : 1; + } + }; + Arrays.sort(expected, cmp); + Arrays.sort(formatted, cmp); + + assertTrue(getErrorMessage(expected, formatted), Arrays.equals(expected, formatted)); + } + + @NotNull + private static String getErrorMessage(ChangedLines[] expected, ChangedLines[] actual) { + return "Expected: " + Arrays.toString(expected) + " Actual: " + Arrays.toString(actual); + } + + private static void reformatDirectory(@NotNull PsiDirectory dir) { + ReformatCodeProcessor processor = new ReformatCodeProcessor(getProject(), dir, true, true); + processor.run(); + } + + class ChangedFilesStructure { + private TestFileStructure myFileStructure; + + public ChangedFilesStructure(@NotNull PsiDirectory directory) { + myFileStructure = new TestFileStructure(getModule(), directory); + } + + public void createDirectoryAndMakeItCurrent() throws IOException { + myFileStructure.createDirectoryAndMakeItCurrent("inner"); + } + + @NotNull + public PsiFile createFile(@NotNull String fileName, + @NotNull String committedContent, + @NotNull String actualContent) throws IOException + { + PsiFile file = myFileStructure.addTestFile(fileName, actualContent); + if (committedContent != actualContent) { + registerCommittedRevision(committedContent, file); + } + return file; + } + + private void registerCommittedRevision(@NotNull String committedContent, @NotNull PsiFile... files) { + List changes = createChanges(committedContent, files); + injectChanges(changes); + } + + @NotNull + private List createChanges(@NotNull String committed, @NotNull PsiFile... files) { + List changes = ContainerUtil.newArrayList(); + for (PsiFile file : files) { + changes.add(createChange(committed, file)); + } + return changes; + } + + private void injectChanges(@NotNull List changes) { + Change[] arr = new Change[changes.size()]; + ContainerUtil.toArray(changes, arr); + myMockChangeListManager.addChanges(arr); + } + + @NotNull + private Change createChange(@NotNull String committed, @NotNull PsiFile file) { + FilePathImpl filePath = new FilePathImpl(file.getVirtualFile()); + ContentRevision before = new SimpleContentRevision(committed, filePath, ""); + ContentRevision after = new SimpleContentRevision("", filePath, ""); + return new Change(before, after); + } + + @NotNull + public PsiDirectory getCurrentDirectory() { + return myFileStructure.getCurrentDirectory(); + } + } +} + diff --git a/platform/platform-tests/testSrc/com/intellij/codeInsight/actions/TestFileStructure.java b/platform/platform-tests/testSrc/com/intellij/codeInsight/actions/TestFileStructure.java new file mode 100644 index 000000000000..6dbe45689332 --- /dev/null +++ b/platform/platform-tests/testSrc/com/intellij/codeInsight/actions/TestFileStructure.java @@ -0,0 +1,128 @@ +/* + * Copyright 2000-2014 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.codeInsight.actions; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.Result; +import com.intellij.openapi.application.WriteAction; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import com.intellij.psi.impl.file.PsiDirectoryFactory; +import com.intellij.testFramework.PsiTestUtil; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class TestFileStructure { + private int myLevel; + @NotNull private Project myProject; + @NotNull private Module myModule; + @NotNull private PsiDirectory myCurrentLevelDirectory; + private List> myFilesForLevel = new ArrayList>(); + + public TestFileStructure(@NotNull Module module, @NotNull PsiDirectory root) { + myProject = module.getProject(); + myModule = module; + myCurrentLevelDirectory = root; + myFilesForLevel.add(new ArrayList()); + myLevel = 0; + } + + @NotNull + public PsiFile addTestFile(@NotNull String name, @NotNull String content) throws IOException { + PsiFile createdFile = createFile(myModule, myCurrentLevelDirectory.getVirtualFile(), name, content); + getCurrentDirectoryFiles().add(createdFile); + return createdFile; + } + + @NotNull + public List getCurrentDirectoryFiles() { + return myFilesForLevel.get(myLevel); + } + + @NotNull + public PsiDirectory getCurrentDirectory() { + return myCurrentLevelDirectory; + } + + @NotNull + public TestFileStructure createDirectoryAndMakeItCurrent(String name) throws IOException { + myLevel++; + myFilesForLevel.add(new ArrayList()); + myCurrentLevelDirectory = createDirectory(myProject, myCurrentLevelDirectory.getVirtualFile(), name); + return this; + } + + public List getFilesAtLevel(int level) { + assert (myLevel >= level); + return myFilesForLevel.get(level); + } + + private PsiFile createFile(final Module module, final VirtualFile vDir, final String fileName, final String text) { + return new WriteAction() { + @Override + protected void run(@NotNull Result result) throws Throwable { + if (!ModuleRootManager.getInstance(module).getFileIndex().isInSourceContent(vDir)) { + PsiTestUtil.addSourceContentToRoots(module, vDir); + } + + final VirtualFile vFile = vDir.createChildData(vDir, fileName); + VfsUtil.saveText(vFile, text); + final PsiFile file = PsiManager.getInstance(myProject).findFile(vFile); + assert (file != null); + result.setResult(file); + } + }.execute().getResultObject(); + } + + public static PsiDirectory createDirectory(@NotNull Project project, @NotNull final VirtualFile parent, @NotNull final String name) throws IOException { + final VirtualFile[] dir = new VirtualFile[1]; + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + try { + dir[0] = parent.createChildDirectory(null, name); + } + catch (IOException e) { + e.printStackTrace(); + } + } + }); + return PsiDirectoryFactory.getInstance(project).createDirectory(dir[0]); + } + + public static void delete(@NotNull final VirtualFile file) { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + try { + file.delete(null); + } + catch (IOException e) { + e.printStackTrace(); + } + } + }); + } +} diff --git a/platform/script-debugger/backend/src/org/jetbrains/debugger/BreakpointBase.java b/platform/script-debugger/backend/src/org/jetbrains/debugger/BreakpointBase.java index 90974e03e594..2335b0973c26 100644 --- a/platform/script-debugger/backend/src/org/jetbrains/debugger/BreakpointBase.java +++ b/platform/script-debugger/backend/src/org/jetbrains/debugger/BreakpointBase.java @@ -78,7 +78,7 @@ public abstract class BreakpointBase extends Breakpoint { return this; } enabled = value; - dirty = true; + dirty = true; return this; } diff --git a/platform/script-debugger/backend/src/org/jetbrains/debugger/ObjectProperty.java b/platform/script-debugger/backend/src/org/jetbrains/debugger/ObjectProperty.java index a3f9a9683fc8..94bdb29a59c6 100644 --- a/platform/script-debugger/backend/src/org/jetbrains/debugger/ObjectProperty.java +++ b/platform/script-debugger/backend/src/org/jetbrains/debugger/ObjectProperty.java @@ -1,11 +1,7 @@ package org.jetbrains.debugger; -import com.intellij.openapi.util.AsyncResult; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.debugger.values.FunctionValue; -import org.jetbrains.debugger.values.ObjectValue; -import org.jetbrains.debugger.values.Value; /** * Exposes additional data if variable is a property of object and its property descriptor @@ -38,10 +34,4 @@ public interface ObjectProperty extends Variable { * @return whether property described as 'enumerable' */ boolean isEnumerable(); - - /** - * Asynchronously evaluates property getter and returns property value - */ - @NotNull - AsyncResult evaluateGet(@NotNull ObjectValue host, @NotNull EvaluateContext evaluateContext); } diff --git a/platform/script-debugger/backend/src/org/jetbrains/debugger/StandaloneVmHelper.java b/platform/script-debugger/backend/src/org/jetbrains/debugger/StandaloneVmHelper.java index 36d2ec0515f2..e9eed257fd8f 100644 --- a/platform/script-debugger/backend/src/org/jetbrains/debugger/StandaloneVmHelper.java +++ b/platform/script-debugger/backend/src/org/jetbrains/debugger/StandaloneVmHelper.java @@ -16,7 +16,7 @@ public final class StandaloneVmHelper extends MessageWriter { private final VmEx vm; - public StandaloneVmHelper(VmEx vm) { + public StandaloneVmHelper(@NotNull VmEx vm) { this.vm = vm; } diff --git a/platform/script-debugger/backend/src/org/jetbrains/debugger/ValueModifier.java b/platform/script-debugger/backend/src/org/jetbrains/debugger/ValueModifier.java index e7bcbbb889b9..d276c1d6e8d2 100644 --- a/platform/script-debugger/backend/src/org/jetbrains/debugger/ValueModifier.java +++ b/platform/script-debugger/backend/src/org/jetbrains/debugger/ValueModifier.java @@ -1,6 +1,7 @@ package org.jetbrains.debugger; import com.intellij.openapi.util.ActionCallback; +import com.intellij.openapi.util.AsyncResult; import org.jetbrains.annotations.NotNull; import org.jetbrains.debugger.values.Value; @@ -13,4 +14,7 @@ public interface ValueModifier { ActionCallback setValue(@NotNull Variable variable, String newValue, @NotNull EvaluateContext evaluateContext); ActionCallback setValue(@NotNull Variable variable, Value newValue, @NotNull EvaluateContext evaluateContext); + + @NotNull + AsyncResult evaluateGet(@NotNull ObjectProperty property, @NotNull EvaluateContext evaluateContext); } \ No newline at end of file diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/VariableView.java b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/VariableView.java index 0b7c43a3684c..e35a488b3829 100644 --- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/VariableView.java +++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/VariableView.java @@ -153,9 +153,9 @@ public final class VariableView extends XNamedValue implements VariableContext { node.setFullValueEvaluator(new XFullValueEvaluator(" (invoke getter)") { @Override public void startEvaluation(@NotNull final XFullValueEvaluationCallback callback) { - ObjectValue host = (ObjectValue)((VariableView)context).getValue(); - assert host != null; - ObsolescentAsyncResults.consume(((ObjectProperty)variable).evaluateGet(host, getEvaluateContext()), node, new PairConsumer() { + ValueModifier valueModifier = variable.getValueModifier(); + assert valueModifier != null; + ObsolescentAsyncResults.consume(valueModifier.evaluateGet((ObjectProperty)variable, getEvaluateContext()), node, new PairConsumer() { @Override public void consume(Value value, XValueNode node) { callback.evaluated(""); diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/VmConnection.java b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/VmConnection.java index 6cdf3306d3f1..ad0bb6f0ac9e 100644 --- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/VmConnection.java +++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/VmConnection.java @@ -70,7 +70,7 @@ public abstract class VmConnection implements Disposable, BrowserC started.setDone(); } - public final void close(@Nullable String message) { + public final void close(@Nullable String message, @NotNull ConnectionStatus status) { if (!closed.compareAndSet(false, true)) { return; } @@ -79,7 +79,7 @@ public abstract class VmConnection implements Disposable, BrowserC if (!started.isProcessed()) { started.setRejected(); } - setState(ConnectionStatus.DISCONNECTED, message); + setState(status, message); Disposer.dispose(this, false); } @@ -101,7 +101,7 @@ public abstract class VmConnection implements Disposable, BrowserC vm = null; callback = currentVm.detach(); } - close(null); + close(null, ConnectionStatus.DISCONNECTED); return callback; } } \ No newline at end of file diff --git a/platform/script-debugger/protocol/protocol-model-generator/src/org/jetbrains/protocolReader/Generator.java b/platform/script-debugger/protocol/protocol-model-generator/src/org/jetbrains/protocolReader/Generator.java index acea0626c3db..e545f0280f81 100644 --- a/platform/script-debugger/protocol/protocol-model-generator/src/org/jetbrains/protocolReader/Generator.java +++ b/platform/script-debugger/protocol/protocol-model-generator/src/org/jetbrains/protocolReader/Generator.java @@ -70,7 +70,7 @@ class Generator { } private static boolean isDomainSkipped(Domain domain) { - if (domain.domain().equals("CSS")) { + if (domain.domain().equals("CSS") || domain.domain().equals("Inspector")) { return false; } diff --git a/platform/platform-impl/src/com/intellij/ide/startupWizardV2/AbstractWizardPage.java b/platform/util-rt/src/com/intellij/openapi/util/Couple.java similarity index 60% rename from platform/platform-impl/src/com/intellij/ide/startupWizardV2/AbstractWizardPage.java rename to platform/util-rt/src/com/intellij/openapi/util/Couple.java index 727fb7326eb3..c078c8a0afff 100644 --- a/platform/platform-impl/src/com/intellij/ide/startupWizardV2/AbstractWizardPage.java +++ b/platform/util-rt/src/com/intellij/openapi/util/Couple.java @@ -13,29 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.ide.startupWizardV2; +package com.intellij.openapi.util; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; - -public abstract class AbstractWizardPage extends JPanel { - public AbstractWizardPage() { +/** + * @author Konstantin Bulenkov + */ +public class Couple extends Pair { + public Couple(T first, T second) { + super(first, second); } - @NotNull - abstract String getID(); - - @NotNull - abstract String getTitle(); - - @NotNull - String getHeader() { - return " "; - } - - @NotNull - String getFooter() { - return " "; + public static Couple newOne(T first, T second) { + return new Couple(first, second); } } diff --git a/platform/util/src/com/intellij/util/io/PersistentHashMap.java b/platform/util/src/com/intellij/util/io/PersistentHashMap.java index 00a10d958bbf..b81b02fa975a 100644 --- a/platform/util/src/com/intellij/util/io/PersistentHashMap.java +++ b/platform/util/src/com/intellij/util/io/PersistentHashMap.java @@ -188,18 +188,7 @@ public class PersistentHashMap extends PersistentEnumeratorDelegate< } private SLRUCache createAppendCache(final KeyDescriptor keyDescriptor) { - final EqualityPolicy hashingStrategy = new EqualityPolicy() { - @Override - public int getHashCode(Key object) { - return keyDescriptor.getHashCode(object); - } - - @Override - public boolean isEqual(Key val1, Key val2) { - return keyDescriptor.isEqual(val1, val2); - } - }; - return new SLRUCache(16 * 1024, 4 * 1024, hashingStrategy) { + return new SLRUCache(16 * 1024, 4 * 1024, keyDescriptor) { @Override @NotNull public BufferExposingByteArrayOutputStream createValue(final Key key) { diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/graph/GraphColorManagerImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/graph/GraphColorManagerImpl.java index d53a8fdc703a..851e1c57cf1a 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/graph/GraphColorManagerImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/graph/GraphColorManagerImpl.java @@ -20,6 +20,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.JBColor; import com.intellij.util.NotNullFunction; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.hash.LinkedHashMap; import com.intellij.vcs.log.Hash; import com.intellij.vcs.log.VcsLogRefManager; import com.intellij.vcs.log.VcsRef; @@ -39,6 +40,14 @@ public class GraphColorManagerImpl implements GraphColorManager { @NotNull private final NotNullFunction myHashGetter; @NotNull private final Map myRefManagers; + @NotNull private final LinkedHashMap myErrorWasReported = new LinkedHashMap(10) { + + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > 100; + } + }; + public GraphColorManagerImpl(@NotNull RefsModel refsModel, @NotNull NotNullFunction hashGetter, @NotNull Map refManagers) { myRefsModel = refsModel; @@ -61,7 +70,10 @@ public class GraphColorManagerImpl implements GraphColorManager { private boolean checkEmptiness(@NotNull Collection refs, int head) { if (refs.isEmpty()) { - LOG.error("No references found at head " + head + " which corresponds to hash " + myHashGetter.fun(head)); + if (!myErrorWasReported.containsKey(head)) { + myErrorWasReported.put(head, head); + LOG.error("No references found at head " + head + " which corresponds to hash " + myHashGetter.fun(head)); + } return false; } return true; diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogColorManagerImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogColorManagerImpl.java index 8f674e6f7f9d..decc60c9c587 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogColorManagerImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogColorManagerImpl.java @@ -5,7 +5,6 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.JBColor; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; -import com.intellij.vcs.log.ui.tables.AbstractVcsLogTableModel; import org.jetbrains.annotations.NotNull; import java.awt.*; @@ -60,9 +59,6 @@ public class VcsLogColorManagerImpl implements VcsLogColorManager { @NotNull @Override public Color getRootColor(@NotNull VirtualFile root) { - if (root == AbstractVcsLogTableModel.FAKE_ROOT) { - return getDefaultRootColor(); - } Color color = myRoots2Colors.get(root); if (color == null) { LOG.error("No color record for root " + root + ". All roots: " + myRoots2Colors); diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/AbstractVcsLogTableModel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/AbstractVcsLogTableModel.java index d18c645f4ed7..262fefbbc212 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/AbstractVcsLogTableModel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/AbstractVcsLogTableModel.java @@ -23,8 +23,6 @@ import java.util.concurrent.atomic.AtomicBoolean; public abstract class AbstractVcsLogTableModel extends AbstractTableModel { - public static final VirtualFile FAKE_ROOT = NullVirtualFile.INSTANCE; - public static final int ROOT_COLUMN = 0; public static final int COMMIT_COLUMN = 1; public static final int AUTHOR_COLUMN = 2; diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/EmptyTableModel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/EmptyTableModel.java index ec8528e092f1..575be9e5e183 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/EmptyTableModel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/EmptyTableModel.java @@ -22,8 +22,8 @@ import com.intellij.vcs.log.VcsShortCommitDetails; import com.intellij.vcs.log.data.DataPack; import com.intellij.vcs.log.data.LoadMoreStage; import com.intellij.vcs.log.data.VcsLogDataHolder; -import com.intellij.vcs.log.ui.render.GraphCommitCell; import com.intellij.vcs.log.ui.VcsLogUiImpl; +import com.intellij.vcs.log.ui.render.GraphCommitCell; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -44,7 +44,7 @@ public class EmptyTableModel extends AbstractVcsLogTableModel { @NotNull @Override public VirtualFile getRoot(int rowIndex) { - return FAKE_ROOT; + throw new AssertionError("Root shouldn't be requested for empty table model. row: " + rowIndex); } @NotNull diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java index 2438acec675c..63320a63404b 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java @@ -61,7 +61,8 @@ public class GraphTableModel extends AbstractVcsLogTableModel { Collection refs = myDataPack.getRefsModel().refsToCommit(head); if (refs.isEmpty()) { LOG.error("No references pointing to head " + head + " identified for commit at row " + rowIndex); - return FAKE_ROOT; + // take the first root: it is the right choice in one-repo case, though it will likely fail in multi-repo case + return myDataPack.getLogProviders().keySet().iterator().next(); } return refs.iterator().next().getRoot(); } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessarilyQualifiedStaticallyImportedElementInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessarilyQualifiedStaticallyImportedElementInspection.java index e33db815bd49..7c6d5a999ecb 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessarilyQualifiedStaticallyImportedElementInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessarilyQualifiedStaticallyImportedElementInspection.java @@ -94,7 +94,7 @@ public class UnnecessarilyQualifiedStaticallyImportedElementInspection extends B if (!(qualifier instanceof PsiJavaCodeReferenceElement)) { return; } - if (PsiTreeUtil.getParentOfType(reference, PsiReferenceExpression.class, PsiImportStatementBase.class) != null) { + if (PsiTreeUtil.getParentOfType(reference, PsiImportStatementBase.class) != null) { return; } if (UnnecessarilyQualifiedStaticUsageInspection.isGenericReference(reference, (PsiJavaCodeReferenceElement)qualifier)) return; diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessarily_qualified_statically_imported_element/chainedMethodCall/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessarily_qualified_statically_imported_element/chainedMethodCall/expected.xml new file mode 100644 index 000000000000..4944dce1ffa2 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessarily_qualified_statically_imported_element/chainedMethodCall/expected.xml @@ -0,0 +1,8 @@ + + + Test.java + 7 + Unnecessarily qualified statically imported element + Statically imported element 'foo' is unnecessarily qualified with <code>A</code> #loc + + \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessarily_qualified_statically_imported_element/chainedMethodCall/src/Test.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessarily_qualified_statically_imported_element/chainedMethodCall/src/Test.java new file mode 100644 index 000000000000..a731da90bd2f --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessarily_qualified_statically_imported_element/chainedMethodCall/src/Test.java @@ -0,0 +1,13 @@ +package p; + +import static p.A.foo; + +class StaticImport { + void example() { + A.foo().toString(); + } +} + +class A { + static Object foo() {return null;} +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessarily_qualified_statically_imported_element/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessarily_qualified_statically_imported_element/simple/expected.xml similarity index 100% rename from plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessarily_qualified_statically_imported_element/expected.xml rename to plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessarily_qualified_statically_imported_element/simple/expected.xml diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessarily_qualified_statically_imported_element/C.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessarily_qualified_statically_imported_element/simple/src/C.java similarity index 100% rename from plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessarily_qualified_statically_imported_element/C.java rename to plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessarily_qualified_statically_imported_element/simple/src/C.java diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/UnnecessarilyQualifiedStaticallyImportedElementInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/UnnecessarilyQualifiedStaticallyImportedElementInspectionTest.java index df7f28b474b9..9dfaba52517a 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/UnnecessarilyQualifiedStaticallyImportedElementInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/UnnecessarilyQualifiedStaticallyImportedElementInspectionTest.java @@ -21,7 +21,7 @@ public class UnnecessarilyQualifiedStaticallyImportedElementInspectionTest extends IGInspectionTestCase { public void test() throws Exception { - doTest("com/siyeh/igtest/style/unnecessarily_qualified_statically_imported_element", + doTest("com/siyeh/igtest/style/unnecessarily_qualified_statically_imported_element/simple", new UnnecessarilyQualifiedStaticallyImportedElementInspection()); } @@ -33,6 +33,10 @@ public class UnnecessarilyQualifiedStaticallyImportedElementInspectionTest doTest(getTestName(true)); } + public void testChainedMethodCall() throws Exception { + doTest(getTestName(true)); + } + private void doTest(String testName) throws Exception { doTest("com/siyeh/igtest/style/unnecessarily_qualified_statically_imported_element/" + testName, new UnnecessarilyQualifiedStaticallyImportedElementInspection()); diff --git a/plugins/ant/src/com/intellij/lang/ant/config/execution/AntBuildMessageView.java b/plugins/ant/src/com/intellij/lang/ant/config/execution/AntBuildMessageView.java index d47ac8d0da19..cb6008231f76 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/execution/AntBuildMessageView.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/execution/AntBuildMessageView.java @@ -90,8 +90,8 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O private AntBuildFileBase myBuildFile; private final String[] myTargets; private int myPriorityThreshold = PRIORITY_BRIEF; - private int myErrorCount; - private int myWarningCount; + private volatile int myErrorCount; + private volatile int myWarningCount; private volatile boolean myIsOutputPaused = false; @NotNull @@ -109,7 +109,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O private final Runnable myFlushLogRunnable = new Runnable() { @Override public void run() { - if (myTreeView != null && myCommandsProcessedCount < myLog.size()) { + if (myCommandsProcessedCount < myLog.size()) { if (!myIsOutputPaused) { new OutputFlusher().doFlush(); myTreeView.scrollToLastMessage(); diff --git a/plugins/ant/src/com/intellij/lang/ant/config/execution/OutputParser.java b/plugins/ant/src/com/intellij/lang/ant/config/execution/OutputParser.java index f96df5472736..3508cdb35e85 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/execution/OutputParser.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/execution/OutputParser.java @@ -47,7 +47,7 @@ public class OutputParser{ private final WeakReference myProgress; private final String myBuildName; private final OSProcessHandler myProcessHandler; - private boolean isStopped; + private volatile boolean isStopped; private List myJavacMessages; private boolean myFirstLineProcessed; private boolean myStartedSuccessfully; diff --git a/plugins/devkit/resources/META-INF/plugin.xml b/plugins/devkit/resources/META-INF/plugin.xml index b05c49186f4f..d0d12d3744f7 100644 --- a/plugins/devkit/resources/META-INF/plugin.xml +++ b/plugins/devkit/resources/META-INF/plugin.xml @@ -66,6 +66,13 @@ bundle="org.jetbrains.idea.devkit.DevKitBundle" groupKey="inspections.group.name" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.idea.devkit.inspections.IntentionDescriptionNotFoundInspection"/> + + +Checks if postfix template (completion) has a description. + + diff --git a/plugins/devkit/src/DevKitBundle.properties b/plugins/devkit/src/DevKitBundle.properties index 07d3b2914baf..6799f6d2415f 100644 --- a/plugins/devkit/src/DevKitBundle.properties +++ b/plugins/devkit/src/DevKitBundle.properties @@ -147,6 +147,9 @@ inspections.component.not.registered.option.ignore.non.public=Ignore non-public inspections.component.not.registered.quickfix.family=Register Component inspections.component.not.registered.quickfix.name=Register {0} inspections.component.not.registered.quickfix.error=Cannot Register {0} + +inspections.component.postfix.template.not.found.description.name=Postfix template Description Checker + InspectionUseGrayColor=Use Gray ant.build.jar.comment=Build archive for plugin ''{0}'' ant.build.jar.description=Build plugin archive for module ''{0}'' diff --git a/plugins/devkit/src/inspections/DescriptionNotFoundInspectionBase.java b/plugins/devkit/src/inspections/DescriptionNotFoundInspectionBase.java new file mode 100644 index 000000000000..d1a2fac52685 --- /dev/null +++ b/plugins/devkit/src/inspections/DescriptionNotFoundInspectionBase.java @@ -0,0 +1,135 @@ +/* + * Copyright 2000-2014 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.devkit.inspections; + + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.ProblemHighlightType; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleUtilCore; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.devkit.inspections.quickfix.CreateHtmlDescriptionFix; +import org.jetbrains.idea.devkit.util.PsiUtil; + +abstract class DescriptionNotFoundInspectionBase extends DevKitInspectionBase { + + @Override + public ProblemDescriptor[] checkClass(@NotNull PsiClass aClass, @NotNull InspectionManager manager, boolean isOnTheFly) { + final Project project = aClass.getProject(); + final PsiIdentifier nameIdentifier = aClass.getNameIdentifier(); + final Module module = ModuleUtilCore.findModuleForPsiElement(aClass); + + if (nameIdentifier == null || module == null || !PsiUtil.isInstantiable(aClass)) return null; + + final PsiClass base = JavaPsiFacade.getInstance(project).findClass(getClassName(), GlobalSearchScope.allScope(project)); + + if (base == null || !aClass.isInheritor(base, true)) return null; + + String descriptionDir = getDescriptionDirName(aClass); + if (StringUtil.isEmptyOrSpaces(descriptionDir)) { + return null; + } + + for (PsiDirectory description : getDescriptionsDirs(module)) { + PsiDirectory dir = description.findSubdirectory(descriptionDir); + if (dir == null) continue; + final PsiFile descr = dir.findFile("description.html"); + if (descr != null) { + if (!hasBeforeAndAfterTemplate(dir.getVirtualFile())) { + PsiElement problem = aClass.getNameIdentifier(); + ProblemDescriptor problemDescriptor = manager.createProblemDescriptor(problem == null ? nameIdentifier : problem, + getHasNotBeforeAfterError(), + isOnTheFly, + ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false); + return new ProblemDescriptor[]{problemDescriptor}; + } + + return null; + } + } + + + final PsiElement problem = aClass.getNameIdentifier(); + final ProblemDescriptor problemDescriptor = manager + .createProblemDescriptor(problem == null ? nameIdentifier : problem, + getHasNotDescriptionError(), isOnTheFly, new LocalQuickFix[]{getFix(module, descriptionDir)}, + ProblemHighlightType.GENERIC_ERROR_OR_WARNING); + return new ProblemDescriptor[]{problemDescriptor}; + } + + protected CreateHtmlDescriptionFix getFix(Module module, String descriptionDir) { + return new CreateHtmlDescriptionFix(descriptionDir, module, true); + } + + @Nullable + private static String getDescriptionDirName(PsiClass aClass) { + String descriptionDir = ""; + PsiClass each = aClass; + while (each != null) { + String name = each.getName(); + if (StringUtil.isEmptyOrSpaces(name)) { + return null; + } + descriptionDir = name + descriptionDir; + each = each.getContainingClass(); + } + return descriptionDir; + } + + private static boolean hasBeforeAndAfterTemplate(@NotNull VirtualFile dir) { + boolean hasBefore = false; + boolean hasAfter = false; + + for (VirtualFile file : dir.getChildren()) { + String name = file.getName(); + if (name.endsWith(".template")) { + if (name.startsWith("before.")) { + hasBefore = true; + } + else if (name.startsWith("after.")) { + hasAfter = true; + } + } + } + + return hasBefore && hasAfter; + } + + @Override + public boolean isEnabledByDefault() { + return true; + } + + @NotNull + protected abstract String getClassName(); + + @NotNull + protected abstract String getHasNotDescriptionError(); + + @NotNull + protected abstract String getHasNotBeforeAfterError(); + + @NotNull + protected abstract PsiDirectory[] getDescriptionsDirs(@NotNull Module module); +} diff --git a/plugins/devkit/src/inspections/IntentionDescriptionNotFoundInspection.java b/plugins/devkit/src/inspections/IntentionDescriptionNotFoundInspection.java index e424c70f1106..bed14c0092a7 100644 --- a/plugins/devkit/src/inspections/IntentionDescriptionNotFoundInspection.java +++ b/plugins/devkit/src/inspections/IntentionDescriptionNotFoundInspection.java @@ -15,118 +15,57 @@ */ package org.jetbrains.idea.devkit.inspections; -import com.intellij.codeInspection.InspectionManager; -import com.intellij.codeInspection.LocalQuickFix; -import com.intellij.codeInspection.ProblemDescriptor; -import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleUtil; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.*; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiPackage; import com.intellij.psi.search.GlobalSearchScope; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.devkit.inspections.quickfix.CreateHtmlDescriptionFix; -import org.jetbrains.idea.devkit.util.PsiUtil; /** * @author Konstantin Bulenkov */ -public class IntentionDescriptionNotFoundInspection extends DevKitInspectionBase{ +public class IntentionDescriptionNotFoundInspection extends DescriptionNotFoundInspectionBase { @NonNls private static final String INTENTION = "com.intellij.codeInsight.intention.IntentionAction"; @NonNls private static final String INSPECTION_DESCRIPTIONS = "intentionDescriptions"; - @Override - public ProblemDescriptor[] checkClass(@NotNull PsiClass aClass, @NotNull InspectionManager manager, boolean isOnTheFly) { - final Project project = aClass.getProject(); - final PsiIdentifier nameIdentifier = aClass.getNameIdentifier(); - final Module module = ModuleUtil.findModuleForPsiElement(aClass); - - if (nameIdentifier == null || module == null || !PsiUtil.isInstantiable(aClass)) return null; - - final PsiClass base = JavaPsiFacade.getInstance(project).findClass(INTENTION, GlobalSearchScope.allScope(project)); - - if (base == null || ! aClass.isInheritor(base, true)) return null; - - String descriptionDir = getDescriptionDirName(aClass); - if (StringUtil.isEmptyOrSpaces(descriptionDir)) { - return null; - } - - for (PsiDirectory description : getIntentionDescriptionsDirs(module)) { - PsiDirectory dir = description.findSubdirectory(descriptionDir); - if (dir == null) continue; - final PsiFile descr = dir.findFile("description.html"); - if (descr != null) { - if (!hasBeforeAndAfterTemplate(dir.getVirtualFile())) { - PsiElement problem = aClass.getNameIdentifier(); - ProblemDescriptor problemDescriptor = manager.createProblemDescriptor(problem == null ? nameIdentifier : problem, - "Intention must have 'before.*.template' and 'after.*.template' beside 'description.html'", - isOnTheFly, - ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false); - return new ProblemDescriptor[]{problemDescriptor}; - } - - return null; - } - } - - - final PsiElement problem = aClass.getNameIdentifier(); - final ProblemDescriptor problemDescriptor = manager - .createProblemDescriptor(problem == null ? nameIdentifier : problem, - "Intention does not have a description", isOnTheFly, new LocalQuickFix[]{new CreateHtmlDescriptionFix(descriptionDir, module, true)}, - ProblemHighlightType.GENERIC_ERROR_OR_WARNING); - return new ProblemDescriptor[]{problemDescriptor}; + protected CreateHtmlDescriptionFix getFix(Module module, String descriptionDir) { + return new CreateHtmlDescriptionFix(descriptionDir, module, true); } - @Nullable - private static String getDescriptionDirName(PsiClass aClass) { - String descriptionDir = ""; - PsiClass each = aClass; - while (each != null) { - String name = each.getName(); - if (StringUtil.isEmptyOrSpaces(name)) { - return null; - } - descriptionDir = name + descriptionDir; - each = each.getContainingClass(); - } - return descriptionDir; + @NotNull + protected String getClassName() { + return INTENTION; } - private static boolean hasBeforeAndAfterTemplate(@NotNull VirtualFile dir) { - boolean hasBefore = false; - boolean hasAfter = false; + @NotNull + protected String getHasNotDescriptionError() { + return "Intention does not have a description"; + } - for (VirtualFile file : dir.getChildren()) { - String name = file.getName(); - if (name.endsWith(".template")) { - if (name.startsWith("before.")) { - hasBefore = true; - } - else if (name.startsWith("after.")) { - hasAfter = true; - } - } - } - - return hasBefore && hasAfter; + @NotNull + protected String getHasNotBeforeAfterError() { + return "Intention must have 'before.*.template' and 'after.*.template' beside 'description.html'"; } public static PsiDirectory[] getIntentionDescriptionsDirs(Module module) { final PsiPackage aPackage = JavaPsiFacade.getInstance(module.getProject()).findPackage(INSPECTION_DESCRIPTIONS); if (aPackage != null) { return aPackage.getDirectories(GlobalSearchScope.moduleWithDependenciesScope(module)); - } else { + } + else { return PsiDirectory.EMPTY_ARRAY; } } + @NotNull + protected PsiDirectory[] getDescriptionsDirs(@NotNull Module module) { + return getIntentionDescriptionsDirs(module); + } + @Nls @NotNull public String getDisplayName() { @@ -137,9 +76,4 @@ public class IntentionDescriptionNotFoundInspection extends DevKitInspectionBase public String getShortName() { return "IntentionDescriptionNotFoundInspection"; } - - @Override - public boolean isEnabledByDefault() { - return true; - } } diff --git a/plugins/devkit/src/inspections/PostfixTemplateDescriptionNotFoundInspection.java b/plugins/devkit/src/inspections/PostfixTemplateDescriptionNotFoundInspection.java new file mode 100644 index 000000000000..b839c873df9b --- /dev/null +++ b/plugins/devkit/src/inspections/PostfixTemplateDescriptionNotFoundInspection.java @@ -0,0 +1,86 @@ +/* + * Copyright 2000-2014 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.devkit.inspections; + +import com.intellij.openapi.module.Module; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiPackage; +import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.devkit.DevKitBundle; +import org.jetbrains.idea.devkit.inspections.quickfix.CreateHtmlDescriptionFix; +import org.jetbrains.idea.devkit.inspections.quickfix.CreatePostfixTemplateHtmlDescriptionFix; + + +public class PostfixTemplateDescriptionNotFoundInspection extends DescriptionNotFoundInspectionBase { + + private static final String POSTFIX_TEMPLATES = "postfixTemplates"; + + @NotNull + @Override + protected PsiDirectory[] getDescriptionsDirs(@NotNull Module module) { + return getPostfixTemplateDirectories(module); + } + + @Override + protected CreateHtmlDescriptionFix getFix(Module module, String descriptionDir) { + return new CreatePostfixTemplateHtmlDescriptionFix(descriptionDir, module); + } + + @NotNull + public static PsiDirectory[] getPostfixTemplateDirectories(Module module) { + final PsiPackage aPackage = JavaPsiFacade.getInstance(module.getProject()).findPackage(POSTFIX_TEMPLATES); + if (aPackage != null) { + return aPackage.getDirectories(GlobalSearchScope.moduleWithDependenciesScope(module)); + } + else { + return PsiDirectory.EMPTY_ARRAY; + } + } + + @NotNull + @Override + protected String getHasNotDescriptionError() { + return "Postfix template does not have a description"; + } + + @NotNull + @Override + protected String getHasNotBeforeAfterError() { + return "Postfix template must have 'before.*.template' and 'after.*.template' beside 'description.html'"; + } + + @NotNull + @Override + protected String getClassName() { + return "com.intellij.codeInsight.template.postfix.templates.PostfixTemplate"; + } + + @Nls + @NotNull + @Override + public String getDisplayName() { + return DevKitBundle.message("inspections.component.postfix.template.not.found.description.name"); + } + + @NotNull + @Override + public String getShortName() { + return "PostfixTemplateDescriptionNotFound"; + } +} diff --git a/plugins/devkit/src/inspections/quickfix/CreateHtmlDescriptionFix.java b/plugins/devkit/src/inspections/quickfix/CreateHtmlDescriptionFix.java index e8f498dd28ea..6dcd46c99254 100644 --- a/plugins/devkit/src/inspections/quickfix/CreateHtmlDescriptionFix.java +++ b/plugins/devkit/src/inspections/quickfix/CreateHtmlDescriptionFix.java @@ -57,75 +57,15 @@ import java.util.List; * @author Konstantin Bulenkov */ public class CreateHtmlDescriptionFix implements LocalQuickFix, Iconable { - private final String myFilename; - private final Module myModule; @NonNls private static final String TEMPLATE_NAME = "InspectionDescription.html"; + private final String myFilename; + protected final Module myModule; private final boolean isIntention; public CreateHtmlDescriptionFix(String filename, Module module, boolean isIntention) { myModule = module; this.isIntention = isIntention; - myFilename = isIntention ? filename : filename + ".html"; - } - - @NotNull - public String getName() { - return DevKitBundle.message("create.description.file"); - } - - @NotNull - public String getFamilyName() { - return "DevKit"; - } - - public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { - final PsiDirectory[] dirs; - if (isIntention) { - dirs = IntentionDescriptionNotFoundInspection.getIntentionDescriptionsDirs(myModule); - } - else { - dirs = InspectionDescriptionNotFoundInspection.getInspectionDescriptionsDirs(myModule); - } - final List virtualFiles = getPotentialRoots(myModule, dirs); - final VirtualFile[] roots = prepare(VfsUtil.toVirtualFileArray(virtualFiles)); - if (roots.length == 1) { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - public void run() { - createDescription(roots[0]); - } - }); - - } - else { - List options = new ArrayList(); - for (VirtualFile file : roots) { - String path = file.getPresentableUrl() + File.separator + getDescriptionFolderName() + File.separator + myFilename; - if (isIntention) { - path += File.separator + "description.html"; - } - options.add(path); - } - final JBList files = new JBList(ArrayUtil.toStringArray(options)); - files.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - final JBPopup popup = JBPopupFactory.getInstance() - .createListPopupBuilder(files) - .setTitle(DevKitBundle.message("select.target.location.of.description", myFilename)) - .setItemChoosenCallback(new Runnable() { - public void run() { - final int index = files.getSelectedIndex(); - if (0 <= index && index < roots.length) { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - public void run() { - createDescription(roots[index]); - } - }); - } - } - }).createPopup(); - final Editor editor = FileEditorManager.getInstance(myModule.getProject()).getSelectedTextEditor(); - if (editor == null) return; - popup.showInBestPositionFor(editor); - } + myFilename = getNormalizedFileName(filename); } private static List getPotentialRoots(Module module, PsiDirectory[] dirs) { @@ -147,6 +87,80 @@ public class CreateHtmlDescriptionFix implements LocalQuickFix, Iconable { } } + private String getNormalizedFileName(String filename) { + return isIntention ? filename : filename + ".html"; + } + + @NotNull + public String getName() { + return DevKitBundle.message("create.description.file"); + } + + @NotNull + public String getFamilyName() { + return "DevKit"; + } + + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + final PsiDirectory[] dirs; + dirs = getDirectories(); + final List virtualFiles = getPotentialRoots(myModule, dirs); + final VirtualFile[] roots = prepare(VfsUtil.toVirtualFileArray(virtualFiles)); + if (roots.length == 1) { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + createDescription(roots[0]); + } + }); + } + else { + List options = new ArrayList(); + for (VirtualFile file : roots) { + String path = getPath(file); + options.add(path); + } + final JBList files = new JBList(ArrayUtil.toStringArray(options)); + files.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + final JBPopup popup = JBPopupFactory.getInstance() + .createListPopupBuilder(files) + .setTitle(DevKitBundle.message("select.target.location.of.description", myFilename)) + .setItemChoosenCallback(new Runnable() { + public void run() { + final int index = files.getSelectedIndex(); + if (0 <= index && index < roots.length) { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + createDescription(roots[index]); + } + }); + } + } + }).createPopup(); + final Editor editor = FileEditorManager.getInstance(myModule.getProject()).getSelectedTextEditor(); + if (editor == null) return; + popup.showInBestPositionFor(editor); + } + } + + private String getPath(VirtualFile file) { + String path = file.getPresentableUrl() + File.separator + getDescriptionFolderName() + File.separator + myFilename; + if (isIntention) { + path += File.separator + "description.html"; + } + return path; + } + + protected PsiDirectory[] getDirectories() { + PsiDirectory[] dirs; + if (isIntention) { + dirs = IntentionDescriptionNotFoundInspection.getIntentionDescriptionsDirs(myModule); + } + else { + dirs = InspectionDescriptionNotFoundInspection.getInspectionDescriptionsDirs(myModule); + } + return dirs; + } + private void createDescription(VirtualFile root) { if (!root.isDirectory()) return; final PsiManager psiManager = PsiManager.getInstance(myModule.getProject()); @@ -169,7 +183,8 @@ public class CreateHtmlDescriptionFix implements LocalQuickFix, Iconable { } } final FileTemplate descrTemplate = FileTemplateManager.getInstance().getJ2eeTemplate(TEMPLATE_NAME); - final PsiElement template = FileTemplateUtil.createFromTemplate(descrTemplate, isIntention? "description.html" : myFilename, null, descrRoot); + final PsiElement template = + FileTemplateUtil.createFromTemplate(descrTemplate, getNewFileName(), null, descrRoot); if (template instanceof PsiFile) { final VirtualFile file = ((PsiFile)template).getVirtualFile(); if (file != null) { @@ -181,6 +196,10 @@ public class CreateHtmlDescriptionFix implements LocalQuickFix, Iconable { } } + private String getNewFileName() { + return isIntention ? "description.html" : myFilename; + } + public Icon getIcon(int flags) { return new LayeredIcon(AllIcons.FileTypes.Html, AllIcons.Actions.New); } @@ -205,7 +224,7 @@ public class CreateHtmlDescriptionFix implements LocalQuickFix, Iconable { return false; } - private String getDescriptionFolderName() { + protected String getDescriptionFolderName() { return isIntention ? "intentionDescriptions" : "inspectionDescriptions"; } } diff --git a/plugins/devkit/src/inspections/quickfix/CreatePostfixTemplateHtmlDescriptionFix.java b/plugins/devkit/src/inspections/quickfix/CreatePostfixTemplateHtmlDescriptionFix.java new file mode 100644 index 000000000000..1e1f9f779f31 --- /dev/null +++ b/plugins/devkit/src/inspections/quickfix/CreatePostfixTemplateHtmlDescriptionFix.java @@ -0,0 +1,39 @@ +/* + * Copyright 2000-2014 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.devkit.inspections.quickfix; + +import com.intellij.openapi.module.Module; +import com.intellij.psi.PsiDirectory; +import org.jetbrains.idea.devkit.inspections.PostfixTemplateDescriptionNotFoundInspection; + + +public class CreatePostfixTemplateHtmlDescriptionFix extends CreateHtmlDescriptionFix { + + public CreatePostfixTemplateHtmlDescriptionFix(String filename, Module module) { + super(filename, module, true); + } + + @Override + protected PsiDirectory[] getDirectories() { + return PostfixTemplateDescriptionNotFoundInspection.getPostfixTemplateDirectories(myModule); + } + + @Override + protected String getDescriptionFolderName() { + return "postfixTemplates"; + } +} diff --git a/plugins/devkit/testData/codeInsight/postfixTemplates/MyQuickFixTemplate.java b/plugins/devkit/testData/codeInsight/postfixTemplates/MyQuickFixTemplate.java new file mode 100644 index 000000000000..de936e4550f6 --- /dev/null +++ b/plugins/devkit/testData/codeInsight/postfixTemplates/MyQuickFixTemplate.java @@ -0,0 +1,6 @@ +import com.intellij.codeInsight.template.postfix.templates.PostfixTemplate; + +public class MyQuickFixTemplate extends PostfixTemplate { + + +} diff --git a/plugins/devkit/testData/codeInsight/postfixTemplates/MyTemplate.java b/plugins/devkit/testData/codeInsight/postfixTemplates/MyTemplate.java new file mode 100644 index 000000000000..e20fbb6be2df --- /dev/null +++ b/plugins/devkit/testData/codeInsight/postfixTemplates/MyTemplate.java @@ -0,0 +1,6 @@ +import com.intellij.codeInsight.template.postfix.templates.PostfixTemplate; + +public class MyTemplate extends PostfixTemplate { + + +} diff --git a/plugins/devkit/testData/codeInsight/postfixTemplates/MyTemplateWithDescription.java b/plugins/devkit/testData/codeInsight/postfixTemplates/MyTemplateWithDescription.java new file mode 100644 index 000000000000..02b9c8928fac --- /dev/null +++ b/plugins/devkit/testData/codeInsight/postfixTemplates/MyTemplateWithDescription.java @@ -0,0 +1,6 @@ +import com.intellij.codeInsight.template.postfix.templates.PostfixTemplate; + +public class MyTemplateWithDescription extends PostfixTemplate { + + +} diff --git a/plugins/devkit/testData/codeInsight/postfixTemplates/MyTemplateWithoutBeforeAfter.java b/plugins/devkit/testData/codeInsight/postfixTemplates/MyTemplateWithoutBeforeAfter.java new file mode 100644 index 000000000000..9e0ae10e8905 --- /dev/null +++ b/plugins/devkit/testData/codeInsight/postfixTemplates/MyTemplateWithoutBeforeAfter.java @@ -0,0 +1,6 @@ +import com.intellij.codeInsight.template.postfix.templates.PostfixTemplate; + +public class MyTemplateWithoutBeforeAfter extends PostfixTemplate{ + + + } diff --git a/plugins/devkit/testData/codeInsight/postfixTemplates/postfixTemplates/MyTemplateWithDescription/after.java.template b/plugins/devkit/testData/codeInsight/postfixTemplates/postfixTemplates/MyTemplateWithDescription/after.java.template new file mode 100644 index 000000000000..675fbd2b9292 --- /dev/null +++ b/plugins/devkit/testData/codeInsight/postfixTemplates/postfixTemplates/MyTemplateWithDescription/after.java.template @@ -0,0 +1 @@ +test after diff --git a/plugins/devkit/testData/codeInsight/postfixTemplates/postfixTemplates/MyTemplateWithDescription/before.java.template b/plugins/devkit/testData/codeInsight/postfixTemplates/postfixTemplates/MyTemplateWithDescription/before.java.template new file mode 100644 index 000000000000..6fbfb79f92a9 --- /dev/null +++ b/plugins/devkit/testData/codeInsight/postfixTemplates/postfixTemplates/MyTemplateWithDescription/before.java.template @@ -0,0 +1 @@ +test before diff --git a/plugins/devkit/testData/codeInsight/postfixTemplates/postfixTemplates/MyTemplateWithDescription/description.html b/plugins/devkit/testData/codeInsight/postfixTemplates/postfixTemplates/MyTemplateWithDescription/description.html new file mode 100644 index 000000000000..6b0d347bb279 --- /dev/null +++ b/plugins/devkit/testData/codeInsight/postfixTemplates/postfixTemplates/MyTemplateWithDescription/description.html @@ -0,0 +1 @@ +test description diff --git a/plugins/devkit/testData/codeInsight/postfixTemplates/postfixTemplates/MyTemplateWithoutBeforeAfter/description.html b/plugins/devkit/testData/codeInsight/postfixTemplates/postfixTemplates/MyTemplateWithoutBeforeAfter/description.html new file mode 100644 index 000000000000..6b0d347bb279 --- /dev/null +++ b/plugins/devkit/testData/codeInsight/postfixTemplates/postfixTemplates/MyTemplateWithoutBeforeAfter/description.html @@ -0,0 +1 @@ +test description diff --git a/plugins/devkit/testSources/codeInsight/PostfixTemplateInspectionTest.java b/plugins/devkit/testSources/codeInsight/PostfixTemplateInspectionTest.java new file mode 100644 index 000000000000..6b655725985d --- /dev/null +++ b/plugins/devkit/testSources/codeInsight/PostfixTemplateInspectionTest.java @@ -0,0 +1,61 @@ +/* + * Copyright 2000-2014 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.devkit.codeInsight; + +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.openapi.application.PluginPathManager; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase; +import org.jetbrains.idea.devkit.inspections.PostfixTemplateDescriptionNotFoundInspection; + +public class PostfixTemplateInspectionTest extends JavaCodeInsightFixtureTestCase { + + @Override + protected String getBasePath() { + return PluginPathManager.getPluginHomePathRelative("devkit") + "/testData/codeInsight/postfixTemplates"; + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + myFixture.enableInspections(PostfixTemplateDescriptionNotFoundInspection.class); + myFixture.addClass("package com.intellij.codeInsight.template.postfix.templates; public class PostfixTemplate {}"); + } + + public void testHighlightingForDescription() { + myFixture.testHighlighting("MyTemplate.java"); + } + + public void testNoHighlighting() { + myFixture.copyDirectoryToProject("postfixTemplates", "postfixTemplates"); + myFixture.testHighlighting("MyTemplateWithDescription.java"); + } + + public void testHighlightingForBeforeAfter() { + myFixture.copyDirectoryToProject("postfixTemplates", "postfixTemplates"); + myFixture.testHighlighting("MyTemplateWithoutBeforeAfter.java"); + } + + public void testQuickFix() { + myFixture.configureByFiles("MyQuickFixTemplate.java"); + IntentionAction item = myFixture.findSingleIntention("Create Description File"); + myFixture.launchAction(item); + + VirtualFile path = myFixture.findFileInTempDir("postfixTemplates/MyQuickFixTemplate/description.html"); + assertNotNull(path); + assertTrue(path.exists()); + } +} diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java b/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java index a41a1727f48f..6e178b9cbc0f 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java @@ -228,7 +228,11 @@ public class GitBranchUtil { String branchName = stdName.substring(slash + 1); GitRemote remote = findRemoteByName(remoteName, remotes); if (remote == null) { - return null; + // user may remove the remote section from .git/config, but leave remote refs untouched in .git/refs/remotes + LOG.info(String.format("No remote found with the name [%s]. All remotes: %s", remoteName, remotes)); + GitRemote fakeRemote = new GitRemote(remoteName, ContainerUtil.emptyList(), Collections.emptyList(), + Collections.emptyList(), Collections.emptyList()); + return new GitStandardRemoteBranch(fakeRemote, branchName, hash); } return new GitStandardRemoteBranch(remote, branchName, hash); } @@ -241,8 +245,6 @@ public class GitBranchUtil { return remote; } } - // user may remove the remote section from .git/config, but leave remote refs untouched in .git/refs/remotes - LOG.info(String.format("No remote found with the name [%s]. All remotes: %s", remoteName, remotes)); return null; } diff --git a/plugins/git4idea/src/git4idea/repo/GitConfig.java b/plugins/git4idea/src/git4idea/repo/GitConfig.java index 0080bf613583..a88e7754b78e 100644 --- a/plugins/git4idea/src/git4idea/repo/GitConfig.java +++ b/plugins/git4idea/src/git4idea/repo/GitConfig.java @@ -135,6 +135,13 @@ public class GitConfig { */ @NotNull static GitConfig read(@NotNull GitPlatformFacade platformFacade, @NotNull File configFile) { + GitConfig emptyConfig = new GitConfig(Collections.emptyList(), Collections.emptyList(), + Collections.emptyList()); + if (!configFile.exists()) { + LOG.info("No .git/config file at " + configFile.getPath()); + return emptyConfig; + } + Ini ini = new Ini(); ini.getConfig().setMultiOption(true); // duplicate keys (e.g. url in [remote]) ini.getConfig().setTree(false); // don't need tree structure: it corrupts url in section name (e.g. [url "http://github.com/"] @@ -143,7 +150,7 @@ public class GitConfig { } catch (IOException e) { LOG.error(new RepoStateException("Couldn't load .git/config file at " + configFile.getPath(), e)); - return new GitConfig(Collections.emptyList(), Collections.emptyList(), Collections.emptyList()); + return emptyConfig; } IdeaPluginDescriptor plugin = platformFacade.getPluginByClassName(GitConfig.class.getName()); diff --git a/plugins/git4idea/src/git4idea/repo/GitRemote.java b/plugins/git4idea/src/git4idea/repo/GitRemote.java index a0695d281bd7..b2e289ce7d40 100644 --- a/plugins/git4idea/src/git4idea/repo/GitRemote.java +++ b/plugins/git4idea/src/git4idea/repo/GitRemote.java @@ -39,7 +39,7 @@ import java.util.List; *

*

* GitRemote instance constructed by {@link GitConfig#read(GitPlatformFacade, File)}} has all these rules applied. - * Thus, for example, if only one {@code url} and no {@code pushUrls} are defined for the remote, + * Thus, for example, if only one {@code url} and no {@code pushUrls} are defined for the remote, * both {@link #getUrls()} and {@link #getPushUrls()} will return this url.
* This is made to avoid urls transformation logic from the code using GitRemote, leaving it all in GitConfig parsing. *

@@ -47,14 +47,14 @@ import java.util.List; * Same applies to fetch and push specs: {@link #getPushRefSpecs()} returns the spec, * even if there are no separate record in {@code .git/config} *

- * + * *

* NB: Not all remote preferences (defined in {@code .git/config} are stored in the object. * If some additional data is needed, add the field, getter, constructor parameter and populate it in {@link GitConfig}. *

- * + * *

Remotes are compared (via equals, hashcode and compareTo) only by names.

- * + * * @author Kirill Likhodedov */ public final class GitRemote implements Comparable { @@ -80,8 +80,8 @@ public final class GitRemote implements Comparable { @NotNull final List myFetchRefSpecs; @NotNull private final List myPushRefSpecs; - GitRemote(@NotNull String name, @NotNull List urls, @NotNull Collection pushUrls, - @NotNull List fetchRefSpecs, @NotNull List pushRefSpecs) { + public GitRemote(@NotNull String name, @NotNull List urls, @NotNull Collection pushUrls, + @NotNull List fetchRefSpecs, @NotNull List pushRefSpecs) { myName = name; myUrls = urls; myPushUrls = pushUrls; diff --git a/plugins/git4idea/tests/git4idea/repo/GitRepositoryReaderNewTest.java b/plugins/git4idea/tests/git4idea/repo/GitRepositoryReaderNewTest.java index 89f382806658..9570cbdc06fe 100644 --- a/plugins/git4idea/tests/git4idea/repo/GitRepositoryReaderNewTest.java +++ b/plugins/git4idea/tests/git4idea/repo/GitRepositoryReaderNewTest.java @@ -16,10 +16,14 @@ package git4idea.repo; import com.intellij.dvcs.repo.Repository; +import com.intellij.openapi.util.Condition; +import com.intellij.util.containers.ContainerUtil; import git4idea.GitLocalBranch; +import git4idea.GitRemoteBranch; import git4idea.test.GitSingleRepoTest; import java.io.File; +import java.util.Collection; import static git4idea.test.GitExecutor.git; import static git4idea.test.GitScenarios.commit; @@ -46,4 +50,24 @@ public class GitRepositoryReaderNewTest extends GitSingleRepoTest { assertEquals("State value is incorrect", Repository.State.REBASING, state); } + // inspired by IDEA-124052 + public void test_remote_reference_without_remote() { + final String INVALID_REMOTE = "invalid-remote"; + final String INVALID_REMOTE_BRANCH = "master"; + git("update-ref refs/remotes/" + INVALID_REMOTE + "/" + INVALID_REMOTE_BRANCH + " HEAD"); + + File gitDir = new File(myRepo.getRoot().getPath(), ".git"); + GitRepositoryReader reader = new GitRepositoryReader(gitDir); + GitConfig config = GitConfig.read(myPlatformFacade, new File(gitDir, "config")); + Collection remotes = config.parseRemotes(); + + Collection remoteBranches = reader.readBranches(remotes).getRemoteBranches(); + assertTrue("Remote branch not found", ContainerUtil.exists(remoteBranches, new Condition() { + @Override + public boolean value(GitRemoteBranch branch) { + return branch.getNameForLocalOperations().equals(INVALID_REMOTE + "/" + INVALID_REMOTE_BRANCH); + } + })); + } + } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/spock/SpockTestFramework.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/spock/SpockTestFramework.java index 9a36c8c83990..77a592325701 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/spock/SpockTestFramework.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/spock/SpockTestFramework.java @@ -20,7 +20,6 @@ import com.intellij.ide.fileTemplates.FileTemplateDescriptor; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod; -import com.intellij.util.PathUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.GroovyFileType; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgFile.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgFile.java index d82cd97c8e43..0d3e2d8c4da2 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgFile.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgFile.java @@ -16,10 +16,11 @@ import com.google.common.base.Objects; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vcs.FilePath; -import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.util.HgUtil; import java.io.File; @@ -53,10 +54,11 @@ public class HgFile { return file; } - @NotNull + @Nullable public String getRelativePath() { if (relativePath == null) { - relativePath = buildRelativePath(VfsUtil.virtualToIoFile(vcsRoot), file); + //For configuration like "d:/.hg" File.getParent method has minimal prefix length, so vcsRoot will be "d:", getParent will be "d:/". + relativePath = FileUtil.getRelativePath(VfsUtilCore.virtualToIoFile(vcsRoot), file); } return relativePath; } @@ -66,17 +68,6 @@ public class HgFile { return VcsUtil.getFilePath(file); } - private static String buildRelativePath(File anchestor, File descendant) { - if (anchestor.equals(descendant)) { - return "."; - } - if (anchestor.equals(descendant.getParentFile())) { - return descendant.getName(); - } - return buildRelativePath(anchestor, descendant.getParentFile()) - + File.separator + descendant.getName(); - } - @Override public boolean equals(Object o) { if (this == o) { diff --git a/plugins/junit/src/com/intellij/execution/junit/JUnit4Framework.java b/plugins/junit/src/com/intellij/execution/junit/JUnit4Framework.java index 61fc645dd227..2b4ff0c4bd84 100644 --- a/plugins/junit/src/com/intellij/execution/junit/JUnit4Framework.java +++ b/plugins/junit/src/com/intellij/execution/junit/JUnit4Framework.java @@ -17,10 +17,13 @@ package com.intellij.execution.junit; import com.intellij.CommonBundle; import com.intellij.codeInsight.AnnotationUtil; +import com.intellij.codeInsight.daemon.impl.quickfix.OrderEntryFix; import com.intellij.codeInsight.intention.AddAnnotationFix; import com.intellij.icons.AllIcons; import com.intellij.ide.fileTemplates.FileTemplateDescriptor; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.module.Module; import com.intellij.openapi.projectRoots.ex.JavaSdkUtil; import com.intellij.openapi.ui.Messages; import com.intellij.psi.*; @@ -34,6 +37,8 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; public class JUnit4Framework extends JavaTestFramework { + private static final Logger LOG = Logger.getInstance("#" + JUnit4Framework.class.getName()); + @NotNull public String getName() { return "JUnit4"; @@ -153,6 +158,16 @@ public class JUnit4Framework extends JavaTestFramework { return new FileTemplateDescriptor("JUnit4 Test Class.java"); } + @Override + public void setupLibrary(Module module) { + try { + OrderEntryFix.addJUnit4Library(false, module); + } + catch (ClassNotFoundException e) { + LOG.info(e); + } + } + @Override public boolean isParameterized(PsiClass clazz) { final PsiAnnotation annotation = AnnotationUtil.findAnnotation(clazz, JUnitUtil.RUN_WITH); diff --git a/plugins/junit/src/com/intellij/execution/junit/TestClassFilter.java b/plugins/junit/src/com/intellij/execution/junit/TestClassFilter.java index 9f9fb7bd054e..2631df75d0ac 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestClassFilter.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestClassFilter.java @@ -23,6 +23,7 @@ import com.intellij.ide.util.ClassFilter; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.Computable; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiClass; @@ -30,6 +31,7 @@ import com.intellij.psi.PsiManager; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiUtilCore; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes; import java.util.ArrayList; import java.util.List; @@ -59,7 +61,9 @@ public class TestClassFilter implements ClassFilter.ClassFilterWithScope { (aClass.isInheritor(myBase, true) || JUnitUtil.isTestClass(aClass))) { final CompilerConfiguration compilerConfiguration = CompilerConfiguration.getInstance(getProject()); final VirtualFile virtualFile = PsiUtilCore.getVirtualFile(aClass); - return !compilerConfiguration.isExcludedFromCompilation(virtualFile) && !compilerConfiguration.isResourceFile(virtualFile); + if (virtualFile == null) return false; + return !compilerConfiguration.isExcludedFromCompilation(virtualFile) && + !ProjectRootManager.getInstance(myProject).getFileIndex().isUnderSourceRootOfType(virtualFile, JavaModuleSourceRootTypes.RESOURCES); } return false; } diff --git a/plugins/junit/src/com/intellij/execution/junit2/inspection/JUnitEntryPoint.java b/plugins/junit/src/com/intellij/execution/junit2/inspection/JUnitEntryPoint.java index b59854e320e6..ca813def140f 100644 --- a/plugins/junit/src/com/intellij/execution/junit2/inspection/JUnitEntryPoint.java +++ b/plugins/junit/src/com/intellij/execution/junit2/inspection/JUnitEntryPoint.java @@ -98,6 +98,11 @@ public class JUnitEntryPoint extends EntryPoint { @Override public String[] getIgnoreAnnotations() { - return new String[]{"org.junit.Rule", "org.mockito.Mock", "org.mockito.InjectMocks", "org.junit.ClassRule", "org.junit.experimental.theories.DataPoint"}; + return new String[]{"org.junit.Rule", + "org.mockito.Mock", + "org.mockito.Spy", + "org.mockito.InjectMocks", + "org.junit.ClassRule", + "org.junit.experimental.theories.DataPoint"}; } } \ No newline at end of file diff --git a/python/src/com/jetbrains/python/psi/impl/PythonLanguageLevelPusher.java b/python/src/com/jetbrains/python/psi/impl/PythonLanguageLevelPusher.java index 67af272bdf1d..6fa7ed5c68bf 100644 --- a/python/src/com/jetbrains/python/psi/impl/PythonLanguageLevelPusher.java +++ b/python/src/com/jetbrains/python/psi/impl/PythonLanguageLevelPusher.java @@ -20,6 +20,9 @@ import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.module.ModuleUtil; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.project.DumbModeTask; +import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.roots.*; @@ -156,27 +159,45 @@ public class PythonLanguageLevelPusher implements FilePropertyPusher updatedSdks = new HashSet(); - final Module[] modules = ModuleManager.getInstance(project).getModules(); - boolean needReparseOpenFiles = false; - for (Module module : modules) { - Sdk newSdk = PythonSdkType.findPythonSdk(module); - if (myModuleSdks.containsKey(module)) { - Sdk oldSdk = myModuleSdks.get(module); - if ((newSdk != null || oldSdk != null) && newSdk != oldSdk) { - needReparseOpenFiles = true; + public void afterRootsChanged(@NotNull final Project project) { + final Runnable updateLanguageLevel = new Runnable() { + @Override + public void run() { + final Set updatedSdks = new HashSet(); + final Module[] modules = ModuleManager.getInstance(project).getModules(); + boolean needReparseOpenFiles = false; + for (Module module : modules) { + Sdk newSdk = PythonSdkType.findPythonSdk(module); + if (myModuleSdks.containsKey(module)) { + Sdk oldSdk = myModuleSdks.get(module); + if ((newSdk != null || oldSdk != null) && newSdk != oldSdk) { + needReparseOpenFiles = true; + } + } + myModuleSdks.put(module, newSdk); + if (newSdk != null && !updatedSdks.contains(newSdk)) { + updatedSdks.add(newSdk); + updateSdkLanguageLevel(project, newSdk); + } } + final boolean finalNeedReparseOpenFiles = needReparseOpenFiles; + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + if (finalNeedReparseOpenFiles) { + FileContentUtil.reparseFiles(project, Collections.emptyList(), true); + } + } + }); } - myModuleSdks.put(module, newSdk); - if (newSdk != null && !updatedSdks.contains(newSdk)) { - updatedSdks.add(newSdk); - updateSdkLanguageLevel(project, newSdk); + }; + final DumbModeTask task = new DumbModeTask() { + @Override + public void performInDumbMode(@NotNull ProgressIndicator indicator) { + ApplicationManager.getApplication().runReadAction(updateLanguageLevel); } - } - if (needReparseOpenFiles) { - FileContentUtil.reparseFiles(project, Collections.emptyList(), true); - } + }; + DumbService.getInstance(project).queueTask(task); } private void updateSdkLanguageLevel(Project project, Sdk sdk) { diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkType.java b/python/src/com/jetbrains/python/sdk/PythonSdkType.java index be9aa9ad0458..e8352db6c434 100644 --- a/python/src/com/jetbrains/python/sdk/PythonSdkType.java +++ b/python/src/com/jetbrains/python/sdk/PythonSdkType.java @@ -287,6 +287,7 @@ public class PythonSdkType extends SdkType { public void consume(@Nullable Sdk sdk) { if (sdk != null) { sdk.putUserData(SDK_CREATOR_COMPONENT_KEY, new WeakReference(parentComponent)); + sdkCreatedCallback.consume(sdk); } } }); @@ -499,6 +500,11 @@ public class PythonSdkType extends SdkType { setupSdkPaths(sdk, project, ownerComponent); } + @Override + public boolean setupSdkPaths(Sdk sdk, SdkModel sdkModel) { + return true; // run setupSdkPaths only once (from PythonSdkDetailsStep). Skip this from showCustomCreateUI + } + public static void setupSdkPaths(Sdk sdk, @Nullable Project project, @Nullable Component ownerComponent) { final SdkModificator sdkModificator = sdk.getSdkModificator(); final boolean success = setupSdkPaths(project, ownerComponent, sdk, sdkModificator);