From 77919bbb497b2c5964e64818805642c32de7fcc4 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 9 Feb 2012 15:32:19 +0100 Subject: [PATCH 01/59] SVN refresh test can now run with lesser delay --- .../idea/svn/SvnChangesCorrectlyRefreshedTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/svn4ideaOld/testSource/org/jetbrains/idea/svn/SvnChangesCorrectlyRefreshedTest.java b/plugins/svn4ideaOld/testSource/org/jetbrains/idea/svn/SvnChangesCorrectlyRefreshedTest.java index d49a3e711301..fbed7a8a9a7a 100644 --- a/plugins/svn4ideaOld/testSource/org/jetbrains/idea/svn/SvnChangesCorrectlyRefreshedTest.java +++ b/plugins/svn4ideaOld/testSource/org/jetbrains/idea/svn/SvnChangesCorrectlyRefreshedTest.java @@ -89,14 +89,14 @@ public class SvnChangesCorrectlyRefreshedTest extends SvnTestCase { //ChangeListManagerImpl.DEBUG = true; final SubTree subTree = new SubTree(myWorkingCopyDir); checkin(); - sleep(1000); + sleep(100); - editFileInCommand(myProject, subTree.myS1File, "new"); + editFileInCommand(myProject, subTree.myS1File, "new content"); final CharSequence text1 = LoadTextUtil.loadText(subTree.myS1File); - Assert.assertEquals("new", text1.toString()); + Assert.assertEquals("new content", text1.toString()); - sleep(1000); + sleep(100); LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(subTree.myS1File.getPath())); VcsDirtyScopeManager.getInstance(myProject).markEverythingDirty(); clManager.ensureUpToDate(false); From 02b57f0ec2c3adf6864278f2a2fc279219122579 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 9 Feb 2012 22:30:08 +0100 Subject: [PATCH 02/59] .ico support --- .../impl/ImageFileTypeManagerImpl.java | 10 ++++++---- .../src/org/intellij/images/vfs/IfsUtil.java | 19 ++++++++++++++++++- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/images/src/org/intellij/images/fileTypes/impl/ImageFileTypeManagerImpl.java b/images/src/org/intellij/images/fileTypes/impl/ImageFileTypeManagerImpl.java index 761f578bb50f..d1af0a440dd6 100644 --- a/images/src/org/intellij/images/fileTypes/impl/ImageFileTypeManagerImpl.java +++ b/images/src/org/intellij/images/fileTypes/impl/ImageFileTypeManagerImpl.java @@ -23,6 +23,7 @@ import com.intellij.openapi.vfs.VirtualFile; import gnu.trove.THashSet; import org.intellij.images.ImagesBundle; import org.intellij.images.fileTypes.ImageFileTypeManager; +import org.intellij.images.vfs.IfsUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -76,15 +77,16 @@ final class ImageFileTypeManagerImpl extends ImageFileTypeManager implements App } public void createFileTypes(final @NotNull FileTypeConsumer consumer) { - final String[] readerFormatNames = ImageIO.getReaderFormatNames(); final Set processed = new THashSet(); + final String[] readerFormatNames = ImageIO.getReaderFormatNames(); for (String format : readerFormatNames) { - final String s = format.toLowerCase(); - if (processed.contains(s)) continue; - processed.add(s); + final String ext = format.toLowerCase(); + processed.add(ext); } + processed.add(IfsUtil.ICO_FORMAT.toLowerCase()); + consumer.consume(imageFileType, StringUtil.join(processed, FileTypeConsumer.EXTENSION_DELIMITER)); } } diff --git a/images/src/org/intellij/images/vfs/IfsUtil.java b/images/src/org/intellij/images/vfs/IfsUtil.java index 8e67e3f6de9d..bb2f1541f299 100644 --- a/images/src/org/intellij/images/vfs/IfsUtil.java +++ b/images/src/org/intellij/images/vfs/IfsUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,9 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.reference.SoftReference; import com.intellij.util.LogicalRoot; import com.intellij.util.LogicalRootsManager; +import org.apache.sanselan.ImageReadException; +import org.apache.sanselan.common.byteSources.ByteSourceArray; +import org.apache.sanselan.formats.ico.IcoImageParser; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -46,9 +49,12 @@ import java.util.Iterator; * @author Alexey Efimov */ public final class IfsUtil { + public static final String ICO_FORMAT = "ico"; + private static final Key TIMESTAMP_KEY = Key.create("Image.timeStamp"); private static final Key FORMAT_KEY = Key.create("Image.format"); private static final Key> BUFFERED_IMAGE_REF_KEY = Key.create("Image.bufferedImage"); + private static final IcoImageParser ICO_IMAGE_PARSER = new IcoImageParser(); /** * Load image data for file and put user data attributes into file. @@ -63,6 +69,17 @@ public final class IfsUtil { if (loadedTimeStamp == null || loadedTimeStamp.longValue() != file.getTimeStamp() || imageRef == null || imageRef.get() == null) { try { final byte[] content = file.contentsToByteArray(); + + if (ICO_FORMAT.equalsIgnoreCase(file.getExtension())) { + try { + final BufferedImage image = ICO_IMAGE_PARSER.getBufferedImage(new ByteSourceArray(content), null); + file.putUserData(FORMAT_KEY, ICO_FORMAT); + file.putUserData(BUFFERED_IMAGE_REF_KEY, new SoftReference(image)); + return true; + } + catch (ImageReadException ignore) { } + } + InputStream inputStream = new ByteArrayInputStream(content, 0, content.length); ImageInputStream imageInputStream = ImageIO.createImageInputStream(inputStream); try { From 35b4fdc301afb1076ba6a85fc34d27d8c7ff155b Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Thu, 9 Feb 2012 23:28:50 +0400 Subject: [PATCH 03/59] IDEA-24310 easy-to-use 'find usages' and 'rename' for value android resources. --- plugins/android/src/META-INF/plugin.xml | 3 + .../android/AndroidRenameHandler.java | 98 ++++++++++++++ .../android/AndroidUsagesTargetProvider.java | 72 ++++++++++ .../testData/findUsages/fu1_values.xml | 5 + .../testData/findUsages/fu2_values.xml | 5 + .../testData/findUsages/fu3_values.xml | 5 + .../testData/findUsages/fu4_values.xml | 5 + .../testData/findUsages/fu5_values.xml | 5 + .../testData/findUsages/fu6_values.xml | 5 + .../testData/findUsages/fu7_values.xml | 5 + .../testData/findUsages/fu8_values.xml | 5 + .../testData/findUsages/fu9_values.xml | 8 ++ .../testData/rename/layoutStrUsage.xml | 4 + .../testData/rename/layoutStrUsage_after.xml | 4 + plugins/android/testData/rename/strings1.xml | 3 + plugins/android/testData/rename/strings2.xml | 3 + plugins/android/testData/rename/strings3.xml | 3 + plugins/android/testData/rename/strings4.xml | 3 + .../android/AndroidFindUsagesTest.java | 123 ++++++++++++++---- .../jetbrains/android/AndroidRenameTest.java | 55 +++++++- 20 files changed, 394 insertions(+), 25 deletions(-) create mode 100644 plugins/android/src/org/jetbrains/android/AndroidRenameHandler.java create mode 100644 plugins/android/src/org/jetbrains/android/AndroidUsagesTargetProvider.java create mode 100644 plugins/android/testData/findUsages/fu1_values.xml create mode 100644 plugins/android/testData/findUsages/fu2_values.xml create mode 100644 plugins/android/testData/findUsages/fu3_values.xml create mode 100644 plugins/android/testData/findUsages/fu4_values.xml create mode 100644 plugins/android/testData/findUsages/fu5_values.xml create mode 100644 plugins/android/testData/findUsages/fu6_values.xml create mode 100644 plugins/android/testData/findUsages/fu7_values.xml create mode 100644 plugins/android/testData/findUsages/fu8_values.xml create mode 100644 plugins/android/testData/findUsages/fu9_values.xml create mode 100644 plugins/android/testData/rename/layoutStrUsage.xml create mode 100644 plugins/android/testData/rename/layoutStrUsage_after.xml create mode 100644 plugins/android/testData/rename/strings1.xml create mode 100644 plugins/android/testData/rename/strings2.xml create mode 100644 plugins/android/testData/rename/strings3.xml create mode 100644 plugins/android/testData/rename/strings4.xml diff --git a/plugins/android/src/META-INF/plugin.xml b/plugins/android/src/META-INF/plugin.xml index 67a616094d46..245e7a2f1ad4 100644 --- a/plugins/android/src/META-INF/plugin.xml +++ b/plugins/android/src/META-INF/plugin.xml @@ -190,6 +190,9 @@ + + + diff --git a/plugins/android/src/org/jetbrains/android/AndroidRenameHandler.java b/plugins/android/src/org/jetbrains/android/AndroidRenameHandler.java new file mode 100644 index 000000000000..2924d9cd3a3b --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/AndroidRenameHandler.java @@ -0,0 +1,98 @@ +package org.jetbrains.android; + +import com.intellij.ide.TitledHandler; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.LangDataKeys; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.xml.XmlAttribute; +import com.intellij.psi.xml.XmlAttributeValue; +import com.intellij.psi.xml.XmlTag; +import com.intellij.refactoring.rename.PsiElementRenameHandler; +import com.intellij.refactoring.rename.RenameDialog; +import com.intellij.refactoring.rename.RenameHandler; +import org.jetbrains.android.dom.wrappers.ValueResourceElementWrapper; +import org.jetbrains.annotations.NotNull; + +/** + * @author Eugene.Kudelevsky + */ +public class AndroidRenameHandler implements RenameHandler, TitledHandler { + @Override + public boolean isAvailableOnDataContext(DataContext dataContext) { + final Editor editor = PlatformDataKeys.EDITOR.getData(dataContext); + if (editor == null) { + return false; + } + + final PsiFile file = LangDataKeys.PSI_FILE.getData(dataContext); + if (file == null) { + return false; + } + + return AndroidUsagesTargetProvider.findValueResourceTagInContext(editor, file) != null; + } + + @Override + public boolean isRenaming(DataContext dataContext) { + return isAvailableOnDataContext(dataContext); + } + + @Override + public void invoke(@NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) { + if (file == null || editor == null) { + return; + } + + final XmlTag tag = AndroidUsagesTargetProvider.findValueResourceTagInContext(editor, file); + if (tag == null) { + return; + } + + final XmlAttribute nameAttribute = tag.getAttribute("name"); + if (nameAttribute == null) { + return; + } + + final XmlAttributeValue attributeValue = nameAttribute.getValueElement(); + if (attributeValue == null) { + return; + } + final RenameDialog dialog = new RenameDialog(project, new ValueResourceElementWrapper(attributeValue), null, editor); + + if (ApplicationManager.getApplication().isUnitTestMode()) { + final String name = PsiElementRenameHandler.DEFAULT_NAME.getData(dataContext); + //noinspection TestOnlyProblems + dialog.performRename(name); + dialog.close(DialogWrapper.OK_EXIT_CODE); + } + else { + dialog.show(); + } + } + + @Override + public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, DataContext dataContext) { + final Editor editor = PlatformDataKeys.EDITOR.getData(dataContext); + if (editor == null) { + return; + } + + final PsiFile file = LangDataKeys.PSI_FILE.getData(dataContext); + if (file == null) { + return; + } + + invoke(project, editor, file, dataContext); + } + + @Override + public String getActionTitle() { + return "Rename Android value resource"; + } +} diff --git a/plugins/android/src/org/jetbrains/android/AndroidUsagesTargetProvider.java b/plugins/android/src/org/jetbrains/android/AndroidUsagesTargetProvider.java new file mode 100644 index 000000000000..da7bad1164e4 --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/AndroidUsagesTargetProvider.java @@ -0,0 +1,72 @@ +package org.jetbrains.android; + +import com.android.resources.ResourceFolderType; +import com.intellij.find.findUsages.PsiElement2UsageTargetAdapter; +import com.intellij.openapi.editor.Editor; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.xml.XmlFile; +import com.intellij.psi.xml.XmlTag; +import com.intellij.usages.UsageTarget; +import com.intellij.usages.UsageTargetProvider; +import org.jetbrains.android.facet.AndroidFacet; +import org.jetbrains.android.resourceManagers.ResourceManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Eugene.Kudelevsky + */ +public class AndroidUsagesTargetProvider implements UsageTargetProvider { + @Override + public UsageTarget[] getTargets(Editor editor, PsiFile file) { + if (editor == null || file == null) { + return UsageTarget.EMPTY_ARRAY; + } + + final XmlTag tag = findValueResourceTagInContext(editor, file); + return tag != null + ? new UsageTarget[]{new PsiElement2UsageTargetAdapter(tag)} + : UsageTarget.EMPTY_ARRAY; + } + + @Override + public UsageTarget[] getTargets(PsiElement psiElement) { + return UsageTarget.EMPTY_ARRAY; + } + + @Nullable + static XmlTag findValueResourceTagInContext(@NotNull Editor editor, @NotNull PsiFile file) { + if (!(file instanceof XmlFile)) { + return null; + } + + final AndroidFacet facet = AndroidFacet.getInstance(file); + if (facet == null) { + return null; + } + + if (!ResourceManager.isInResourceSubdirectory(file, ResourceFolderType.VALUES.getName())) { + return null; + } + + final PsiElement element = file.findElementAt(editor.getCaretModel().getOffset()); + if (element == null) { + return null; + } + + final XmlTag tag = PsiTreeUtil.getParentOfType(element, XmlTag.class); + if (tag == null) { + return null; + } + + final String name = tag.getAttributeValue("name"); + if (name == null || name.length() == 0) { + return null; + } + + final XmlTag parentTag = tag.getParentTag(); + return parentTag != null && parentTag.getParentTag() == null ? tag : null; + } +} diff --git a/plugins/android/testData/findUsages/fu1_values.xml b/plugins/android/testData/findUsages/fu1_values.xml new file mode 100644 index 000000000000..7030fd307cf3 --- /dev/null +++ b/plugins/android/testData/findUsages/fu1_values.xml @@ -0,0 +1,5 @@ + + hello + + + \ No newline at end of file diff --git a/plugins/android/testData/findUsages/fu2_values.xml b/plugins/android/testData/findUsages/fu2_values.xml new file mode 100644 index 000000000000..ae503ae09b39 --- /dev/null +++ b/plugins/android/testData/findUsages/fu2_values.xml @@ -0,0 +1,5 @@ + + ng name="hello">hello + + + \ No newline at end of file diff --git a/plugins/android/testData/findUsages/fu3_values.xml b/plugins/android/testData/findUsages/fu3_values.xml new file mode 100644 index 000000000000..0f71c487817f --- /dev/null +++ b/plugins/android/testData/findUsages/fu3_values.xml @@ -0,0 +1,5 @@ + + name="hello">hello + + + \ No newline at end of file diff --git a/plugins/android/testData/findUsages/fu4_values.xml b/plugins/android/testData/findUsages/fu4_values.xml new file mode 100644 index 000000000000..68bcff440083 --- /dev/null +++ b/plugins/android/testData/findUsages/fu4_values.xml @@ -0,0 +1,5 @@ + + hello + + + \ No newline at end of file diff --git a/plugins/android/testData/findUsages/fu5_values.xml b/plugins/android/testData/findUsages/fu5_values.xml new file mode 100644 index 000000000000..88982c39bb12 --- /dev/null +++ b/plugins/android/testData/findUsages/fu5_values.xml @@ -0,0 +1,5 @@ + + >hello + + + \ No newline at end of file diff --git a/plugins/android/testData/findUsages/fu6_values.xml b/plugins/android/testData/findUsages/fu6_values.xml new file mode 100644 index 000000000000..3319786f7050 --- /dev/null +++ b/plugins/android/testData/findUsages/fu6_values.xml @@ -0,0 +1,5 @@ + + hello + + + \ No newline at end of file diff --git a/plugins/android/testData/findUsages/fu7_values.xml b/plugins/android/testData/findUsages/fu7_values.xml new file mode 100644 index 000000000000..cac0b17f269a --- /dev/null +++ b/plugins/android/testData/findUsages/fu7_values.xml @@ -0,0 +1,5 @@ + + hellotring> + + + \ No newline at end of file diff --git a/plugins/android/testData/findUsages/fu8_values.xml b/plugins/android/testData/findUsages/fu8_values.xml new file mode 100644 index 000000000000..b3349b91a06f --- /dev/null +++ b/plugins/android/testData/findUsages/fu8_values.xml @@ -0,0 +1,5 @@ + + hello</string> + + + \ No newline at end of file diff --git a/plugins/android/testData/findUsages/fu9_values.xml b/plugins/android/testData/findUsages/fu9_values.xml new file mode 100644 index 000000000000..2c8a4248c85b --- /dev/null +++ b/plugins/android/testData/findUsages/fu9_values.xml @@ -0,0 +1,8 @@ + + hello + + + str1 + str2 + + \ No newline at end of file diff --git a/plugins/android/testData/rename/layoutStrUsage.xml b/plugins/android/testData/rename/layoutStrUsage.xml new file mode 100644 index 000000000000..72f3d5e274a2 --- /dev/null +++ b/plugins/android/testData/rename/layoutStrUsage.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plugins/android/testData/rename/layoutStrUsage_after.xml b/plugins/android/testData/rename/layoutStrUsage_after.xml new file mode 100644 index 000000000000..a2db8f608af7 --- /dev/null +++ b/plugins/android/testData/rename/layoutStrUsage_after.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plugins/android/testData/rename/strings1.xml b/plugins/android/testData/rename/strings1.xml new file mode 100644 index 000000000000..3a956ed1c142 --- /dev/null +++ b/plugins/android/testData/rename/strings1.xml @@ -0,0 +1,3 @@ + + HellO! + \ No newline at end of file diff --git a/plugins/android/testData/rename/strings2.xml b/plugins/android/testData/rename/strings2.xml new file mode 100644 index 000000000000..a516f0490b97 --- /dev/null +++ b/plugins/android/testData/rename/strings2.xml @@ -0,0 +1,3 @@ + + HellO! + \ No newline at end of file diff --git a/plugins/android/testData/rename/strings3.xml b/plugins/android/testData/rename/strings3.xml new file mode 100644 index 000000000000..9a555511326d --- /dev/null +++ b/plugins/android/testData/rename/strings3.xml @@ -0,0 +1,3 @@ + + HellO!ng> + \ No newline at end of file diff --git a/plugins/android/testData/rename/strings4.xml b/plugins/android/testData/rename/strings4.xml new file mode 100644 index 000000000000..a2cc809bcb54 --- /dev/null +++ b/plugins/android/testData/rename/strings4.xml @@ -0,0 +1,3 @@ + + tring name="str">HellO! + \ No newline at end of file diff --git a/plugins/android/testSrc/org/jetbrains/android/AndroidFindUsagesTest.java b/plugins/android/testSrc/org/jetbrains/android/AndroidFindUsagesTest.java index bdc34d014777..6dd6f4b58898 100644 --- a/plugins/android/testSrc/org/jetbrains/android/AndroidFindUsagesTest.java +++ b/plugins/android/testSrc/org/jetbrains/android/AndroidFindUsagesTest.java @@ -17,21 +17,23 @@ package org.jetbrains.android; import com.intellij.codeInsight.TargetElementUtilBase; +import com.intellij.openapi.actionSystem.DataProvider; +import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture; import com.intellij.usageView.UsageInfo; +import com.intellij.usages.PsiElementUsageTarget; +import com.intellij.usages.UsageTarget; +import com.intellij.usages.UsageTargetUtil; +import org.jetbrains.annotations.NonNls; +import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.ArrayList; /** - * Created by IntelliJ IDEA. - * User: Eugene.Kudelevsky - * Date: Aug 5, 2009 - * Time: 4:48:01 PM - * To change this template use File | Settings | File Templates. + * @author Eugene.Kudelevsky */ public class AndroidFindUsagesTest extends AndroidTestCase { private static final String BASE_PATH = "/findUsages/"; @@ -39,13 +41,12 @@ public class AndroidFindUsagesTest extends AndroidTestCase { @Override public void setUp() throws Exception { super.setUp(); - myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml"); myFixture.copyFileToProject(BASE_PATH + "picture3.gif", "res/drawable/picture3.gif"); myFixture.copyFileToProject(BASE_PATH + "R.java", "gen/p1/p2/R.java"); } - public List findCodeUsages(String path) throws Throwable { - Collection usages = findElementAtCaret(path, myFixture, BASE_PATH); + public List findCodeUsages(String path, String pathInProject) throws Throwable { + Collection usages = findUsages(path, myFixture, pathInProject); List result = new ArrayList(); for (UsageInfo usage : usages) { if (!usage.isNonCodeUsage) { @@ -56,70 +57,146 @@ public class AndroidFindUsagesTest extends AndroidTestCase { } public void testFileResource() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml"); myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); myFixture.copyFileToProject(BASE_PATH + "styles.xml", "res/values/styles.xml"); - Collection references = findCodeUsages("fu1_layout.xml"); + Collection references = findCodeUsages("fu1_layout.xml", "res/layout/fu1_layout.xml"); assertEquals(3, references.size()); } public void testValueResource() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml"); myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); - Collection references = findCodeUsages("fu2_layout.xml"); + Collection references = findCodeUsages("fu2_layout.xml", "res/layout/fu2_layout.xml"); + assertEquals(2, references.size()); + } + + public void testValueResource1() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); + myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml"); + Collection references = findCodeUsages("fu1_values.xml", "res/values/fu1_values.xml"); + assertEquals(2, references.size()); + } + + public void testValueResource2() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); + myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml"); + Collection references = findCodeUsages("fu2_values.xml", "res/values/fu2_values.xml"); + assertEquals(2, references.size()); + } + + public void testValueResource3() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); + myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml"); + Collection references = findCodeUsages("fu2_values.xml", "res/values/fu3_values.xml"); + assertEquals(2, references.size()); + } + + public void testValueResource4() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); + myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml"); + Collection references = findCodeUsages("fu2_values.xml", "res/values/fu4_values.xml"); + assertEquals(2, references.size()); + } + + public void testValueResource5() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); + myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml"); + Collection references = findCodeUsages("fu2_values.xml", "res/values/fu5_values.xml"); + assertEquals(2, references.size()); + } + + public void testValueResource6() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); + myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml"); + Collection references = findCodeUsages("fu2_values.xml", "res/values/fu6_values.xml"); + assertEquals(2, references.size()); + } + + public void testValueResource7() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); + myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml"); + Collection references = findCodeUsages("fu2_values.xml", "res/values/fu7_values.xml"); + assertEquals(2, references.size()); + } + + public void testValueResource8() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); + myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml"); + Collection references = findCodeUsages("fu2_values.xml", "res/values/f8_values.xml"); assertEquals(2, references.size()); } public void testValueItemResource() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml"); myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); - Collection references = findCodeUsages("fu5_layout.xml"); + Collection references = findCodeUsages("fu5_layout.xml", "res/layout/fu5_layout.xml"); assertEquals(2, references.size()); } public void testFileResourceField() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml"); myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml"); - Collection references = findCodeUsages("Fu3.java"); + Collection references = findCodeUsages("Fu3.java", "src/p1/p2/Fu3.java"); assertEquals(2, references.size()); } public void testValueResourceField() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml"); myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml"); - Collection references = findCodeUsages("Fu4.java"); + Collection references = findCodeUsages("Fu4.java", "src/p1/p2/Fu4.java"); assertEquals(2, references.size()); } public void testValueItemResourceField() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml"); myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml"); - Collection references = findCodeUsages("Fu6.java"); + Collection references = findCodeUsages("Fu6.java", "src/p1/p2/Fu6.java"); assertEquals(2, references.size()); } public void testIdResource() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml"); myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); - Collection references = findCodeUsages("fu7_layout.xml"); + Collection references = findCodeUsages("fu7_layout.xml", "res/layout/fu7_layout.xml"); assertEquals(2, references.size()); } public void testIdResourceField() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml"); myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml"); - Collection references = findCodeUsages("Fu8.java"); + Collection references = findCodeUsages("Fu8.java", "src/p1/p2/Fu8.java"); assertEquals(2, references.size()); } public void testIdResourceDeclaration() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml"); myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); - Collection references = findCodeUsages("fu9_layout.xml"); + Collection references = findCodeUsages("fu9_layout.xml", "res/layout/fu9_layout.xml"); assertEquals(2, references.size()); } public void testStringArray() throws Throwable { + myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml"); myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java"); - Collection references = findCodeUsages("stringArray.xml"); + Collection references = findCodeUsages("stringArray.xml", "res/layout/stringArray.xml"); assertEquals(2, references.size()); } - private static Collection findElementAtCaret(String fileName, JavaCodeInsightTestFixture fixture, String basePath) throws Throwable { - String newFilePath = "res/layout/" + fileName; - VirtualFile file = fixture.copyFileToProject(basePath + fileName, newFilePath); - return findUsages(file, fixture); + private static Collection findUsages(String fileName, final JavaCodeInsightTestFixture fixture, String newFilePath) + throws Throwable { + VirtualFile file = fixture.copyFileToProject(BASE_PATH + fileName, newFilePath); + fixture.configureFromExistingVirtualFile(file); + + final UsageTarget[] targets = UsageTargetUtil.findUsageTargets(new DataProvider() { + @Override + public Object getData(@NonNls String dataId) { + return ((EditorEx)fixture.getEditor()).getDataContext().getData(dataId); + } + }); + + assert targets != null && targets.length > 0 && targets[0] instanceof PsiElementUsageTarget; + return fixture.findUsages(((PsiElementUsageTarget)targets[0]).getElement()); } public static Collection findUsages(VirtualFile file, JavaCodeInsightTestFixture fixture) throws Exception { diff --git a/plugins/android/testSrc/org/jetbrains/android/AndroidRenameTest.java b/plugins/android/testSrc/org/jetbrains/android/AndroidRenameTest.java index 2221080aa23b..6e022c678f55 100644 --- a/plugins/android/testSrc/org/jetbrains/android/AndroidRenameTest.java +++ b/plugins/android/testSrc/org/jetbrains/android/AndroidRenameTest.java @@ -18,8 +18,10 @@ package org.jetbrains.android; import com.android.sdklib.SdkConstants; import com.intellij.codeInsight.TargetElementUtilBase; +import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; @@ -28,8 +30,10 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.refactoring.PackageWrapper; import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesProcessor; import com.intellij.refactoring.move.moveClassesOrPackages.SingleSourceRootMoveDestination; -import com.intellij.refactoring.rename.RenameProcessor; -import com.intellij.refactoring.rename.RenamePsiElementProcessor; +import com.intellij.refactoring.rename.*; +import org.jetbrains.annotations.NonNls; + +import java.io.IOException; /** * Created by IntelliJ IDEA. @@ -132,6 +136,53 @@ public class AndroidRenameTest extends AndroidTestCase { myFixture.checkResultByFile("res/values/strings.xml", BASE_PATH + "strings_after.xml", true); } + public void testValueResource1() throws Throwable { + doTestStringRename("strings1.xml"); + } + + public void testValueResource2() throws Throwable { + doTestStringRename("strings2.xml"); + } + + public void testValueResource3() throws Throwable { + doTestStringRename("strings3.xml"); + } + + public void testValueResource4() throws Throwable { + doTestStringRename("strings4.xml"); + } + + private void doTestStringRename(String fileName) throws IOException { + createManifest(); + VirtualFile file = myFixture.copyFileToProject(BASE_PATH + fileName, "res/values/strings.xml"); + myFixture.configureFromExistingVirtualFile(file); + + myFixture.copyFileToProject(BASE_PATH + "layoutStrUsage.xml", "res/layout/layoutStrUsage.xml"); + myFixture.copyFileToProject(BASE_PATH + "R2.java", R_JAVA_PATH); + + findHandlerAndDoRename(); + + myFixture.checkResultByFile(BASE_PATH + "strings_after.xml"); + myFixture.checkResultByFile(R_JAVA_PATH, BASE_PATH + "R_value_after.java", true); + myFixture.checkResultByFile("res/layout/layoutStrUsage.xml", BASE_PATH + "layoutStrUsage_after.xml", true); + } + + private void findHandlerAndDoRename() throws IOException { + final DataContext editorContext = ((EditorEx)myFixture.getEditor()).getDataContext(); + final DataContext context = new DataContext() { + @Override + public Object getData(@NonNls String dataId) { + return PsiElementRenameHandler.DEFAULT_NAME.getName().equals(dataId) + ? "str1" + : editorContext.getData(dataId); + } + }; + final RenameHandler renameHandler = RenameHandlerRegistry.getInstance().getRenameHandler(context); + assertNotNull(renameHandler); + + renameHandler.invoke(myFixture.getProject(), myFixture.getEditor(), myFixture.getFile(), context); + } + public void testJavaReferenceToFileResource() throws Throwable { createManifest(); VirtualFile file = myFixture.copyFileToProject(BASE_PATH + "R3.java", R_JAVA_PATH); From f6289371ef41f9067542d37b8dd81f41f0cc5ed3 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Thu, 9 Feb 2012 23:30:31 +0400 Subject: [PATCH 04/59] title for rename handler (can be available in group with AndroidRenameHandler) --- .../com/intellij/xml/refactoring/XmlTagRenameHandler.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/xml/impl/src/com/intellij/xml/refactoring/XmlTagRenameHandler.java b/xml/impl/src/com/intellij/xml/refactoring/XmlTagRenameHandler.java index 8d4ed2a0bda8..e2531e7956fc 100644 --- a/xml/impl/src/com/intellij/xml/refactoring/XmlTagRenameHandler.java +++ b/xml/impl/src/com/intellij/xml/refactoring/XmlTagRenameHandler.java @@ -23,6 +23,7 @@ package com.intellij.xml.refactoring; import com.intellij.featureStatistics.FeatureUsageTracker; +import com.intellij.ide.TitledHandler; import com.intellij.lang.Language; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.LangDataKeys; @@ -45,7 +46,7 @@ import com.intellij.xml.impl.schema.AnyXmlElementDescriptor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class XmlTagRenameHandler implements RenameHandler { +public class XmlTagRenameHandler implements RenameHandler, TitledHandler { private static final Logger LOG = Logger.getInstance("#com.intellij.xml.refactoring.XmlTagRenameHandler"); @@ -74,6 +75,11 @@ public class XmlTagRenameHandler implements RenameHandler { return isAvailableOnDataContext(dataContext); } + @Override + public String getActionTitle() { + return "Rename XML tag"; + } + private static boolean isInplaceRenameAvailable(final Editor editor) { return editor.getSettings().isVariableInplaceRenameEnabled(); } From b3a9e1d728d8d12e122b12602c8286d19a106bcb Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Fri, 10 Feb 2012 14:47:57 +0400 Subject: [PATCH 05/59] fix tests: provide path for community output directory --- plugins/android/src/META-INF/plugin.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/android/src/META-INF/plugin.xml b/plugins/android/src/META-INF/plugin.xml index 245e7a2f1ad4..879eb049c278 100644 --- a/plugins/android/src/META-INF/plugin.xml +++ b/plugins/android/src/META-INF/plugin.xml @@ -198,6 +198,7 @@ + From bd679f42d710f33a308d4124c00f65daa3e18bea Mon Sep 17 00:00:00 2001 From: anna Date: Fri, 10 Feb 2012 11:53:27 +0100 Subject: [PATCH 06/59] revert: waiting for a fix --- .../src/com/intellij/execution/impl/ConsoleViewImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java index 24102411122a..e9c60bb92039 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java @@ -500,7 +500,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo } private ModalityState getStateForUpdate() { - return null;//myStateForUpdate != null ? myStateForUpdate.compute() : ModalityState.stateForComponent(this); + return myStateForUpdate != null ? myStateForUpdate.compute() : ModalityState.stateForComponent(this); } private void requestFlushImmediately() { From 5ce639ae27ffa2f842fcb8ecc184148a8811d46f Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Thu, 9 Feb 2012 17:02:32 +0400 Subject: [PATCH 07/59] GitSmartOperationDialog: "checkout" -> operation title --- .../branch/GitSmartOperationDialog.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/plugins/git4idea/src/git4idea/branch/GitSmartOperationDialog.java b/plugins/git4idea/src/git4idea/branch/GitSmartOperationDialog.java index 0d8a187664e4..9eb9b8c6193b 100644 --- a/plugins/git4idea/src/git4idea/branch/GitSmartOperationDialog.java +++ b/plugins/git4idea/src/git4idea/branch/GitSmartOperationDialog.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,6 @@ package git4idea.branch; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.ui.ChangesBrowser; import com.intellij.ui.IdeBorderFactory; @@ -31,6 +30,8 @@ import java.awt.event.ActionEvent; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; +import static com.intellij.openapi.util.text.StringUtil.capitalize; + /** * The dialog that is shown when the error * "Your local changes to the following files would be overwritten by merge/checkout" @@ -46,7 +47,7 @@ class GitSmartOperationDialog extends DialogWrapper { private final Project myProject; private final List myChanges; - @NotNull private final String myCapitalizedOperationTitle; + @NotNull private final String myOperationTitle; private final boolean myForceButton; /** @@ -71,10 +72,10 @@ class GitSmartOperationDialog extends DialogWrapper { super(project); myProject = project; myChanges = changes; - myCapitalizedOperationTitle = StringUtil.capitalize(operationTitle); + myOperationTitle = operationTitle; myForceButton = forceButton; - setOKButtonText("Smart " + myCapitalizedOperationTitle); - setCancelButtonText("Don't " + myCapitalizedOperationTitle); + setOKButtonText("Smart " + capitalize(myOperationTitle)); + setCancelButtonText("Don't " + capitalize(myOperationTitle)); getCancelAction().putValue(FOCUSED_ACTION, Boolean.TRUE); init(); } @@ -82,15 +83,15 @@ class GitSmartOperationDialog extends DialogWrapper { @Override protected Action[] createLeftSideActions() { if (myForceButton) { - return new Action[] {new ForceCheckoutAction(myCapitalizedOperationTitle) }; + return new Action[] {new ForceCheckoutAction(myOperationTitle) }; } return new Action[0]; } @Override protected JComponent createNorthPanel() { - JBLabel description = new JBLabel("Your local changes to the following files would be overwritten by checkout.
" + - "IDEA can stash the changes, checkout and unstash them after that."); + JBLabel description = new JBLabel("Your local changes to the following files would be overwritten by " + myOperationTitle + + ".
IDEA can stash the changes, " + myOperationTitle + " and unstash them after that."); description.setBorder(IdeBorderFactory.createEmptyBorder(0, 0, 10, 0)); return description; } @@ -112,7 +113,7 @@ class GitSmartOperationDialog extends DialogWrapper { private class ForceCheckoutAction extends AbstractAction { ForceCheckoutAction(@NotNull String operationTitle) { - super("Force " + operationTitle); + super("Force " + capitalize(operationTitle)); } @Override From d8c483d3077c04be2e32203bd966f06207926278 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Thu, 9 Feb 2012 17:03:15 +0400 Subject: [PATCH 08/59] GitStashChangesSaver: show only one conflict resolving dialog for several conflicting roots: collect conflicts and then display them at once. --- .../git4idea/stash/GitStashChangesSaver.java | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/plugins/git4idea/src/git4idea/stash/GitStashChangesSaver.java b/plugins/git4idea/src/git4idea/stash/GitStashChangesSaver.java index 9ce2fe859bde..24265cf34d37 100644 --- a/plugins/git4idea/src/git4idea/stash/GitStashChangesSaver.java +++ b/plugins/git4idea/src/git4idea/stash/GitStashChangesSaver.java @@ -77,9 +77,22 @@ public class GitStashChangesSaver extends GitChangesSaver { } public void load() throws VcsException { + Collection conflictedRoots = new ArrayList(); for (VirtualFile root : myStashedRoots) { - loadRoot(root); + boolean conflict = loadRoot(root); + if (conflict) { + conflictedRoots.add(root); + } } + + boolean conflictsResolved = new UnstashConflictResolver(myProject, myStashedRoots, myParams).merge(); + if (conflictsResolved) { + LOG.info("load: all conflicts resolved, dropping stash in " + myStashedRoots); + for (VirtualFile root : conflictedRoots) { + GitStashUtils.dropStash(myProject, root); + } + } + // we'll refresh more but this way we needn't compute what files under roots etc LocalFileSystem.getInstance().refreshIoFiles(myChangeManager.getAffectedPaths()); } @@ -122,7 +135,11 @@ public class GitStashChangesSaver extends GitChangesSaver { } } - private void loadRoot(final VirtualFile root) throws VcsException { + /** + * Returns true if the root was loaded with conflict. + * False is returned in all other cases: in the case of success and in case of some other error. + */ + private boolean loadRoot(final VirtualFile root) throws VcsException { LOG.info("loadRoot " + root); myProgressIndicator.setText(GitHandlerUtil.formatOperationName("Unstashing changes to", root)); final GitLineHandler handler = new GitLineHandler(myProject, root, GitCommand.STASH); @@ -159,26 +176,21 @@ public class GitStashChangesSaver extends GitChangesSaver { if (failure.get()) { if (conflict.get()) { - boolean conflictsResolved = new UnstashConflictResolver(myProject, root, myStashedRoots, myParams).merge(); - if (conflictsResolved) { - LOG.info("loadRoot " + root + " conflicts resolved, dropping stash"); - GitStashUtils.dropStash(myProject, root); - } + return true; } else { LOG.info("unstash failed " + handler.errors()); GitUIUtil.notifyImportantError(myProject, "Couldn't unstash", "
" + GitUIUtil.stringifyErrors(handler.errors())); } } + return false; } private static class UnstashConflictResolver extends GitConflictResolver { - private final VirtualFile myRoot; private final Set myStashedRoots; - public UnstashConflictResolver(@NotNull Project project, @NotNull VirtualFile root, @NotNull Set stashedRoots, @Nullable Params params) { - super(project, Collections.singleton(root), makeParamsOrUse(params)); - myRoot = root; + public UnstashConflictResolver(@NotNull Project project, @NotNull Set stashedRoots, @Nullable Params params) { + super(project, stashedRoots, makeParamsOrUse(params)); myStashedRoots = stashedRoots; } @@ -206,7 +218,7 @@ public class GitStashChangesSaver extends GitChangesSaver { if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { if (event.getDescription().equals("saver")) { // we don't use #showSavedChanges to specify unmerged root first - GitUnstashDialog.showUnstashDialog(myProject, new ArrayList(myStashedRoots), myRoot, + GitUnstashDialog.showUnstashDialog(myProject, new ArrayList(myStashedRoots), myStashedRoots.iterator().next(), new HashSet()); } else if (event.getDescription().equals("resolve")) { mergeNoProceed(); From 36823438097561d0c8b8520482f3fae17901b026 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Thu, 9 Feb 2012 17:17:33 +0400 Subject: [PATCH 09/59] Hide balloon with a link, only when the link is clicked, not on any event. --- .../src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java index d96b8b17f2b8..c7ac33742fe9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java @@ -1873,7 +1873,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements @Override public void hyperlinkUpdate(HyperlinkEvent e) { - if (myBalloon != null) { + if (myBalloon != null && e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { myBalloon.hide(); } if (myListener != null) { From 28155b5e1314165ffd93632ef3417b6c871a961d Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Thu, 9 Feb 2012 17:21:30 +0400 Subject: [PATCH 10/59] Propose to delete branch after merge. In the successful notification about merged branch propose to delete this branch. Clicking the link invokes new GitBranchOperationsProcessor.delete. --- .../git4idea/branch/GitBranchOperation.java | 2 +- .../branch/GitBranchOperationsProcessor.java | 2 +- .../git4idea/branch/GitMergeOperation.java | 23 +++++++++++++++++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java b/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java index d9676498e5e1..456f6922f096 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java @@ -159,7 +159,7 @@ abstract class GitBranchOperation { NotificationManager.getInstance(myProject).notify(GitVcs.NOTIFICATION_GROUP_ID, "", message, NotificationType.INFORMATION); } - protected void notifySuccess() { + protected final void notifySuccess() { notifySuccess(getSuccessMessage()); } diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java b/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java index e066aa825424..4f68d4dcd8aa 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java @@ -247,7 +247,7 @@ public final class GitBranchOperationsProcessor { for (GitRepository repository : myRepositories) { revisions.put(repository, repository.getCurrentRevision()); } - new GitMergeOperation(myProject, myRepositories, branchName, getCurrentBranch(), revisions, indicator).execute(); + new GitMergeOperation(myProject, myRepositories, branchName, getCurrentBranch(), mySelectedRepository, revisions, indicator).execute(); } /** diff --git a/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java b/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java index fce48e4c0643..05e0069dc8db 100644 --- a/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java @@ -15,6 +15,8 @@ */ package git4idea.branch; +import com.intellij.notification.Notification; +import com.intellij.notification.NotificationListener; import com.intellij.notification.NotificationType; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; @@ -35,6 +37,7 @@ import git4idea.repo.GitRepository; import git4idea.util.GitPreservingProcess; import org.jetbrains.annotations.NotNull; +import javax.swing.event.HyperlinkEvent; import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; @@ -52,6 +55,7 @@ class GitMergeOperation extends GitBranchOperation { @NotNull private final ChangeListManager myChangeListManager; @NotNull private final String myBranchToMerge; @NotNull private final String myCurrentBranch; + @NotNull private final GitRepository myCurrentRepository; @NotNull private final Map myCurrentRevisionsBeforeMerge; // true in value if unstash will be needed after resolving conflicts. @@ -59,13 +63,13 @@ class GitMergeOperation extends GitBranchOperation { private GitPreservingProcess myPreservingProcess; protected GitMergeOperation(@NotNull Project project, @NotNull Collection repositories, - @NotNull String branchToMerge, - @NotNull String currentBranch, + @NotNull String branchToMerge, @NotNull String currentBranch, @NotNull GitRepository currentRepository, @NotNull Map currentRevisionsBeforeMerge, @NotNull ProgressIndicator indicator) { super(project, repositories, indicator); myBranchToMerge = branchToMerge; myCurrentBranch = currentBranch; + myCurrentRepository = currentRepository; myCurrentRevisionsBeforeMerge = currentRevisionsBeforeMerge; myChangeListManager = ChangeListManager.getInstance(myProject); } @@ -133,6 +137,21 @@ class GitMergeOperation extends GitBranchOperation { restoreLocalChanges(); } + @Override + protected void notifySuccess(@NotNull String message) { + String description = message + "
Delete " + myBranchToMerge + ""; + NotificationManager.getInstance(myProject).notify(GitVcs.NOTIFICATION_GROUP_ID, "", description, NotificationType.INFORMATION, + new NotificationListener() { + @Override + public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) { + if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED && event.getDescription().equalsIgnoreCase("delete")) { + new GitBranchOperationsProcessor(myProject, new ArrayList(getRepositories()), myCurrentRepository). + deleteBranch(myBranchToMerge); + } + } + }); + } + private boolean resolveConflicts() { if (!myConflictedRepositories.isEmpty()) { GitMerger merger = new GitMerger(myProject); From ca652fcca7ac1d16bd032f8d4bbc1451a285c264 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Thu, 9 Feb 2012 19:23:52 +0400 Subject: [PATCH 11/59] Fix messages in tests --- plugins/git4idea/src/git4idea/branch/GitMergeOperation.java | 2 +- .../tests/git4idea/branch/GitBranchOperationsTest.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java b/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java index 05e0069dc8db..dde3d9a2abac 100644 --- a/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java @@ -130,7 +130,7 @@ class GitMergeOperation extends GitBranchOperation { notifySuccess(); } else { - notifySuccess("Already up-to-date."); + notifySuccess("Already up-to-date"); } } diff --git a/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java b/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java index 958213bbd41f..69dc52cb57c4 100644 --- a/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java +++ b/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java @@ -492,7 +492,7 @@ public class GitBranchOperationsTest extends AbstractVcsTestCase { public void merge_simple_without_problems() throws Exception { prepareBranchWithCommit("feature", myUltimate, myCommunity, myContrib); doMerge("feature"); - assertNotify(NotificationType.INFORMATION, "Merged feature to master"); + assertNotify(NotificationType.INFORMATION, "Merged feature to master
Delete feature"); assertFile(myUltimate, "unmerged_branch_file", "content"); assertFile(myCommunity, "unmerged_branch_file", "content"); @@ -514,7 +514,7 @@ public class GitBranchOperationsTest extends AbstractVcsTestCase { doMerge("master2"); - assertNotify(NotificationType.INFORMATION, "Already up-to-date."); + assertNotify(NotificationType.INFORMATION, "Already up-to-date
Delete master2"); } @Test @@ -525,7 +525,7 @@ public class GitBranchOperationsTest extends AbstractVcsTestCase { doMerge("master2"); - assertNotify(NotificationType.INFORMATION, "Merged master2 to master"); + assertNotify(NotificationType.INFORMATION, "Merged master2 to master
Delete master2"); assertFile(myCommunity, "unmerged_branch_file", "content"); assertNull(myUltimate.getRoot().findChild("unmerged_branch_file")); } From 2292dd7069812cc094e6e6403dbf05a529272343 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Thu, 9 Feb 2012 19:25:16 +0400 Subject: [PATCH 12/59] Don't refresh automatically on unstash. Add the capability to refresh() method and call it from GitUpdateProcess. --- .../src/git4idea/stash/GitChangesSaver.java | 5 +++++ .../git4idea/stash/GitShelveChangesSaver.java | 12 ++++++++++-- .../git4idea/stash/GitStashChangesSaver.java | 17 +++++++++++------ .../src/git4idea/update/GitUpdateProcess.java | 1 + 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/plugins/git4idea/src/git4idea/stash/GitChangesSaver.java b/plugins/git4idea/src/git4idea/stash/GitChangesSaver.java index 589e847d342b..7b1bb953cf38 100644 --- a/plugins/git4idea/src/git4idea/stash/GitChangesSaver.java +++ b/plugins/git4idea/src/git4idea/stash/GitChangesSaver.java @@ -51,6 +51,11 @@ public abstract class GitChangesSaver { protected GitConflictResolver.Params myParams; + /** + * Refreshes files changed during save or load. + */ + public abstract void refresh(); + /** * Returns an instance of the proper GitChangesSaver depending on the chosen save changes policy. * @return {@link GitStashChangesSaver}, {@link GitShelveChangesSaver} or {@link GitDumbChangesSaver} diff --git a/plugins/git4idea/src/git4idea/stash/GitShelveChangesSaver.java b/plugins/git4idea/src/git4idea/stash/GitShelveChangesSaver.java index ca5aa577ce80..55d2829e6d87 100644 --- a/plugins/git4idea/src/git4idea/stash/GitShelveChangesSaver.java +++ b/plugins/git4idea/src/git4idea/stash/GitShelveChangesSaver.java @@ -89,11 +89,19 @@ public class GitShelveChangesSaver extends GitChangesSaver { return myShelvedChangeList != null; } - @Override public String getSaverName() { + @Override + public String getSaverName() { return "shelf"; } - @Override protected void showSavedChanges() { + @Override + protected void showSavedChanges() { myShelveViewManager.activateView(myShelvedChangeList); } + + @Override + public void refresh() { + // refreshed inside shelve manager + } + } diff --git a/plugins/git4idea/src/git4idea/stash/GitStashChangesSaver.java b/plugins/git4idea/src/git4idea/stash/GitStashChangesSaver.java index 24265cf34d37..c81bf8dbc64b 100644 --- a/plugins/git4idea/src/git4idea/stash/GitStashChangesSaver.java +++ b/plugins/git4idea/src/git4idea/stash/GitStashChangesSaver.java @@ -35,8 +35,8 @@ import git4idea.commands.*; import git4idea.config.GitVcsSettings; import git4idea.convert.GitFileSeparatorConverter; import git4idea.merge.GitConflictResolver; -import git4idea.util.GitUIUtil; import git4idea.ui.GitUnstashDialog; +import git4idea.util.GitUIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -92,9 +92,6 @@ public class GitStashChangesSaver extends GitChangesSaver { GitStashUtils.dropStash(myProject, root); } } - - // we'll refresh more but this way we needn't compute what files under roots etc - LocalFileSystem.getInstance().refreshIoFiles(myChangeManager.getAffectedPaths()); } @Override @@ -102,14 +99,22 @@ public class GitStashChangesSaver extends GitChangesSaver { return !myStashedRoots.isEmpty(); } - @Override public String getSaverName() { + @Override + public String getSaverName() { return "stash"; } - @Override protected void showSavedChanges() { + @Override + protected void showSavedChanges() { GitUnstashDialog.showUnstashDialog(myProject, new ArrayList(myStashedRoots), myStashedRoots.iterator().next(), new HashSet()); } + @Override + public void refresh() { + // we'll refresh more but this way we needn't compute what files under roots etc + LocalFileSystem.getInstance().refreshIoFiles(myChangeManager.getAffectedPaths()); + } + private void stash(Collection roots) throws VcsException { for (VirtualFile root : roots) { final String message = GitHandlerUtil.formatOperationName("Stashing changes from", root); diff --git a/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java b/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java index 6f4c81c8aeb6..9e0209a15d0a 100644 --- a/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java +++ b/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java @@ -215,6 +215,7 @@ public class GitUpdateProcess { final ContinuationFinalTasksInserter finalTasksInserter = new ContinuationFinalTasksInserter(context); finalTasksInserter.allNextAreFinal(); mySaver.restoreLocalChanges(context); + mySaver.refresh(); finalTasksInserter.removeFinalPropertyAdder(); } From 12b55a7321b012fa3de93293c625898456f19576 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Thu, 9 Feb 2012 19:33:51 +0400 Subject: [PATCH 13/59] Add mnemonic to "Force checkout/merge" --- .../git4idea/src/git4idea/branch/GitSmartOperationDialog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/git4idea/src/git4idea/branch/GitSmartOperationDialog.java b/plugins/git4idea/src/git4idea/branch/GitSmartOperationDialog.java index 9eb9b8c6193b..f03b940f4bf8 100644 --- a/plugins/git4idea/src/git4idea/branch/GitSmartOperationDialog.java +++ b/plugins/git4idea/src/git4idea/branch/GitSmartOperationDialog.java @@ -113,7 +113,7 @@ class GitSmartOperationDialog extends DialogWrapper { private class ForceCheckoutAction extends AbstractAction { ForceCheckoutAction(@NotNull String operationTitle) { - super("Force " + capitalize(operationTitle)); + super("&Force " + capitalize(operationTitle)); } @Override From 2406fba76ac378874a7e63535314d3c6f969f1d2 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Fri, 10 Feb 2012 14:08:19 +0400 Subject: [PATCH 14/59] better name for GitBranchOperationsProcessor#getCurrentBranchOrRev --- .../branch/GitBranchOperationsProcessor.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java b/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java index 4f68d4dcd8aa..887983904b2c 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java @@ -81,7 +81,7 @@ public final class GitBranchOperationsProcessor { } @NotNull - private String getCurrentBranch() { + private String getCurrentBranchOrRev() { if (myRepositories.size() > 1) { GitMultiRootBranchConfig multiRootBranchConfig = new GitMultiRootBranchConfig(myRepositories); String currentBranch = multiRootBranchConfig.getCurrentBranch(); @@ -121,7 +121,7 @@ public final class GitBranchOperationsProcessor { } private void doCheckoutNewBranch(@NotNull final String name, @NotNull ProgressIndicator indicator) { - new GitCheckoutNewBranchOperation(myProject, myRepositories, name, getCurrentBranch(), indicator).execute(); + new GitCheckoutNewBranchOperation(myProject, myRepositories, name, getCurrentBranchOrRev(), indicator).execute(); } /** @@ -162,7 +162,7 @@ public final class GitBranchOperationsProcessor { } private void doCheckout(@NotNull ProgressIndicator indicator, @NotNull String reference, @Nullable String newBranch) { - new GitCheckoutOperation(myProject, myRepositories, reference, newBranch, getCurrentBranch(), indicator).execute(); + new GitCheckoutOperation(myProject, myRepositories, reference, newBranch, getCurrentBranchOrRev(), indicator).execute(); } public void deleteBranch(final String branchName) { @@ -174,7 +174,7 @@ public final class GitBranchOperationsProcessor { } private void doDelete(final String branchName, ProgressIndicator indicator) { - new GitDeleteBranchOperation(myProject, myRepositories, branchName, getCurrentBranch(), indicator).execute(); + new GitDeleteBranchOperation(myProject, myRepositories, branchName, getCurrentBranchOrRev(), indicator).execute(); } /** @@ -197,7 +197,7 @@ public final class GitBranchOperationsProcessor { LOG.error("The task to get compare info didn't finish. Repositories: \n" + myRepositories + "\nbranch name: " + branchName); return; } - displayCompareDialog(branchName, getCurrentBranch(), myCompareInfo); + displayCompareDialog(branchName, getCurrentBranchOrRev(), myCompareInfo); } }.runInBackground(); } @@ -247,7 +247,7 @@ public final class GitBranchOperationsProcessor { for (GitRepository repository : myRepositories) { revisions.put(repository, repository.getCurrentRevision()); } - new GitMergeOperation(myProject, myRepositories, branchName, getCurrentBranch(), mySelectedRepository, revisions, indicator).execute(); + new GitMergeOperation(myProject, myRepositories, branchName, getCurrentBranchOrRev(), mySelectedRepository, revisions, indicator).execute(); } /** From 0d42ddfea256f7f3fad228cdb0dc0a3605e3ef10 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Fri, 10 Feb 2012 14:28:08 +0400 Subject: [PATCH 15/59] PopupFactoryImpl: use the preselected action condition in sub-popups. --- .../intellij/ui/popup/PopupFactoryImpl.java | 87 +++++++++++++------ 1 file changed, 59 insertions(+), 28 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ui/popup/PopupFactoryImpl.java b/platform/platform-impl/src/com/intellij/ui/popup/PopupFactoryImpl.java index 2057539a4037..1e6e8f9940ae 100644 --- a/platform/platform-impl/src/com/intellij/ui/popup/PopupFactoryImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/popup/PopupFactoryImpl.java @@ -208,20 +208,8 @@ public class PopupFactoryImpl extends JBPopupFactory { builder.buildGroup(actionGroup); final List items = builder.getItems(); - int defaultOptionIndex = 0; - if (preselectActionCondition != null) { - for (int i = 0; i < items.size(); i++) { - final AnAction action = items.get(i).getAction(); - if (preselectActionCondition.value(action)) { - defaultOptionIndex = i; - break; - } - } - } - return new ActionPopupStep(items, title, component, showNumbers || honorActionMnemonics && itemsHaveMnemonics(items), - defaultOptionIndex, - false, showDisabledActions); + preselectActionCondition, false, showDisabledActions); } @Override @@ -300,14 +288,42 @@ public class PopupFactoryImpl extends JBPopupFactory { return createActionsStep(actionGroup, dataContext, showNumbers, showDisabledActions, title, component, honorActionMnemonics, 0, false); } - private static ListPopupStep createActionsStep(ActionGroup actionGroup, @NotNull DataContext dataContext, boolean showNumbers, boolean useAlphaAsNumbers, boolean showDisabledActions, - String title, Component component, boolean honorActionMnemonics, int defaultOptionIndex, - final boolean autoSelectionEnabled) { - final ActionStepBuilder builder = new ActionStepBuilder(dataContext, showNumbers, useAlphaAsNumbers, showDisabledActions, honorActionMnemonics); - builder.buildGroup(actionGroup); - final List items = builder.getItems(); + private static ListPopupStep createActionsStep(ActionGroup actionGroup, @NotNull DataContext dataContext, + boolean showNumbers, boolean useAlphaAsNumbers, boolean showDisabledActions, + String title, Component component, boolean honorActionMnemonics, + final int defaultOptionIndex, final boolean autoSelectionEnabled) { + final List items = makeActionItemsFromActionGroup(actionGroup, dataContext, showNumbers, useAlphaAsNumbers, + showDisabledActions, honorActionMnemonics); + return new ActionPopupStep(items, title, component, showNumbers || honorActionMnemonics && itemsHaveMnemonics(items), + new Condition() { + @Override + public boolean value(AnAction action) { + return defaultOptionIndex >= 0 && + defaultOptionIndex < items.size() && + items.get(defaultOptionIndex).getAction().equals(action); + } + }, autoSelectionEnabled, showDisabledActions); + } - return new ActionPopupStep(items, title, component, showNumbers || honorActionMnemonics && itemsHaveMnemonics(items), defaultOptionIndex, + private static List makeActionItemsFromActionGroup(ActionGroup actionGroup, + DataContext dataContext, + boolean showNumbers, + boolean useAlphaAsNumbers, + boolean showDisabledActions, + boolean honorActionMnemonics) { + final ActionStepBuilder builder = new ActionStepBuilder(dataContext, showNumbers, useAlphaAsNumbers, showDisabledActions, + honorActionMnemonics); + builder.buildGroup(actionGroup); + return builder.getItems(); + } + + private static ListPopupStep createActionsStep(ActionGroup actionGroup, @NotNull DataContext dataContext, + boolean showNumbers, boolean useAlphaAsNumbers, boolean showDisabledActions, + String title, Component component, boolean honorActionMnemonics, + Condition preselectActionCondition, boolean autoSelectionEnabled) { + final List items = makeActionItemsFromActionGroup(actionGroup, dataContext, showNumbers, useAlphaAsNumbers, + showDisabledActions, honorActionMnemonics); + return new ActionPopupStep(items, title, component, showNumbers || honorActionMnemonics && itemsHaveMnemonics(items), preselectActionCondition, autoSelectionEnabled, showDisabledActions); } @@ -487,21 +503,35 @@ public class PopupFactoryImpl extends JBPopupFactory { private final boolean myAutoSelectionEnabled; private final boolean myShowDisabledActions; private Runnable myFinalRunnable; + @Nullable private final Condition myPreselectActionCondition; - private ActionPopupStep(@NotNull final List items, - final String title, - Component context, - boolean enableMnemonics, - final int defaultOptionIndex, final boolean autoSelection, boolean showDisabledActions) { + private ActionPopupStep(@NotNull final List items, final String title, Component context, boolean enableMnemonics, + @Nullable Condition preselectActionCondition, final boolean autoSelection, boolean showDisabledActions) { myItems = items; myTitle = title; myContext = context; myEnableMnemonics = enableMnemonics; - myDefaultOptionIndex = defaultOptionIndex; + myDefaultOptionIndex = getDefaultOptionIndexFromSelectCondition(preselectActionCondition, items); + myPreselectActionCondition = preselectActionCondition; myAutoSelectionEnabled = autoSelection; myShowDisabledActions = showDisabledActions; } + private static int getDefaultOptionIndexFromSelectCondition(@Nullable Condition preselectActionCondition, + @NotNull List items) { + int defaultOptionIndex = 0; + if (preselectActionCondition != null) { + for (int i = 0; i < items.size(); i++) { + final AnAction action = items.get(i).getAction(); + if (preselectActionCondition.value(action)) { + defaultOptionIndex = i; + break; + } + } + } + return defaultOptionIndex; + } + @NotNull public List getValues() { return myItems; @@ -552,13 +582,14 @@ public class PopupFactoryImpl extends JBPopupFactory { final DataContext dataContext = myContext != null ? mgr.getDataContext(myContext) : mgr.getDataContext(); if (action instanceof ActionGroup && (!finalChoice || !((ActionGroup)action).canBePerformed(dataContext))) { - return JBPopupFactory.getInstance().createActionsStep((ActionGroup)action, dataContext, myEnableMnemonics, myShowDisabledActions, null, myContext, false); + return createActionsStep((ActionGroup)action, dataContext, myEnableMnemonics, true, myShowDisabledActions, null, myContext, false, + myPreselectActionCondition, false); } else { myFinalRunnable = new Runnable() { public void run() { action.actionPerformed( - new AnActionEvent(null, dataContext, ActionPlaces.UNKNOWN, (Presentation)action.getTemplatePresentation().clone(), + new AnActionEvent(null, dataContext, ActionPlaces.UNKNOWN, action.getTemplatePresentation().clone(), ActionManager.getInstance(), 0)); } }; From a83c894c7d23a33aad872db560fe4437cd5f01e5 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Fri, 10 Feb 2012 14:31:29 +0400 Subject: [PATCH 16/59] Don't return null from getInstance(): better to handle disposed project, where it is needed. --- plugins/git4idea/src/git4idea/config/GitVcsSettings.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/plugins/git4idea/src/git4idea/config/GitVcsSettings.java b/plugins/git4idea/src/git4idea/config/GitVcsSettings.java index b05c7370d1f8..d5d7ef1f20e8 100644 --- a/plugins/git4idea/src/git4idea/config/GitVcsSettings.java +++ b/plugins/git4idea/src/git4idea/config/GitVcsSettings.java @@ -80,11 +80,7 @@ public class GitVcsSettings implements PersistentStateComponent Date: Fri, 10 Feb 2012 14:34:38 +0400 Subject: [PATCH 17/59] GitBranchPopup: preselect the recent branch. Store recent branch information for common branches and for each repository (preselect such in sub-popups and if branches diverge or not synched). --- .../git4idea/branch/GitBranchOperation.java | 21 ++++++++++++++- .../branch/GitCheckoutNewBranchOperation.java | 6 ++--- .../git4idea/branch/GitCheckoutOperation.java | 5 ++-- .../branch/GitDeleteBranchOperation.java | 4 +-- .../git4idea/branch/GitMergeOperation.java | 2 +- .../src/git4idea/config/GitVcsSettings.java | 22 ++++++++++++++++ .../git4idea/ui/branch/GitBranchPopup.java | 26 ++++++++++++++++++- .../ui/branch/GitBranchPopupActions.java | 10 +++++++ 8 files changed, 86 insertions(+), 10 deletions(-) diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java b/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java index 456f6922f096..99a5a01bf2e7 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java @@ -34,6 +34,7 @@ import com.intellij.util.Function; import com.intellij.util.ui.UIUtil; import git4idea.*; import git4idea.commands.GitMessageWithFilesDetector; +import git4idea.config.GitVcsSettings; import git4idea.merge.GitConflictResolver; import git4idea.repo.GitRepository; import git4idea.util.UntrackedFilesNotifier; @@ -59,18 +60,22 @@ abstract class GitBranchOperation { @NotNull protected final Project myProject; @NotNull private final Collection myRepositories; + @NotNull private final String myCurrentBranchOrRev; @NotNull private final ProgressIndicator myIndicator; + private final GitVcsSettings mySettings; @NotNull private final Collection mySuccessfulRepositories; @NotNull private final Collection myRemainingRepositories; protected GitBranchOperation(@NotNull Project project, @NotNull Collection repositories, - @NotNull ProgressIndicator indicator) { + @NotNull String currentBranchOrRev, @NotNull ProgressIndicator indicator) { myProject = project; myRepositories = repositories; + myCurrentBranchOrRev = currentBranchOrRev; myIndicator = indicator; mySuccessfulRepositories = new ArrayList(); myRemainingRepositories = new ArrayList(myRepositories); + mySettings = GitVcsSettings.getInstance(myProject); } protected abstract void execute(); @@ -242,6 +247,20 @@ abstract class GitBranchOperation { return pluralize("repository", getSuccessfulRepositories().size()); } + /** + * Updates the recently visited branch in the settings. + * This is to be performed after successful checkout operation. + */ + protected void updateRecentBranch() { + if (getRepositories().size() == 1) { + GitRepository repository = myRepositories.iterator().next(); + mySettings.setRecentBranchOfRepository(repository.getRoot().getPath(), myCurrentBranchOrRev); + } + else { + mySettings.setRecentCommonBranch(myCurrentBranchOrRev); + } + } + private void showUnmergedFilesDialogWithRollback() { final AtomicBoolean ok = new AtomicBoolean(); UIUtil.invokeAndWaitIfNeeded(new Runnable() { diff --git a/plugins/git4idea/src/git4idea/branch/GitCheckoutNewBranchOperation.java b/plugins/git4idea/src/git4idea/branch/GitCheckoutNewBranchOperation.java index 27f135bac9a3..553277e329f4 100644 --- a/plugins/git4idea/src/git4idea/branch/GitCheckoutNewBranchOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitCheckoutNewBranchOperation.java @@ -44,9 +44,8 @@ class GitCheckoutNewBranchOperation extends GitBranchOperation { @NotNull private final String myPreviousBranch; GitCheckoutNewBranchOperation(@NotNull Project project, @NotNull Collection repositories, - @NotNull String newBranchName, @NotNull String previousBranch, - @NotNull ProgressIndicator indicator) { - super(project, repositories, indicator); + @NotNull String newBranchName, @NotNull String previousBranch, @NotNull ProgressIndicator indicator) { + super(project, repositories, previousBranch, indicator); myNewBranchName = newBranchName; myProject = project; myPreviousBranch = previousBranch; @@ -77,6 +76,7 @@ class GitCheckoutNewBranchOperation extends GitBranchOperation { if (!fatalErrorHappened) { notifySuccess(); + updateRecentBranch(); } } diff --git a/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java b/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java index 6585ce74fd73..e3530b19e040 100644 --- a/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java @@ -59,7 +59,7 @@ class GitCheckoutOperation extends GitBranchOperation { GitCheckoutOperation(@NotNull Project project, @NotNull Collection repositories, @NotNull String startPointReference, @Nullable String newBranch, @NotNull String previousBranch, @NotNull ProgressIndicator indicator) { - super(project, repositories, indicator); + super(project, repositories, previousBranch, indicator); myStartPointReference = startPointReference; myNewBranch = newBranch; myPreviousBranch = previousBranch; @@ -104,10 +104,11 @@ class GitCheckoutOperation extends GitBranchOperation { if (!fatalErrorHappened) { notifySuccess(); + updateRecentBranch(); } } - private boolean smartCheckoutOrNotify(@NotNull GitRepository repository, + private boolean smartCheckoutOrNotify(@NotNull GitRepository repository, @NotNull GitMessageWithFilesDetector localChangesOverwrittenByCheckout) { Pair, List> conflictingRepositoriesAndAffectedChanges = getConflictingRepositoriesAndAffectedChanges(repository, localChangesOverwrittenByCheckout, myPreviousBranch, myStartPointReference); diff --git a/plugins/git4idea/src/git4idea/branch/GitDeleteBranchOperation.java b/plugins/git4idea/src/git4idea/branch/GitDeleteBranchOperation.java index 0c4c89fa3f69..b21d46ffc41b 100644 --- a/plugins/git4idea/src/git4idea/branch/GitDeleteBranchOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitDeleteBranchOperation.java @@ -53,8 +53,8 @@ class GitDeleteBranchOperation extends GitBranchOperation { private final String myCurrentBranch; GitDeleteBranchOperation(@NotNull Project project, @NotNull Collection repositories, - @NotNull String branchName, @NotNull String currentBranch, @NotNull ProgressIndicator indicator) { - super(project, repositories, indicator); + @NotNull String branchName, @NotNull String currentBranch, @NotNull ProgressIndicator indicator) { + super(project, repositories, currentBranch, indicator); myBranchName = branchName; myCurrentBranch = currentBranch; } diff --git a/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java b/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java index dde3d9a2abac..5009f1ca5400 100644 --- a/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java @@ -66,7 +66,7 @@ class GitMergeOperation extends GitBranchOperation { @NotNull String branchToMerge, @NotNull String currentBranch, @NotNull GitRepository currentRepository, @NotNull Map currentRevisionsBeforeMerge, @NotNull ProgressIndicator indicator) { - super(project, repositories, indicator); + super(project, repositories, currentBranch, indicator); myBranchToMerge = branchToMerge; myCurrentBranch = currentBranch; myCurrentRepository = currentRepository; diff --git a/plugins/git4idea/src/git4idea/config/GitVcsSettings.java b/plugins/git4idea/src/git4idea/config/GitVcsSettings.java index d5d7ef1f20e8..61ccb83bc04a 100644 --- a/plugins/git4idea/src/git4idea/config/GitVcsSettings.java +++ b/plugins/git4idea/src/git4idea/config/GitVcsSettings.java @@ -26,7 +26,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * Git VCS settings @@ -70,6 +72,8 @@ public class GitVcsSettings implements PersistentStateComponent RECENT_BRANCH_BY_REPOSITORY = new HashMap(); + public String RECENT_COMMON_BRANCH = null; } public GitVcsSettings(GitVcsApplicationSettings appSettings) { @@ -168,4 +172,22 @@ public class GitVcsSettings implements PersistentStateComponent getRecentBranchesByRepository() { + return myState.RECENT_BRANCH_BY_REPOSITORY; + } + + public void setRecentBranchOfRepository(@NotNull String repositoryPath, @NotNull String branch) { + myState.RECENT_BRANCH_BY_REPOSITORY.put(repositoryPath, branch); + } + + @Nullable + public String getRecentCommonBranch() { + return myState.RECENT_COMMON_BRANCH; + } + + public void setRecentCommonBranch(@NotNull String branch) { + myState.RECENT_COMMON_BRANCH = branch; + } + } diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java index 715e459f40ac..395488cd219d 100644 --- a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java +++ b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java @@ -27,6 +27,7 @@ import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.ListPopup; import com.intellij.openapi.ui.popup.PopupStep; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.IconLoader; import com.intellij.ui.popup.PopupFactoryImpl; import com.intellij.ui.popup.WizardPopup; @@ -88,10 +89,33 @@ class GitBranchPopup { String title = createPopupTitle(currentRepository); + Condition preselectActionCondition = new Condition() { + @Override + public boolean value(AnAction action) { + if (action instanceof GitBranchPopupActions.LocalBranchActions) { + GitBranchPopupActions.LocalBranchActions branchAction = (GitBranchPopupActions.LocalBranchActions)action; + String branchName = branchAction.getBranchName(); + + String recentBranch; + List repositories = branchAction.getRepositories(); + if (repositories.size() == 1) { + recentBranch = myVcsSettings.getRecentBranchesByRepository().get(repositories.iterator().next().getRoot().getPath()); + } + else { + recentBranch = myVcsSettings.getRecentCommonBranch(); + } + + if (recentBranch != null && recentBranch.equals(branchName)) { + return true; + } + } + return false; + } + }; myPopup = new PopupFactoryImpl.ActionGroupPopup( title, createActions(), SimpleDataContext.getProjectContext(project), - false, false, false, true, null, -1, null, null) { + false, false, false, true, null, -1, preselectActionCondition, null) { @Override protected WizardPopup createPopup(WizardPopup parent, PopupStep step, Object parentValue) { WizardPopup popup = super.createPopup(parent, step, parentValue); diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java index ba4d118967ea..fa6e23495187 100644 --- a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java +++ b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java @@ -180,6 +180,16 @@ class GitBranchPopupActions { } } + @NotNull + List getRepositories() { + return myRepositories; + } + + @NotNull + public String getBranchName() { + return myBranchName; + } + @NotNull @Override public AnAction[] getChildren(@Nullable AnActionEvent e) { From e07375b2904266ebc289e26db5eebe91ba92aa72 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Fri, 10 Feb 2012 14:43:44 +0400 Subject: [PATCH 18/59] Add icon to Git -> Branches action --- plugins/git4idea/src/META-INF/plugin.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/git4idea/src/META-INF/plugin.xml b/plugins/git4idea/src/META-INF/plugin.xml index 266e2f06b86d..732ef0e79d7f 100644 --- a/plugins/git4idea/src/META-INF/plugin.xml +++ b/plugins/git4idea/src/META-INF/plugin.xml @@ -37,7 +37,7 @@ - + From 9aef4f08b9c5274d71a63c4164353baa6deb3249 Mon Sep 17 00:00:00 2001 From: "Maxim.Medvedev" Date: Fri, 10 Feb 2012 15:13:31 +0400 Subject: [PATCH 19/59] IDEA-80693 Groovy: Extract Closure Parameter: do not add class prefix to static fields/methods accessed from within a class where they are defined --- .../java2groovy/OldReferencesResolver.java | 37 ++++++++++--------- .../extract/closure/ExtractClosureTest.groovy | 32 ++++++++++++++++ 2 files changed, 52 insertions(+), 17 deletions(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/java2groovy/OldReferencesResolver.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/java2groovy/OldReferencesResolver.java index e5b86d8c915a..eb0d89729d9a 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/java2groovy/OldReferencesResolver.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/java2groovy/OldReferencesResolver.java @@ -169,27 +169,30 @@ public class OldReferencesResolver { // "naked" field and methods (should become qualified) else if ((subj instanceof PsiField || subj instanceof PsiMethod) && oldRef.getQualifierExpression() == null) { - boolean isStatic = subj instanceof PsiField && ((PsiField)subj).hasModifierProperty(PsiModifier.STATIC) || - subj instanceof PsiMethod && ((PsiMethod)subj).hasModifierProperty(PsiModifier.STATIC); + PsiElement newResolved = newExpr instanceof GrReferenceExpression ? ((GrReferenceExpression)newExpr).resolve() : null; + if (myInstanceRef != null || !subj.getManager().areElementsEquivalent(newResolved, subj)) { + boolean isStatic = subj instanceof PsiField && ((PsiField)subj).hasModifierProperty(PsiModifier.STATIC) || + subj instanceof PsiMethod && ((PsiMethod)subj).hasModifierProperty(PsiModifier.STATIC); - String name = ((PsiNamedElement)subj).getName(); - boolean shouldBeAt = subj instanceof PsiField && - !PsiTreeUtil.isAncestor(((PsiMember)subj).getContainingClass(), newExpr, true) && - GroovyPropertyUtils.findGetterForField((PsiField)subj) != null; - final GrReferenceExpression fromText = factory.createReferenceExpressionFromText("qualifier." + (shouldBeAt ? "@" : "") + name); - if (isStatic) { - final GrReferenceExpression qualifier = factory.createReferenceElementForClass(((PsiMember)subj).getContainingClass()); - newExpr = newExpr.replace(fromText); - ((GrReferenceExpression)newExpr).setQualifier(qualifier); - newExpr = ((GrReferenceExpression)newExpr).getReferenceNameElement(); - } - else { - if (myInstanceRef != null) { - GrExpression instanceRef = getInstanceRef(factory); - fromText.setQualifier(instanceRef); + String name = ((PsiNamedElement)subj).getName(); + boolean shouldBeAt = subj instanceof PsiField && + !PsiTreeUtil.isAncestor(((PsiMember)subj).getContainingClass(), newExpr, true) && + GroovyPropertyUtils.findGetterForField((PsiField)subj) != null; + final GrReferenceExpression fromText = factory.createReferenceExpressionFromText("qualifier." + (shouldBeAt ? "@" : "") + name); + if (isStatic) { + final GrReferenceExpression qualifier = factory.createReferenceElementForClass(((PsiMember)subj).getContainingClass()); newExpr = newExpr.replace(fromText); + ((GrReferenceExpression)newExpr).setQualifier(qualifier); newExpr = ((GrReferenceExpression)newExpr).getReferenceNameElement(); } + else { + if (myInstanceRef != null) { + GrExpression instanceRef = getInstanceRef(factory); + fromText.setQualifier(instanceRef); + newExpr = newExpr.replace(fromText); + newExpr = ((GrReferenceExpression)newExpr).getReferenceNameElement(); + } + } } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureTest.groovy index e0fc82bc952e..e95a942334fb 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureTest.groovy @@ -221,6 +221,38 @@ class ArrowToKneeException extends Exception{} def killMonsters(){2} def collectLoot(){3} def becomeTownGuard(){} +''') + } + + void testDontQualify() { + doTest(''' +class Some { + private static int smth = 1 + private static void doSmth() {} + + void m1() { + println smth + doSmth() + } + void m2() { + m1() + } +} +''', ''' +class Some { + private static int smth = 1 + private static void doSmth() {} + + void m1(Closure closure) { + closure() + } + void m2() { + m1 { + println smth + doSmth() + } + } +} ''') } } From be299ee97059a42f3f1a3d99362a7bfea75830d8 Mon Sep 17 00:00:00 2001 From: "Maxim.Medvedev" Date: Fri, 10 Feb 2012 15:25:33 +0400 Subject: [PATCH 20/59] fix CCE --- .../codeInspection/local/GroovyPostHighlightingPass.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java index 6635d44b6086..c61ef6fb13b9 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java @@ -25,6 +25,7 @@ import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInspection.InspectionProfile; import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection; +import com.intellij.codeInspection.ex.InspectionToolWrapper; import com.intellij.lang.annotation.Annotation; import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.lang.annotation.AnnotationSession; @@ -86,7 +87,8 @@ public class GroovyPostHighlightingPass extends TextEditorHighlightingPass { if (!fileIndex.isInContent(virtualFile)) { return; } - final UnusedDeclarationInspection deadCodeInspection = (UnusedDeclarationInspection)profile.getInspectionTool(UnusedDeclarationInspection.SHORT_NAME, myFile); + final InspectionToolWrapper wrapper = (InspectionToolWrapper)profile.getInspectionTool(UnusedDeclarationInspection.SHORT_NAME, myFile); + final UnusedDeclarationInspection deadCodeInspection = wrapper != null ? (UnusedDeclarationInspection)wrapper.getTool() : null; final GlobalUsageHelper usageHelper = new GlobalUsageHelper() { public boolean isCurrentFileAlreadyChecked() { return false; From bc7167b31ff3357d70d8c15c768f693788157e66 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 10 Feb 2012 12:29:51 +0100 Subject: [PATCH 21/59] fix css completion test --- .../intellij/codeInsight/completion/TemplateInsertHandler.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/TemplateInsertHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/TemplateInsertHandler.java index 4d15a58b1740..531c28aff3ee 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/TemplateInsertHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/TemplateInsertHandler.java @@ -78,7 +78,8 @@ public abstract class TemplateInsertHandler implements InsertHandler { String lookupString = editor.getDocument().getCharsSequence().subSequence(startOffset, endOffset).toString(); lookupItem.setLookupString(lookupString); - final OffsetMap offsetMap = context.getOffsetMap(); + final OffsetMap offsetMap = new OffsetMap(document); + offsetMap.addOffset(CompletionInitializationContext.START_OFFSET, startOffset); offsetMap.addOffset(CompletionInitializationContext.SELECTION_END_OFFSET, endOffset); offsetMap.addOffset(CompletionInitializationContext.IDENTIFIER_END_OFFSET, endOffset); From cd463262bbfc1d016e921896b29cd92d83cf86a6 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 10 Feb 2012 12:42:39 +0100 Subject: [PATCH 22/59] less invasive logging for component creation failures --- .../intellij/openapi/components/impl/ComponentManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/core-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java b/platform/core-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java index d0153c3796aa..c26dd1c90dc2 100644 --- a/platform/core-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java @@ -124,7 +124,7 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements protected synchronized Object createComponent(Class componentInterface) { final Object component = getPicoContainer().getComponentInstance(componentInterface.getName()); - assert component != null : "Can't instantiate component for: " + componentInterface; + LOG.assertTrue(component != null, "Can't instantiate component for: " + componentInterface); return component; } From 9ab4753e354d0192e30d4fc85f52b87131d18b33 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Fri, 10 Feb 2012 13:04:17 +0100 Subject: [PATCH 23/59] correctly cleanup round context --- .../jps/incremental/CompileContext.java | 17 +++++++++-------- .../org/jetbrains/jps/incremental/FSState.java | 5 ++++- .../jps/incremental/IncProjectBuilder.java | 4 ++-- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java index 994633a6ecb0..f4d3ba5dcce7 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java @@ -163,20 +163,21 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler myCompilingTests = compilingTests; } + void beforeCompileRound(@NotNull ModuleChunk chunk) { + myFsState.beforeNextRoundStart(); + } + + public void afterCompileRound() { + myFsState.clearContextRoundData(); + } + public void onChunkBuildStart(ModuleChunk chunk) { myFsState.setContextChunk(chunk); } - void beforeNextCompileRound(@NotNull ModuleChunk chunk) { - myFsState.beforeNextRoundStart(); - } - - public void clearContextRoundData() { - myFsState.clearContextRoundData(); - } - void onChunkBuildComplete(@NotNull ModuleChunk chunk) throws IOException { myDataManager.flush(true); + myFsState.clearContextChunk(); if (!myErrorsFound && !myCancelStatus.isCanceled()) { final boolean compilingTests = isCompilingTests(); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/FSState.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/FSState.java index 1c2874f47004..63874bc38d67 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/FSState.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/FSState.java @@ -52,6 +52,10 @@ public class FSState { myContextModules.addAll(chunk.getModules()); } + public void clearContextChunk() { + myContextModules.clear(); + } + public void beforeNextRoundStart() { myLastRoundDelta = myCurrentRoundDelta; myCurrentRoundDelta = new FilesDelta(); @@ -60,7 +64,6 @@ public class FSState { public void clearContextRoundData() { myCurrentRoundDelta = null; myLastRoundDelta = null; - myContextModules.clear(); } public void clearRecompile(RootDescriptor rd) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java index 45a26b84ca8a..7d65af0c3949 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java @@ -389,7 +389,7 @@ public class IncProjectBuilder { boolean nextPassRequired; do { nextPassRequired = false; - context.beforeNextCompileRound(chunk); + context.beforeCompileRound(chunk); if (!context.isProjectRebuild()) { syncOutputFiles(context, chunk); @@ -440,7 +440,7 @@ public class IncProjectBuilder { } while (nextPassRequired); - context.clearContextRoundData(); + context.afterCompileRound(); } } From 25c2fcbeb6867f4f85dc8abfcdb518e925e2a95f Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Fri, 10 Feb 2012 16:05:42 +0400 Subject: [PATCH 24/59] getting context fixed --- .../src/com/intellij/codeInspection/ex/InspectionTool.java | 2 +- .../intellij/codeInspection/ex/InspectionToolRegistrar.java | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionTool.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionTool.java index 9733185e63c3..279ef0b60f33 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionTool.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionTool.java @@ -64,7 +64,7 @@ public abstract class InspectionTool extends InspectionProfileEntry { } public RefManager getRefManager() { - return myContext.getRefManager(); + return getContext().getRefManager(); } public abstract void runInspection(@NotNull AnalysisScope scope, @NotNull InspectionManager manager); diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolRegistrar.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolRegistrar.java index 6cd4ec9b9344..acaa6fbee662 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolRegistrar.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolRegistrar.java @@ -339,6 +339,11 @@ public class InspectionToolRegistrar { getTool().runInspection(scope, manager); } + @Override + public GlobalInspectionContextImpl getContext() { + return getTool().getContext(); + } + @NotNull @Override public JobDescriptor[] getJobDescriptors(GlobalInspectionContext globalInspectionContext) { From 40cc655a84946938504ecb45793829dd06808689 Mon Sep 17 00:00:00 2001 From: Anton Makeev Date: Fri, 10 Feb 2012 13:16:58 +0100 Subject: [PATCH 25/59] Do not show 'Index Rebuild' balloon by default. Whose who desperately need to see it, please set Registry->ide.showIndexRebuildMessage=true --- .../src/com/intellij/util/indexing/FileBasedIndex.java | 7 ++++++- .../platform-resources-en/src/misc/registry.properties | 5 +++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java index 920ccaba4933..619ac7132312 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java @@ -44,6 +44,7 @@ import com.intellij.openapi.project.*; import com.intellij.openapi.roots.*; import com.intellij.openapi.util.*; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vfs.*; import com.intellij.openapi.vfs.ex.VirtualFileManagerEx; import com.intellij.openapi.vfs.newvfs.BulkFileListener; @@ -280,6 +281,7 @@ public class FileBasedIndex implements ApplicationComponent { versionChanged |= registerIndexer(extension, currentVersionCorrupted); } FileUtil.delete(corruptionMarker); + String rebuildNotification = null; if (currentVersionCorrupted) { rebuildNotification = "Index files on disk are corrupted. Indices will be rebuilt."; @@ -287,10 +289,13 @@ public class FileBasedIndex implements ApplicationComponent { else if (versionChanged) { rebuildNotification = "Index file format has changed for some indices. These indices will be rebuilt."; } - if (rebuildNotification != null && !ApplicationManager.getApplication().isHeadlessEnvironment()) { + if (rebuildNotification != null + && !ApplicationManager.getApplication().isHeadlessEnvironment() + && Registry.is("ide.showIndexRebuildMessage")) { new NotificationGroup("Indexing", NotificationDisplayType.BALLOON, false) .createNotification("Index Rebuild", rebuildNotification, NotificationType.INFORMATION, null).notify(null); } + dropUnregisteredIndices(); // check if rebuild was requested for any index during registration diff --git a/platform/platform-resources-en/src/misc/registry.properties b/platform/platform-resources-en/src/misc/registry.properties index 45a72e198390..8cc86d0f4215 100644 --- a/platform/platform-resources-en/src/misc/registry.properties +++ b/platform/platform-resources-en/src/misc/registry.properties @@ -99,6 +99,8 @@ editor.mouseSelectionStateResetDeadzone=4 editor.use.new.tabs=true editor.smarterSelectionQuoting=true +ide.showIndexRebuildMessage=false + ide.tabbedPane.bufferedPaint=true ide.tabbedPane.dragOutMultiplier=1.2 @@ -108,6 +110,7 @@ ide.mac.message.dialogs.as.sheets=true ide.mac.inplaceDialogMnemonicsFix=true ide.mac.hide.cursor.when.typing=false ide.mac.show.native.help=false +ide.mac.useNativeClipboard=false debugger.valueTooltipAutoShow=true debugger.valueTooltipAutoShow.description=Auto show tooltip on mouse over @@ -171,8 +174,6 @@ projectView.hide.dot.idea=true show.live.templates.in.completion=false documentation.component.editor.font=false -ide.mac.useNativeClipboard=false - show.all.classes.on.first.completion=false ide.enable.toolwindow.stack=false From 377c95ee90b18686a6ece83d5844903377817808 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 10 Feb 2012 13:35:41 +0100 Subject: [PATCH 26/59] correct fix for deadlock: register Maven file type via FileTypeFactory --- .../updateSettings/impl/UpdateChecker.java | 2 -- .../utils/MavenEnvironmentRegistrar.java | 20 ----------- .../maven/utils/MavenFileTypeFactory.java | 34 +++++++++++++++++++ .../src/main/resources/META-INF/plugin.xml | 1 + 4 files changed, 35 insertions(+), 22 deletions(-) create mode 100644 plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenFileTypeFactory.java diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java index ec767c5fd4c7..dd6d07f04f75 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java @@ -148,7 +148,6 @@ public final class UpdateChecker { public static ActionCallback updateAndShowResult() { final ActionCallback result = new ActionCallback(); final Application app = ApplicationManager.getApplication(); - /* app.executeOnPooledThread(new Runnable() { @Override public void run() { @@ -164,7 +163,6 @@ public final class UpdateChecker { }); } }); - */ return result; } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenEnvironmentRegistrar.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenEnvironmentRegistrar.java index 90daa24baf34..dac328542705 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenEnvironmentRegistrar.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenEnvironmentRegistrar.java @@ -16,15 +16,9 @@ package org.jetbrains.idea.maven.utils; -import com.intellij.ide.highlighter.XmlFileType; -import com.intellij.openapi.application.AccessToken; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.PathMacros; -import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.components.ApplicationComponent; -import com.intellij.openapi.fileTypes.FileTypeManager; import org.jetbrains.annotations.NotNull; -import org.jetbrains.idea.maven.model.MavenConstants; import java.io.File; @@ -37,23 +31,9 @@ public class MavenEnvironmentRegistrar implements ApplicationComponent { } public void initComponent() { - registerFileTypes(); registerPathVariable(); } - private void registerFileTypes() { - // we should not change file types in unit test mode - if (ApplicationManager.getApplication().isUnitTestMode()) return; - - AccessToken accessToken = WriteAction.start(); - try { - FileTypeManager.getInstance().associateExtension(XmlFileType.INSTANCE, MavenConstants.POM_EXTENSION); - } - finally { - accessToken.finish(); - } - } - private void registerPathVariable() { File repository = MavenUtil.resolveLocalRepository(null, null, null); PathMacros macros = PathMacros.getInstance(); diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenFileTypeFactory.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenFileTypeFactory.java new file mode 100644 index 000000000000..05b51b4ea8ac --- /dev/null +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenFileTypeFactory.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.idea.maven.utils; + +import com.intellij.ide.highlighter.XmlFileType; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.fileTypes.FileTypeConsumer; +import com.intellij.openapi.fileTypes.FileTypeFactory; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.maven.model.MavenConstants; + +/** + * @author yole + */ +public class MavenFileTypeFactory extends FileTypeFactory { + @Override + public void createFileTypes(@NotNull FileTypeConsumer consumer) { + if (ApplicationManager.getApplication().isUnitTestMode()) return; + consumer.consume(XmlFileType.INSTANCE, MavenConstants.POM_EXTENSION); + } +} diff --git a/plugins/maven/src/main/resources/META-INF/plugin.xml b/plugins/maven/src/main/resources/META-INF/plugin.xml index 8d1e661b9d57..3857f71c8f87 100644 --- a/plugins/maven/src/main/resources/META-INF/plugin.xml +++ b/plugins/maven/src/main/resources/META-INF/plugin.xml @@ -15,6 +15,7 @@ org.intellij.groovy + From 992515d6815f162690c5ab1ce6c393e534b45447 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Fri, 10 Feb 2012 14:08:49 +0100 Subject: [PATCH 27/59] several memory leaks IDEA-75220, IDEA-80916, IDEA-80009, IDEA-76082 --- .../ide/impl/StructureViewWrapperImpl.java | 9 ++++++++- .../openapi/wm/impl/ToolWindowManagerImpl.java | 18 +++++++++--------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/impl/StructureViewWrapperImpl.java b/platform/lang-impl/src/com/intellij/ide/impl/StructureViewWrapperImpl.java index 911ec07db1db..20cf9e787b77 100644 --- a/platform/lang-impl/src/com/intellij/ide/impl/StructureViewWrapperImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/impl/StructureViewWrapperImpl.java @@ -87,7 +87,7 @@ public class StructureViewWrapperImpl implements StructureViewWrapper, Disposabl myUpdateQueue = new MergingUpdateQueue("StructureView", Registry.intValue("structureView.coalesceTime"), false, myToolWindow.getComponent(), this, myToolWindow.getComponent(), true); myUpdateQueue.setRestartTimerOnAdd(true); - ActionManager.getInstance().addTimerListener(500, new TimerListener() { + final TimerListener timerListener = new TimerListener() { public ModalityState getModalityState() { return ModalityState.stateForComponent(myToolWindow.getComponent()); } @@ -95,6 +95,13 @@ public class StructureViewWrapperImpl implements StructureViewWrapper, Disposabl public void run() { checkUpdate(); } + }; + ActionManager.getInstance().addTimerListener(500, timerListener); + Disposer.register(this, new Disposable() { + @Override + public void dispose() { + ActionManager.getInstance().removeTimerListener(timerListener); + } }); myToolWindow.getComponent().addHierarchyListener(new HierarchyListener() { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java index c7ac33742fe9..c5f32e12a57f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java @@ -200,7 +200,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements } public void fileClosed(FileEditorManager source, VirtualFile file) { - getFocusManagerImpl().doWhenFocusSettlesDown(new ExpirableRunnable.ForProject(myProject) { + getFocusManagerImpl(myProject).doWhenFocusSettlesDown(new ExpirableRunnable.ForProject(myProject) { public void run() { if (!hasOpenEditorFiles()) { focusToolWinowByDefault(null); @@ -351,8 +351,8 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements return myFileEditorManager.getOpenFiles().length > 0; } - private static FocusManagerImpl getFocusManagerImpl() { - return FocusManagerImpl.getInstance(); + private static IdeFocusManager getFocusManagerImpl(Project project) { + return IdeFocusManager.getInstance(project); } public Project getProject() { @@ -619,7 +619,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements }).doWhenRejected(new Runnable() { public void run() { if (forced) { - getFocusManagerImpl().requestFocus(new FocusCommand() { + getFocusManagerImpl(myProject).requestFocus(new FocusCommand() { public ActionCallback run() { final ArrayList cmds = new ArrayList(); @@ -719,7 +719,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements final ArrayList commandList, boolean forced, boolean autoFocusContents) { - if (!getFocusManagerImpl().isUnforcedRequestAllowed() && !forced) return; + if (/*!getFocusManagerImpl(myProject).isUnforcedRequestAllowed() && */!forced) return; if (LOG.isDebugEnabled()) { LOG.debug("enter: activateToolWindowImpl(" + id + ")"); @@ -2002,15 +2002,15 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements return; } final WindowInfoImpl info = getInfo(myId); - getFocusManagerImpl().myFocusedComponentAlaram.cancelAllRequests(); + //getFocusManagerImpl(myProject)..cancelAllRequests(); if (!info.isActive()) { - getFocusManagerImpl().myFocusedComponentAlaram.addRequest(new EdtRunnable() { + getFocusManagerImpl(myProject).doWhenFocusSettlesDown(new EdtRunnable() { public void runEdt() { if (!myLayout.isToolWindowRegistered(myId)) return; activateToolWindow(myId, false, false); } - }, 100); + }); } } } @@ -2128,7 +2128,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements } public ActionCallback requestDefaultFocus(final boolean forced) { - return getFocusManagerImpl().requestFocus(new FocusCommand() { + return getFocusManagerImpl(myProject).requestFocus(new FocusCommand() { public ActionCallback run() { return processDefaultFocusRequest(forced); } From cb0442de53dc10eb4b4d2373db6c58062745b815 Mon Sep 17 00:00:00 2001 From: anna Date: Fri, 10 Feb 2012 12:14:32 +0100 Subject: [PATCH 28/59] IDEA-76599 Quickfix to change a double literal to a float literal --- .../impl/analysis/HighlightMethodUtil.java | 2 + .../daemon/impl/analysis/HighlightUtil.java | 2 +- .../quickfix/ConvertDoubleToFloatFix.java | 109 ++++++++++++++++++ .../quickFix/convertDoubleToFloat/after1.java | 7 ++ .../quickFix/convertDoubleToFloat/after2.java | 7 ++ .../quickFix/convertDoubleToFloat/after3.java | 7 ++ .../quickFix/convertDoubleToFloat/after4.java | 7 ++ .../quickFix/convertDoubleToFloat/after5.java | 7 ++ .../convertDoubleToFloat/before1.java | 7 ++ .../convertDoubleToFloat/before2.java | 7 ++ .../convertDoubleToFloat/before3.java | 7 ++ .../convertDoubleToFloat/before4.java | 7 ++ .../convertDoubleToFloat/before5.java | 7 ++ .../convertDoubleToFloat/before6.java | 7 ++ .../convertDoubleToFloat/before7.java | 7 ++ .../quickFix/ConvertDoubleToFloatFixTest.java | 29 +++++ 16 files changed, 225 insertions(+), 1 deletion(-) create mode 100644 java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertDoubleToFloatFix.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after1.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after2.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after3.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after4.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after5.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before1.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before2.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before3.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before4.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before5.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before6.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before7.java create mode 100644 java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ConvertDoubleToFloatFixTest.java diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java index 90ffa0ab8fcf..e8a00be3524b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java @@ -498,6 +498,7 @@ public class HighlightMethodUtil { AddTypeArgumentsFix.REGISTRAR.registerCastActions(methodCandidates, methodCall, highlightInfo, fixRange); registerMethodAccessLevelIntentions(methodCandidates, methodCall, list, highlightInfo); ChangeMethodSignatureFromUsageFix.registerIntentions(methodCandidates, list, highlightInfo, fixRange); + ConvertDoubleToFloatFix.registerIntentions(methodCandidates, list, highlightInfo, fixRange); WrapExpressionFix.registerWrapAction(methodCandidates, list.getExpressions(), highlightInfo); ChangeParameterClassFix.registerQuickFixActions(methodCall, list, highlightInfo); if (methodCandidates.length == 0) { @@ -1273,6 +1274,7 @@ public class HighlightMethodUtil { if (classReference != null) { ConstructorParametersFixer.registerFixActions(classReference, constructorCall, info, getFixRange(infoElement)); ChangeMethodSignatureFromUsageFix.registerIntentions(results, list, info, null); + ConvertDoubleToFloatFix.registerIntentions(results, list, info, null); PermuteArgumentsFix.registerFix(info, constructorCall, toMethodCandidates(results), getFixRange(list)); ChangeParameterClassFix.registerQuickFixActions(constructorCall, list, info); QuickFixAction.registerQuickFixAction(info, getFixRange(list), new SurroundWithArrayFix(constructorCall), null); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java index 1ac11d19ccaf..5d6a82078bc7 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -1014,7 +1014,7 @@ public class HighlightUtil { } // true if floating point literal consists of zeros only - private static boolean isFPZero(final String text) { + public static boolean isFPZero(final String text) { for (int i = 0; i < text.length(); i++) { final char c = text.charAt(i); if (Character.isDigit(c) && c != '0') return false; diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertDoubleToFloatFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertDoubleToFloatFix.java new file mode 100644 index 000000000000..cb8122b75a75 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertDoubleToFloatFix.java @@ -0,0 +1,109 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.daemon.impl.quickfix; + +import com.intellij.codeInsight.daemon.impl.HighlightInfo; +import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil; +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; + +/** + * User: anna + * Date: 2/10/12 + */ +public class ConvertDoubleToFloatFix implements IntentionAction { + private final PsiExpression myExpression; + + public ConvertDoubleToFloatFix(PsiExpression expression) { + myExpression = expression; + } + + @NotNull + @Override + public String getText() { + return "Convert '" + myExpression.getText() + "' to float"; + } + + @NotNull + @Override + public String getFamilyName() { + return getText(); + } + + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + if (myExpression.isValid()) { + if (!StringUtil.endsWithIgnoreCase(myExpression.getText(), "d")) { + final PsiLiteralExpression expression = (PsiLiteralExpression)createFloatingPointExpression(project); + final Object value = expression.getValue(); + return value instanceof Float && !((Float)value).isInfinite() && !(((Float)value).floatValue() == 0 && !HighlightUtil.isFPZero(expression.getText())); + } + } + return false; + } + + @Override + public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + myExpression.replace(createFloatingPointExpression(project)); + } + + private PsiExpression createFloatingPointExpression(Project project) { + return JavaPsiFacade.getElementFactory(project).createExpressionFromText(myExpression.getText() + "f", myExpression); + } + + @Override + public boolean startInWriteAction() { + return true; + } + + public static void registerIntentions(@NotNull JavaResolveResult[] candidates, + @NotNull PsiExpressionList list, + @NotNull HighlightInfo highlightInfo, + TextRange fixRange) { + if (candidates.length == 0) return; + PsiExpression[] expressions = list.getExpressions(); + for (JavaResolveResult candidate : candidates) { + registerIntention(expressions, highlightInfo, fixRange, candidate, list); + } + } + + private static void registerIntention(@NotNull PsiExpression[] expressions, + @NotNull HighlightInfo highlightInfo, + TextRange fixRange, + @NotNull JavaResolveResult candidate, + @NotNull PsiElement context) { + if (!candidate.isStaticsScopeCorrect()) return; + PsiMethod method = (PsiMethod)candidate.getElement(); + if (method != null && context.getManager().isInProject(method)) { + final PsiParameter[] parameters = method.getParameterList().getParameters(); + if (parameters.length == expressions.length) { + for (int i = 0, length = parameters.length; i < length; i++) { + PsiParameter parameter = parameters[i]; + final PsiExpression expression = expressions[i]; + if (expression instanceof PsiLiteralExpression && PsiType.FLOAT.equals(parameter.getType()) && PsiType.DOUBLE.equals(expression.getType())) { + QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, new ConvertDoubleToFloatFix(expression), null); + } + } + } + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after1.java new file mode 100644 index 000000000000..150bd12f3c60 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after1.java @@ -0,0 +1,7 @@ +// "Convert '1e1' to float" "true" +class Test { + void bar() { + foo(1e1f); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after2.java new file mode 100644 index 000000000000..99cdfdf2f2af --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after2.java @@ -0,0 +1,7 @@ +// "Convert '2.' to float" "true" +class Test { + void bar() { + foo(2.f); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after3.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after3.java new file mode 100644 index 000000000000..9272f41b2410 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after3.java @@ -0,0 +1,7 @@ +// "Convert '.3' to float" "true" +class Test { + void bar() { + foo(.3f); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after4.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after4.java new file mode 100644 index 000000000000..9d3993fd0f27 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after4.java @@ -0,0 +1,7 @@ +// "Convert '0.0' to float" "true" +class Test { + void bar() { + foo(0.0f); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after5.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after5.java new file mode 100644 index 000000000000..7e70cf492967 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after5.java @@ -0,0 +1,7 @@ +// "Convert '3.14' to float" "true" +class Test { + void bar() { + foo(3.14f); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before1.java new file mode 100644 index 000000000000..e476b77bc9e0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before1.java @@ -0,0 +1,7 @@ +// "Convert '1e1' to float" "true" +class Test { + void bar() { + foo(1e1); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before2.java new file mode 100644 index 000000000000..fa67aa86c9bf --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before2.java @@ -0,0 +1,7 @@ +// "Convert '2.' to float" "true" +class Test { + void bar() { + foo(2.); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before3.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before3.java new file mode 100644 index 000000000000..3f6fb07e7b48 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before3.java @@ -0,0 +1,7 @@ +// "Convert '.3' to float" "true" +class Test { + void bar() { + foo(.3); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before4.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before4.java new file mode 100644 index 000000000000..92cb59d6872e --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before4.java @@ -0,0 +1,7 @@ +// "Convert '0.0' to float" "true" +class Test { + void bar() { + foo(0.0); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before5.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before5.java new file mode 100644 index 000000000000..9541ec5647fe --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before5.java @@ -0,0 +1,7 @@ +// "Convert '3.14' to float" "true" +class Test { + void bar() { + foo(3.14); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before6.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before6.java new file mode 100644 index 000000000000..1799fb8943ee --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before6.java @@ -0,0 +1,7 @@ +// "Convert '1e-9d' to float" "false" +class Test { + void bar() { + foo(1e-9d); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before7.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before7.java new file mode 100644 index 000000000000..fe93892a6b6d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before7.java @@ -0,0 +1,7 @@ +// "Convert '1e137' to float" "false" +class Test { + void bar() { + foo(1e137); + } + void foo(float f){} +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ConvertDoubleToFloatFixTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ConvertDoubleToFloatFixTest.java new file mode 100644 index 000000000000..1f57ad9d67a7 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ConvertDoubleToFloatFixTest.java @@ -0,0 +1,29 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.daemon.quickFix; + +/** + * @author cdr + */ +public class ConvertDoubleToFloatFixTest extends LightQuickFix15TestCase { + + public void test() throws Exception { doAllTests(); } + + @Override + protected String getBasePath() { + return "/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat"; + } +} From fbf99fd29b26439b02d22fd488b59964b28de78e Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 10 Feb 2012 14:27:15 +0100 Subject: [PATCH 29/59] show autopopup after completing a package when and only when there was a dot inserted after the previous package --- .../intellij/codeInsight/editorActions/JavaTypedHandler.java | 2 +- .../com/intellij/codeInsight/lookup/PackageLookupItem.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java index d684041bc68b..bd44b70fdc28 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java @@ -60,7 +60,7 @@ public class JavaTypedHandler extends TypedHandlerDelegate { } //do not show lookup when typing varargs ellipsis - final PsiElement prevSibling = lastElement.getPrevSibling(); + final PsiElement prevSibling = PsiTreeUtil.prevVisibleLeaf(lastElement); if (prevSibling == null || ".".equals(prevSibling.getText())) return false; PsiElement parent = prevSibling; do { diff --git a/java/java-impl/src/com/intellij/codeInsight/lookup/PackageLookupItem.java b/java/java-impl/src/com/intellij/codeInsight/lookup/PackageLookupItem.java index 4374d9f6b3f4..168d5444ca71 100644 --- a/java/java-impl/src/com/intellij/codeInsight/lookup/PackageLookupItem.java +++ b/java/java-impl/src/com/intellij/codeInsight/lookup/PackageLookupItem.java @@ -33,6 +33,8 @@ class PackageLookupItem extends LookupItem { @Override public void handleInsert(InsertionContext context) { super.handleInsert(context); - AutoPopupController.getInstance(context.getProject()).scheduleAutoPopup(context.getEditor(), null); + if (getTailType() == TailType.DOT || context.getCompletionChar() == '.') { + AutoPopupController.getInstance(context.getProject()).scheduleAutoPopup(context.getEditor(), null); + } } } From a58a8ec63760670691e02b19478a3781cf52b127 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 10 Feb 2012 14:28:42 +0100 Subject: [PATCH 30/59] EA-33623 - AIOOBE: ExpectedTypesProvider$MyParentVisitor.visitPolyadicExpression --- .../src/com/intellij/codeInsight/ExpectedTypesProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java index 128276a52113..dfba4c4c2224 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java @@ -590,7 +590,7 @@ public class ExpectedTypesProvider { } return; } - PsiExpression anotherExpr = index > 0 ? operands[0] : operands[1]; + PsiExpression anotherExpr = index > 0 ? operands[0] : index < operands.length ? operands[1] : null; PsiType anotherType = anotherExpr != null ? anotherExpr.getType() : null; IElementType i = expr.getOperationTokenType(); if (i == JavaTokenType.MINUS || From 4900a53a49e956689ac52ba4a31048660d414a77 Mon Sep 17 00:00:00 2001 From: Serega Vasiliev Date: Fri, 10 Feb 2012 15:22:13 +0100 Subject: [PATCH 31/59] dom perfomance improvements (peter) --- .../psi/util/CachedValuesManager.java | 7 +++++-- .../intellij/util/xml/impl/DomImplUtil.java | 20 ++++++++++++------- .../util/xml/impl/DomInvocationHandler.java | 4 ---- .../xml/impl/DomRootInvocationHandler.java | 1 - .../xml/impl/FixedChildDescriptionImpl.java | 1 - .../GetCompositeCollectionInvocation.java | 1 - .../xml/impl/GetFixedChildInvocation.java | 1 - .../intellij/util/xml/impl/GetInvocation.java | 1 - 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java b/platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java index e2c805e5cc5e..49391709ed00 100644 --- a/platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java +++ b/platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java @@ -93,17 +93,20 @@ public abstract class CachedValuesManager { } public static class MemoizationKey extends Key { + private final String myName; + public MemoizationKey(@NotNull @NonNls String name) { super(name); + myName = name; } public int hashCode() { - return toString().hashCode(); + return myName.hashCode(); } @Override public boolean equals(Object obj) { - return obj instanceof MemoizationKey && toString().equals(obj.toString()); + return obj instanceof MemoizationKey && myName.equals(((MemoizationKey)obj).myName); } } diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/DomImplUtil.java b/xml/dom-impl/src/com/intellij/util/xml/impl/DomImplUtil.java index d7d5bfb5d9dc..822aa9f0c701 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/DomImplUtil.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/DomImplUtil.java @@ -21,6 +21,7 @@ import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiErrorElement; import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiInvalidElementAccessException; import com.intellij.psi.impl.source.tree.TreeElement; import com.intellij.psi.xml.*; import com.intellij.util.ReflectionCache; @@ -149,14 +150,19 @@ public class DomImplUtil { } return ContainerUtil.findAll(tag.getSubTags(), new Condition() { public boolean value(XmlTag childTag) { - if (!childTag.isValid()) { - LOG.error("tag.getSubTags() returned invalid, " + - "tag=" + tag + ", " + - "containing file: " + tag.getContainingFile() + - "subTag.parent=" + childTag.getNode().getTreeParent()); - return false; + try { + return isNameSuitable(name, childTag.getLocalName(), childTag.getName(), childTag.getNamespace(), file); + } + catch (PsiInvalidElementAccessException e) { + if (!childTag.isValid()) { + LOG.error("tag.getSubTags() returned invalid, " + + "tag=" + tag + ", " + + "containing file: " + tag.getContainingFile() + + "subTag.parent=" + childTag.getNode().getTreeParent()); + return false; + } + throw e; } - return isNameSuitable(name, childTag.getLocalName(), childTag.getName(), childTag.getNamespace(), file); } }); } diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/DomInvocationHandler.java b/xml/dom-impl/src/com/intellij/util/xml/impl/DomInvocationHandler.java index 44d69049c9a7..b7480910ed49 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/DomInvocationHandler.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/DomInvocationHandler.java @@ -132,8 +132,6 @@ public abstract class DomInvocationHandler subTags = tagsGetter.fun(this); if (subTags.isEmpty()) return Collections.emptyList(); diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/DomRootInvocationHandler.java b/xml/dom-impl/src/com/intellij/util/xml/impl/DomRootInvocationHandler.java index f03e9b9b3782..d504a0a14401 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/DomRootInvocationHandler.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/DomRootInvocationHandler.java @@ -89,7 +89,6 @@ public class DomRootInvocationHandler extends DomInvocationHandler result = new SmartList(); final DomInvocationHandler handler = DomManagerImpl.getDomInvocationHandler(element); if (handler != null) { - handler.assertValid(); for (int i = 0; i < myCount; i++) { result.add(handler.getFixedChild(Pair.create(this, i)).getProxy()); } diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/GetCompositeCollectionInvocation.java b/xml/dom-impl/src/com/intellij/util/xml/impl/GetCompositeCollectionInvocation.java index b4457905f8c6..37c6602922c4 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/GetCompositeCollectionInvocation.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/GetCompositeCollectionInvocation.java @@ -33,7 +33,6 @@ class GetCompositeCollectionInvocation implements Invocation { } public Object invoke(final DomInvocationHandler handler, final Object[] args) throws Throwable { - handler.assertValid(); Map map = new THashMap(); for (final CollectionChildDescriptionImpl qname : myQnames) { for (DomElement element : handler.getCollectionChildren(qname, qname.getTagsGetter())) { diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/GetFixedChildInvocation.java b/xml/dom-impl/src/com/intellij/util/xml/impl/GetFixedChildInvocation.java index fb22399fdf08..689a01f5a22f 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/GetFixedChildInvocation.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/GetFixedChildInvocation.java @@ -13,7 +13,6 @@ public class GetFixedChildInvocation implements Invocation { } public Object invoke(final DomInvocationHandler handler, final Object[] args) throws Throwable { - handler.assertValid(); return handler.getFixedChild(myPair).getProxy(); } } diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/GetInvocation.java b/xml/dom-impl/src/com/intellij/util/xml/impl/GetInvocation.java index 9f833cf1fd63..a59f30d4dd7d 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/GetInvocation.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/GetInvocation.java @@ -30,7 +30,6 @@ public class GetInvocation implements Invocation { } public Object invoke(final DomInvocationHandler handler, final Object[] args) throws Throwable { - handler.assertValid(); if (myConverter == Converter.EMPTY_CONVERTER) { return getValueInner(handler, myConverter); } From 01ee49fb8b81f4b491296703ecf315daf52a11d5 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 10 Feb 2012 15:07:33 +0100 Subject: [PATCH 32/59] usage targets may become invalid (EA-33613) --- .../com/intellij/usages/impl/UsageViewTreeCellRenderer.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/platform/usageView/src/com/intellij/usages/impl/UsageViewTreeCellRenderer.java b/platform/usageView/src/com/intellij/usages/impl/UsageViewTreeCellRenderer.java index a4fbf29eccce..33e6e09a3dba 100644 --- a/platform/usageView/src/com/intellij/usages/impl/UsageViewTreeCellRenderer.java +++ b/platform/usageView/src/com/intellij/usages/impl/UsageViewTreeCellRenderer.java @@ -68,6 +68,11 @@ class UsageViewTreeCellRenderer extends ColoredTreeCellRenderer { if (userObject instanceof UsageTarget) { UsageTarget usageTarget = (UsageTarget)userObject; + if (!usageTarget.isValid()) { + append(UsageViewBundle.message("node.invalid"), ourInvalidAttributes); + return; + } + final ItemPresentation presentation = usageTarget.getPresentation(); LOG.assertTrue(presentation != null); if (showAsReadOnly) { From c83cc1970e4624423aa7de3d3ecbbf5a7a0577f8 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 10 Feb 2012 15:32:52 +0100 Subject: [PATCH 33/59] IDEA-81192 Event Log: special html characters are not replaced (see screenshot) --- .../src/com/intellij/notification/EventLog.java | 5 ++++- .../testSrc/com/intellij/notification/EventLogTest.groovy | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/notification/EventLog.java b/platform/platform-impl/src/com/intellij/notification/EventLog.java index 88c37d54a8f3..acb1dd32c986 100644 --- a/platform/platform-impl/src/com/intellij/notification/EventLog.java +++ b/platform/platform-impl/src/com/intellij/notification/EventLog.java @@ -165,7 +165,7 @@ public class EventLog implements Notifications { content = title + (StringUtil.isNotEmpty(content) ? ": " + content : ""); } - content = StringUtil.replace(StringUtil.convertLineSeparators(content), " ", " "); + content = StringUtil.convertLineSeparators(content); boolean hasHtml = false; while (true) { Matcher tagMatcher = TAG_PATTERN.matcher(content); @@ -248,6 +248,9 @@ public class EventLog implements Notifications { } private static void appendText(Document document, String text) { + text = StringUtil.replace(text, " ", " "); + text = StringUtil.replace(text, "»", ">>"); + text = StringUtil.replace(text, "«", "<<"); document.insertString(document.getTextLength(), StringUtil.unescapeXml(text)); } diff --git a/platform/platform-tests/testSrc/com/intellij/notification/EventLogTest.groovy b/platform/platform-tests/testSrc/com/intellij/notification/EventLogTest.groovy index 3b1360036d49..baf2f08ef1d4 100644 --- a/platform/platform-tests/testSrc/com/intellij/notification/EventLogTest.groovy +++ b/platform/platform-tests/testSrc/com/intellij/notification/EventLogTest.groovy @@ -29,9 +29,9 @@ class EventLogTest extends LightPlatformTestCase { PlatformTestCase.initPlatformLangPrefix() } - public void testNbsp() { - def entry = EventLog.formatForLog(new Notification("xxx", "Title", "Hello world", NotificationType.ERROR)) - assert entry.message == 'Title: Hello world' + public void testHtmlEntities() { + def entry = EventLog.formatForLog(new Notification("xxx", "Title", "Hello world«»", NotificationType.ERROR)) + assert entry.message == 'Title: Hello world<<>>' } public void testParseMultilineText() { From 0d36f69fdfb9219f2ebb3de7adf82d35fb72d6a4 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 10 Feb 2012 15:42:02 +0100 Subject: [PATCH 34/59] fix CCE in tests --- .../codeInspection/local/GroovyPostHighlightingPass.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java index c61ef6fb13b9..b29f0906545b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java @@ -25,7 +25,6 @@ import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInspection.InspectionProfile; import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection; -import com.intellij.codeInspection.ex.InspectionToolWrapper; import com.intellij.lang.annotation.Annotation; import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.lang.annotation.AnnotationSession; @@ -87,8 +86,7 @@ public class GroovyPostHighlightingPass extends TextEditorHighlightingPass { if (!fileIndex.isInContent(virtualFile)) { return; } - final InspectionToolWrapper wrapper = (InspectionToolWrapper)profile.getInspectionTool(UnusedDeclarationInspection.SHORT_NAME, myFile); - final UnusedDeclarationInspection deadCodeInspection = wrapper != null ? (UnusedDeclarationInspection)wrapper.getTool() : null; + final UnusedDeclarationInspection deadCodeInspection = (UnusedDeclarationInspection)profile.getUnwrappedTool(UnusedDeclarationInspection.SHORT_NAME, myFile); final GlobalUsageHelper usageHelper = new GlobalUsageHelper() { public boolean isCurrentFileAlreadyChecked() { return false; From 13242b71c3edf2ac31e5a2704ba384038a16721a Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Fri, 10 Feb 2012 18:47:40 +0400 Subject: [PATCH 35/59] initializing context fixed --- .../intellij/codeInspection/ex/InspectionToolRegistrar.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolRegistrar.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolRegistrar.java index acaa6fbee662..3cf54d5b3cee 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolRegistrar.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolRegistrar.java @@ -340,8 +340,8 @@ public class InspectionToolRegistrar { } @Override - public GlobalInspectionContextImpl getContext() { - return getTool().getContext(); + public void initialize(@NotNull GlobalInspectionContextImpl context) { + getTool().initialize(context); } @NotNull From 446f677828dec2a936e20cb0459720bb3cff0b7b Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Fri, 10 Feb 2012 18:48:29 +0400 Subject: [PATCH 36/59] Git NotificationManager: defend against empty content in notifications --- plugins/git4idea/src/git4idea/NotificationManager.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/git4idea/src/git4idea/NotificationManager.java b/plugins/git4idea/src/git4idea/NotificationManager.java index 7977bca38c30..fa1290128cbf 100644 --- a/plugins/git4idea/src/git4idea/NotificationManager.java +++ b/plugins/git4idea/src/git4idea/NotificationManager.java @@ -21,6 +21,7 @@ import com.intellij.notification.NotificationListener; import com.intellij.notification.NotificationType; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -37,6 +38,12 @@ public class NotificationManager { public void notify(@NotNull NotificationGroup notificationGroup, @NotNull String title, @NotNull String message, @NotNull NotificationType type, @Nullable NotificationListener listener) { + // title can be empty; description can't be neither null, nor empty + if (StringUtil.isEmptyOrSpaces(message)) { + message = title; + title = ""; + } + // if both title and description were empty, then it is a problem in the calling code => Notifications engine assertion will notify. createNotification(notificationGroup, title, message, type, listener).notify(myProject); } From 226c141009ee96c9bda65f97b5d1cb6d88e684df Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Fri, 10 Feb 2012 18:53:40 +0400 Subject: [PATCH 37/59] IDEA-78011 Git: Deleting remote branch Show confirmation. Also propose to delete local branch(es) tracking the remote branch via checkbox. Don't propose to delete current branch, but warn about it. Join notifications about remote and local branch deletetions into a single one - for this call GitDeleteOperation with an overridden notifySuccess(). --- plugins/git4idea/src/git4idea/GitBranch.java | 16 +- .../branch/GitBranchOperationsProcessor.java | 153 +++++++++++++++++- .../git4idea/src/git4idea/commands/Git.java | 20 ++- .../ui/branch/GitBranchPopupActions.java | 26 ++- .../ui/branch/GitMultiRootBranchConfig.java | 30 ++++ 5 files changed, 224 insertions(+), 21 deletions(-) diff --git a/plugins/git4idea/src/git4idea/GitBranch.java b/plugins/git4idea/src/git4idea/GitBranch.java index 1714fe74e304..e04e9cc1677b 100644 --- a/plugins/git4idea/src/git4idea/GitBranch.java +++ b/plugins/git4idea/src/git4idea/GitBranch.java @@ -17,6 +17,7 @@ package git4idea; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VirtualFile; @@ -91,11 +92,16 @@ public class GitBranch extends GitReference { */ @NotNull public String getShortName() { - String name = getName(); - if (myRemote) { - return name.substring(name.indexOf('/') + 1); - } - return name; + return splitNameOfRemoteBranch(getName()).getSecond(); + } + + /** + * Returns the remote and the "local" name of a remote branch. + * Expects branch in format "origin/master", i.e. remote/branch + */ + public static Pair splitNameOfRemoteBranch(String branchName) { + int firstSlash = branchName.indexOf('/'); + return Pair.create(branchName.substring(0, firstSlash), branchName.substring(firstSlash + 1)); } /** diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java b/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java index 887983904b2c..c8eaed476653 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java @@ -15,18 +15,25 @@ */ package git4idea.branch; +import com.intellij.notification.NotificationType; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsException; import com.intellij.util.ui.UIUtil; +import git4idea.GitBranch; import git4idea.GitExecutionException; import git4idea.GitVcs; +import git4idea.NotificationManager; import git4idea.commands.Git; +import git4idea.commands.GitCommandResult; +import git4idea.commands.GitCompoundResult; import git4idea.history.GitHistoryUtils; import git4idea.history.browser.GitCommit; import git4idea.repo.GitRepository; @@ -38,10 +45,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; /** * Executor of Git branching operations. @@ -168,13 +173,147 @@ public final class GitBranchOperationsProcessor { public void deleteBranch(final String branchName) { new CommonBackgroundTask(myProject, "Deleting " + branchName, myCallInAwtAfterExecution) { @Override public void execute(@NotNull ProgressIndicator indicator) { - doDelete(branchName, indicator); + new GitDeleteBranchOperation(myProject, myRepositories, branchName, getCurrentBranchOrRev(), indicator).execute(); } }.runInBackground(); } - private void doDelete(final String branchName, ProgressIndicator indicator) { - new GitDeleteBranchOperation(myProject, myRepositories, branchName, getCurrentBranchOrRev(), indicator).execute(); + public void deleteRemoteBranch(@NotNull final String branchName) { + final Collection trackingBranches = findTrackingBranches(branchName); + String currentBranch = getCurrentBranchOrRev(); + boolean currentBranchTracksBranchToDelete = false; + if (trackingBranches.contains(currentBranch)) { + currentBranchTracksBranchToDelete = true; + trackingBranches.remove(currentBranch); + } + + final DeleteRemoteBranchDecision decision = confirmBranchDeletion(branchName, trackingBranches, currentBranchTracksBranchToDelete); + + if (decision.delete()) { + new CommonBackgroundTask(myProject, "Deleting " + branchName, myCallInAwtAfterExecution) { + @Override public void execute(@NotNull ProgressIndicator indicator) { + boolean deletedSuccessfully = doDeleteRemote(branchName); + if (deletedSuccessfully) { + final Collection successfullyDeletedLocalBranches = new ArrayList(1); + if (decision.deleteTracking()) { + for (final String branch : trackingBranches) { + indicator.setText("Deleting " + branch); + new GitDeleteBranchOperation(myProject, myRepositories, branch, getCurrentBranchOrRev(), indicator) { + @Override + protected void notifySuccess(@NotNull String message) { + // do nothing - will display a combo notification for all deleted branches below + successfullyDeletedLocalBranches.add(branch); + } + }.execute(); + } + } + notifySuccessfulDeletion(branchName, successfullyDeletedLocalBranches); + } + } + }.runInBackground(); + } + } + + @NotNull + private Collection findTrackingBranches(@NotNull String remoteBranch) { + return new GitMultiRootBranchConfig(myRepositories).getTrackingBranches(remoteBranch); + } + + private boolean doDeleteRemote(String branchName) { + GitCompoundResult result = new GitCompoundResult(myProject); + for (GitRepository repository : myRepositories) { + Pair pair = GitBranch.splitNameOfRemoteBranch(branchName); + GitCommandResult res = Git.push(repository, pair.getFirst(), ":" + pair.getSecond()); + result.append(repository, res); + repository.update(GitRepository.TrackedTopic.BRANCHES); + } + if (!result.totalSuccess()) { + NotificationManager.getInstance(myProject).notifyError("Failed to delete remote branch " + branchName, + result.getErrorOutputWithReposIndication()); + } + return result.totalSuccess(); + } + + private void notifySuccessfulDeletion(@NotNull String remoteBranchName, @NotNull Collection localBranches) { + String message = ""; + if (!localBranches.isEmpty()) { + message = "Also deleted local " + StringUtil.pluralize("branch", localBranches.size()) + ": " + StringUtil.join(localBranches, ", "); + } + NotificationManager.getInstance(myProject).notify(GitVcs.NOTIFICATION_GROUP_ID, "Deleted remote branch " + remoteBranchName, + message, NotificationType.INFORMATION); + } + + private DeleteRemoteBranchDecision confirmBranchDeletion(@NotNull String branchName, @NotNull Collection trackingBranches, + boolean currentBranchTracksBranchToDelete) { + String title = "Delete Remote Branch"; + String message = "Delete remote branch " + branchName; + + boolean delete; + final boolean deleteTracking; + if (trackingBranches.isEmpty()) { + delete = Messages.showYesNoDialog(myProject, message, title, "Delete", "Cancel", Messages.getQuestionIcon()) == Messages.OK; + deleteTracking = false; + } + else { + if (currentBranchTracksBranchToDelete) { + message += "\n\nCurrent branch " + getCurrentBranchOrRev() + " tracks " + branchName + " but won't be deleted."; + } + final String checkboxMessage; + if (trackingBranches.size() == 1) { + checkboxMessage = "Delete tracking local branch " + trackingBranches.iterator().next() + " as well"; + } + else { + checkboxMessage = "Delete tracking local branches " + StringUtil.join(trackingBranches, ", "); + } + + final AtomicBoolean deleteChoice = new AtomicBoolean(); + delete = Messages.OK == Messages.showYesNoDialog(message, title, "Delete", "Cancel", Messages.getQuestionIcon(), new DialogWrapper.DoNotAskOption() { + @Override + public boolean isToBeShown() { + return true; + } + + @Override + public void setToBeShown(boolean value, int exitCode) { + deleteChoice.set(!value); + } + + @Override + public boolean canBeHidden() { + return true; + } + + @Override + public boolean shouldSaveOptionsOnCancel() { + return false; + } + + @Override + public String getDoNotShowMessage() { + return checkboxMessage; + } + }); + deleteTracking = deleteChoice.get(); + } + return new DeleteRemoteBranchDecision(delete, deleteTracking); + } + + private static class DeleteRemoteBranchDecision { + private final boolean delete; + private final boolean deleteTracking; + + private DeleteRemoteBranchDecision(boolean delete, boolean deleteTracking) { + this.delete = delete; + this.deleteTracking = deleteTracking; + } + + public boolean delete() { + return delete; + } + + public boolean deleteTracking() { + return deleteTracking; + } } /** diff --git a/plugins/git4idea/src/git4idea/commands/Git.java b/plugins/git4idea/src/git4idea/commands/Git.java index 27f94bf775b9..bbe265ba0977 100644 --- a/plugins/git4idea/src/git4idea/commands/Git.java +++ b/plugins/git4idea/src/git4idea/commands/Git.java @@ -256,19 +256,27 @@ public class Git { return run(h); } - public static GitCommandResult push(@NotNull GitRepository repository, @NotNull GitPushSpec pushSpec, @NotNull GitLineHandlerListener... listeners) { - final GitLineHandlerPasswordRequestAware h = new GitLineHandlerPasswordRequestAware(repository.getProject(), repository.getRoot(), GitCommand.PUSH); + @NotNull + public static GitCommandResult push(@NotNull GitRepository repository, @NotNull String remote, @NotNull String spec, + @NotNull GitLineHandlerListener... listeners) { + final GitLineHandlerPasswordRequestAware h = new GitLineHandlerPasswordRequestAware(repository.getProject(), repository.getRoot(), + GitCommand.PUSH); h.setSilent(false); - for (GitLineHandlerListener listener : listeners) { h.addLineListener(listener); } + h.addParameters(remote); + h.addParameters(spec); + return run(h, true); + } + + @NotNull + public static GitCommandResult push(@NotNull GitRepository repository, @NotNull GitPushSpec pushSpec, + @NotNull GitLineHandlerListener... listeners) { GitRemote remote = pushSpec.getRemote(); - h.addParameters(remote.getName()); GitBranch remoteBranch = pushSpec.getDest(); String destination = remoteBranch.getName().replaceFirst(remote.getName() + "/", ""); - h.addParameters(pushSpec.getSource().getName() + ":" + destination); - return run(h, true); + return push(repository, remote.getName(), pushSpec.getSource().getName() + ":" + destination); } private static GitCommandResult run(@NotNull GitLineHandler handler) { diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java index fa6e23495187..692bd47d525d 100644 --- a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java +++ b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java @@ -251,9 +251,6 @@ class GitBranchPopupActions { } - /** - * Action to delete a branch. - */ private static class DeleteAction extends DumbAwareAction { private final Project myProject; private final List myRepositories; @@ -302,6 +299,7 @@ class GitBranchPopupActions { new CheckoutRemoteBranchAction(myProject, myRepositories, myBranchName, mySelectedRepository), new CompareAction(myProject, myRepositories, myBranchName, mySelectedRepository), new MergeAction(myProject, myRepositories, myBranchName, mySelectedRepository), + new RemoteDeleteAction(myProject, myRepositories, myBranchName, mySelectedRepository) }; } @@ -336,6 +334,28 @@ class GitBranchPopupActions { return myRemoteBranchName.substring(slashPosition+1); } } + + private static class RemoteDeleteAction extends DumbAwareAction { + private final Project myProject; + private final List myRepositories; + private final String myBranchName; + private final GitRepository mySelectedRepository; + + RemoteDeleteAction(@NotNull Project project, @NotNull List repositories, @NotNull String branchName, + @NotNull GitRepository selectedRepository) { + super("Delete"); + myProject = project; + myRepositories = repositories; + myBranchName = branchName; + mySelectedRepository = selectedRepository; + } + + @Override + public void actionPerformed(AnActionEvent e) { + new GitBranchOperationsProcessor(myProject, myRepositories, mySelectedRepository).deleteRemoteBranch(myBranchName); + } + } + } private static class CompareAction extends DumbAwareAction { diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java b/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java index a4040993053e..9aedb95d9477 100644 --- a/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java +++ b/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java @@ -24,6 +24,7 @@ import git4idea.repo.GitRepository; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -110,6 +111,35 @@ public class GitMultiRootBranchConfig { return trackedRemote + "/" + trackedBranch; } + /** + * Returns local branches which track the given remote branch. Usually there is 0 or 1 such branches. + */ + @NotNull + public Collection getTrackingBranches(@NotNull String remoteBranch) { + Collection trackingBranches = null; + for (GitRepository repository : myRepositories) { + Collection tb = getTrackingBranches(repository, remoteBranch); + if (trackingBranches == null) { + trackingBranches = tb; + } + else { + trackingBranches.retainAll(tb); + } + } + return trackingBranches == null ? Collections.emptyList() : trackingBranches; + } + + @NotNull + public static Collection getTrackingBranches(@NotNull GitRepository repository, @NotNull String remoteBranch) { + Collection trackingBranches = new ArrayList(1); + for (GitBranchTrackInfo trackInfo : repository.getConfig().getBranchTrackInfos()) { + if (remoteBranch.equals(trackInfo.getRemote().getName() + "/" + trackInfo.getRemoteBranch())) { + trackingBranches.add(trackInfo.getBranch()); + } + } + return trackingBranches; + } + @Nullable private static Pair getTrackedBranchAndRemote(@NotNull GitRepository repository, @NotNull String branch) { for (GitBranchTrackInfo trackInfo : repository.getConfig().getBranchTrackInfos()) { From cf843a27864cc2fd951a4574df5809f984cfd45f Mon Sep 17 00:00:00 2001 From: "kirill.safonov" Date: Fri, 10 Feb 2012 18:45:52 +0400 Subject: [PATCH 38/59] all capitals --- .../intellij/openapi/diff/impl/patch/formove/PathsVerifier.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PathsVerifier.java b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PathsVerifier.java index ffca0ed834c2..7ab196a1b4b1 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PathsVerifier.java +++ b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PathsVerifier.java @@ -564,7 +564,7 @@ public class PathsVerifier { public Collection doDelayed() { final List result = new LinkedList(); if (! myOverrideExisting.isEmpty()) { - final String title = "Overwrite existing files"; + final String title = "Overwrite Existing Files"; final Collection selected = AbstractVcsHelper.getInstance(myProject).selectFilePathsToProcess( new ArrayList(myOverrideExisting.keySet()), title, "\nThe following files should be created by patch, but they already exist.\nDo you want to overwrite them?\n", title, From 54c030e9beb8bec7a688886220e0f671837d39c5 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 10 Feb 2012 16:24:48 +0100 Subject: [PATCH 39/59] diagnostics --- .../psi/impl/source/codeStyle/CodeStyleSchemeImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleSchemeImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleSchemeImpl.java index b358c506ae5b..0971828fc653 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleSchemeImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleSchemeImpl.java @@ -133,14 +133,14 @@ public class CodeStyleSchemeImpl implements JDOMExternalizable, CodeStyleScheme, public static CodeStyleSchemeImpl readScheme(Document document) throws InvalidDataException, JDOMException, IOException{ Element root = document.getRootElement(); if (root == null){ - throw new InvalidDataException(); + throw new InvalidDataException("No root element in code style scheme file"); } String schemeName = root.getAttributeValue(NAME); String parentName = root.getAttributeValue(PARENT); - if (schemeName == null){ - throw new InvalidDataException(); + if (schemeName == null) { + throw new InvalidDataException("Name attribute missing in code style scheme file"); } return new CodeStyleSchemeImpl(schemeName, parentName, root); From 4840d541ed7b10008dc5532b7d82709deb680ca8 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Fri, 10 Feb 2012 17:14:31 +0400 Subject: [PATCH 40/59] fix memory leak: [thread local] strong ref for SaxBuilder also references Element processed --- .../com/intellij/openapi/util/JDOMUtil.java | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/platform/util/src/com/intellij/openapi/util/JDOMUtil.java b/platform/util/src/com/intellij/openapi/util/JDOMUtil.java index a7826308a2c6..02076e7106a6 100644 --- a/platform/util/src/com/intellij/openapi/util/JDOMUtil.java +++ b/platform/util/src/com/intellij/openapi/util/JDOMUtil.java @@ -36,6 +36,7 @@ import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import java.io.*; +import java.lang.ref.SoftReference; import java.net.URL; import java.util.ArrayList; import java.util.Collections; @@ -47,17 +48,7 @@ import java.util.List; */ @SuppressWarnings({"HardCodedStringLiteral"}) public class JDOMUtil { - private static final ThreadLocal ourSaxBuilder = new ThreadLocal(){ - protected SAXBuilder initialValue() { - SAXBuilder saxBuilder = new SAXBuilder(); - saxBuilder.setEntityResolver(new EntityResolver() { - public InputSource resolveEntity(String publicId, String systemId) { - return new InputSource(new CharArrayReader(ArrayUtil.EMPTY_CHAR_ARRAY)); - } - }); - return saxBuilder; - } - }; + private static final ThreadLocal> ourSaxBuilder = new ThreadLocal>(); private JDOMUtil() { } @@ -317,14 +308,27 @@ public class JDOMUtil { @NotNull public static Document loadDocument(char[] chars, int length) throws IOException, JDOMException { - SAXBuilder builder = ourSaxBuilder.get(); - return builder.build(new CharArrayReader(chars, 0, length)); + return getSaxBuilder().build(new CharArrayReader(chars, 0, length)); + } + + private static SAXBuilder getSaxBuilder() { + SoftReference reference = ourSaxBuilder.get(); + SAXBuilder saxBuilder = reference != null ? reference.get() : null; + if (saxBuilder == null) { + saxBuilder = new SAXBuilder(); + saxBuilder.setEntityResolver(new EntityResolver() { + public InputSource resolveEntity(String publicId, String systemId) { + return new InputSource(new CharArrayReader(ArrayUtil.EMPTY_CHAR_ARRAY)); + } + }); + ourSaxBuilder.set(new SoftReference(saxBuilder)); + } + return saxBuilder; } @NotNull public static Document loadDocument(CharSequence seq) throws IOException, JDOMException { - SAXBuilder builder = ourSaxBuilder.get(); - return builder.build(new CharSequenceReader(seq)); + return getSaxBuilder().build(new CharSequenceReader(seq)); } @NotNull @@ -351,10 +355,9 @@ public class JDOMUtil { @NotNull public static Document loadDocument(@NotNull InputStream stream) throws JDOMException, IOException { - SAXBuilder saxBuilder = ourSaxBuilder.get(); InputStreamReader reader = new InputStreamReader(stream, ENCODING); try { - return saxBuilder.build(reader); + return getSaxBuilder().build(reader); } finally { reader.close(); From 849bc0e7071e37b1e61d157cf13ef35080d196d9 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Fri, 10 Feb 2012 19:31:39 +0400 Subject: [PATCH 41/59] prefer to use THashMap instead of TreeMap & do not store JDOM's Element for read-only components state --- .../impl/stores/ModuleStoreImpl.java | 9 ++-- .../impl/stores/ComponentStoreImpl.java | 6 ++- .../CompoundExternalizationSession.java | 4 +- .../impl/stores/StateStorageManagerImpl.java | 11 +++-- .../impl/stores/XmlElementStorage.java | 45 ++++++++----------- 5 files changed, 38 insertions(+), 37 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java b/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java index 5d0e994a317c..c7304c1774ea 100644 --- a/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java +++ b/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java @@ -28,6 +28,8 @@ import com.intellij.openapi.project.ex.ProjectEx; import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.ArrayUtil; +import gnu.trove.THashMap; import org.jdom.Attribute; import org.jdom.Element; import org.jetbrains.annotations.NonNls; @@ -100,13 +102,13 @@ public class ModuleStoreImpl extends BaseFileConfigurableStoreImpl implements IM public ModuleFileData(final String rootElementName, Module module) { super(rootElementName); myModule = module; - myOptions = new TreeMap(); + myOptions = new THashMap(2); } protected ModuleFileData(final ModuleFileData storageData) { super(storageData); - myOptions = new TreeMap(storageData.myOptions); + myOptions = new THashMap(storageData.myOptions); myModule = storageData.myModule; } @@ -130,7 +132,8 @@ public class ModuleStoreImpl extends BaseFileConfigurableStoreImpl implements IM final Element root = super.save(); myOptions.put(VERSION_OPTION, Integer.toString(myVersion)); - Set options = myOptions.keySet(); + String[] options = ArrayUtil.toStringArray(myOptions.keySet()); + Arrays.sort(options); for (String option : options) { root.setAttribute(option, myOptions.get(option)); } diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java index 2a4de0fe062f..ad9042e4212c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java @@ -32,6 +32,7 @@ import com.intellij.util.ArrayUtil; import com.intellij.util.ReflectionCache; import com.intellij.util.ReflectionUtil; import com.intellij.util.io.fs.IFile; +import gnu.trove.THashMap; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -44,7 +45,7 @@ import java.util.*; abstract class ComponentStoreImpl implements IComponentStore { private static final Logger LOG = Logger.getInstance("#com.intellij.components.ComponentStoreImpl"); - private final Map myComponents = Collections.synchronizedMap(new TreeMap()); + private final Map myComponents = Collections.synchronizedMap(new THashMap()); private final List mySettingsSavingComponents = Collections.synchronizedList(new ArrayList()); @Nullable private SaveSessionImpl mySession; @@ -470,7 +471,8 @@ abstract class ComponentStoreImpl implements IComponentStore { final StateStorageManager.ExternalizationSession session = storageManager.startExternalization(); - final String[] names = ArrayUtil.toStringArray(myComponents.keySet()); + String[] names = ArrayUtil.toStringArray(myComponents.keySet()); + Arrays.sort(names); for (String name : names) { Object component = myComponents.get(name); diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/CompoundExternalizationSession.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/CompoundExternalizationSession.java index f01ebe3fd15f..9e1b202676ac 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/CompoundExternalizationSession.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/CompoundExternalizationSession.java @@ -16,16 +16,16 @@ package com.intellij.openapi.components.impl.stores; import com.intellij.openapi.components.StateStorage; +import gnu.trove.THashMap; import java.util.Collection; -import java.util.HashMap; import java.util.Map; /** * @author mike */ public class CompoundExternalizationSession { - private final Map mySessions = new HashMap(); + private final Map mySessions = new THashMap(1); public StateStorage.ExternalizationSession getExternalizationSession(StateStorage stateStore) { StateStorage.ExternalizationSession session = mySessions.get(stateStore); diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java index c30837efe7a9..a8f94b8a3fb5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java @@ -31,6 +31,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.MultiMap; import com.intellij.util.io.fs.IFile; +import gnu.trove.THashMap; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; @@ -58,8 +59,8 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di } private final Map myMacros = new HashMap(); - private final Map myStorages = new HashMap(); - private final Map myPathToStorage = new HashMap(); + private final Map myStorages = new THashMap(); + private final Map myPathToStorage = new THashMap(); private final TrackingPathMacroSubstitutor myPathMacroSubstitutor; private final String myRootTagName; private Object mySession; @@ -160,7 +161,7 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di } private Map loadVersions() { - TreeMap result = new TreeMap(); + THashMap result = new THashMap(); String filePath = getNotNullVersionsFilePath(); if (filePath != null) { try { @@ -580,8 +581,10 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di public static Element createComponentVersionsXml(Map versions) { Element vers = new Element("versions"); + String[] componentNames = ArrayUtil.toStringArray(versions.keySet()); + Arrays.sort(componentNames); - for (String name : versions.keySet()) { + for (String name : componentNames) { long version = versions.get(name); if (version != 0) { Element element = new Element("component"); diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java index 4b9d7324ba75..b439c3e212dc 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java @@ -26,8 +26,10 @@ import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.ArrayUtil; import com.intellij.util.containers.StringInterner; import com.intellij.util.io.fs.IFile; +import gnu.trove.THashMap; import org.jdom.Attribute; import org.jdom.Document; import org.jdom.Element; @@ -62,7 +64,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { protected Integer myProviderUpToDateHash; private boolean mySavingDisabled = false; - private final Map myStorageComponentStates = new TreeMap(); + private final Map myStorageComponentStates = new THashMap(); // at loading we store Element, on setState Integer of hash// at loading we store Element, on setState Integer of hash private final ComponentVersionProvider myLocalVersionProvider; private final ComponentVersionProvider myRemoteVersionProvider; @@ -126,8 +128,6 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { final StorageData storageData = getStorageData(false); final Element state = storageData.getState(componentName); - - if (state != null) { if (!myStorageComponentStates.containsKey(componentName)) { myStorageComponentStates.put(componentName, state); @@ -309,19 +309,20 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { if (element.getAttributes().isEmpty() && element.getChildren().isEmpty()) return; myStorageData.setState(componentName, element); + int hash = JDOMUtil.getTreeHash(element); - Element oldElement = myStorageComponentStates.get(componentName); try { - if (oldElement != null && !JDOMUtil.areElementsEqual(oldElement, element)) { + Object oldElementState = myStorageComponentStates.get(componentName); + + if (oldElementState instanceof Element && !JDOMUtil.areElementsEqual((Element)oldElementState, element) || + oldElementState instanceof Integer && hash != (Integer)oldElementState + ) { myListener.componentStateChanged(componentName); } } finally { - myStorageComponentStates.put(componentName, (Element)element.clone()); + myStorageComponentStates.put(componentName, hash); } - - - } } @@ -396,10 +397,6 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { protected abstract void doSave() throws StateStorageException; - public void clearHash() { - myUpToDateHash = null; - } - protected Integer calcHash() { return null; } @@ -469,10 +466,6 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { return myUpToDateHash != null && myUpToDateHash.equals(hash); } - public boolean isHashUpToDate() { - return isHashUpToDate(calcHash()); - } - protected Document getDocumentToSave() { if (myDocumentToSave != null) return myDocumentToSave; @@ -520,8 +513,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { } private Map loadVersions(Document copy) { - - HashMap result = new HashMap(); + THashMap result = new THashMap(); List list = copy.getRootElement().getChildren(COMPONENT); for (Object o : list) { @@ -550,13 +542,13 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { private Integer myHash; public StorageData(final String rootElementName) { - myComponentStates = new TreeMap(); + myComponentStates = new THashMap(); myRootElementName = rootElementName; } protected StorageData(StorageData storageData) { myRootElementName = storageData.myRootElementName; - myComponentStates = new TreeMap(storageData.myComponentStates); + myComponentStates = new THashMap(storageData.myComponentStates); } protected void load(@NotNull Element rootElement) throws IOException { @@ -603,8 +595,9 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { @NotNull protected Element save() { Element rootElement = new Element(myRootElementName); - - for (String componentName : myComponentStates.keySet()) { + String[] componentNames = ArrayUtil.toStringArray(myComponentStates.keySet()); + Arrays.sort(componentNames); + for (String componentName : componentNames) { assert componentName != null; final Element element = myComponentStates.get(componentName); @@ -617,7 +610,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { } @Nullable - public Element getState(final String name) { + private Element getState(final String name) { final Element e = myComponentStates.get(name); if (e != null) { @@ -628,7 +621,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { return e; } - public void removeState(final String componentName) { + private void removeState(final String componentName) { myComponentStates.remove(componentName); clearHash(); } @@ -799,7 +792,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { } private void loadProviderVersions() { - myProviderVersions = new TreeMap(); + myProviderVersions = new THashMap(); for (RoamingType type : RoamingType.values()) { Document doc = null; if (myStreamProvider.isEnabled()) { From b902b14fc4a59f6da828fd77e4d39ece282a8c35 Mon Sep 17 00:00:00 2001 From: Alexander Doroshko Date: Fri, 10 Feb 2012 19:33:01 +0400 Subject: [PATCH 42/59] better logging --- .../org/jetbrains/idea/maven/project/MavenProject.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java index 767438724e2a..6503756ea1c7 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java @@ -802,14 +802,17 @@ public class MavenProject { @NotNull public ModuleType getModuleType() { + MavenImporter mavenImporter = null; ModuleType typeFromImporter = null; + for (MavenImporter each : getSuitableImporters()) { final ModuleType moduleType = each.getModuleType(); if (typeFromImporter != null && !typeFromImporter.equals(moduleType)) { MavenLog.LOG.error("Incompatible plugins: " + each.getClass().getName() + " wants to create " + - moduleType.getName() + " for project " + getName() + " whereas some other importer requires " + - typeFromImporter.getName()); + moduleType.getName() + " for project " + getName() + + " whereas " + mavenImporter.getClass().getName() + " requires " + typeFromImporter.getName()); } + mavenImporter = each; typeFromImporter = moduleType; } return typeFromImporter != null ? typeFromImporter : StdModuleTypes.JAVA; From cb907f41286dec974dba53d8c77187f684bb2adf Mon Sep 17 00:00:00 2001 From: anna Date: Fri, 10 Feb 2012 16:09:18 +0100 Subject: [PATCH 43/59] visibility inspection: do not suggest private for constants used in class modifier lists and for inner classes used in extends/implements (IDEA-81161) --- .../visibility/VisibilityInspection.java | 21 ++++++++++++++++++ .../expected.xml | 22 +++++++++++++++++++ .../src/ThisClass.java | 9 ++++++++ .../VisibilityInspectionTest.java | 7 ++++++ 4 files changed, 59 insertions(+) create mode 100644 java/java-tests/testData/inspection/visibility/usedFromAnnotationsExtendsList/expected.xml create mode 100644 java/java-tests/testData/inspection/visibility/usedFromAnnotationsExtendsList/src/ThisClass.java diff --git a/java/java-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java b/java/java-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java index d8028dee779f..c1f79c9a9e33 100644 --- a/java/java-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java @@ -334,6 +334,9 @@ public class VisibilityInspection extends GlobalJavaInspectionTool { if (accessModifier == PsiModifier.PRIVATE) { if (SUGGEST_PRIVATE_FOR_INNERS) { + if (isInExtendsList(to, fromTopLevel.getElement().getExtendsList())) return false; + if (isInExtendsList(to, fromTopLevel.getElement().getImplementsList())) return false; + if (isInAnnotations(to, fromTopLevel)) return false; return fromTopLevel == toOwner || fromOwner == toTopLevel || toOwner != null && refUtil.getOwnerClass(toOwner) == from; } @@ -354,6 +357,24 @@ public class VisibilityInspection extends GlobalJavaInspectionTool { return false; } + private static boolean isInAnnotations(final RefJavaElement to, final RefClass fromTopLevel) { + final PsiModifierList modifierList = fromTopLevel.getElement().getModifierList(); + if (modifierList == null) return false; + final PsiElement toElement = to.getElement(); + + final boolean [] resolved = new boolean[] {false}; + modifierList.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + if (resolved[0]) return; + super.visitReferenceExpression(expression); + if (expression.resolve() == toElement) { + resolved[0] = true; + } + } + }); + return resolved[0]; + } private static boolean isInExtendsList(final RefJavaElement to, final PsiReferenceList extendsList) { if (extendsList != null) { diff --git a/java/java-tests/testData/inspection/visibility/usedFromAnnotationsExtendsList/expected.xml b/java/java-tests/testData/inspection/visibility/usedFromAnnotationsExtendsList/expected.xml new file mode 100644 index 000000000000..81532476144b --- /dev/null +++ b/java/java-tests/testData/inspection/visibility/usedFromAnnotationsExtendsList/expected.xml @@ -0,0 +1,22 @@ + + + + ThisClass.java + 5 + Declaration access can be weaker + + + + Can be package local + + + ThisClass.java + 4 + Declaration access can be weaker + + + + Can be package local + + + diff --git a/java/java-tests/testData/inspection/visibility/usedFromAnnotationsExtendsList/src/ThisClass.java b/java/java-tests/testData/inspection/visibility/usedFromAnnotationsExtendsList/src/ThisClass.java new file mode 100644 index 000000000000..67433f26feee --- /dev/null +++ b/java/java-tests/testData/inspection/visibility/usedFromAnnotationsExtendsList/src/ThisClass.java @@ -0,0 +1,9 @@ +import java.util.ArrayList; +@SuppressWarnings(ThisClass.PUBLICFINALNAME) +public class ThisClass extends ArrayList { + public static final String PUBLICFINALNAME = "stuff"; + public static class FF {} + + public static void main(String[] args) { + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/VisibilityInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/VisibilityInspectionTest.java index 4eb8bd32ef39..9cbb9ef2f697 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/VisibilityInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/VisibilityInspectionTest.java @@ -102,4 +102,11 @@ public class VisibilityInspectionTest extends InspectionTestCase { myTool.SUGGEST_PRIVATE_FOR_INNERS = false; doTest("visibility/typeArguments", myTool, false, true); } + + public void testUsedFromAnnotationsExtendsList() throws Exception { + myTool.SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS = true; + myTool.SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES = true; + myTool.SUGGEST_PRIVATE_FOR_INNERS = true; + doTest("visibility/usedFromAnnotationsExtendsList", myTool, false, true); + } } From ba961d59adbd9e907be46397e004c444307ada18 Mon Sep 17 00:00:00 2001 From: anna Date: Fri, 10 Feb 2012 16:47:41 +0100 Subject: [PATCH 44/59] highlight error: access to a private field from a class annotation is not possible --- .../analysis/AnnotationsHighlightUtil.java | 33 +++++++++++++++++++ .../impl/analysis/HighlightVisitorImpl.java | 1 + ...ightInaccessibleFromClassModifierList.java | 4 +++ .../daemon/LightAdvHighlightingJdk7Test.java | 4 +++ 4 files changed, 42 insertions(+) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/HighlightInaccessibleFromClassModifierList.java diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java index 8f9282affd6f..017ec0dea27d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java @@ -28,6 +28,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.psi.*; import com.intellij.psi.impl.source.tree.java.PsiAnnotationImpl; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.IncorrectOperationException; @@ -247,6 +248,38 @@ public class AnnotationsHighlightUtil { return highlightInfo; } + public static HighlightInfo checkForeignInnerClassesUsed(final PsiAnnotation annotation) { + final HighlightInfo[] infos = new HighlightInfo[1]; + final PsiAnnotationOwner owner = annotation.getOwner(); + if (owner instanceof PsiModifierList) { + final PsiElement parent = ((PsiModifierList)owner).getParent(); + if (parent instanceof PsiClass) { + annotation.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitElement(PsiElement element) { + if (infos[0] != null) return; + super.visitElement(element); + } + + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + final PsiElement resolve = expression.resolve(); + if (resolve instanceof PsiField && + ((PsiMember)resolve).hasModifierProperty(PsiModifier.PRIVATE) && + PsiTreeUtil.isAncestor(parent, resolve, true)) { + String description = JavaErrorMessages.message("private.symbol", + HighlightUtil.formatField((PsiField)resolve), + HighlightUtil.formatClass((PsiClass)parent)); + infos[0] = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, description); + } + } + }); + } + } + return infos[0]; + } + private static PsiField[] getFields(final PsiClass elementTypeClass, @NonNls final String... names) { PsiField[] result = new PsiField[names.length]; for (int i = 0; i < names.length; i++) { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index 8703ff06fd77..1c6f41d71759 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -184,6 +184,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkMissingAttributes(annotation)); if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkTargetAnnotationDuplicates(annotation)); if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkDuplicateAnnotations(annotation)); + if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkForeignInnerClassesUsed(annotation)); } @Override public void visitAnnotationArrayInitializer(PsiArrayInitializerMemberValue initializer) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/HighlightInaccessibleFromClassModifierList.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/HighlightInaccessibleFromClassModifierList.java new file mode 100644 index 000000000000..e02db8fb902f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/HighlightInaccessibleFromClassModifierList.java @@ -0,0 +1,4 @@ +@SuppressWarnings(ThisClass.FOO) +public class ThisClass { + private static final String FOO = "foo"; +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java index 7e2951ec1186..55a041c9e77c 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java @@ -176,6 +176,10 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase { doTest(false, false); } + public void testHighlightInaccessibleFromClassModifierList() throws Exception { + doTest(false, false); + } + public void testDynamicallyAddIgnoredAnnotations() throws Exception { ExtensionPoint point = Extensions.getRootArea().getExtensionPoint(ExtensionPoints.DEAD_CODE_TOOL); EntryPoint extension = new EntryPoint() { From 0a1488ecf08694ab426defad9d6ae41f6073d2c5 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Fri, 10 Feb 2012 16:46:59 +0100 Subject: [PATCH 45/59] don't go deeper than it's needed when searching --- .../fileStructure/filtering/SelectLeafFirst.java | 13 +++++++++++++ .../fileStructure/filtering/SelectLeafFirst.tree | 5 +++++ .../fileStructure/filtering/SelectLeafFirst2.java | 13 +++++++++++++ .../fileStructure/filtering/SelectLeafFirst2.tree | 5 +++++ .../JavaFileStructureFilteringTest.java | 2 ++ .../com/intellij/ide/util/FileStructurePopup.java | 5 +++++ 6 files changed, 43 insertions(+) create mode 100644 java/java-tests/testData/fileStructure/filtering/SelectLeafFirst.java create mode 100644 java/java-tests/testData/fileStructure/filtering/SelectLeafFirst.tree create mode 100644 java/java-tests/testData/fileStructure/filtering/SelectLeafFirst2.java create mode 100644 java/java-tests/testData/fileStructure/filtering/SelectLeafFirst2.tree diff --git a/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst.java b/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst.java new file mode 100644 index 000000000000..45eda4e21e07 --- /dev/null +++ b/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst.java @@ -0,0 +1,13 @@ +class SelectLeafFirst { + void aaa(){} + + void bbb(){} + void clear(){} + void zzz(){} + class ClearClass { + void kkk(){} + void www(){} + void clear(){} + void yyy(){} + } +} \ No newline at end of file diff --git a/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst.tree b/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst.tree new file mode 100644 index 000000000000..69af4146c71c --- /dev/null +++ b/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst.tree @@ -0,0 +1,5 @@ +-SelectLeafFirst.java + -SelectLeafFirst + [clear():void] + -ClearClass + clear():void \ No newline at end of file diff --git a/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst2.java b/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst2.java new file mode 100644 index 000000000000..06d505284632 --- /dev/null +++ b/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst2.java @@ -0,0 +1,13 @@ +class SelectLeafFirst2 { + void aaa(){} + void bbb(){} + void clear(){} + void zzz(){} + class ClearClass { + void kkk(){} + + void www(){} + void clear(){} + void yyy(){} + } +} \ No newline at end of file diff --git a/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst2.tree b/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst2.tree new file mode 100644 index 000000000000..cb8224d167d5 --- /dev/null +++ b/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst2.tree @@ -0,0 +1,5 @@ +-SelectLeafFirst2.java + -SelectLeafFirst2 + clear():void + -ClearClass + [clear():void] \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/ide/fileStructure/JavaFileStructureFilteringTest.java b/java/java-tests/testSrc/com/intellij/ide/fileStructure/JavaFileStructureFilteringTest.java index 848828f915b6..7875a69ed5b1 100644 --- a/java/java-tests/testSrc/com/intellij/ide/fileStructure/JavaFileStructureFilteringTest.java +++ b/java/java-tests/testSrc/com/intellij/ide/fileStructure/JavaFileStructureFilteringTest.java @@ -29,5 +29,7 @@ public class JavaFileStructureFilteringTest extends JavaFileStructureTestCase { public void testAnonymousType()throws Exception{checkTree("point");} public void testCamel()throws Exception{checkTree("sohe");} public void testCamel2()throws Exception{checkTree("soHe");} + public void testSelectLeafFirst()throws Exception{checkTree("clear");} + public void testSelectLeafFirst2()throws Exception{checkTree("clear");} } diff --git a/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java b/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java index 1d6b184ad403..e3658fde5afa 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java +++ b/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java @@ -818,11 +818,16 @@ public class FileStructurePopup implements Disposable { final Object object = ((DefaultMutableTreeNode)last).getUserObject(); if (object instanceof FilteringTreeStructure.FilteringNode) { FilteringTreeStructure.FilteringNode node = (FilteringTreeStructure.FilteringNode)object; + FilteringTreeStructure.FilteringNode candidate = node; + while (node != null) { elements.add(getPsi(node)); node = node.getParentNode(); } final int size = ContainerUtil.intersection(parents, elements).size(); + if (size == elements.size() - 1 && size == parents.size() && candidate.children().isEmpty()) { + return p.node; + } if (size > max) { max = size; cur.clear(); From db59b7c021039830fe9137f955a275fa932e8c4f Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 10 Feb 2012 17:31:45 +0100 Subject: [PATCH 46/59] allow specifying fixed file name via AttributesDefaults --- .../ide/fileTemplates/actions/AttributesDefaults.java | 10 ++++++++++ .../actions/CreateFromTemplateActionBase.java | 1 + .../ide/fileTemplates/ui/CreateFromTemplateDialog.java | 7 ++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/AttributesDefaults.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/AttributesDefaults.java index 38f85cb9e1bb..3a53701e0500 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/AttributesDefaults.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/AttributesDefaults.java @@ -32,6 +32,7 @@ public class AttributesDefaults { private final String myDefaultName; private final TextRange myDefaultRange; private final Map> myNamesToValueAndRangeMap = new HashMap>(); + private boolean myFixedName; public AttributesDefaults(@NonNls @Nullable final String defaultName, @Nullable final TextRange defaultRange) { @@ -78,4 +79,13 @@ public class AttributesDefaults { final Pair valueAndRange = myNamesToValueAndRangeMap.get(attributeKey); return valueAndRange == null ? null : valueAndRange.first; } + + public boolean isFixedName() { + return myFixedName; + } + + public AttributesDefaults withFixedName(boolean fixedName) { + myFixedName = fixedName; + return this; + } } diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateActionBase.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateActionBase.java index 93f0f2940212..4e71423b46ca 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateActionBase.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateActionBase.java @@ -63,6 +63,7 @@ public abstract class CreateFromTemplateActionBase extends AnAction { } } + @Nullable protected PsiDirectory getTargetDirectory(DataContext dataContext, IdeView view) { return DirectoryChooserUtil.getOrChooseDirectory(view); } diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java index 4a22227d958a..a3506db2ffbd 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java @@ -65,6 +65,11 @@ public class CreateFromTemplateDialog extends DialogWrapper { myDefaultProperties = defaultProperties == null ? FileTemplateManager.getInstance().getDefaultProperties() : defaultProperties; FileTemplateUtil.fillDefaultProperties(myDefaultProperties, directory); + boolean mustEnterName = !myTemplate.isTemplateOfType(StdFileTypes.JAVA); + if (attributesDefaults != null && attributesDefaults.isFixedName()) { + myDefaultProperties.setProperty(FileTemplate.ATTRIBUTE_NAME, attributesDefaults.getDefaultFileName()); + mustEnterName = false; + } String[] unsetAttributes = null; try { @@ -75,7 +80,7 @@ public class CreateFromTemplateDialog extends DialogWrapper { } if (unsetAttributes != null) { - myAttrPanel = new CreateFromTemplatePanel(unsetAttributes, !myTemplate.isTemplateOfType(StdFileTypes.JAVA), attributesDefaults); + myAttrPanel = new CreateFromTemplatePanel(unsetAttributes, mustEnterName, attributesDefaults); myAttrComponent = myAttrPanel.getComponent(); init(); } From 9beb9183826e6f482e7223a4dd3e2f9e9e1d7cfe Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 10 Feb 2012 17:37:50 +0100 Subject: [PATCH 47/59] order of fields in create from template dialog is same as order of unset attributes in template --- .../src/com/intellij/ide/fileTemplates/FileTemplateUtil.java | 2 +- .../intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java index 3ed275e3a9f0..eab211ad86d0 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java @@ -118,7 +118,7 @@ public class FileTemplateUtil{ } public static String[] calculateAttributes(String templateContent, Properties properties, boolean includeDummies) throws ParseException { - final Set unsetAttributes = new HashSet(); + final Set unsetAttributes = new LinkedHashSet(); final Set definedAttributes = new HashSet(); //noinspection HardCodedStringLiteral SimpleNode template = RuntimeSingleton.parse(new StringReader(templateContent), "MyTemplate"); diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java index b42b97ab74f2..bfac28500a54 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java @@ -57,7 +57,6 @@ public class CreateFromTemplatePanel{ myMustEnterName = mustEnterName; myUnsetAttributes = unsetAttributes; myAttributesDefaults = attributesDefaults; - Arrays.sort(myUnsetAttributes); } public boolean hasSomethingToAsk() { From bc41299b51b6a5e615f6da29b93df4187974aefc Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 10 Feb 2012 17:51:00 +0100 Subject: [PATCH 48/59] cleanup --- .../ui/CreateFromTemplateDialog.java | 2 +- .../ui/CreateFromTemplatePanel.java | 25 ++++++++----------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java index a3506db2ffbd..1bc050415a9a 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java @@ -115,7 +115,7 @@ public class CreateFromTemplateDialog extends DialogWrapper { } } - private void doCreate(final String fileName) { + private void doCreate(@Nullable final String fileName) { try { myCreatedElement = FileTemplateUtil.createFromTemplate(myTemplate, fileName, myAttrPanel.getProperties(myDefaultProperties), myDirectory); diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java index bfac28500a54..71068baeab5c 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java @@ -19,8 +19,7 @@ package com.intellij.ide.fileTemplates.ui; import com.intellij.ide.IdeBundle; import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.ide.fileTemplates.actions.AttributesDefaults; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.ui.impl.DialogWrapperPeerImpl; +import com.intellij.openapi.ui.DialogWrapperPeer; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.ui.ScrollPaneFactory; @@ -37,8 +36,6 @@ import java.util.Properties; */ public class CreateFromTemplatePanel{ - private static final Logger LOG = Logger.getInstance("#com.intellij.ide.fileTemplates.ui.CreateFromTemplatePanel"); - private JPanel myMainPanel; private JPanel myAttrPanel; private JTextField myFilenameField; @@ -47,7 +44,7 @@ public class CreateFromTemplatePanel{ private int myLastRow = 0; - private int myHorisontalMargin = -1; + private int myHorizontalMargin = -1; private int myVerticalMargin = -1; private final boolean myMustEnterName; private final AttributesDefaults myAttributesDefaults; @@ -94,16 +91,16 @@ public class CreateFromTemplatePanel{ return myMainPanel; } - public void ensureFitToScreen(int horisontalMargin, int verticalMargin){ - myHorisontalMargin = horisontalMargin; + public void ensureFitToScreen(int horizontalMargin, int verticalMargin){ + myHorizontalMargin = horizontalMargin; myVerticalMargin = verticalMargin; } private Dimension getMainPanelPreferredSize(Dimension superPreferredSize){ - if((myHorisontalMargin > 0) && (myVerticalMargin > 0)){ + if((myHorizontalMargin > 0) && (myVerticalMargin > 0)){ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Dimension preferredSize = superPreferredSize; - Dimension maxSize = new Dimension(screenSize.width - myHorisontalMargin, screenSize.height - myVerticalMargin); + Dimension maxSize = new Dimension(screenSize.width - myHorizontalMargin, screenSize.height - myVerticalMargin); int width = Math.min(preferredSize.width, maxSize.width); int height = Math.min(preferredSize.height, maxSize.height); if(height < preferredSize.height){ @@ -133,7 +130,7 @@ public class CreateFromTemplatePanel{ // set predefined file name value myFilenameField.setText(fileName); final TextRange selectionRange; - // select range from default attrubutes or select file name without extension + // select range from default attributes or select file name without extension if (myAttributesDefaults.getDefaultFileNameSelection() != null) { selectionRange = myAttributesDefaults.getDefaultFileNameSelection(); } else { @@ -193,17 +190,17 @@ public class CreateFromTemplatePanel{ } } - public Properties getProperties(Properties predefinedProperties){ + public Properties getProperties(Properties predefinedProperties) { Properties result = (Properties) predefinedProperties.clone(); for (Pair pair : myAttributes) { - result.put(pair.first, pair.second.getText()); + result.setProperty(pair.first, pair.second.getText()); } return result; } - private void setPredefinedSelectionFor(final JTextField field, final TextRange selectionRange) { + private static void setPredefinedSelectionFor(final JTextField field, final TextRange selectionRange) { field.select(selectionRange.getStartOffset(), selectionRange.getEndOffset()); - field.putClientProperty(DialogWrapperPeerImpl.HAVE_INITIAL_SELECTION, true); + field.putClientProperty(DialogWrapperPeer.HAVE_INITIAL_SELECTION, true); } } From ef2af40b07fcc35ec7578087fdeb4ef1795d22ea Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 10 Feb 2012 17:53:55 +0100 Subject: [PATCH 49/59] more deadlock avoidance (IDEA-81206) --- .../connect/StatisticsHttpClientSender.java | 3 +- .../impl/CheckForUpdateAction.java | 5 ++- .../updateSettings/impl/UpdateChecker.java | 36 +++++++++---------- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/connect/StatisticsHttpClientSender.java b/platform/platform-impl/src/com/intellij/internal/statistic/connect/StatisticsHttpClientSender.java index 535b8ad9b53c..c3f3fb4d615d 100644 --- a/platform/platform-impl/src/com/intellij/internal/statistic/connect/StatisticsHttpClientSender.java +++ b/platform/platform-impl/src/com/intellij/internal/statistic/connect/StatisticsHttpClientSender.java @@ -15,6 +15,7 @@ */ package com.intellij.internal.statistic.connect; +import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.application.ApplicationNamesInfo; import com.intellij.openapi.updateSettings.impl.UpdateChecker; import com.intellij.openapi.util.text.StringUtil; @@ -39,7 +40,7 @@ public class StatisticsHttpClientSender implements StatisticsDataSender { post.setRequestBody(new NameValuePair[]{ new NameValuePair("content", content), - new NameValuePair("uuid", UpdateChecker.getInstallationUID()), + new NameValuePair("uuid", UpdateChecker.getInstallationUID(PropertiesComponent.getInstance())), new NameValuePair("ide", ApplicationNamesInfo.getInstance().getProductName()), }); diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/CheckForUpdateAction.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/CheckForUpdateAction.java index 006173d6e2d0..f9cd94fea2d6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/CheckForUpdateAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/CheckForUpdateAction.java @@ -16,6 +16,7 @@ package com.intellij.openapi.updateSettings.impl; import com.intellij.ide.plugins.PluginHostsConfigurable; +import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.PlatformDataKeys; @@ -46,7 +47,9 @@ public class CheckForUpdateAction extends AnAction implements DumbAware { ProgressManager.getInstance().run(new Task.Modal(project, "Checking for updates", false) { @Override public void run(@NotNull ProgressIndicator indicator) { - final CheckForUpdateResult result = UpdateChecker.checkForUpdates(true); + final CheckForUpdateResult result = UpdateChecker.checkForUpdates(UpdateSettings.getInstance(), PropertiesComponent.getInstance(), + true + ); final List updatedPlugins = UpdateChecker.updatePlugins(true, hostsConfigurable); ApplicationManager.getApplication().invokeLater(new Runnable() { diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java index dd6d07f04f75..ebf23d0ca097 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java @@ -148,10 +148,12 @@ public final class UpdateChecker { public static ActionCallback updateAndShowResult() { final ActionCallback result = new ActionCallback(); final Application app = ApplicationManager.getApplication(); + final PropertiesComponent propertiesComponent = PropertiesComponent.getInstance(); + final UpdateSettings updateSettings = UpdateSettings.getInstance(); app.executeOnPooledThread(new Runnable() { @Override public void run() { - final CheckForUpdateResult checkForUpdateResult = checkForUpdates(); + final CheckForUpdateResult checkForUpdateResult = checkForUpdates(updateSettings, propertiesComponent, false); final List updatedPlugins = updatePlugins(false, null); app.invokeLater(new Runnable() { @@ -344,11 +346,11 @@ public final class UpdateChecker { } @NotNull - public static CheckForUpdateResult doCheckForUpdates(final UpdateSettings settings) { + public static CheckForUpdateResult doCheckForUpdates(final UpdateSettings settings, final PropertiesComponent instance) { ApplicationInfo appInfo = ApplicationInfo.getInstance(); BuildNumber currentBuild = appInfo.getBuild(); int majorVersion = Integer.parseInt(appInfo.getMajorVersion()); - final UpdatesXmlLoader loader = new UpdatesXmlLoader(getUpdateUrl(), getInstallationUID(), null); + final UpdatesXmlLoader loader = new UpdatesXmlLoader(getUpdateUrl(), getInstallationUID(instance), null); final UpdatesInfo info; try { info = loader.loadUpdatesInfo(); @@ -364,25 +366,21 @@ public final class UpdateChecker { return strategy.checkForUpdates(); } - @NotNull - public static CheckForUpdateResult checkForUpdates() { - return checkForUpdates(false); - } - - @NotNull - public static CheckForUpdateResult checkForUpdates(final boolean disregardIgnoredBuilds) { + public static CheckForUpdateResult checkForUpdates(final UpdateSettings updateSettings, + final PropertiesComponent propertiesComponent, + final boolean disregardIgnoredBuilds) { if (LOG.isDebugEnabled()) { LOG.debug("enter: auto checkForUpdates()"); } - UserUpdateSettings settings = UpdateSettings.getInstance(); + UserUpdateSettings settings = updateSettings; if (disregardIgnoredBuilds) { settings = new UserUpdateSettings() { @NotNull @Override public List getKnownChannelsIds() { - return UpdateSettings.getInstance().getKnownChannelsIds(); + return updateSettings.getKnownChannelsIds(); } @Override @@ -392,21 +390,21 @@ public final class UpdateChecker { @Override public void setKnownChannelIds(List ids) { - UpdateSettings.getInstance().setKnownChannelIds(ids); + updateSettings.setKnownChannelIds(ids); } @NotNull @Override public ChannelStatus getSelectedChannelStatus() { - return UpdateSettings.getInstance().getSelectedChannelStatus(); + return updateSettings.getSelectedChannelStatus(); } }; } - final CheckForUpdateResult result = doCheckForUpdates(UpdateSettings.getInstance()); + final CheckForUpdateResult result = doCheckForUpdates(updateSettings, propertiesComponent); if (result.getState() == UpdateStrategy.State.LOADED) { - UpdateSettings.getInstance().LAST_TIME_CHECKED = System.currentTimeMillis(); + updateSettings.LAST_TIME_CHECKED = System.currentTimeMillis(); settings.setKnownChannelIds(result.getAllChannelsIds()); } @@ -442,12 +440,13 @@ public final class UpdateChecker { } final InputStream[] inputStreams = new InputStream[]{null}; final Exception[] exception = new Exception[]{null}; + final PropertiesComponent propertiesComponent = PropertiesComponent.getInstance(); Future downloadThreadFuture = ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { public void run() { try { HttpConfigurable.getInstance().prepareURL(url); - String uid = getInstallationUID(); + String uid = getInstallationUID(propertiesComponent); final URL requestUrl = new URL(url + "?build=" + ApplicationInfo.getInstance().getBuild().asString() + "&uid=" + uid + ADDITIONAL_REQUEST_OPTIONS); @@ -475,8 +474,7 @@ public final class UpdateChecker { return inputStreams[0]; } - public static String getInstallationUID() { - final PropertiesComponent propertiesComponent = PropertiesComponent.getInstance(); + public static String getInstallationUID(final PropertiesComponent propertiesComponent) { String uid = ""; if (!propertiesComponent.isValueSet(INSTALLATION_UID)) { try { From 4dc22f8c877fe0cb144fa1291802e253d5dffff7 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Fri, 10 Feb 2012 14:08:33 +0100 Subject: [PATCH 50/59] progress cleanup --- .../jps/incremental/java/JavaBuilder.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java index ac1d7e09b598..acbd1140f795 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java @@ -257,7 +257,7 @@ public class JavaBuilder extends ModuleLevelBuilder { if (hasSourcesToCompile) { final Set sourcePath = TEMPORARY_SOURCE_ROOTS_KEY.get(context, Collections.emptySet()); - final String chunkName = chunk.getName(); + final String chunkName = getChunkPresentableName(chunk); context.processMessage(new ProgressMessage("Compiling java [" + chunkName + "]")); final boolean compiledOk = compileJava(chunk, files, classpath, platformCp, sourcePath, outs, context, diagnosticSink, outputSink); @@ -316,6 +316,24 @@ public class JavaBuilder extends ModuleLevelBuilder { return exitCode; } + private static String getChunkPresentableName(ModuleChunk chunk) { + final Set modules = chunk.getModules(); + if (modules.isEmpty()) { + return ""; + } + if (modules.size() == 1) { + return modules.iterator().next().getName(); + } + final StringBuilder buf = new StringBuilder(); + for (Module module : modules) { + if (buf.length() > 0) { + buf.append(","); + } + buf.append(module.getName()); + } + return buf.toString(); + } + private boolean compileJava(ModuleChunk chunk, Collection files, Collection classpath, Collection platformCp, From 2c7fecececb38540493d99578ce6579f1803f64a Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Fri, 10 Feb 2012 17:47:38 +0100 Subject: [PATCH 51/59] javac canceling (embedded and external) checkCanceled convenience method in context waitFor() API for RequestFuture --- .../compiler/CompileServerManager.java | 10 +-- .../intellij/compiler/impl/CompileDriver.java | 36 ++-------- .../org/jetbrains/jps/api/RequestFuture.java | 29 ++++++-- .../jps/incremental/CompileContext.java | 13 +++- .../jps/incremental/IncProjectBuilder.java | 21 ++---- .../jps/incremental/java/JavaBuilder.java | 23 ++++--- .../jetbrains/jps/javac/JavacFileManager.java | 28 ++++++++ .../org/jetbrains/jps/javac/JavacMain.java | 15 +++-- .../org/jetbrains/jps/javac/JavacServer.java | 66 +++++++++++++++---- 9 files changed, 153 insertions(+), 88 deletions(-) diff --git a/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java b/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java index ffbcdd9586d9..649db10233dd 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java @@ -284,13 +284,7 @@ public class CompileServerManager implements ApplicationComponent{ } try { for (RequestFuture future : futures) { - try { - future.get(); - } - catch (InterruptedException ignored) { - } - catch (java.util.concurrent.ExecutionException ignored) { - } + future.waitFor(); } } finally { @@ -447,7 +441,7 @@ public class CompileServerManager implements ApplicationComponent{ connected = client.connect(NetUtils.getLocalHostString(), port); if (connected) { final RequestFuture setupFuture = sendSetupRequest(client); - setupFuture.get(); + setupFuture.waitFor(); myProcessHandler = processHandler; myClient = client; } diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java index 857d42b0632b..0b1bf1f4605c 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java @@ -99,7 +99,7 @@ import org.jetbrains.jps.api.RequestFuture; import java.io.*; import java.util.*; -import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; public class CompileDriver { @@ -591,15 +591,10 @@ public class CompileDriver { final Set artifacts = ArtifactCompileScope.getArtifactsToBuild(myProject, compileContext.getCompileScope(), true); final RequestFuture future = compileOnServer(compileContext, modules, artifacts, paths, callback); if (future != null) { - try { - startCancelWatcher(indicator, future); - future.get(); - } - catch (InterruptedException e) { - LOG.error(e); // todo - } - catch (ExecutionException e) { - LOG.error(e); // todo + while (!future.waitFor(200L , TimeUnit.MILLISECONDS)) { + if (indicator.isCanceled()) { + future.cancel(true); + } } } else { @@ -686,27 +681,6 @@ public class CompileDriver { }); } - private static void startCancelWatcher(final ProgressIndicator indicator, final RequestFuture future) { - ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { - public void run() { - while (true) { - try { - Thread.sleep(200L); - if (future.isDone() || future.isCancelled()) { - break; - } - if (indicator.isCanceled()) { - future.cancel(true); - break; - } - } - catch (InterruptedException ignored) { - } - } - } - }); - } - private static List fetchFiles(CompileContextImpl context) { if (context.isRebuild()) { return Collections.emptyList(); diff --git a/jps/jps-builders/src/org/jetbrains/jps/api/RequestFuture.java b/jps/jps-builders/src/org/jetbrains/jps/api/RequestFuture.java index 7ff90b9cdc7a..7366541b20cd 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/api/RequestFuture.java +++ b/jps/jps-builders/src/org/jetbrains/jps/api/RequestFuture.java @@ -79,17 +79,34 @@ public class RequestFuture implements Future { return myDone.get(); } - public Object get() throws InterruptedException, ExecutionException { - while (!isDone()) { - mySemaphore.tryAcquire(100L, TimeUnit.MILLISECONDS); + public void waitFor() { + try { + while (!isDone()) { + mySemaphore.tryAcquire(100L, TimeUnit.MILLISECONDS); + } } + catch (InterruptedException ignored) { + } + } + + public boolean waitFor(long timeout, TimeUnit unit) { + try { + if (!isDone()) { + mySemaphore.tryAcquire(timeout, unit); + } + } + catch (InterruptedException ignored) { + } + return isDone(); + } + + public Object get() throws InterruptedException, ExecutionException { + waitFor(); return null; } public Object get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { - if (!isDone()) { - mySemaphore.tryAcquire(timeout, unit); - } + waitFor(timeout, unit); return null; } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java index f4d3ba5dcce7..90bd4e549c4e 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java @@ -23,6 +23,7 @@ import java.util.*; * Date: 9/17/11 */ public class CompileContext extends UserDataHolderBase implements MessageHandler{ + private static final String CANCELED_MESSAGE = "The build has been canceled"; private final CompileScope myScope; private final boolean myIsMake; private final boolean myIsProjectRebuild; @@ -155,10 +156,20 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler return myCompilingTests; } - public CanceledStatus getCancelStatus() { + public final CanceledStatus getCancelStatus() { return myCancelStatus; } + public final boolean isCanceled() { + return getCancelStatus().isCanceled(); + } + + public final void checkCanceled() throws ProjectBuildException { + if (isCanceled()) { + throw new ProjectBuildException(CANCELED_MESSAGE); + } + } + void setCompilingTests(boolean compilingTests) { myCompilingTests = compilingTests; } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java index 7d65af0c3949..5270a2c7c27a 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java @@ -24,7 +24,7 @@ import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.util.*; -import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; /** * @author Eugene Zhuravlev @@ -34,7 +34,6 @@ public class IncProjectBuilder { private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.incremental.IncProjectBuilder"); public static final String COMPILE_SERVER_NAME = "COMPILE SERVER"; - private static final String CANCELED_MESSAGE = "The build has been canceled"; private final ProjectDescriptor myProjectDescriptor; private final BuilderRegistry myBuilderRegistry; @@ -119,11 +118,7 @@ public class IncProjectBuilder { if (descriptor != null) { try { final RequestFuture future = descriptor.client.sendShutdownRequest(); - future.get(); - } - catch (InterruptedException ignored) { - } - catch (ExecutionException ignored) { + future.waitFor(500L, TimeUnit.MILLISECONDS); } finally { // ensure process is not running @@ -229,9 +224,7 @@ public class IncProjectBuilder { // check that output and source roots are not overlapping final List filesToDelete = new ArrayList(); for (File outputRoot : rootsToDelete) { - if (myCancelStatus.isCanceled()) { - throw new ProjectBuildException(CANCELED_MESSAGE); - } + context.checkCanceled(); boolean okToDelete = true; if (PathUtil.isUnder(allSourceRoots, outputRoot)) { okToDelete = false; @@ -401,9 +394,7 @@ public class IncProjectBuilder { if (buildResult == ModuleLevelBuilder.ExitCode.ABORT) { throw new ProjectBuildException("Builder " + builder.getDescription() + " requested build stop"); } - if (myCancelStatus.isCanceled()) { - throw new ProjectBuildException(CANCELED_MESSAGE); - } + context.checkCanceled(); if (buildResult == ModuleLevelBuilder.ExitCode.ADDITIONAL_PASS_REQUIRED) { if (!nextPassRequired) { // recalculate basis @@ -447,9 +438,7 @@ public class IncProjectBuilder { private void runProjectLevelBuilders(CompileContext context) throws ProjectBuildException { for (ProjectLevelBuilder builder : myBuilderRegistry.getProjectLevelBuilders()) { builder.build(context); - if (myCancelStatus.isCanceled()) { - throw new ProjectBuildException(CANCELED_MESSAGE); - } + context.checkCanceled(); } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java index acbd1140f795..bfde575cf4d9 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java @@ -42,8 +42,8 @@ import java.net.ServerSocket; import java.net.URL; import java.net.URLClassLoader; import java.util.*; -import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; /** * @author Eugene Zhuravlev @@ -263,8 +263,13 @@ public class JavaBuilder extends ModuleLevelBuilder { final boolean compiledOk = compileJava(chunk, files, classpath, platformCp, sourcePath, outs, context, diagnosticSink, outputSink); final Map chunkSourcePath = ProjectPaths.getSourceRootsWithDependents(chunk, context.isCompilingTests()); + + context.checkCanceled(); + final ClassLoader compiledClassesLoader = createInstrumentationClassLoader(classpath, platformCp, chunkSourcePath, outputSink); + context.checkCanceled(); + if (!forms.isEmpty()) { try { context.processMessage(new ProgressMessage("Instrumenting forms [" + chunkName + "]")); @@ -275,6 +280,8 @@ public class JavaBuilder extends ModuleLevelBuilder { } } + context.checkCanceled(); + if (addNotNullAssertions) { try { context.processMessage(new ProgressMessage("Adding NotNull assertions [" + chunkName + "]")); @@ -285,6 +292,8 @@ public class JavaBuilder extends ModuleLevelBuilder { } } + context.checkCanceled(); + if (!compiledOk && diagnosticSink.getErrorCount() == 0) { diagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, "Compilation failed: internal java compiler error")); } @@ -356,14 +365,10 @@ public class JavaBuilder extends ModuleLevelBuilder { final RequestFuture future = client.sendCompileRequest( options, files, classpath, platformCp, sourcePath, outs, diagnosticSink, classesConsumer ); - try { - future.get(); - } - catch (InterruptedException e) { - e.printStackTrace(System.err); - } - catch (ExecutionException e) { - e.printStackTrace(System.err); + while (!future.waitFor(100L, TimeUnit.MILLISECONDS)) { + if (context.isCanceled()) { + future.cancel(true); + } } rc = future.getResponseHandler().isTerminatedSuccessfully(); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacFileManager.java b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacFileManager.java index a7aac0fce6dc..73e238f9bdd7 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacFileManager.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacFileManager.java @@ -66,6 +66,18 @@ class JavacFileManager extends ForwardingJavaFileManager sourcePath, Map> outputDirToRoots, final DiagnosticOutputConsumer outConsumer, - final OutputFileConsumer outputSink, @Nullable CanceledStatus canceledStatus) { + final OutputFileConsumer outputSink, + CanceledStatus canceledStatus) { final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); for (File outputDir : outputDirToRoots.keySet()) { outputDir.mkdirs(); } - final JavacFileManager fileManager = new JavacFileManager(new ContextImpl(compiler, outConsumer, outputSink)); + final JavacFileManager fileManager = new JavacFileManager(new ContextImpl(compiler, outConsumer, outputSink, canceledStatus)); fileManager.handleOption("-bootclasspath", Collections.singleton("").iterator()); // this will clear cached stuff fileManager.handleOption("-extdirs", Collections.singleton("").iterator()); // this will clear cached stuff @@ -111,10 +111,15 @@ public class JavacMain { private final StandardJavaFileManager myStdManager; private final DiagnosticOutputConsumer myOutConsumer; private final OutputFileConsumer myOutputFileSink; + private final CanceledStatus myCanceledStatus; - public ContextImpl(@NotNull JavaCompiler compiler, @NotNull DiagnosticOutputConsumer outConsumer, @NotNull OutputFileConsumer sink) { + public ContextImpl(@NotNull JavaCompiler compiler, + @NotNull DiagnosticOutputConsumer outConsumer, + @NotNull OutputFileConsumer sink, + CanceledStatus canceledStatus) { myOutConsumer = outConsumer; myOutputFileSink = sink; + myCanceledStatus = canceledStatus; StandardJavaFileManager stdManager = null; final Class optimizedManagerClass = ClasspathBootstrap.getOptimizedFileManagerClass(); if (optimizedManagerClass != null) { @@ -136,7 +141,7 @@ public class JavacMain { } public boolean isCanceled() { - return false; // todo + return myCanceledStatus.isCanceled(); } public StandardJavaFileManager getStandardFileManager() { diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java index 2b75d6dc7673..537cdf6a64e8 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java @@ -11,9 +11,9 @@ import org.jboss.netty.handler.codec.protobuf.ProtobufEncoder; import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.api.CanceledStatus; -import javax.tools.Diagnostic; -import javax.tools.JavaFileObject; +import javax.tools.*; import java.io.File; import java.net.InetSocketAddress; import java.util.*; @@ -32,10 +32,11 @@ public class JavacServer { private final ChannelGroup myAllOpenChannels = new DefaultChannelGroup("javac-server"); private final ChannelFactory myChannelFactory; private final ChannelPipelineFactory myPipelineFactory; + private ExecutorService myThreadPool; public JavacServer() { - final ExecutorService threadPool = Executors.newCachedThreadPool(); - myChannelFactory = new NioServerSocketChannelFactory(threadPool, threadPool, 1); + myThreadPool = Executors.newCachedThreadPool(); + myChannelFactory = new NioServerSocketChannelFactory(myThreadPool, myThreadPool, 1); final ChannelRegistrar channelRegistrar = new ChannelRegistrar(); final ChannelHandler compilationRequestsHandler = new CompilationRequestsHandler(); myPipelineFactory = new ChannelPipelineFactory() { @@ -103,7 +104,15 @@ public class JavacServer { } - public static JavacRemoteProto.Message compile(final ChannelHandlerContext ctx, final UUID sessionId, List options, Collection files, Collection classpath, Collection platformCp, Collection sourcePath, Map> outs) { + public static JavacRemoteProto.Message compile(final ChannelHandlerContext ctx, + final UUID sessionId, + List options, + Collection files, + Collection classpath, + Collection platformCp, + Collection sourcePath, + Map> outs, + final CanceledStatus canceledStatus) { final DiagnosticOutputConsumer diagnostic = new DiagnosticOutputConsumer() { public void outputLineAvailable(String line) { Channels.write(ctx.getChannel(), JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createStdOutputResponse(line))); @@ -122,7 +131,7 @@ public class JavacServer { }; try { - final boolean rc = JavacMain.compile(options, files, classpath, platformCp, sourcePath, outs, diagnostic, outputSink, null/*todo*/); + final boolean rc = JavacMain.compile(options, files, classpath, platformCp, sourcePath, outs, diagnostic, outputSink, canceledStatus); return JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createBuildCompletedResponse(rc)); } catch (Throwable e) { @@ -131,8 +140,14 @@ public class JavacServer { } } - public static void cancelBuild() { - // todo + private final Set myCancelHandlers = Collections.synchronizedSet(new HashSet()); + + public void cancelBuilds() { + synchronized (myCancelHandlers) { + for (CancelHandler handler : myCancelHandlers) { + handler.cancel(); + } + } } private static List toFiles(List paths) { @@ -145,7 +160,7 @@ public class JavacServer { private class CompilationRequestsHandler extends SimpleChannelHandler { - public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { + public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) throws Exception { final JavacRemoteProto.Message msg = (JavacRemoteProto.Message)e.getMessage(); final UUID sessionId = JavacProtoUtil.fromProtoUUID(msg.getSessionId()); final JavacRemoteProto.Message.Type messageType = msg.getMessageType(); @@ -172,14 +187,26 @@ public class JavacServer { outs.put(new File(outputGroup.getOutputRoot()), srcRoots); } - reply = compile(ctx, sessionId, options, files, cp, platformCp, srcPath, outs); + final CancelHandler cancelHandler = new CancelHandler(); + myCancelHandlers.add(cancelHandler); + myThreadPool.submit(new Runnable() { + public void run() { + try { + final JavacRemoteProto.Message exitMsg = compile(ctx, sessionId, options, files, cp, platformCp, srcPath, outs, cancelHandler); + Channels.write(ctx.getChannel(), exitMsg); + } + finally { + myCancelHandlers.remove(cancelHandler); + } + } + }); } else if (requestType == JavacRemoteProto.Message.Request.Type.CANCEL){ - cancelBuild(); + cancelBuilds(); reply = JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createRequestAckResponse()); } else if (requestType == JavacRemoteProto.Message.Request.Type.SHUTDOWN){ - cancelBuild(); + cancelBuilds(); new Thread("StopThread") { public void run() { JavacServer.this.stop(); @@ -213,4 +240,19 @@ public class JavacServer { super.channelOpen(ctx, e); } } + + private static class CancelHandler implements CanceledStatus { + private volatile boolean myIsCanceled = false; + + private CancelHandler() { + } + + public void cancel() { + myIsCanceled = true; + } + + public boolean isCanceled() { + return myIsCanceled; + } + } } \ No newline at end of file From 31d0a6b540c34c640a67a9b241a102c0dcedc62f Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 10 Feb 2012 18:18:32 +0100 Subject: [PATCH 52/59] put text fields to the right of, not under labels --- .../ide/fileTemplates/ui/CreateFromTemplatePanel.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java index 71068baeab5c..4fd7bb5a1e4f 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java @@ -115,8 +115,7 @@ public class CreateFromTemplatePanel{ } private void updateShown() { - final Insets insets = new Insets(2, 2, 2, 2); - myAttrPanel.add(Box.createHorizontalStrut(200), new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insets, 0, 0)); + final Insets insets = new Insets(2, 4, 4, 2); if(myMustEnterName || Arrays.asList(myUnsetAttributes).contains(FileTemplate.ATTRIBUTE_NAME)){ final JLabel filenameLabel = new JLabel(IdeBundle.message("label.file.name")); myAttrPanel.add(filenameLabel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, insets, 0, 0)); @@ -147,15 +146,17 @@ public class CreateFromTemplatePanel{ } } } - myAttrPanel.add(myFilenameField, new GridBagConstraints(0, 2, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insets, 0, 0)); + myAttrPanel.add(myFilenameField, new GridBagConstraints(1, 1, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insets, 0, 0)); } + myLastRow = 2; for (String attribute : myUnsetAttributes) { if (attribute.equals(FileTemplate.ATTRIBUTE_NAME)) { // already asked above continue; } final JLabel label = new JLabel(attribute.replace('_', ' ') + ":"); final JTextField field = new JTextField(); + field.setColumns(30); if (myAttributesDefaults != null) { final String defaultValue = myAttributesDefaults.getDefaultValueFor(attribute); final TextRange selectionRange = myAttributesDefaults.getRangeFor(attribute); @@ -168,9 +169,9 @@ public class CreateFromTemplatePanel{ } } myAttributes.add(new Pair(attribute, field)); - myAttrPanel.add(label, new GridBagConstraints(0, myLastRow * 2 + 3, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, + myAttrPanel.add(label, new GridBagConstraints(0, myLastRow, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, insets, 0, 0)); - myAttrPanel.add(field, new GridBagConstraints(0, myLastRow * 2 + 4, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, + myAttrPanel.add(field, new GridBagConstraints(1, myLastRow, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insets, 0, 0)); myLastRow++; } From 51687bc9556c59416c455f450eda3c1e58a6d4c5 Mon Sep 17 00:00:00 2001 From: anna Date: Fri, 10 Feb 2012 18:03:37 +0100 Subject: [PATCH 53/59] inplace: preserve caret position; stop template when dialog would be open --- .../introduce/inplace/InplaceVariableIntroducer.java | 5 +++++ .../refactoring/rename/inplace/InplaceRefactoring.java | 8 ++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java b/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java index 21f0e587b203..1a0027304954 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java +++ b/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java @@ -148,6 +148,11 @@ public abstract class InplaceVariableIntroducer extends In protected void collectAdditionalElementsToRename(List> stringUsages) { } + @Override + protected int restoreCaretOffset(int offset) { + return myCaretRangeMarker.isValid() ? myCaretRangeMarker.getStartOffset() : offset; + } + @Override protected String getCommandName() { return myTitle; diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java index 9164e640fa5c..d27119aa63a6 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java @@ -104,7 +104,7 @@ public abstract class InplaceRefactoring { protected StartMarkAction myMarkAction; protected PsiElement myScope; - private RangeMarker myCaretRangeMarker; + protected RangeMarker myCaretRangeMarker; public InplaceRefactoring(Editor editor, PsiNamedElement elementToRename, Project project) { this(editor, elementToRename, project, elementToRename != null ? elementToRename.getName() : null, @@ -245,6 +245,10 @@ public abstract class InplaceRefactoring { } else { revertState(); + final TemplateState templateState = TemplateManagerImpl.getTemplateState(InjectedLanguageUtil.getTopLevelEditor(myEditor)); + if (templateState != null) { + templateState.gotoEnd(true); + } } return false; } @@ -350,7 +354,7 @@ public abstract class InplaceRefactoring { } protected int restoreCaretOffset(int offset) { - return myCaretRangeMarker.isValid() ? myCaretRangeMarker.getStartOffset() : offset; + return offset; } protected void navigateToAlreadyStarted(Document oldDocument, int exitCode) { From 0ab60fac592d7790a05ed8f5175ea7103d3d24e8 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 10 Feb 2012 18:43:24 +0100 Subject: [PATCH 54/59] extend create from template API: pass DataContext to getAttributesDefaults(), add callback after element was created --- .../actions/CreateFromTemplateActionBase.java | 10 ++++++++-- .../ide/fileTemplates/ui/CreateFromTemplateDialog.java | 4 ++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateActionBase.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateActionBase.java index 4e71423b46ca..4d700b0ae1d6 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateActionBase.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateActionBase.java @@ -55,8 +55,11 @@ public abstract class CreateFromTemplateActionBase extends AnAction { } else { FileTemplateManager.getInstance().addRecentName(selectedTemplate.getName()); - PsiElement createdElement = new CreateFromTemplateDialog(project, dir, selectedTemplate, getAttributesDefaults()).create(); + final AttributesDefaults defaults = getAttributesDefaults(dataContext); + final CreateFromTemplateDialog dialog = new CreateFromTemplateDialog(project, dir, selectedTemplate, defaults); + PsiElement createdElement = dialog.create(); if (createdElement != null) { + elementCreated(dialog, createdElement); view.selectElement(createdElement); } } @@ -74,7 +77,10 @@ public abstract class CreateFromTemplateActionBase extends AnAction { protected abstract FileTemplate getTemplate(final Project project, final PsiDirectory dir); @Nullable - public AttributesDefaults getAttributesDefaults() { + public AttributesDefaults getAttributesDefaults(DataContext dataContext) { return null; } + + protected void elementCreated(CreateFromTemplateDialog dialog, PsiElement createdElement) { + } } diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java index 1bc050415a9a..aaa153d3161e 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java @@ -125,6 +125,10 @@ public class CreateFromTemplateDialog extends DialogWrapper { } } + public Properties getEnteredProperties() { + return myAttrPanel.getProperties(new Properties()); + } + private void showErrorDialog(final Exception e) { Messages.showMessageDialog(myProject, filterMessage(e.getMessage()), getErrorMessage(), Messages.getErrorIcon()); } From 75c48309a83be259942a698f12d2ff1037608097 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Fri, 10 Feb 2012 21:47:26 +0400 Subject: [PATCH 55/59] moved murmur String hash method into StringHash --- .../openapi/util/text/StringHash.java | 38 +++++++++++++++ .../intellij/util/lang/ClasspathCache.java | 46 ++----------------- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/platform/util/src/com/intellij/openapi/util/text/StringHash.java b/platform/util/src/com/intellij/openapi/util/text/StringHash.java index 404a935616b5..e20c15f08a92 100644 --- a/platform/util/src/com/intellij/openapi/util/text/StringHash.java +++ b/platform/util/src/com/intellij/openapi/util/text/StringHash.java @@ -151,5 +151,43 @@ public class StringHash { return h; } + public static int murmur(String data, int seed) { + final int length = data.length(); + // 'm' and 'r' are mixing constants generated offline. + // They're not really 'magic', they just happen to work well. + final int m = 0x5bd1e995; + final int r = 24; + // Initialize the hash to a random value + int h = seed ^ length; + int length4 = length >> 2; + + for (int i = 0; i < length4; i++) { + final int i4 = i << 2; + int k = data.charAt(i4) + (data.charAt(i4 + 1) << 8) + + (data.charAt(i4 + 2) << 16) + (data.charAt(i4 + 3) << 24); + k *= m; + k ^= k >>> r; + k *= m; + h *= m; + h ^= k; + } + + // Handle the last few bytes of the input array + switch (length % 4) { + case 3: + h ^= data.charAt((length & ~3) + 2) << 16; + case 2: + h ^= data.charAt((length & ~3) + 1) << 8; + case 1: + h ^= data.charAt(length & ~3); + h *= m; + } + + h ^= h >>> 13; + h *= m; + h ^= h >>> 15; + + return h; + } } diff --git a/platform/util/src/com/intellij/util/lang/ClasspathCache.java b/platform/util/src/com/intellij/util/lang/ClasspathCache.java index 8b13a3f35a55..658cda05f986 100644 --- a/platform/util/src/com/intellij/util/lang/ClasspathCache.java +++ b/platform/util/src/com/intellij/util/lang/ClasspathCache.java @@ -19,6 +19,7 @@ */ package com.intellij.util.lang; +import com.intellij.openapi.util.text.StringHash; import com.intellij.util.ArrayUtil; import com.intellij.util.SmartList; import com.intellij.util.containers.HashMap; @@ -273,7 +274,7 @@ public class ClasspathCache { } private boolean maybeContains(String name, Loader loader) { - int hash = hashFromNameAndLoader(name, loader, murmur(name, SEED)); + int hash = hashFromNameAndLoader(name, loader, StringHash.murmur(name, SEED)); int hash2 = hashFromNameAndLoader(name, loader, hash); for (int i = 0; i < myHashFunctionCount; ++i) { @@ -283,7 +284,7 @@ public class ClasspathCache { } public void add(String name, Loader loader) { - int hash1 = hashFromNameAndLoader(name, loader, murmur(name, SEED)); + int hash1 = hashFromNameAndLoader(name, loader, StringHash.murmur(name, SEED)); int hash2 = hashFromNameAndLoader(name, loader, hash1); for (int i = 0; i < myHashFunctionCount; ++i) { @@ -292,7 +293,7 @@ public class ClasspathCache { } private int hashFromNameAndLoader(String name, Loader loader, int n) { - int hash = murmur(name, n); + int hash = StringHash.murmur(name, n); int i = loader.getIndex(); while (i > 0) { hash = hash * n + ((i % 10) + '0'); @@ -300,45 +301,6 @@ public class ClasspathCache { } return hash; } - - private static int murmur(String data, int seed) { - final int length = data.length(); - // 'm' and 'r' are mixing constants generated offline. - // They're not really 'magic', they just happen to work well. - final int m = 0x5bd1e995; - final int r = 24; - // Initialize the hash to a random value - int h = seed ^ length; - int length4 = length >> 2; - - for (int i = 0; i < length4; i++) { - final int i4 = i << 2; - int k = data.charAt(i4) + (data.charAt(i4 + 1) << 8) + - (data.charAt(i4 + 2) << 16) + (data.charAt(i4 + 3) << 24); - k *= m; - k ^= k >>> r; - k *= m; - h *= m; - h ^= k; - } - - // Handle the last few bytes of the input array - switch (length % 4) { - case 3: - h ^= data.charAt((length & ~3) + 2) << 16; - case 2: - h ^= data.charAt((length & ~3) + 1) << 8; - case 1: - h ^= data.charAt(length & ~3); - h *= m; - } - - h ^= h >>> 13; - h *= m; - h ^= h >>> 15; - - return h; - } } static class DebugInfo { From 8a4916c1e91ac96ec53deea6fb3b753ce5ae6a2a Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 10 Feb 2012 18:51:02 +0100 Subject: [PATCH 56/59] decouple core file template logic from StdFileTypes.JAVA --- .../JavaCreateFromTemplateHandler.java | 21 +++++++++++++++++++ .../CreateFromTemplateHandler.java | 4 ++++ .../DefaultCreateFromTemplateHandler.java | 16 ++++++++++++++ .../ide/fileTemplates/FileTemplateUtil.java | 12 +++-------- .../ui/CreateFromTemplateDialog.java | 5 ++--- 5 files changed, 46 insertions(+), 12 deletions(-) diff --git a/java/java-impl/src/com/intellij/ide/fileTemplates/JavaCreateFromTemplateHandler.java b/java/java-impl/src/com/intellij/ide/fileTemplates/JavaCreateFromTemplateHandler.java index 56556548f0e4..7507f9dfd68b 100644 --- a/java/java-impl/src/com/intellij/ide/fileTemplates/JavaCreateFromTemplateHandler.java +++ b/java/java-impl/src/com/intellij/ide/fileTemplates/JavaCreateFromTemplateHandler.java @@ -15,6 +15,7 @@ */ package com.intellij.ide.fileTemplates; +import com.intellij.ide.IdeBundle; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.fileTypes.ex.FileTypeManagerEx; @@ -108,6 +109,26 @@ public class JavaCreateFromTemplateHandler implements CreateFromTemplateHandler return false; } + @Override + public boolean isNameRequired() { + return false; + } + + @Override + public String getErrorMessage() { + return IdeBundle.message("title.cannot.create.class"); + } + + @Override + public Properties prepareProperties(Properties props) { + String packageName = props.getProperty(FileTemplate.ATTRIBUTE_PACKAGE_NAME); + if(packageName == null || packageName.length() == 0){ + props = new Properties(props); + props.setProperty(FileTemplate.ATTRIBUTE_PACKAGE_NAME, FileTemplate.ATTRIBUTE_PACKAGE_NAME); + } + return props; + } + public static boolean canCreate(PsiDirectory dir) { return JavaDirectoryService.getInstance().getPackage(dir) != null; } diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/CreateFromTemplateHandler.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/CreateFromTemplateHandler.java index 2caae4e51a95..0eb494ca6d3e 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/CreateFromTemplateHandler.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/CreateFromTemplateHandler.java @@ -35,4 +35,8 @@ public interface CreateFromTemplateHandler { Properties props) throws IncorrectOperationException; boolean canCreate(final PsiDirectory[] dirs); + boolean isNameRequired(); + String getErrorMessage(); + + Properties prepareProperties(Properties props); } diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/DefaultCreateFromTemplateHandler.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/DefaultCreateFromTemplateHandler.java index 91bfa6dda7b9..bf61fb7d5c3a 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/DefaultCreateFromTemplateHandler.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/DefaultCreateFromTemplateHandler.java @@ -16,6 +16,7 @@ package com.intellij.ide.fileTemplates; +import com.intellij.ide.IdeBundle; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiDirectory; @@ -67,4 +68,19 @@ public class DefaultCreateFromTemplateHandler implements CreateFromTemplateHandl public boolean canCreate(final PsiDirectory[] dirs) { return true; } + + @Override + public boolean isNameRequired() { + return true; + } + + @Override + public String getErrorMessage() { + return IdeBundle.message("title.cannot.create.file"); + } + + @Override + public Properties prepareProperties(Properties props) { + return props; + } } diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java index eab211ad86d0..d23ba3acea8f 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java @@ -279,13 +279,8 @@ public class FileTemplateUtil{ props.setProperty(dummyRef, ""); } - if (template.isTemplateOfType(StdFileTypes.JAVA)){ - String packageName = props.getProperty(FileTemplate.ATTRIBUTE_PACKAGE_NAME); - if(packageName == null || packageName.length() == 0){ - props = new Properties(props); - props.setProperty(FileTemplate.ATTRIBUTE_PACKAGE_NAME, FileTemplate.ATTRIBUTE_PACKAGE_NAME); - } - } + final CreateFromTemplateHandler handler = findHandler(template); + props = handler.prepareProperties(props); final Properties props_ = props; String mergedText = ClassLoaderUtil.runWithClassLoader(classLoader != null ? classLoader : FileTemplateUtil.class.getClassLoader(), @@ -304,7 +299,6 @@ public class FileTemplateUtil{ ApplicationManager.getApplication().runWriteAction(new Runnable(){ public void run(){ try{ - CreateFromTemplateHandler handler = findHandler(template); result [0] = handler.createFromTemplate(project, directory, fileName, template, templateText, finalProps); } catch (Exception ex){ @@ -322,7 +316,7 @@ public class FileTemplateUtil{ return result[0]; } - private static CreateFromTemplateHandler findHandler(final FileTemplate template) { + public static CreateFromTemplateHandler findHandler(final FileTemplate template) { for(CreateFromTemplateHandler handler: Extensions.getExtensions(CreateFromTemplateHandler.EP_NAME)) { if (handler.handlesTemplate(template)) { return handler; diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java index aaa153d3161e..a73db7bcf071 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java @@ -22,7 +22,6 @@ import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.ide.fileTemplates.FileTemplateManager; import com.intellij.ide.fileTemplates.FileTemplateUtil; import com.intellij.ide.fileTemplates.actions.AttributesDefaults; -import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; @@ -65,7 +64,7 @@ public class CreateFromTemplateDialog extends DialogWrapper { myDefaultProperties = defaultProperties == null ? FileTemplateManager.getInstance().getDefaultProperties() : defaultProperties; FileTemplateUtil.fillDefaultProperties(myDefaultProperties, directory); - boolean mustEnterName = !myTemplate.isTemplateOfType(StdFileTypes.JAVA); + boolean mustEnterName = FileTemplateUtil.findHandler(template).isNameRequired(); if (attributesDefaults != null && attributesDefaults.isFixedName()) { myDefaultProperties.setProperty(FileTemplate.ATTRIBUTE_NAME, attributesDefaults.getDefaultFileName()); mustEnterName = false; @@ -134,7 +133,7 @@ public class CreateFromTemplateDialog extends DialogWrapper { } private String getErrorMessage() { - return myTemplate.isTemplateOfType(StdFileTypes.JAVA) ? IdeBundle.message("title.cannot.create.class") : IdeBundle.message("title.cannot.create.file"); + return FileTemplateUtil.findHandler(myTemplate).getErrorMessage(); } @Nullable From 9cd1c49cb2b7cdfaa251f0cd34aaab28ad5123e7 Mon Sep 17 00:00:00 2001 From: Alexander Doroshko Date: Fri, 10 Feb 2012 21:46:35 +0400 Subject: [PATCH 57/59] Guarantee that different maven importers won't require different module types for one maven project --- .../idea/maven/importing/MavenImporter.java | 35 ++++++++++++++++--- .../idea/maven/project/MavenProject.java | 17 ++------- 2 files changed, 33 insertions(+), 19 deletions(-) diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenImporter.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenImporter.java index b46464c7fd95..843f8d2caa97 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenImporter.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenImporter.java @@ -20,7 +20,10 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.module.StdModuleTypes; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Pair; +import com.intellij.util.containers.ContainerUtil; +import gnu.trove.THashSet; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -31,10 +34,7 @@ import org.jetbrains.idea.maven.server.NativeMavenProjectHolder; import org.jetbrains.idea.maven.utils.MavenJDOMUtil; import org.jetbrains.idea.maven.utils.MavenProcessCanceledException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; +import java.util.*; public abstract class MavenImporter { public static ExtensionPointName EXTENSION_POINT_NAME = ExtensionPointName.create("org.jetbrains.idea.maven.importer"); @@ -48,12 +48,37 @@ public abstract class MavenImporter { public static List getSuitableImporters(MavenProject p) { final List result = new ArrayList(); + final Set moduleTypes = new THashSet(); for (MavenImporter importer : EXTENSION_POINT_NAME.getExtensions()) { if (importer.isApplicable(p)) { result.add(importer); + moduleTypes.add(importer.getModuleType()); } } - return result; + + if (moduleTypes.size() <= 1) { + return result; + } + + // This code is reached when several importers say that they are applicable but they want to have different module types. + // Now we select one module type and return only those importers that are ok with it. + // If possible - return at least one importer that explicitly supports packaging of the given maven project. + ModuleType moduleType = result.get(0).getModuleType(); + for (MavenImporter importer : result) { + final List supportedPackagings = new ArrayList(); + importer.getSupportedPackagings(supportedPackagings); + if (supportedPackagings.contains(p.getPackaging())) { + moduleType = importer.getModuleType(); + break; + } + } + + final ModuleType finalModuleType = moduleType; + return ContainerUtil.filter(result, new Condition() { + public boolean value(final MavenImporter importer) { + return importer.getModuleType() == finalModuleType; + } + }); } public boolean isApplicable(MavenProject mavenProject) { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java index 6503756ea1c7..015bd7f96012 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java @@ -802,20 +802,9 @@ public class MavenProject { @NotNull public ModuleType getModuleType() { - MavenImporter mavenImporter = null; - ModuleType typeFromImporter = null; - - for (MavenImporter each : getSuitableImporters()) { - final ModuleType moduleType = each.getModuleType(); - if (typeFromImporter != null && !typeFromImporter.equals(moduleType)) { - MavenLog.LOG.error("Incompatible plugins: " + each.getClass().getName() + " wants to create " + - moduleType.getName() + " for project " + getName() + - " whereas " + mavenImporter.getClass().getName() + " requires " + typeFromImporter.getName()); - } - mavenImporter = each; - typeFromImporter = moduleType; - } - return typeFromImporter != null ? typeFromImporter : StdModuleTypes.JAVA; + final List importers = getSuitableImporters(); + // getSuitableImporters() guarantees that all returned importers require the same module type + return importers.size() > 0 ? importers.get(0).getModuleType() : StdModuleTypes.JAVA; } @NotNull From 70a933619c6958bc2cb701bcada5fdeac16d93a9 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 10 Feb 2012 18:55:22 +0100 Subject: [PATCH 58/59] take name from properties if not specified as explicit parameter --- .../ide/fileTemplates/FileTemplateUtil.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java index d23ba3acea8f..0d0ec3f10408 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java @@ -258,7 +258,7 @@ public class FileTemplateUtil{ } public static PsiElement createFromTemplate(@NotNull final FileTemplate template, - @NonNls @Nullable final String fileName, + @NonNls @Nullable String fileName, @Nullable Properties props, @NotNull final PsiDirectory directory, @Nullable ClassLoader classLoader) throws Exception { @@ -269,9 +269,16 @@ public class FileTemplateUtil{ FileTemplateManager.getInstance().addRecentName(template.getName()); fillDefaultProperties(props, directory); + final CreateFromTemplateHandler handler = findHandler(template); if (fileName != null && props.getProperty(FileTemplate.ATTRIBUTE_NAME) == null) { props.setProperty(FileTemplate.ATTRIBUTE_NAME, fileName); } + else if (fileName == null && handler.isNameRequired()) { + fileName = props.getProperty(FileTemplate.ATTRIBUTE_NAME); + if (fileName == null) { + throw new Exception("File name must be specified"); + } + } //Set escaped references to dummy values to remove leading "\" (if not already explicitely set) String[] dummyRefs = calculateAttributes(template.getText(), props, true); @@ -279,10 +286,10 @@ public class FileTemplateUtil{ props.setProperty(dummyRef, ""); } - final CreateFromTemplateHandler handler = findHandler(template); props = handler.prepareProperties(props); final Properties props_ = props; + final String fileName_ = fileName; String mergedText = ClassLoaderUtil.runWithClassLoader(classLoader != null ? classLoader : FileTemplateUtil.class.getClassLoader(), new ThrowableComputable() { @Override @@ -299,7 +306,7 @@ public class FileTemplateUtil{ ApplicationManager.getApplication().runWriteAction(new Runnable(){ public void run(){ try{ - result [0] = handler.createFromTemplate(project, directory, fileName, template, templateText, finalProps); + result [0] = handler.createFromTemplate(project, directory, fileName_, template, templateText, finalProps); } catch (Exception ex){ commandException[0] = ex; From c25e5f4ce6878615f6f1fcc473f4e3b54718cf7b Mon Sep 17 00:00:00 2001 From: anna Date: Fri, 10 Feb 2012 19:43:54 +0100 Subject: [PATCH 59/59] show doc for correct parameter (IDEA-81184) --- .../hint/ParameterInfoComponent.java | 4 +++ .../hint/ParameterInfoController.java | 25 ++++++++++++++----- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoComponent.java index 59f6ca91c914..dbc7dc81c0a4 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoComponent.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoComponent.java @@ -79,6 +79,10 @@ class ParameterInfoComponent extends JPanel{ myCurrentParameterIndex = -1; } + public Object getHighlighted() { + return myHighlighted; + } + class MyParameterContext implements ParameterInfoUIContextEx { private int i; public void setupUIComponentPresentation(String text, diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java index 9bf5c61e90cb..31401edbb0ed 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java @@ -113,20 +113,33 @@ public class ParameterInfoController { int selectedParameterIndex = myComponent.getCurrentParameterIndex(); List params = new ArrayList(objects.length); + final Object highlighted = myComponent.getHighlighted(); for(Object o:objects) { - final Object[] availableParams = myHandler.getParametersForDocumentation(o, context); + if (highlighted != null && !o.equals(highlighted)) continue; + collectParams(context, selectedParameterIndex, params, o); + } - if (availableParams != null && - selectedParameterIndex < availableParams.length && - selectedParameterIndex >= 0 - ) { - params.add(availableParams[selectedParameterIndex]); + //choose anything when highlighted is not applicable + if (highlighted != null && params.isEmpty()) { + for (Object o : objects) { + collectParams(context, selectedParameterIndex, params, o); } } return ArrayUtil.toObjectArray(params); } + private void collectParams(ParameterInfoContext context, int selectedParameterIndex, List params, Object o) { + final Object[] availableParams = myHandler.getParametersForDocumentation(o, context); + + if (availableParams != null && + selectedParameterIndex < availableParams.length && + selectedParameterIndex >= 0 + ) { + params.add(availableParams[selectedParameterIndex]); + } + } + private static ArrayList getAllControllers(Editor editor) { ArrayList array = editor.getUserData(ALL_CONTROLLERS_KEY); if (array == null){