From 323727f189734651de49cc8737bfaa0cdf8b64e4 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Mon, 11 Apr 2011 18:47:47 +0400 Subject: [PATCH 001/102] IDEA-67886 IDEA-67758 map help ids --- .../jetbrains/android/actions/NewAndroidComponentDialog.java | 5 +++++ .../android/compiler/AndroidDexCompilerSettingsFactory.java | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/android/src/org/jetbrains/android/actions/NewAndroidComponentDialog.java b/plugins/android/src/org/jetbrains/android/actions/NewAndroidComponentDialog.java index aa3cbd09b151..701629831d0c 100644 --- a/plugins/android/src/org/jetbrains/android/actions/NewAndroidComponentDialog.java +++ b/plugins/android/src/org/jetbrains/android/actions/NewAndroidComponentDialog.java @@ -216,6 +216,11 @@ public class NewAndroidComponentDialog extends DialogWrapper { return myNameField; } + @Override + protected String getHelpId() { + return "reference.new.android.component"; + } + @Override protected JComponent createCenterPanel() { return myPanel; diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidDexCompilerSettingsFactory.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidDexCompilerSettingsFactory.java index d3acbcb3eaf9..4afcfc11a93c 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidDexCompilerSettingsFactory.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidDexCompilerSettingsFactory.java @@ -63,7 +63,7 @@ public class AndroidDexCompilerSettingsFactory implements CompilerSettingsFactor @Override public String getHelpTopic() { - return null; + return "settings.android.dx.compiler"; } @Override From 1c2b3236d2e17555422e0d50436296cbddf0ab76 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Mon, 11 Apr 2011 18:59:18 +0400 Subject: [PATCH 002/102] fix manageSpaceActivity attribute --- .../org/jetbrains/android/dom/manifest/Application.java | 2 ++ .../android/testData/dom/manifest/ManageSpaceActivity.xml | 7 +++++++ .../testData/dom/manifest/ManageSpaceActivity_after.xml | 7 +++++++ .../org/jetbrains/android/dom/AndroidManifestDomTest.java | 5 +++++ 4 files changed, 21 insertions(+) create mode 100644 plugins/android/testData/dom/manifest/ManageSpaceActivity.xml create mode 100644 plugins/android/testData/dom/manifest/ManageSpaceActivity_after.xml diff --git a/plugins/android/src/org/jetbrains/android/dom/manifest/Application.java b/plugins/android/src/org/jetbrains/android/dom/manifest/Application.java index c0c00735cf2b..299637052793 100644 --- a/plugins/android/src/org/jetbrains/android/dom/manifest/Application.java +++ b/plugins/android/src/org/jetbrains/android/dom/manifest/Application.java @@ -16,6 +16,7 @@ package org.jetbrains.android.dom.manifest; import com.intellij.psi.PsiClass; +import com.intellij.util.xml.Attribute; import com.intellij.util.xml.Convert; import com.intellij.util.xml.ExtendClass; import org.jetbrains.android.dom.AndroidAttributeValue; @@ -53,6 +54,7 @@ public interface Application extends ManifestElement { @Convert(PackageClassConverter.class) @ExtendClass("android.app.Activity") + @Attribute("manageSpaceActivity") AndroidAttributeValue getManageSpaceActivity(); @Convert(PackageClassConverter.class) diff --git a/plugins/android/testData/dom/manifest/ManageSpaceActivity.xml b/plugins/android/testData/dom/manifest/ManageSpaceActivity.xml new file mode 100644 index 000000000000..484ed7c56704 --- /dev/null +++ b/plugins/android/testData/dom/manifest/ManageSpaceActivity.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/plugins/android/testData/dom/manifest/ManageSpaceActivity_after.xml b/plugins/android/testData/dom/manifest/ManageSpaceActivity_after.xml new file mode 100644 index 000000000000..7dbec8354eec --- /dev/null +++ b/plugins/android/testData/dom/manifest/ManageSpaceActivity_after.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/plugins/android/testSrc/org/jetbrains/android/dom/AndroidManifestDomTest.java b/plugins/android/testSrc/org/jetbrains/android/dom/AndroidManifestDomTest.java index ee773714e680..ddd54fe706e5 100644 --- a/plugins/android/testSrc/org/jetbrains/android/dom/AndroidManifestDomTest.java +++ b/plugins/android/testSrc/org/jetbrains/android/dom/AndroidManifestDomTest.java @@ -150,6 +150,11 @@ public class AndroidManifestDomTest extends AndroidDomTest { doTestCompletion(); } + public void testManageSpaceActivity() throws Throwable { + copyFileToProject("MyActivity.java", "src/p1/p2/MyActivity.java"); + doTestCompletion(); + } + private void doTestCompletion() throws Throwable { toTestCompletion(getTestName(false) + ".xml", getTestName(false) + "_after.xml"); } From 9ab67a792f708b8424ad8ab609f6c9aad22c4dbf Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Mon, 11 Apr 2011 19:36:44 +0400 Subject: [PATCH 003/102] try to suggest Android SDK path, if ANDROID_HOME is not set --- .../android/maven/AndroidFacetImporter.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/plugins/android/src/org/jetbrains/android/maven/AndroidFacetImporter.java b/plugins/android/src/org/jetbrains/android/maven/AndroidFacetImporter.java index 8600fb1f9340..7a85ef242625 100644 --- a/plugins/android/src/org/jetbrains/android/maven/AndroidFacetImporter.java +++ b/plugins/android/src/org/jetbrains/android/maven/AndroidFacetImporter.java @@ -18,7 +18,9 @@ package org.jetbrains.android.maven; import com.android.sdklib.IAndroidTarget; import com.intellij.facet.FacetType; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; +import com.intellij.openapi.projectRoots.ProjectJdkTable; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.roots.ModuleRootManager; @@ -34,6 +36,7 @@ import org.jetbrains.android.facet.AndroidFacetConfiguration; import org.jetbrains.android.facet.AndroidFacetType; import org.jetbrains.android.facet.AndroidRootUtil; import org.jetbrains.android.sdk.AndroidSdk; +import org.jetbrains.android.sdk.AndroidSdkType; import org.jetbrains.android.sdk.AndroidSdkUtils; import org.jetbrains.android.sdk.EmptySdkLog; import org.jetbrains.android.util.AndroidUtils; @@ -55,6 +58,8 @@ import java.util.Map; * @author Eugene.Kudelevsky */ public class AndroidFacetImporter extends FacetImporter { + private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.maven.AndroidFacetImporter"); + public AndroidFacetImporter() { super("com.jayway.maven.plugins.android.generation2", "maven-android-plugin", FacetType.findInstance(AndroidFacetType.class), "Android"); } @@ -116,6 +121,13 @@ public class AndroidFacetImporter extends FacetImporter androidSdks = ProjectJdkTable.getInstance().getSdksOfType(AndroidSdkType.getInstance()); + for (Sdk androidSdk : androidSdks) { + final VirtualFile sdkHome = androidSdk.getHomeDirectory(); + + if (sdkHome != null && sdkHome.exists() && sdkHome.isValid() && sdkHome.isDirectory()) { + return sdkHome.getPath(); + } + } + + return null; + } + private void configurePaths(AndroidFacet facet, MavenProject project) { Module module = facet.getModule(); String moduleDirPath = AndroidRootUtil.getModuleDirPath(module); From 39c80e7413aaab57d0b7534d86375701fee1e68d Mon Sep 17 00:00:00 2001 From: Kirill Kalishev Date: Tue, 12 Apr 2011 17:23:25 +0400 Subject: [PATCH 004/102] TreeUI: avoid flickering for bg loading structure with new nodes on every getChildren --- .../com/intellij/ide/util/treeView/AbstractTreeUi.java | 8 +++++++- .../com/intellij/ide/util/treeView/NodeDescriptor.java | 7 +++++++ .../ide/util/treeView/PresentableNodeDescriptor.java | 10 ++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java index ed3cd5262dea..2927e0cc18da 100644 --- a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java +++ b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java @@ -2873,6 +2873,11 @@ public class AbstractTreeUi { if (parentNode.getUserObject() instanceof NodeDescriptor) { final NodeDescriptor parentDescriptor = getDescriptorFrom(parentNode); childDesc.set(getTreeStructure().createDescriptor(elementFromMap, parentDescriptor)); + NodeDescriptor oldDesc = getDescriptorFrom(childNode); + if (oldDesc != null) { + childDesc.get().applyFrom(oldDesc); + } + childNode.setUserObject(childDesc.get()); newElement.set(elementFromMap); forceRemapping.set(true); @@ -3132,7 +3137,8 @@ public class AbstractTreeUi { } protected static boolean doUpdateNodeDescriptor(final NodeDescriptor descriptor) { - return descriptor.update(); + boolean update = descriptor.update(); + return update; } private void makeLoadingOrLeafIfNoChildren(final DefaultMutableTreeNode node) { diff --git a/platform/platform-api/src/com/intellij/ide/util/treeView/NodeDescriptor.java b/platform/platform-api/src/com/intellij/ide/util/treeView/NodeDescriptor.java index 89faab481dbd..5fd80c07e8a9 100644 --- a/platform/platform-api/src/com/intellij/ide/util/treeView/NodeDescriptor.java +++ b/platform/platform-api/src/com/intellij/ide/util/treeView/NodeDescriptor.java @@ -115,6 +115,13 @@ public abstract class NodeDescriptor { myWasDeclaredAlwaysLeaf = leaf; } + public void applyFrom(NodeDescriptor desc) { + myOpenIcon = desc.myOpenIcon; + myClosedIcon = desc.myClosedIcon; + myName = desc.myName; + myColor = desc.myColor; + } + public abstract static class NodeComparator implements Comparator { private long myStamp; diff --git a/platform/platform-api/src/com/intellij/ide/util/treeView/PresentableNodeDescriptor.java b/platform/platform-api/src/com/intellij/ide/util/treeView/PresentableNodeDescriptor.java index bafb35c0da4c..2c02f588f9dc 100644 --- a/platform/platform-api/src/com/intellij/ide/util/treeView/PresentableNodeDescriptor.java +++ b/platform/platform-api/src/com/intellij/ide/util/treeView/PresentableNodeDescriptor.java @@ -46,6 +46,16 @@ public abstract class PresentableNodeDescriptor extends NodeDescriptor { return apply(presentation, null); } + @Override + public void applyFrom(NodeDescriptor desc) { + if (desc instanceof PresentableNodeDescriptor) { + PresentableNodeDescriptor pnd = (PresentableNodeDescriptor)desc; + apply(pnd.getPresentation()); + } else { + super.applyFrom(desc); + } + } + protected final boolean apply(PresentationData presentation, @Nullable PresentationData before) { myOpenIcon = presentation.getIcon(true); myClosedIcon = presentation.getIcon(false); From 0cbf29c51a5335e2bc6921268df1839078b49872 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Tue, 12 Apr 2011 19:44:20 +0400 Subject: [PATCH 005/102] fix exception when manifest is out of module --- .../dom/converters/ConstantFieldConverter.java | 8 ++++++-- .../dom/converters/PackageClassConverter.java | 13 ++++++++++--- .../dom/manifest/ManifestDomFileDescription.java | 4 +++- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/plugins/android/src/org/jetbrains/android/dom/converters/ConstantFieldConverter.java b/plugins/android/src/org/jetbrains/android/dom/converters/ConstantFieldConverter.java index 8dae75193224..911bc8d77ee3 100644 --- a/plugins/android/src/org/jetbrains/android/dom/converters/ConstantFieldConverter.java +++ b/plugins/android/src/org/jetbrains/android/dom/converters/ConstantFieldConverter.java @@ -15,6 +15,7 @@ */ package org.jetbrains.android.dom.converters; +import com.intellij.openapi.module.Module; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.xml.ConvertContext; @@ -41,8 +42,11 @@ public class ConstantFieldConverter extends ResolvingConverter { LookupClass lookupClass = element.getAnnotation(LookupClass.class); LookupPrefix lookupPrefix = element.getAnnotation(LookupPrefix.class); if (lookupClass != null && lookupPrefix != null) { - PsiClass psiClass = JavaPsiFacade.getInstance(context.getPsiManager().getProject()).findClass(lookupClass.value(), - GlobalSearchScope.allScope(context.getModule().getProject())); + final Module module = context.getModule(); + final GlobalSearchScope scope = module != null ? + GlobalSearchScope.allScope(module.getProject()) : + context.getInvocationElement().getResolveScope(); + PsiClass psiClass = JavaPsiFacade.getInstance(context.getPsiManager().getProject()).findClass(lookupClass.value(), scope); if (psiClass != null) { PsiField[] psiFields = psiClass.getFields(); for(PsiField field: psiFields) { diff --git a/plugins/android/src/org/jetbrains/android/dom/converters/PackageClassConverter.java b/plugins/android/src/org/jetbrains/android/dom/converters/PackageClassConverter.java index 61bac36b8730..1455df54150b 100644 --- a/plugins/android/src/org/jetbrains/android/dom/converters/PackageClassConverter.java +++ b/plugins/android/src/org/jetbrains/android/dom/converters/PackageClassConverter.java @@ -77,7 +77,10 @@ public class PackageClassConverter extends ResolvingConverter implemen className = packageName + "." + s; } JavaPsiFacade facade = JavaPsiFacade.getInstance(context.getPsiManager().getProject()); - GlobalSearchScope scope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(context.getModule()); + final Module module = context.getModule(); + GlobalSearchScope scope = module != null + ? GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module) + : context.getInvocationElement().getResolveScope(); PsiClass psiClass = facade.findClass(className, scope); if (psiClass == null) { psiClass = facade.findClass(s, scope); @@ -264,7 +267,9 @@ public class PackageClassConverter extends ResolvingConverter implemen if (!myStartsWithPoint) { final PsiElement element = myIsPackage ? facade.findPackage(value) : - facade.findClass(value, myModule.getModuleWithDependenciesScope()); + facade.findClass(value, myModule != null + ? myModule.getModuleWithDependenciesScope() + : myElement.getResolveScope()); if (element != null) { return element; @@ -275,7 +280,9 @@ public class PackageClassConverter extends ResolvingConverter implemen if (relativeName != null) { return myIsPackage ? facade.findPackage(relativeName) : - facade.findClass(relativeName, myModule.getModuleWithDependenciesScope()); + facade.findClass(relativeName, myModule != null + ? myModule.getModuleWithDependenciesScope() + : myElement.getResolveScope()); } return null; } diff --git a/plugins/android/src/org/jetbrains/android/dom/manifest/ManifestDomFileDescription.java b/plugins/android/src/org/jetbrains/android/dom/manifest/ManifestDomFileDescription.java index 03461b9631e4..acea0d6bb5f5 100644 --- a/plugins/android/src/org/jetbrains/android/dom/manifest/ManifestDomFileDescription.java +++ b/plugins/android/src/org/jetbrains/android/dom/manifest/ManifestDomFileDescription.java @@ -17,6 +17,7 @@ package org.jetbrains.android.dom.manifest; import com.android.sdklib.SdkConstants; import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleUtil; import com.intellij.psi.xml.XmlFile; import com.intellij.util.xml.DomFileDescription; import org.jetbrains.android.facet.AndroidFacet; @@ -40,7 +41,8 @@ public class ManifestDomFileDescription extends DomFileDescription { if (!file.getName().equals(SdkConstants.FN_ANDROID_MANIFEST_XML)) { return false; } - return AndroidFacet.getInstance(file) != null; + final Module module = ModuleUtil.findModuleForPsiElement(file); + return module == null || AndroidFacet.getInstance(module) != null; } protected void initializeFileDescription() { From efa71142dbbd1d19551dc61b6b8d63341ee18c93 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Tue, 12 Apr 2011 19:44:57 +0400 Subject: [PATCH 006/102] do not check debuggable option anymore --- .../run/AndroidRunConfigurationBase.java | 44 +------------------ 1 file changed, 2 insertions(+), 42 deletions(-) diff --git a/plugins/android/src/org/jetbrains/android/run/AndroidRunConfigurationBase.java b/plugins/android/src/org/jetbrains/android/run/AndroidRunConfigurationBase.java index f761e33f4230..764438e8314a 100644 --- a/plugins/android/src/org/jetbrains/android/run/AndroidRunConfigurationBase.java +++ b/plugins/android/src/org/jetbrains/android/run/AndroidRunConfigurationBase.java @@ -27,7 +27,6 @@ import com.intellij.execution.executors.DefaultDebugExecutor; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.ui.ConsoleView; import com.intellij.ide.util.PropertiesComponent; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.Project; @@ -44,10 +43,8 @@ import com.intellij.psi.xml.XmlAttributeValue; import com.intellij.util.PsiNavigateUtil; import com.intellij.util.containers.HashMap; import com.intellij.util.xml.GenericAttributeValue; -import com.intellij.util.xml.converters.values.BooleanValueConverter; import org.jdom.Element; import org.jetbrains.android.actions.AndroidEnableDdmsAction; -import org.jetbrains.android.dom.manifest.Application; import org.jetbrains.android.dom.manifest.Manifest; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.AndroidFacetConfiguration; @@ -171,14 +168,14 @@ public abstract class AndroidRunConfigurationBase extends ModuleBasedConfigurati return true; } - private static boolean containsRealDevice(@NotNull IDevice[] devices) { + /*private static boolean containsRealDevice(@NotNull IDevice[] devices) { for (IDevice device : devices) { if (!device.isEmulator()) { return true; } } return false; - } + }*/ public RunProfileState getState(@NotNull final Executor executor, @NotNull ExecutionEnvironment env) throws ExecutionException { final Module module = getConfigurationModule().getModule(); @@ -207,11 +204,6 @@ public abstract class AndroidRunConfigurationBase extends ModuleBasedConfigurati if (!activateDdmsIfNeccessary(facet)) { return null; } - if (!CHOOSE_DEVICE_MANUALLY && PREFERRED_AVD.length() == 0) { - if (!checkDebuggableOption(facet)) { - return null; - } - } } String aPackage = getPackageName(facet); @@ -224,11 +216,6 @@ public abstract class AndroidRunConfigurationBase extends ModuleBasedConfigurati if (CHOOSE_DEVICE_MANUALLY) { IDevice[] devices = chooseDevicesManually(facet); if (devices.length > 0) { - if (debug && containsRealDevice(devices)) { - if (!checkDebuggableOption(facet)) { - return null; - } - } targetDevices = devices; PropertiesComponent.getInstance(getProject()).setValue(ANDROID_TARGET_DEVICES_PROPERTY, toString(targetDevices)); } @@ -249,33 +236,6 @@ public abstract class AndroidRunConfigurationBase extends ModuleBasedConfigurati return null; } - private static boolean checkDebuggableOption(@NotNull AndroidFacet facet) { - Manifest manifest = facet.getManifest(); - // validated in checkConfiguration() - assert manifest != null; - final Application application = manifest.getApplication(); - if (application != null) { - String debuggable = application.getDebuggable().getValue(); - BooleanValueConverter booleanValueConverter = BooleanValueConverter.getInstance(true); - if (debuggable == null || !booleanValueConverter.isTrue(debuggable)) { - Project project = facet.getModule().getProject(); - int result = Messages.showYesNoCancelDialog(project, AndroidBundle.message("android.manifest.debuggable.attribute.not.true.warning"), - CommonBundle.getWarningTitle(), - Messages.getWarningIcon()); - if (result == 0) { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - application.getDebuggable().setValue("true"); - } - }); - } - return result != 2; - } - } - return true; - } - private static boolean activateDdmsIfNeccessary(@NotNull AndroidFacet facet) { final Project project = facet.getModule().getProject(); final boolean ddmsEnabled = AndroidEnableDdmsAction.isDdmsEnabled(); From 818c97551cd51e657111852985f669c3bb9e0bb1 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Tue, 12 Apr 2011 20:07:37 +0400 Subject: [PATCH 007/102] IDEA-64014 support for debug builds --- .../actions/ExportSignedPackageAction.java | 59 ++------- .../android/compiler/AndroidAptCompiler.java | 13 +- .../android/compiler/AndroidCompileUtil.java | 43 ++++++- .../compiler/AndroidPackagingCompiler.java | 83 +++++++++--- .../AndroidResourcesPackagingCompiler.java | 119 ++++++++++++++++-- .../compiler/ResourcesValidityState.java | 2 +- .../compiler/tools/AndroidApkBuilder.java | 20 +-- .../android/exportSignedPackage/ApkStep.java | 32 +++-- .../exportSignedPackage/CheckModulePanel.java | 14 +-- 9 files changed, 262 insertions(+), 123 deletions(-) diff --git a/plugins/android/src/org/jetbrains/android/actions/ExportSignedPackageAction.java b/plugins/android/src/org/jetbrains/android/actions/ExportSignedPackageAction.java index 41a929ec24b0..33b1181cff0b 100644 --- a/plugins/android/src/org/jetbrains/android/actions/ExportSignedPackageAction.java +++ b/plugins/android/src/org/jetbrains/android/actions/ExportSignedPackageAction.java @@ -21,14 +21,8 @@ import com.intellij.facet.ProjectFacetManager; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataKeys; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.compiler.CompileContext; -import com.intellij.openapi.compiler.CompileScope; -import com.intellij.openapi.compiler.CompileStatusNotification; -import com.intellij.openapi.compiler.CompilerManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.ui.Messages; import org.jetbrains.android.exportSignedPackage.CheckModulePanel; import org.jetbrains.android.exportSignedPackage.ExportSignedPackageWizard; import org.jetbrains.android.facet.AndroidFacet; @@ -51,55 +45,18 @@ public class ExportSignedPackageAction extends AnAction { e.getPresentation().setEnabled(project != null && ProjectFacetManager.getInstance(project).getFacets(AndroidFacet.ID).size() > 0); } - private static void makeProjectIfNeccessaryAndRun(final Project project, final Runnable afterAction) { - final CompilerManager manager = CompilerManager.getInstance(project); - final CompileScope compileScope = manager.createProjectCompileScope(project); - if (!manager.isUpToDate(compileScope)) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - public void run() { - final int result = Messages.showYesNoDialog(project, AndroidBundle.message("android.export.signed.package.make.question"), - AndroidBundle.message("android.export.signed.package.action.text"), - Messages.getQuestionIcon()); - if (result == 0) { - manager.make(compileScope, new CompileStatusNotification() { - public void finished(boolean aborted, int errors, int warnings, CompileContext compileContext) { - if (!aborted && errors == 0) { - afterAction.run(); - } - } - }); - } - else { - afterAction.run(); - } - } - }); - } - else { - ApplicationManager.getApplication().invokeLater(afterAction); - } - } - @Override public void actionPerformed(AnActionEvent e) { final Project project = e.getData(DataKeys.PROJECT); assert project != null; - final Runnable exportRunnable = new Runnable() { - public void run() { - List facets = ProjectFacetManager.getInstance(project).getFacets(AndroidFacet.ID); - assert facets.size() > 0; - if (facets.size() == 1) { - if (!checkFacet(facets.get(0))) return; - } - ExportSignedPackageWizard wizard = new ExportSignedPackageWizard(project, facets); - wizard.show(); - } - }; - ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { - public void run() { - makeProjectIfNeccessaryAndRun(project, exportRunnable); - } - }); + + List facets = ProjectFacetManager.getInstance(project).getFacets(AndroidFacet.ID); + assert facets.size() > 0; + if (facets.size() == 1) { + if (!checkFacet(facets.get(0))) return; + } + ExportSignedPackageWizard wizard = new ExportSignedPackageWizard(project, facets); + wizard.show(); } private static boolean checkFacet(final AndroidFacet facet) { diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java index 193c9f9c0f2a..7dec4b76a687 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java @@ -114,7 +114,7 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { try { Map> messages = AndroidApt - .compile(aptItem.myAndroidTarget, aptItem.myManifestPath, aptItem.mySourceRootPath, aptItem.myResourcesPaths, + .compile(aptItem.myAndroidTarget, aptItem.myManifestFile.getPath(), aptItem.mySourceRootPath, aptItem.myResourcesPaths, aptItem.myAssetsPath, aptItem.myCustomPackage ? aptItem.myPackage : null ); AndroidCompileUtil.addMessages(context, messages); @@ -169,7 +169,7 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { final static class AptGenerationItem implements GenerationItem { final Module myModule; - final String myManifestPath; + final VirtualFile myManifestFile; final String[] myResourcesPaths; final String myAssetsPath; final String mySourceRootPath; @@ -179,7 +179,7 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { final boolean myCustomPackage; private AptGenerationItem(@NotNull Module module, - @NotNull String manifestPath, + @NotNull VirtualFile manifestFile, @NotNull String[] resourcesPaths, @Nullable String assetsPath, @NotNull String sourceRootPath, @@ -187,7 +187,7 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { @NotNull String aPackage, boolean customPackage) { myModule = module; - myManifestPath = manifestPath; + myManifestFile = manifestFile; myResourcesPaths = resourcesPaths; myAssetsPath = assetsPath; mySourceRootPath = sourceRootPath; @@ -290,12 +290,11 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { AndroidCompileUtil.createSourceRootIfNotExist(sourceRootPath, module); String assetsDirPath = assetsDir != null ? assetsDir.getPath() : null; - String manifestPath = manifestFile.getPath(); - items.add(new AptGenerationItem(module, manifestPath, resPaths, assetsDirPath, sourceRootPath, target, + items.add(new AptGenerationItem(module, manifestFile, resPaths, assetsDirPath, sourceRootPath, target, packageName, false)); for (String libPackage : AndroidUtils.getDepLibsPackages(module)) { - items.add(new AptGenerationItem(module, manifestPath, resPaths, assetsDirPath, sourceRootPath, target, + items.add(new AptGenerationItem(module, manifestFile, resPaths, assetsDirPath, sourceRootPath, target, libPackage, true)); } } diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java index fd3e4cecca9f..45a7c88c4e2a 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java @@ -34,11 +34,9 @@ import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.*; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.Key; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vfs.LocalFileSystem; -import com.intellij.openapi.vfs.ReadonlyStatusHandler; -import com.intellij.openapi.vfs.VfsUtil; -import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.*; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiFile; @@ -64,10 +62,17 @@ public class AndroidCompileUtil { private static final Pattern ourMessagePattern = Pattern.compile("(.+):(\\d+):.+"); + private static final Key RELEASE_BUILD_KEY = new Key("RELEASE_BUILD_KEY"); + private AndroidCompileUtil() { } static void addMessages(final CompileContext context, final Map> messages) { + addMessages(context, messages, null); + } + + static void addMessages(final CompileContext context, final Map> messages, + @Nullable final Map presentableFilesMap) { ApplicationManager.getApplication().runReadAction(new Runnable() { public void run() { if (context.getProject().isDisposed()) return; @@ -80,7 +85,7 @@ public class AndroidCompileUtil { if (matcher.matches()) { String fileName = matcher.group(1); if (new File(fileName).exists()) { - url = "file://" + fileName; + url = getPresentableFile("file://" + fileName, presentableFilesMap); line = Integer.parseInt(matcher.group(2)); } } @@ -91,6 +96,25 @@ public class AndroidCompileUtil { }); } + @NotNull + private static String getPresentableFile(@NotNull String url, @Nullable Map presentableFilesMap) { + final VirtualFile file = VirtualFileManager.getInstance().findFileByUrl(url); + if (file == null) { + return url; + } + + if (presentableFilesMap == null) { + return url; + } + + for (Map.Entry entry : presentableFilesMap.entrySet()) { + if (file == entry.getValue()) { + return entry.getKey().getUrl(); + } + } + return url; + } + private static void collectChildrenRecursively(@NotNull VirtualFile root, @NotNull VirtualFile anchor, @NotNull Collection result) { @@ -364,4 +388,13 @@ public class AndroidCompileUtil { RunConfiguration runConfiguration = CompileStepBeforeRun.getRunConfiguration(context); return !(runConfiguration instanceof JUnitConfiguration); } + + public static boolean isReleaseBuild(@NotNull CompileContext context) { + final Boolean value = context.getCompileScope().getUserData(RELEASE_BUILD_KEY); + return value != null && value.booleanValue(); + } + + public static void setReleaseBuild(@NotNull CompileScope compileScope) { + compileScope.putUserData(RELEASE_BUILD_KEY, Boolean.TRUE); + } } diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidPackagingCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidPackagingCompiler.java index a7738f792ee7..0db7a7adc348 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidPackagingCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidPackagingCompiler.java @@ -48,6 +48,8 @@ import java.util.*; */ public class AndroidPackagingCompiler implements PackagingCompiler { + public static final String UNSIGNED_SUFFIX = ".unsigned"; + public void processOutdatedItem(CompileContext context, String url, @Nullable ValidityState state) { } @@ -125,13 +127,12 @@ public class AndroidPackagingCompiler implements PackagingCompiler { AndroidBundle.message("android.compilation.error.apk.path.not.specified", module.getName()), null, -1, -1); continue; } - AptPackagingItem item = - new AptPackagingItem(sdkPath, manifestFile, resPackagePath, outputPath, configuration.GENERATE_UNSIGNED_APK, module); - item.setNativeLibsFolders(collectNativeLibsFolders(facet)); - item.setClassesDexPath(classesDexPath); - item.setSourceRoots(sourceRoots); - item.setExternalLibraries(externalJars); - items.add(item); + items.add(createItem(module, facet, manifestFile, sourceRoots, externalJars, resPackagePath, classesDexPath, sdkPath, + outputPath, false)); + + items.add(createItem(module, facet, manifestFile, sourceRoots, externalJars, + resPackagePath + AndroidResourcesPackagingCompiler.RELEASE_SUFFIX, classesDexPath, sdkPath, + outputPath + UNSIGNED_SUFFIX, true)); } } } @@ -139,6 +140,24 @@ public class AndroidPackagingCompiler implements PackagingCompiler { return items.toArray(new ProcessingItem[items.size()]); } + private static AptPackagingItem createItem(Module module, + AndroidFacet facet, + VirtualFile manifestFile, + VirtualFile[] sourceRoots, + VirtualFile[] externalJars, + String resPackagePath, + String classesDexPath, + String sdkPath, + String outputPath, + boolean unsigned) { + AptPackagingItem item = new AptPackagingItem(sdkPath, manifestFile, resPackagePath, outputPath, unsigned, module); + item.setNativeLibsFolders(collectNativeLibsFolders(facet)); + item.setClassesDexPath(classesDexPath); + item.setSourceRoots(sourceRoots); + item.setExternalLibraries(externalJars); + return item; + } + @NotNull private static VirtualFile[] collectNativeLibsFolders(AndroidFacet facet) { List result = new ArrayList(); @@ -179,11 +198,13 @@ public class AndroidPackagingCompiler implements PackagingCompiler { continue; } + if (!shouldGenerateApk(item.myModule, context, item.isUnsigned())) { + continue; + } + try { - - String[] externalLibPaths = getPaths(item.getExternalLibraries()); - - final Map> apkuBuilderMessages = AndroidApkBuilder + final String[] externalLibPaths = getPaths(item.getExternalLibraries()); + final Map> messages = AndroidApkBuilder .execute(item.mySdkPath, item.getResPackagePath(), item.getClassesDexPath(), @@ -191,9 +212,8 @@ public class AndroidPackagingCompiler implements PackagingCompiler { externalLibPaths, item.getNativeLibsFolders(), item.getFinalPath(), - item.isGenerateUnsignedApk()); - - AndroidCompileUtil.addMessages(context, apkuBuilderMessages); + item.isUnsigned()); + AndroidCompileUtil.addMessages(context, messages); } catch (final IOException e) { ApplicationManager.getApplication().runReadAction(new Runnable() { @@ -210,6 +230,29 @@ public class AndroidPackagingCompiler implements PackagingCompiler { return result.toArray(new ProcessingItem[result.size()]); } + public static boolean shouldGenerateApk(Module module, CompileContext context, boolean unsigned) { + final boolean releaseBuild = AndroidCompileUtil.isReleaseBuild(context); + + if (!unsigned) { + return !releaseBuild; + } + + final AndroidFacet facet = AndroidFacet.getInstance(module); + if (facet == null) { + return true; + } + + if (releaseBuild) { + return true; + } + + if (facet.getConfiguration().GENERATE_UNSIGNED_APK) { + return true; + } + + return false; + } + @NotNull public String getDescription() { return "Android Packaging Compiler"; @@ -232,20 +275,20 @@ public class AndroidPackagingCompiler implements PackagingCompiler { private VirtualFile[] myNativeLibsFolders; private VirtualFile[] mySourceRoots; private VirtualFile[] myExternalLibraries; - private final boolean myGenerateUnsignedApk; + private final boolean myUnsigned; private final Module myModule; private AptPackagingItem(String sdkPath, @NotNull VirtualFile manifestFile, @NotNull String resPackagePath, @NotNull String finalPath, - boolean generateUnsignedApk, + boolean unsigned, @NotNull Module module) { mySdkPath = sdkPath; myManifestFile = manifestFile; myResPackagePath = resPackagePath; myFinalPath = finalPath; - myGenerateUnsignedApk = generateUnsignedApk; + myUnsigned = unsigned; myModule = module; } @@ -302,12 +345,12 @@ public class AndroidPackagingCompiler implements PackagingCompiler { @Nullable public ValidityState getValidityState() { - return new MyValidityState(myManifestFile, myResPackagePath, myClassesDexPath, myFinalPath, myGenerateUnsignedApk, mySourceRoots, + return new MyValidityState(myManifestFile, myResPackagePath, myClassesDexPath, myFinalPath, myUnsigned, mySourceRoots, myExternalLibraries, myNativeLibsFolders); } - public boolean isGenerateUnsignedApk() { - return myGenerateUnsignedApk; + public boolean isUnsigned() { + return myUnsigned; } } diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidResourcesPackagingCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidResourcesPackagingCompiler.java index f3845c0775be..90567df2deaf 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidResourcesPackagingCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidResourcesPackagingCompiler.java @@ -17,21 +17,30 @@ package org.jetbrains.android.compiler; import com.android.sdklib.IAndroidTarget; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.compiler.*; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.android.compiler.tools.AndroidApt; +import org.jetbrains.android.dom.manifest.Application; +import org.jetbrains.android.dom.manifest.Manifest; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.AndroidFacetConfiguration; import org.jetbrains.android.facet.AndroidRootUtil; import org.jetbrains.android.util.AndroidBundle; +import org.jetbrains.android.util.AndroidUtils; import org.jetbrains.annotations.NotNull; import java.io.DataInput; +import java.io.DataOutput; import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -39,6 +48,10 @@ import java.util.Map; * @author Eugene.Kudelevsky */ public class AndroidResourcesPackagingCompiler implements ClassPostProcessingCompiler { + private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.compiler.AndroidResourcesPackagingCompiler"); + + public static final String RELEASE_SUFFIX = ".release"; + @NotNull @Override public ProcessingItem[] getProcessingItems(CompileContext context) { @@ -65,7 +78,9 @@ public class AndroidResourcesPackagingCompiler implements ClassPostProcessingCom context.addMessage(CompilerMessageCategory.WARNING, "Resource directory not found for module " + module.getName(), null, -1, -1); } - items.add(new MyItem(module, target, manifestFile, resourcesDirPaths, assetsDirPath, outputPath)); + + items.add(new MyItem(module, target, manifestFile, resourcesDirPaths, assetsDirPath, outputPath, false)); + items.add(new MyItem(module, target, manifestFile, resourcesDirPaths, assetsDirPath, outputPath + RELEASE_SUFFIX, true)); } } } @@ -92,12 +107,32 @@ public class AndroidResourcesPackagingCompiler implements ClassPostProcessingCom continue; } + if (!AndroidPackagingCompiler.shouldGenerateApk(item.myModule, context, item.myReleasePackage)) { + continue; + } + + final VirtualFile preprocessedManifestFile; + try { + preprocessedManifestFile = item.myReleasePackage + ? item.myManifestFile + : copyManifestAndSetDebuggableToTrue(item.myModule, item.myManifestFile); + } + catch (IOException e) { + LOG.info(e); + context.addMessage(CompilerMessageCategory.ERROR, "Cannot preprocess AndroidManifest.xml for debug build", + item.myManifestFile.getUrl(), -1, -1); + continue; + } + + final Map presentableFilesMap = Collections.singletonMap(item.myManifestFile, preprocessedManifestFile); + try { Map> messages = AndroidApt.packageResources(item.myAndroidTarget, - item.myManifestFile.getPath(), - item.myResourceDirPaths, item.myAssetsDirPath, + preprocessedManifestFile.getPath(), + item.myResourceDirPaths, + item.myAssetsDirPath, item.myOutputPath); - AndroidCompileUtil.addMessages(context, messages); + AndroidCompileUtil.addMessages(context, messages, presentableFilesMap); } catch (final IOException e) { ApplicationManager.getApplication().runReadAction(new Runnable() { @@ -114,6 +149,58 @@ public class AndroidResourcesPackagingCompiler implements ClassPostProcessingCom return result.toArray(new ProcessingItem[result.size()]); } + private static VirtualFile copyManifestAndSetDebuggableToTrue(@NotNull final Module module, @NotNull final VirtualFile manifestFile) + throws IOException { + + final File dir = FileUtil.createTempDirectory("android_manifest_copy", "tmp"); + final VirtualFile vDir = LocalFileSystem.getInstance().findFileByIoFile(dir); + if (vDir == null) { + throw new IOException("Cannot create temp directory for manifest copy"); + } + + final VirtualFile[] manifestFileCopy = new VirtualFile[1]; + + ApplicationManager.getApplication().invokeAndWait(new Runnable() { + @Override + public void run() { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + try { + manifestFileCopy[0] = manifestFile.copy(module.getProject(), vDir, manifestFile.getName()); + } + catch (IOException e) { + LOG.info(e); + return; + } + + if (manifestFileCopy[0] == null) { + return; + } + + final Manifest manifestInCopy = AndroidUtils.loadDomElement(module, manifestFileCopy[0], Manifest.class); + if (manifestInCopy == null) { + return; + } + + final Application applicationInCopy = manifestInCopy.getApplication(); + if (applicationInCopy == null) { + return; + } + applicationInCopy.getDebuggable().setValue(Boolean.TRUE.toString()); + } + }); + + ApplicationManager.getApplication().saveAll(); + } + }, ModalityState.defaultModalityState()); + + if (manifestFileCopy[0] == null) { + throw new IOException("Cannot copy manifest file to " + vDir.getPath()); + } + return manifestFileCopy[0]; + } + @NotNull @Override public String getDescription() { @@ -139,13 +226,15 @@ public class AndroidResourcesPackagingCompiler implements ClassPostProcessingCom final String myOutputPath; private final boolean myFileExists; + private final boolean myReleasePackage; private MyItem(Module module, IAndroidTarget androidTarget, VirtualFile manifestFile, String[] resourceDirPaths, String assetsDirPath, - String outputPath) { + String outputPath, + boolean releasePackage) { myModule = module; myAndroidTarget = androidTarget; myManifestFile = manifestFile; @@ -153,6 +242,7 @@ public class AndroidResourcesPackagingCompiler implements ClassPostProcessingCom myAssetsDirPath = assetsDirPath; myOutputPath = outputPath; myFileExists = new File(outputPath).exists(); + myReleasePackage = releasePackage; } @NotNull @@ -164,20 +254,23 @@ public class AndroidResourcesPackagingCompiler implements ClassPostProcessingCom @Override public ValidityState getValidityState() { - return new MyValidityState(myModule, myFileExists); + return new MyValidityState(myModule, myFileExists, myReleasePackage); } } private static class MyValidityState extends ResourcesValidityState { private final boolean myOutputFileExists; + private final boolean myReleaseBuild; - public MyValidityState(Module module, boolean outputFileExists) { + public MyValidityState(Module module, boolean outputFileExists, boolean releaseBuild) { super(module); myOutputFileExists = outputFileExists; + myReleaseBuild = releaseBuild; } public MyValidityState(DataInput is) throws IOException { super(is); + myReleaseBuild = is.readBoolean(); myOutputFileExists = true; } @@ -186,10 +279,20 @@ public class AndroidResourcesPackagingCompiler implements ClassPostProcessingCom if (!(otherState instanceof MyValidityState)) { return false; } - if (myOutputFileExists != ((MyValidityState)otherState).myOutputFileExists) { + final MyValidityState otherState1 = (MyValidityState)otherState; + if (myOutputFileExists != otherState1.myOutputFileExists) { + return false; + } + if (myReleaseBuild != otherState1.myReleaseBuild) { return false; } return super.equalsTo(otherState); } + + @Override + public void save(DataOutput os) throws IOException { + super.save(os); + os.writeBoolean(myReleaseBuild); + } } } diff --git a/plugins/android/src/org/jetbrains/android/compiler/ResourcesValidityState.java b/plugins/android/src/org/jetbrains/android/compiler/ResourcesValidityState.java index 4aa5018fbf59..80f593a39a59 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/ResourcesValidityState.java +++ b/plugins/android/src/org/jetbrains/android/compiler/ResourcesValidityState.java @@ -49,7 +49,7 @@ public class ResourcesValidityState implements ValidityState { IAndroidTarget target = platform != null ? platform.getTarget() : null; myAndroidTargetName = target != null ? target.getFullName() : ""; - VirtualFile manifestFile = AndroidRootUtil.getManifestFile(module); + VirtualFile manifestFile = AndroidRootUtil.getManifestFileForCompiler(facet); if (manifestFile != null) { myResourceTimestamps.put(manifestFile.getPath(), manifestFile.getTimeStamp()); } diff --git a/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java b/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java index 1ab3d84bc543..1c011cff99ff 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java +++ b/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java @@ -43,16 +43,13 @@ import java.util.*; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; -import static com.intellij.openapi.compiler.CompilerMessageCategory.ERROR; -import static com.intellij.openapi.compiler.CompilerMessageCategory.INFORMATION; -import static com.intellij.openapi.compiler.CompilerMessageCategory.WARNING; +import static com.intellij.openapi.compiler.CompilerMessageCategory.*; /** * @author yole */ public class AndroidApkBuilder { private static final String UNALIGNED_SUFFIX = ".unaligned"; - private static final String UNSIGNED_SUFFIX = ".unsigned"; private AndroidApkBuilder() { } @@ -114,18 +111,13 @@ public class AndroidApkBuilder { @NotNull String[] externalJars, @NotNull VirtualFile[] nativeLibsFolders, @NotNull String finalApk, - boolean generateUnsignedApk) throws IOException { - String unsignedApk = finalApk + UNSIGNED_SUFFIX; - - Map> map; - if (generateUnsignedApk) { - map = filterUsingKeystoreMessages( - finalPackage(resPackagePath, dexPath, sourceRoots, externalJars, nativeLibsFolders, unsignedApk, false)); - } - else { - map = new HashMap>(); + boolean unsigned) throws IOException { + if (unsigned) { + return filterUsingKeystoreMessages( + finalPackage(resPackagePath, dexPath, sourceRoots, externalJars, nativeLibsFolders, finalApk, false)); } + final Map> map = new HashMap>(); final String zipAlignPath = sdkPath + File.separator + AndroidUtils.toolPath(SdkConstants.FN_ZIPALIGN); boolean withAlignment = new File(zipAlignPath).exists(); String unalignedApk = finalApk + UNALIGNED_SUFFIX; diff --git a/plugins/android/src/org/jetbrains/android/exportSignedPackage/ApkStep.java b/plugins/android/src/org/jetbrains/android/exportSignedPackage/ApkStep.java index 2779fd25bbca..13e67e9d4f3d 100644 --- a/plugins/android/src/org/jetbrains/android/exportSignedPackage/ApkStep.java +++ b/plugins/android/src/org/jetbrains/android/exportSignedPackage/ApkStep.java @@ -27,7 +27,10 @@ import com.intellij.execution.process.ProcessEvent; import com.intellij.ide.util.PropertiesComponent; import com.intellij.ide.wizard.CommitStepException; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.compiler.CompilerPaths; +import com.intellij.openapi.compiler.CompileContext; +import com.intellij.openapi.compiler.CompileScope; +import com.intellij.openapi.compiler.CompileStatusNotification; +import com.intellij.openapi.compiler.CompilerManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; @@ -38,6 +41,8 @@ import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.android.compiler.AndroidCompileUtil; +import org.jetbrains.android.compiler.AndroidPackagingCompiler; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.sdk.AndroidPlatform; import org.jetbrains.android.util.AndroidBundle; @@ -166,7 +171,8 @@ class ApkStep extends ExportSignedPackageWizardStep { assert certificate != null; SignedJarBuilder builder = new SignedJarBuilder(fos, privateKey, certificate); Module module = myWizard.getFacet().getModule(); - String srcApkPath = CompilerPaths.getModuleOutputPath(module, false) + '/' + module.getName() + ".apk"; + //String srcApkPath = CompilerPaths.getModuleOutputPath(module, false) + '/' + module.getName() + ".apk"; + String srcApkPath = myWizard.getFacet().getApkPath() + AndroidPackagingCompiler.UNSIGNED_SUFFIX; FileInputStream fis = new FileInputStream(new File(FileUtil.toSystemDependentName(srcApkPath))); try { builder.writeZip(fis, null); @@ -255,11 +261,23 @@ class ApkStep extends ExportSignedPackageWizardStep { catch (Exception e) { throw new CommitStepException(e.getMessage()); } - String title = AndroidBundle.message("android.extract.package.task.title"); - ProgressManager.getInstance().run(new Task.Backgroundable(myWizard.getProject(), title, true, null) { - - public void run(@NotNull ProgressIndicator indicator) { - createAndAlignApk(apkPath); + + final CompilerManager manager = CompilerManager.getInstance(myWizard.getProject()); + final CompileScope compileScope = manager.createModuleCompileScope(facet.getModule(), true); + AndroidCompileUtil.setReleaseBuild(compileScope); + + manager.make(compileScope, new CompileStatusNotification() { + public void finished(boolean aborted, int errors, int warnings, CompileContext compileContext) { + if (aborted || errors != 0) { + return; + } + + final String title = AndroidBundle.message("android.extract.package.task.title"); + ProgressManager.getInstance().run(new Task.Backgroundable(myWizard.getProject(), title, true, null) { + public void run(@NotNull ProgressIndicator indicator) { + createAndAlignApk(apkPath); + } + }); } }); } diff --git a/plugins/android/src/org/jetbrains/android/exportSignedPackage/CheckModulePanel.java b/plugins/android/src/org/jetbrains/android/exportSignedPackage/CheckModulePanel.java index c23f62b6bd93..a0ea8f4a2801 100644 --- a/plugins/android/src/org/jetbrains/android/exportSignedPackage/CheckModulePanel.java +++ b/plugins/android/src/org/jetbrains/android/exportSignedPackage/CheckModulePanel.java @@ -20,17 +20,12 @@ import com.intellij.openapi.compiler.DummyCompileContext; import com.intellij.openapi.module.Module; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.VerticalFlowLayout; -import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.xml.converters.values.BooleanValueConverter; -import org.jetbrains.android.dom.manifest.Application; -import org.jetbrains.android.dom.manifest.Manifest; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.util.AndroidBundle; import javax.swing.*; import java.awt.*; -import java.io.File; /** * @author Eugene.Kudelevsky @@ -49,25 +44,24 @@ public class CheckModulePanel extends JPanel { final DummyCompileContext compileContext = DummyCompileContext.getInstance(); VirtualFile outputDirectory = compileContext.getModuleOutputDirectory(module); if (outputDirectory != null) { - String outputOsPath = FileUtil.toSystemDependentName(outputDirectory.getPath()); - String apkFilePath = outputOsPath + File.separator + module.getName() + ".apk"; + /*String apkFilePath = facet.getApkPath(); File f = new File(apkFilePath); if (!f.isFile()) { addError(AndroidBundle.message("android.file.not.exist.error", f.getPath())); - } + }*/ } else { addError(AndroidBundle.message("android.unable.to.get.output.directory.error")); } - Manifest manifest = facet.getManifest(); + /*Manifest manifest = facet.getManifest(); assert manifest != null; Application application = manifest.getApplication(); assert application != null; String debuggable = application.getDebuggable().getValue(); if (debuggable != null && BooleanValueConverter.getInstance(true).isTrue(debuggable)) { addWarning(AndroidBundle.message("android.export.signed.package.debuggable.warning")); - } + }*/ } public boolean hasError() { From cc023d603499c6540840b6054180acd72cf4adb4 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Tue, 12 Apr 2011 22:20:56 +0200 Subject: [PATCH 008/102] new "Add Array Creation Expression" intention --- .../IntentionPowerPak/src/META-INF/plugin.xml | 5 ++ .../siyeh/IntentionPowerPackBundle.properties | 2 + .../AddArrayCreationExpressionIntention.java | 55 +++++++++++++++++++ .../ArrayCreationExpressionPredicate.java | 37 +++++++++++++ .../after.java.template | 3 + .../before.java.template | 3 + .../description.html | 15 +++++ 7 files changed, 120 insertions(+) create mode 100644 plugins/IntentionPowerPak/src/com/siyeh/ipp/braces/AddArrayCreationExpressionIntention.java create mode 100644 plugins/IntentionPowerPak/src/com/siyeh/ipp/braces/ArrayCreationExpressionPredicate.java create mode 100644 plugins/IntentionPowerPak/src/intentionDescriptions/AddArrayCreationExpressionIntention/after.java.template create mode 100644 plugins/IntentionPowerPak/src/intentionDescriptions/AddArrayCreationExpressionIntention/before.java.template create mode 100644 plugins/IntentionPowerPak/src/intentionDescriptions/AddArrayCreationExpressionIntention/description.html diff --git a/plugins/IntentionPowerPak/src/META-INF/plugin.xml b/plugins/IntentionPowerPak/src/META-INF/plugin.xml index eadf9c617e86..52b01ff7b6c2 100644 --- a/plugins/IntentionPowerPak/src/META-INF/plugin.xml +++ b/plugins/IntentionPowerPak/src/META-INF/plugin.xml @@ -150,6 +150,11 @@ --> + + com.siyeh.ipp.braces.AddArrayCreationExpressionIntention + intention.category.declaration + + com.siyeh.ipp.decls.SimplifyVariableIntention intention.category.declaration diff --git a/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties b/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties index e907ff127049..c77e8e25ceb2 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties +++ b/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties @@ -145,6 +145,7 @@ split.multicatch.intention.family.name=Split Multi-Catch into Separate Catch Blo replace.arm.with.try.finally.intention.name=Replace Automatic Resource Management with 'try finally' replace.arm.with.try.finally.intention.family.name=Replace Automatic Resource Management with Try-Finally obscure.thrown.exceptions.intention.family.name=Replace Exceptions in Throws Clause with Single More General Exception +add.array.creation.expression.intention.family.name=Add Array Creation Expression #hand made demorgans.intention.name1=Replace '\\&\\&' with '||' @@ -177,6 +178,7 @@ swap.method.call.arguments.intention.name=Swap ''{0}'' and ''{1}'' flip.setter.call.intention.name=Flip Setter Call adapter.to.listener.intention.name=Replace extension of ''{0}'' with ''Listener'' implementation obscure.thrown.exceptions.intention.name=Replace with ''throws {0}'' +add.array.creation.expression.intention.name=Add ''new {0}'' #categories intention.category.numbers=Numbers diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/braces/AddArrayCreationExpressionIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/braces/AddArrayCreationExpressionIntention.java new file mode 100644 index 000000000000..b0b5ee223aec --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/braces/AddArrayCreationExpressionIntention.java @@ -0,0 +1,55 @@ +/* + * Copyright 2011 Bas Leijdekkers + * + * 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.siyeh.ipp.braces; + +import com.intellij.psi.PsiArrayInitializerExpression; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiType; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.IntentionPowerPackBundle; +import com.siyeh.ipp.base.MutablyNamedIntention; +import com.siyeh.ipp.base.PsiElementPredicate; +import org.jetbrains.annotations.NotNull; + +public class AddArrayCreationExpressionIntention extends MutablyNamedIntention { + + @NotNull + protected PsiElementPredicate getElementPredicate() { + return new ArrayCreationExpressionPredicate(); + } + + protected String getTextForElement(PsiElement element) { + final PsiArrayInitializerExpression arrayInitializerExpression = + (PsiArrayInitializerExpression)element; + final PsiType type = arrayInitializerExpression.getType(); + assert type != null; + return IntentionPowerPackBundle.message("add.array.creation.expression.intention.name", type.getPresentableText()); + } + + protected void processIntention(@NotNull PsiElement element) + throws IncorrectOperationException { + final PsiArrayInitializerExpression arrayInitializerExpression = + (PsiArrayInitializerExpression)element; + final PsiType type = arrayInitializerExpression.getType(); + if (type == null) { + return; + } + final String typeText = type.getCanonicalText(); + final String newExpressionText = + "new " + typeText + arrayInitializerExpression.getText(); + replaceExpression(newExpressionText, arrayInitializerExpression); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/braces/ArrayCreationExpressionPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/braces/ArrayCreationExpressionPredicate.java new file mode 100644 index 000000000000..0b93852a877a --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/braces/ArrayCreationExpressionPredicate.java @@ -0,0 +1,37 @@ +/* + * Copyright 2011 Bas Leijdekkers + * + * 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.siyeh.ipp.braces; + +import com.intellij.psi.PsiArrayInitializerExpression; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiNewExpression; +import com.siyeh.ipp.base.PsiElementPredicate; +import org.jetbrains.annotations.NotNull; + +class ArrayCreationExpressionPredicate implements PsiElementPredicate { + + public boolean satisfiedBy(@NotNull PsiElement element) { + if (!(element instanceof PsiArrayInitializerExpression)) { + return false; + } + final PsiArrayInitializerExpression arrayInitializerExpression = (PsiArrayInitializerExpression)element; + if (arrayInitializerExpression.getType() == null) { + return false; + } + final PsiElement parent = element.getParent(); + return !(parent instanceof PsiNewExpression); + } +} diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/AddArrayCreationExpressionIntention/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/AddArrayCreationExpressionIntention/after.java.template new file mode 100644 index 000000000000..feec2a48e650 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/AddArrayCreationExpressionIntention/after.java.template @@ -0,0 +1,3 @@ +public class X { + private final String[] ss = new String[]{}; +} diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/AddArrayCreationExpressionIntention/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/AddArrayCreationExpressionIntention/before.java.template new file mode 100644 index 000000000000..a95d1e983b2e --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/AddArrayCreationExpressionIntention/before.java.template @@ -0,0 +1,3 @@ +public class X { + private final String[] ss = {}; +} diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/AddArrayCreationExpressionIntention/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/AddArrayCreationExpressionIntention/description.html new file mode 100644 index 000000000000..47e0628b84b1 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/AddArrayCreationExpressionIntention/description.html @@ -0,0 +1,15 @@ + From 19375d608623a8a99031f3b5684fb036201ac287 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Tue, 12 Apr 2011 15:59:17 +0400 Subject: [PATCH 009/102] [hg] Notification about successful push. HgPushAction: retrieve number of pushed commits. HgCommandResultNotifier: able to notify about success. --- .../action/HgCommandResultNotifier.java | 18 +++++++--- .../hg4idea/action/HgCreateTagAction.java | 2 +- .../zmlx/hg4idea/action/HgMqRebaseAction.java | 2 +- .../org/zmlx/hg4idea/action/HgPullAction.java | 2 +- .../org/zmlx/hg4idea/action/HgPushAction.java | 36 ++++++++++++++++++- .../HgSwitchWorkingDirectoryAction.java | 2 +- 6 files changed, 52 insertions(+), 10 deletions(-) diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommandResultNotifier.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommandResultNotifier.java index 21b977587f73..a89a642854c7 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommandResultNotifier.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommandResultNotifier.java @@ -12,31 +12,39 @@ // limitations under the License. package org.zmlx.hg4idea.action; +import com.intellij.notification.Notification; +import com.intellij.notification.NotificationType; +import com.intellij.notification.Notifications; import com.intellij.openapi.project.Project; import com.intellij.vcsUtil.VcsUtil; import org.apache.commons.lang.StringUtils; +import org.jetbrains.annotations.Nullable; +import org.zmlx.hg4idea.HgErrorUtil; +import org.zmlx.hg4idea.HgVcs; import org.zmlx.hg4idea.execution.HgCommandResult; import java.util.List; final class HgCommandResultNotifier { - private final Project project; + private final Project myProject; HgCommandResultNotifier(Project project) { - this.project = project; + myProject = project; } - public void process(HgCommandResult result) { + public void process(HgCommandResult result, @Nullable String successTitle, @Nullable String successDescription) { List out = result.getOutputLines(); List err = result.getErrorLines(); if (!out.isEmpty()) { - VcsUtil.showStatusMessage(project, out.get(out.size() - 1)); + VcsUtil.showStatusMessage(myProject, out.get(out.size() - 1)); } if (!err.isEmpty()) { VcsUtil.showErrorMessage( - project, "" + StringUtils.join(err, "
") + "", "Error" + myProject, "" + StringUtils.join(err, "
") + "", "Error" ); + } else if (!HgErrorUtil.isAbort(result) && successTitle != null && successDescription != null) { + Notifications.Bus.notify(new Notification(HgVcs.NOTIFICATION_GROUP_ID, successTitle, successDescription, NotificationType.INFORMATION), myProject); } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCreateTagAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCreateTagAction.java index af702917e2e1..ef97b082d720 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCreateTagAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCreateTagAction.java @@ -49,7 +49,7 @@ public class HgCreateTagAction extends HgAbstractGlobalAction { new HgTagCreateCommand(project, dialog.getRepository(), dialog.getTagName()).execute(new HgCommandResultHandler() { @Override public void process(@Nullable HgCommandResult result) { - new HgCommandResultNotifier(project).process(result); + new HgCommandResultNotifier(project).process(result, null, null); } }); } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgMqRebaseAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgMqRebaseAction.java index 82b398ca8483..6757d873c336 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgMqRebaseAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgMqRebaseAction.java @@ -64,7 +64,7 @@ public class HgMqRebaseAction extends HgAbstractGlobalAction { pullCommand.execute(new HgCommandResultHandler() { @Override public void process(@Nullable HgCommandResult result) { - new HgCommandResultNotifier(project).process(result); + new HgCommandResultNotifier(project).process(result, null, null); String currentBranch = new HgTagBranchCommand(project, repository).getCurrentBranch(); if (StringUtils.isBlank(currentBranch)) { diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPullAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPullAction.java index 15d705be9c6c..25da45b3e888 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPullAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPullAction.java @@ -54,7 +54,7 @@ public class HgPullAction extends HgAbstractGlobalAction { command.execute(new HgCommandResultHandler() { @Override public void process(@Nullable HgCommandResult result) { - new HgCommandResultNotifier(project).process(result); + new HgCommandResultNotifier(project).process(result, null, null); } }); } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPushAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPushAction.java index 838623bd2177..b4e70d27d85d 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPushAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPushAction.java @@ -12,17 +12,25 @@ // limitations under the License. package org.zmlx.hg4idea.action; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.Nullable; +import org.zmlx.hg4idea.HgErrorUtil; import org.zmlx.hg4idea.command.HgPushCommand; import org.zmlx.hg4idea.execution.HgCommandResult; import org.zmlx.hg4idea.execution.HgCommandResultHandler; import org.zmlx.hg4idea.ui.HgPushDialog; import java.util.Collection; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class HgPushAction extends HgAbstractGlobalAction { + private static final Logger LOG = Logger.getInstance(HgPushAction.class); + private static Pattern PUSH_COMMITS_PATTERN = Pattern.compile(".*added (\\d+) changesets.*"); protected HgGlobalCommandBuilder getHgGlobalCommandBuilder(final Project project) { return new HgGlobalCommandBuilder() { @@ -52,11 +60,37 @@ public class HgPushAction extends HgAbstractGlobalAction { command.execute(new HgCommandResultHandler() { @Override public void process(@Nullable HgCommandResult result) { - new HgCommandResultNotifier(project).process(result); + int commitsNum = getNumberOfPushedCommits(result); + String title = null; + String description = null; + if (commitsNum >= 0) { + title = "Pushed successfully"; + description = "Pushed " + commitsNum + " " + StringUtil.pluralize("commit", commitsNum) + "."; + } + new HgCommandResultNotifier(project).process(result, title, description); } }); } }; } + private static int getNumberOfPushedCommits(HgCommandResult result) { + if (!HgErrorUtil.isAbort(result)) { + final List outputLines = result.getOutputLines(); + for (String outputLine : outputLines) { + final Matcher matcher = PUSH_COMMITS_PATTERN.matcher(outputLine.trim()); + if (matcher.matches()) { + try { + return Integer.parseInt(matcher.group(1)); + } + catch (NumberFormatException e) { + LOG.info("getNumberOfPushedCommits ", e); + return -1; + } + } + } + } + return -1; + } + } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgSwitchWorkingDirectoryAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgSwitchWorkingDirectoryAction.java index d9d18ff94490..da7ea7417ed7 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgSwitchWorkingDirectoryAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgSwitchWorkingDirectoryAction.java @@ -61,7 +61,7 @@ public class HgSwitchWorkingDirectoryAction extends HgAbstractGlobalAction { @Override public void run() { HgCommandResult result = command.execute(); - new HgCommandResultNotifier(project).process(result); + new HgCommandResultNotifier(project).process(result, null, null); project.getMessageBus().syncPublisher(HgVcs.BRANCH_TOPIC).update(project); } }); From af0585f3404778a52c9d256685a8410a9c46d53f Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Wed, 13 Apr 2011 11:51:30 +0400 Subject: [PATCH 010/102] HgPushAction refactoring Transform to HgAction, get rid of HgBuilderCommands. HgPusher to show dialog and perform push, to be able to call it without action. --- .../src/org/zmlx/hg4idea/HgPusher.java | 97 +++++++++++++++++++ .../hg4idea/src/org/zmlx/hg4idea/HgUtil.java | 18 +++- .../action/HgAbstractGlobalAction.java | 19 +--- .../src/org/zmlx/hg4idea/action/HgAction.java | 67 +++++++++++++ .../action/HgCommandResultNotifier.java | 4 +- .../org/zmlx/hg4idea/action/HgPushAction.java | 79 +-------------- 6 files changed, 187 insertions(+), 97 deletions(-) create mode 100644 plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java create mode 100644 plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAction.java diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java new file mode 100644 index 000000000000..6d9932321be5 --- /dev/null +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java @@ -0,0 +1,97 @@ +/* + * Copyright 2000-2011 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.zmlx.hg4idea; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vcs.ProjectLevelVcsManager; +import org.jetbrains.annotations.Nullable; +import org.zmlx.hg4idea.action.HgCommandResultNotifier; +import org.zmlx.hg4idea.command.HgPushCommand; +import org.zmlx.hg4idea.execution.HgCommandResult; +import org.zmlx.hg4idea.execution.HgCommandResultHandler; +import org.zmlx.hg4idea.ui.HgPushDialog; + +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author Kirill Likhodedov + */ +public class HgPusher { + + private static final Logger LOG = Logger.getInstance(HgPusher.class); + private static Pattern PUSH_COMMITS_PATTERN = Pattern.compile(".*added (\\d+) changesets.*"); + + private final Project myProject; + private final ProjectLevelVcsManager myVcsManager; + + public HgPusher(Project project) { + myProject = project; + myVcsManager = ProjectLevelVcsManager.getInstance(project); + } + + public void showDialogAndPush() { + HgPushDialog dialog = new HgPushDialog(myProject); + dialog.setRoots(HgUtil.getHgRepositories(myProject)); + dialog.show(); + if (dialog.isOK()) { + push(myProject, dialog); + } + } + + private static void push(final Project project, HgPushDialog dialog) { + final HgPushCommand command = new HgPushCommand(project, dialog.getRepository(), dialog.getTarget()); + command.setRevision(dialog.getRevision()); + command.setForce(dialog.isForce()); + command.setBranch(dialog.getBranch()); + command.execute(new HgCommandResultHandler() { + @Override + public void process(@Nullable HgCommandResult result) { + int commitsNum = getNumberOfPushedCommits(result); + String title = null; + String description = null; + if (commitsNum >= 0) { + title = "Pushed successfully"; + description = "Pushed " + commitsNum + " " + StringUtil.pluralize("commit", commitsNum) + "."; + } + new HgCommandResultNotifier(project).process(result, title, description); + } + }); + } + + private static int getNumberOfPushedCommits(HgCommandResult result) { + if (!HgErrorUtil.isAbort(result)) { + final List outputLines = result.getOutputLines(); + for (String outputLine : outputLines) { + final Matcher matcher = PUSH_COMMITS_PATTERN.matcher(outputLine.trim()); + if (matcher.matches()) { + try { + return Integer.parseInt(matcher.group(1)); + } + catch (NumberFormatException e) { + LOG.info("getNumberOfPushedCommits ", e); + return -1; + } + } + } + } + return -1; + } + +} diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgUtil.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgUtil.java index 610c5281f4c3..9a8c4b6fc989 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgUtil.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgUtil.java @@ -20,9 +20,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.ShutDownTracker; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vcs.FilePath; -import com.intellij.openapi.vcs.FileStatus; -import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vcs.changes.ContentRevision; @@ -323,4 +321,18 @@ public abstract class HgUtil { return filePath; } } + + /** + * Returns all HG roots in the project. + */ + public static @NotNull List getHgRepositories(@NotNull Project project) { + final List repos = new LinkedList(); + for (VcsRoot root : ProjectLevelVcsManager.getInstance(project).getAllVcsRoots()) { + if (HgVcs.VCS_NAME.equals(root.vcs.getName())) { + repos.add(root.path); + } + } + return repos; + } + } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java index 5a08c2c6122e..e752629af847 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java @@ -15,19 +15,14 @@ package org.zmlx.hg4idea.action; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.intellij.openapi.vcs.ProjectLevelVcsManager; -import com.intellij.openapi.vcs.VcsRoot; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.HgUtil; -import org.zmlx.hg4idea.HgVcs; import org.zmlx.hg4idea.execution.HgCommandException; import java.lang.reflect.InvocationTargetException; import java.util.Collection; -import java.util.LinkedList; -import java.util.List; abstract class HgAbstractGlobalAction extends AnAction { @@ -41,7 +36,7 @@ abstract class HgAbstractGlobalAction extends AnAction { return; } - HgGlobalCommand command = getHgGlobalCommandBuilder(project).build(findRepos(project)); + HgGlobalCommand command = getHgGlobalCommandBuilder(project).build(HgUtil.getHgRepositories(project)); if (command == null) { return; } @@ -67,21 +62,9 @@ abstract class HgAbstractGlobalAction extends AnAction { Project project = PlatformDataKeys.PROJECT.getData(dataContext); if (project == null) { presentation.setEnabled(false); - return; } } - private List findRepos(Project project) { - List repos = new LinkedList(); - VcsRoot[] roots = ProjectLevelVcsManager.getInstance(project).getAllVcsRoots(); - for (VcsRoot root : roots) { - if (HgVcs.VCS_NAME.equals(root.vcs.getName())) { - repos.add(root.path); - } - } - return repos; - } - protected interface HgGlobalCommand { VirtualFile getRepo(); void execute() throws HgCommandException; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAction.java new file mode 100644 index 000000000000..b2f9c62cfe08 --- /dev/null +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAction.java @@ -0,0 +1,67 @@ +/* + * Copyright 2000-2011 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.zmlx.hg4idea.action; + +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.ProjectLevelVcsManager; +import com.intellij.openapi.vcs.VcsRoot; +import com.intellij.openapi.vfs.VirtualFile; +import org.zmlx.hg4idea.HgVcs; + +import java.util.LinkedList; +import java.util.List; + +/** + * @author Kirill Likhodedov + */ +public abstract class HgAction extends AnAction { + @Override + public void actionPerformed(AnActionEvent event) { + final DataContext dataContext = event.getDataContext(); + final Project project = PlatformDataKeys.PROJECT.getData(dataContext); + if (project == null) { + return; + } + + execute(project); + } + + @Override + public void update(AnActionEvent e) { + Presentation presentation = e.getPresentation(); + final DataContext dataContext = e.getDataContext(); + + Project project = PlatformDataKeys.PROJECT.getData(dataContext); + if (project == null) { + presentation.setEnabled(false); + } + } + + public abstract void execute(Project project); + + private static List findRepos(Project project) { + List repos = new LinkedList(); + VcsRoot[] roots = ProjectLevelVcsManager.getInstance(project).getAllVcsRoots(); + for (VcsRoot root : roots) { + if (HgVcs.VCS_NAME.equals(root.vcs.getName())) { + repos.add(root.path); + } + } + return repos; + } + +} diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommandResultNotifier.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommandResultNotifier.java index a89a642854c7..7b2aba879952 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommandResultNotifier.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommandResultNotifier.java @@ -25,11 +25,11 @@ import org.zmlx.hg4idea.execution.HgCommandResult; import java.util.List; -final class HgCommandResultNotifier { +public final class HgCommandResultNotifier { private final Project myProject; - HgCommandResultNotifier(Project project) { + public HgCommandResultNotifier(Project project) { myProject = project; } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPushAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPushAction.java index b4e70d27d85d..b55bfc50abf7 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPushAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgPushAction.java @@ -14,83 +14,14 @@ package org.zmlx.hg4idea.action; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.VirtualFile; -import org.jetbrains.annotations.Nullable; -import org.zmlx.hg4idea.HgErrorUtil; -import org.zmlx.hg4idea.command.HgPushCommand; -import org.zmlx.hg4idea.execution.HgCommandResult; -import org.zmlx.hg4idea.execution.HgCommandResultHandler; -import org.zmlx.hg4idea.ui.HgPushDialog; +import org.zmlx.hg4idea.HgPusher; -import java.util.Collection; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class HgPushAction extends HgAbstractGlobalAction { +public class HgPushAction extends HgAction { private static final Logger LOG = Logger.getInstance(HgPushAction.class); - private static Pattern PUSH_COMMITS_PATTERN = Pattern.compile(".*added (\\d+) changesets.*"); - protected HgGlobalCommandBuilder getHgGlobalCommandBuilder(final Project project) { - return new HgGlobalCommandBuilder() { - public HgGlobalCommand build(Collection repos) { - HgPushDialog dialog = new HgPushDialog(project); - dialog.setRoots(repos); - dialog.show(); - if (dialog.isOK()) { - return buildCommand(dialog, project); - } - return null; - } - }; - } - - private HgGlobalCommand buildCommand(final HgPushDialog dialog, final Project project) { - return new HgGlobalCommand() { - public VirtualFile getRepo() { - return dialog.getRepository(); - } - - public void execute() { - HgPushCommand command = new HgPushCommand(project, dialog.getRepository(), dialog.getTarget()); - command.setRevision(dialog.getRevision()); - command.setForce(dialog.isForce()); - command.setBranch(dialog.getBranch()); - command.execute(new HgCommandResultHandler() { - @Override - public void process(@Nullable HgCommandResult result) { - int commitsNum = getNumberOfPushedCommits(result); - String title = null; - String description = null; - if (commitsNum >= 0) { - title = "Pushed successfully"; - description = "Pushed " + commitsNum + " " + StringUtil.pluralize("commit", commitsNum) + "."; - } - new HgCommandResultNotifier(project).process(result, title, description); - } - }); - } - }; - } - - private static int getNumberOfPushedCommits(HgCommandResult result) { - if (!HgErrorUtil.isAbort(result)) { - final List outputLines = result.getOutputLines(); - for (String outputLine : outputLines) { - final Matcher matcher = PUSH_COMMITS_PATTERN.matcher(outputLine.trim()); - if (matcher.matches()) { - try { - return Integer.parseInt(matcher.group(1)); - } - catch (NumberFormatException e) { - LOG.info("getNumberOfPushedCommits ", e); - return -1; - } - } - } - } - return -1; + @Override + public void execute(final Project project) { + new HgPusher(project).showDialogAndPush(); } } From 621addf1b0b992a58ec400f1118652c6b8ab7c54 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Wed, 13 Apr 2011 11:52:11 +0400 Subject: [PATCH 011/102] IDEA-60254 "Commit and Push" button for Mercurial - HgCommitAndPushExecutor. --- .../hg4idea/src/org/zmlx/hg4idea/HgVcs.java | 10 ++++ .../provider/commit/HgCheckinEnvironment.java | 46 ++++++++++++------- .../commit/HgCommitAndPushExecutor.java | 43 +++++++++++++++++ 3 files changed, 83 insertions(+), 16 deletions(-) create mode 100644 plugins/hg4idea/src/org/zmlx/hg4idea/provider/commit/HgCommitAndPushExecutor.java diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java index bf1551d06c6c..a58acb43336b 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java @@ -33,6 +33,7 @@ import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vcs.RepositoryChangeListener; import com.intellij.openapi.vcs.annotate.AnnotationProvider; import com.intellij.openapi.vcs.changes.ChangeProvider; +import com.intellij.openapi.vcs.changes.CommitExecutor; import com.intellij.openapi.vcs.checkin.CheckinEnvironment; import com.intellij.openapi.vcs.diff.DiffProvider; import com.intellij.openapi.vcs.history.VcsHistoryProvider; @@ -53,6 +54,7 @@ import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.provider.*; import org.zmlx.hg4idea.provider.annotate.HgAnnotationProvider; import org.zmlx.hg4idea.provider.commit.HgCheckinEnvironment; +import org.zmlx.hg4idea.provider.commit.HgCommitAndPushExecutor; import org.zmlx.hg4idea.provider.update.HgIntegrateEnvironment; import org.zmlx.hg4idea.provider.update.HgUpdateEnvironment; import org.zmlx.hg4idea.ui.HgChangesetStatus; @@ -107,6 +109,7 @@ public class HgVcs extends AbstractVcs { private HgExecutableValidator myExecutableValidator; private final Object myExecutableValidatorLock = new Object(); private File myPromptHooksExtensionFile; + private CommitExecutor myCommitAndPushExecutor; public HgVcs(Project project, HgGlobalSettings globalSettings, HgProjectSettings projectSettings, @@ -126,6 +129,7 @@ public class HgVcs extends AbstractVcs { commitedChangesProvider = new HgCachingCommitedChangesProvider(project); myDirStateChangeListener = new RepositoryChangeListener(myProject, ".hg/dirstate"); myMergeProvider = new HgMergeProvider(myProject); + myCommitAndPushExecutor = new HgCommitAndPushExecutor(checkinEnvironment); } public String getDisplayName() { @@ -383,4 +387,10 @@ public class HgVcs extends AbstractVcs { public boolean reportsIgnoredDirectories() { return false; } + + @Override + public List getCommitExecutors() { + return Collections.singletonList(myCommitAndPushExecutor); + } + } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/commit/HgCheckinEnvironment.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/commit/HgCheckinEnvironment.java index 0a85a46b1ea5..a0901648cbfa 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/commit/HgCheckinEnvironment.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/commit/HgCheckinEnvironment.java @@ -28,27 +28,28 @@ import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.NullableFunction; import com.intellij.util.PairConsumer; +import com.intellij.util.ui.UIUtil; import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.NotNull; -import org.zmlx.hg4idea.HgChange; -import org.zmlx.hg4idea.HgFile; -import org.zmlx.hg4idea.HgRevisionNumber; -import org.zmlx.hg4idea.HgVcsMessages; +import org.zmlx.hg4idea.*; import org.zmlx.hg4idea.command.*; import org.zmlx.hg4idea.execution.HgCommandException; +import javax.swing.*; import java.util.*; public class HgCheckinEnvironment implements CheckinEnvironment { - private final Project project; + private final Project myProject; + private boolean myNextCommitIsPushed; public HgCheckinEnvironment(Project project) { - this.project = project; + myProject = project; } public RefreshableOnComponent createAdditionalOptionsPanel(CheckinProjectPanel panel, PairConsumer additionalDataConsumer) { + myNextCommitIsPushed = false; return null; } @@ -72,7 +73,7 @@ public class HgCheckinEnvironment implements CheckinEnvironment { VirtualFile repo = entry.getKey(); Set selectedFiles = entry.getValue(); - HgCommitCommand command = new HgCommitCommand(project, repo, preparedComment); + HgCommitCommand command = new HgCommitCommand(myProject, repo, preparedComment); if (isMergeCommit(repo)) { //partial commits are not allowed during merges @@ -109,17 +110,27 @@ public class HgCheckinEnvironment implements CheckinEnvironment { exceptions.add(e); } } + + // push if needed + if (myNextCommitIsPushed && exceptions.isEmpty()) { + UIUtil.invokeLaterIfNeeded(new Runnable() { + public void run() { + new HgPusher(myProject).showDialogAndPush(); + } + }); + } + return exceptions; } private boolean isMergeCommit(VirtualFile repo) { - return new HgWorkingCopyRevisionsCommand(project).parents(repo).size() > 1; + return new HgWorkingCopyRevisionsCommand(myProject).parents(repo).size() > 1; } private Set getChangedFilesNotInCommit(VirtualFile repo, Set selectedFiles) { - List parents = new HgWorkingCopyRevisionsCommand(project).parents(repo); + List parents = new HgWorkingCopyRevisionsCommand(myProject).parents(repo); - HgStatusCommand statusCommand = new HgStatusCommand(project); + HgStatusCommand statusCommand = new HgStatusCommand(myProject); statusCommand.setBaseRevision(parents.get(0)); statusCommand.setIncludeUnknown(false); statusCommand.setIncludeIgnored(false); @@ -144,7 +155,7 @@ public class HgCheckinEnvironment implements CheckinEnvironment { Runnable runnable = new Runnable() { public void run() { choice[0] = Messages.showOkCancelDialog( - project, + myProject, HgVcsMessages.message("hg4idea.commit.partial.merge.message", filesNotIncludedString), HgVcsMessages.message("hg4idea.commit.partial.merge.title"), null @@ -165,9 +176,9 @@ public class HgCheckinEnvironment implements CheckinEnvironment { } public List scheduleMissingFileForDeletion(List files) { - HgRemoveCommand command = new HgRemoveCommand(project); + HgRemoveCommand command = new HgRemoveCommand(myProject); for (FilePath filePath : files) { - VirtualFile vcsRoot = VcsUtil.getVcsRootFor(project, filePath); + VirtualFile vcsRoot = VcsUtil.getVcsRootFor(myProject, filePath); if (vcsRoot == null) { continue; } @@ -177,9 +188,9 @@ public class HgCheckinEnvironment implements CheckinEnvironment { } public List scheduleUnversionedFilesForAddition(List files) { - final HgAddCommand command = new HgAddCommand(project); + final HgAddCommand command = new HgAddCommand(myProject); for (final VirtualFile file : files) { - final VirtualFile vcsRoot = VcsUtil.getVcsRootFor(project, file); + final VirtualFile vcsRoot = VcsUtil.getVcsRootFor(myProject, file); if (vcsRoot == null) { continue; } @@ -218,7 +229,7 @@ public class HgCheckinEnvironment implements CheckinEnvironment { return; } - VirtualFile repo = VcsUtil.getVcsRootFor(project, filePath); + VirtualFile repo = VcsUtil.getVcsRootFor(myProject, filePath); if (repo == null || filePath.isDirectory()) { return; } @@ -232,4 +243,7 @@ public class HgCheckinEnvironment implements CheckinEnvironment { hgFiles.add(new HgFile(repo, filePath)); } + public void setNextCommitIsPushed(boolean pushed) { + myNextCommitIsPushed = true; + } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/commit/HgCommitAndPushExecutor.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/commit/HgCommitAndPushExecutor.java new file mode 100644 index 000000000000..e240b9d852bf --- /dev/null +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/commit/HgCommitAndPushExecutor.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2011 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.zmlx.hg4idea.provider.commit; + +import com.intellij.openapi.vcs.changes.CommitExecutor; +import com.intellij.openapi.vcs.changes.CommitSession; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; + +/** + * @author Kirill Likhodedov + */ +public class HgCommitAndPushExecutor implements CommitExecutor { + private final HgCheckinEnvironment myCheckinEnvironment; + + public HgCommitAndPushExecutor(HgCheckinEnvironment checkinEnvironment) { + myCheckinEnvironment = checkinEnvironment; + } + + @Nls + public String getActionText() { + return "Commit and &Push..."; + } + + @NotNull + public CommitSession createCommitSession() { + myCheckinEnvironment.setNextCommitIsPushed(true); + return CommitSession.VCS_COMMIT; + } +} From 646ea233a6f569d4b639ee6ed37116349e452f75 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Wed, 13 Apr 2011 09:57:45 +0200 Subject: [PATCH 012/102] cleanup --- .../braces/AddArrayCreationExpressionIntention.java | 13 +++++++++---- .../braces/ArrayCreationExpressionPredicate.java | 3 ++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/braces/AddArrayCreationExpressionIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/braces/AddArrayCreationExpressionIntention.java index b0b5ee223aec..eeb783710930 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/braces/AddArrayCreationExpressionIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/braces/AddArrayCreationExpressionIntention.java @@ -26,30 +26,35 @@ import org.jetbrains.annotations.NotNull; public class AddArrayCreationExpressionIntention extends MutablyNamedIntention { + @Override @NotNull protected PsiElementPredicate getElementPredicate() { return new ArrayCreationExpressionPredicate(); } + @Override protected String getTextForElement(PsiElement element) { final PsiArrayInitializerExpression arrayInitializerExpression = - (PsiArrayInitializerExpression)element; + (PsiArrayInitializerExpression)element; final PsiType type = arrayInitializerExpression.getType(); assert type != null; - return IntentionPowerPackBundle.message("add.array.creation.expression.intention.name", type.getPresentableText()); + return IntentionPowerPackBundle.message( + "add.array.creation.expression.intention.name", + type.getPresentableText()); } + @Override protected void processIntention(@NotNull PsiElement element) throws IncorrectOperationException { final PsiArrayInitializerExpression arrayInitializerExpression = - (PsiArrayInitializerExpression)element; + (PsiArrayInitializerExpression)element; final PsiType type = arrayInitializerExpression.getType(); if (type == null) { return; } final String typeText = type.getCanonicalText(); final String newExpressionText = - "new " + typeText + arrayInitializerExpression.getText(); + "new " + typeText + arrayInitializerExpression.getText(); replaceExpression(newExpressionText, arrayInitializerExpression); } } diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/braces/ArrayCreationExpressionPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/braces/ArrayCreationExpressionPredicate.java index 0b93852a877a..1c6424ce8cb0 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/braces/ArrayCreationExpressionPredicate.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/braces/ArrayCreationExpressionPredicate.java @@ -27,7 +27,8 @@ class ArrayCreationExpressionPredicate implements PsiElementPredicate { if (!(element instanceof PsiArrayInitializerExpression)) { return false; } - final PsiArrayInitializerExpression arrayInitializerExpression = (PsiArrayInitializerExpression)element; + final PsiArrayInitializerExpression arrayInitializerExpression = + (PsiArrayInitializerExpression)element; if (arrayInitializerExpression.getType() == null) { return false; } From dbb27d2579f6f9fff3bd6a241950b040211cd0f1 Mon Sep 17 00:00:00 2001 From: Denis Zhdanov Date: Wed, 13 Apr 2011 12:10:06 +0400 Subject: [PATCH 013/102] IDEA-68003 Java Formatter: Correct formatting of anonymous classes at method call arguments 1. Corrected formatting of anonymous class used as aligned method call arguments; 2. Corresponding tests are added; 3. Green code policy is applied at affected classes; --- .../psi/formatter/java/AbstractJavaBlock.java | 65 ++++--- .../psi/formatter/java/CodeBlockBlock.java | 26 +-- .../psi/formatter/java/JavaFormatterUtil.java | 176 ++++++++++++++++++ .../java/JavaSpacePropertyProcessor.java | 9 +- .../java/JavaFormatterIndentationTest.java | 95 +++++++++- .../src/com/intellij/formatting/Indent.java | 10 +- .../formatting/AbstractBlockWrapper.java | 60 +++--- .../formatting/CompositeBlockWrapper.java | 9 - .../com/intellij/formatting/IndentImpl.java | 12 +- .../intellij/formatting/LeafBlockWrapper.java | 5 - 10 files changed, 372 insertions(+), 95 deletions(-) create mode 100644 java/java-impl/src/com/intellij/psi/formatter/java/JavaFormatterUtil.java diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java index f9259449c61d..f654587578f8 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java @@ -26,6 +26,7 @@ import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleSettings; +import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.intellij.psi.formatter.FormatterUtil; import com.intellij.psi.formatter.common.AbstractBlock; import com.intellij.psi.formatter.java.wrap.JavaWrapManager; @@ -44,6 +45,7 @@ import org.jetbrains.annotations.Nullable; import java.util.*; +import static com.intellij.psi.formatter.java.JavaFormatterUtil.isFirstAmongOthersAnonymousClassMethodCallArguments; import static java.util.Arrays.asList; public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlock, ReservedWrapsProvider { @@ -258,7 +260,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo if (parentType == JavaElementType.MODIFIER_LIST) return Indent.getNoneIndent(); if (parentType == JspElementType.JSP_CODE_BLOCK) return Indent.getNormalIndent(); if (parentType == JspElementType.JSP_CLASS_LEVEL_DECLARATION_STATEMENT) return Indent.getNormalIndent(); - if (parentType == ElementType.DUMMY_HOLDER) return Indent.getNoneIndent(); + if (parentType == TokenType.DUMMY_HOLDER) return Indent.getNoneIndent(); if (parentType == JavaElementType.CLASS) return Indent.getNoneIndent(); if (parentType == JavaElementType.IF_STATEMENT) return Indent.getNoneIndent(); if (parentType == JavaElementType.TRY_STATEMENT) return Indent.getNoneIndent(); @@ -285,7 +287,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo } protected static boolean isRBrace(final ASTNode child) { - return child.getElementType() == ElementType.RBRACE; + return child.getElementType() == JavaTokenType.RBRACE; } public Spacing getSpacing(Block child1, Block child2) { @@ -363,7 +365,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo else if (nodeType == JavaElementType.CLASS || nodeType == JavaElementType.METHOD) { return Alignment.createAlignment(); } - else if (nodeType == JavaElementType.MODIFIER_LIST) { + else if (nodeType == JavaElementType.MODIFIER_LIST || nodeType == JavaElementType.NEW_EXPRESSION) { return myAlignment; } @@ -838,7 +840,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo // Here '@NotNull' has a 'class' node as a parent but we want to use field annotation setting value. Hence, we check if subsequent // parsed info is valid. for (ASTNode node = child.getTreeNext(); node != null; node = node.getTreeNext()) { - if (JavaTokenType.WHITE_SPACE == node.getElementType() || node instanceof PsiTypeElement) { + if (TokenType.WHITE_SPACE == node.getElementType() || node instanceof PsiTypeElement) { continue; } if (node instanceof PsiErrorElement) { @@ -856,7 +858,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo if (nodeType == JavaElementType.LOCAL_VARIABLE) { return mySettings.VARIABLE_ANNOTATION_WRAP; } - return CodeStyleSettings.DO_NOT_WRAP; + return CommonCodeStyleSettings.DO_NOT_WRAP; } @Nullable @@ -922,7 +924,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo // There is a special case - comment block that is located at the very start of the line. We don't reformat such a blocks, // hence, no alignment should be applied to them in order to avoid subsequent blocks aligned with the same alignment to // be located at the left editor edge as well. - if (previous != null && previous.getElementType() == JavaTokenType.WHITE_SPACE && previous.getChars().length() > 0 + if (previous != null && previous.getElementType() == TokenType.WHITE_SPACE && previous.getChars().length() > 0 && previous.getChars().charAt(previous.getChars().length() - 1) == '\n') { return null; } else { @@ -940,6 +942,12 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo return null; } + else if (nodeType == JavaElementType.ANONYMOUS_CLASS && role == ChildRole.RBRACE + && isFirstAmongOthersAnonymousClassMethodCallArguments(myNode)) + { + return myAlignment; + } + else { return defaultAlignment; } @@ -1015,11 +1023,11 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo private static WrapType getWrapType(final int wrap) { switch (wrap) { - case CodeStyleSettings.WRAP_ALWAYS: + case CommonCodeStyleSettings.WRAP_ALWAYS: return WrapType.ALWAYS; - case CodeStyleSettings.WRAP_AS_NEEDED: + case CommonCodeStyleSettings.WRAP_AS_NEEDED: return WrapType.NORMAL; - case CodeStyleSettings.DO_NOT_WRAP: + case CommonCodeStyleSettings.DO_NOT_WRAP: return WrapType.NONE; default: return WrapType.CHOP_DOWN_IF_LONG; @@ -1040,12 +1048,12 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo private ASTNode processParenthesisBlock(final IElementType from, final IElementType to, final List result, ASTNode child, - final WrappingStrategy wrappingStrategy, final boolean doAlign - ) { + final WrappingStrategy wrappingStrategy, final boolean doAlign) + { final Indent externalIndent = Indent.getNoneIndent(); - final Indent internalIndent = Indent.getContinuationIndent(myIndentSettings.USE_RELATIVE_INDENTS); - final Indent internalIndentEnforcedToParent = Indent.getIndent(Indent.Type.CONTINUATION, myIndentSettings.USE_RELATIVE_INDENTS, true); - AlignmentStrategy alignmentStrategy = AlignmentStrategy.wrap(createAlignment(doAlign, null), ElementType.COMMA); + final Indent internalIndent = Indent.getContinuationWithoutFirstIndent(myIndentSettings.USE_RELATIVE_INDENTS); + final Indent internalIndentEnforcedToChildren = Indent.getIndent(Indent.Type.CONTINUATION, myIndentSettings.USE_RELATIVE_INDENTS, true); + AlignmentStrategy alignmentStrategy = AlignmentStrategy.wrap(createAlignment(doAlign, null), JavaTokenType.COMMA); setChildIndent(internalIndent); setChildAlignment(alignmentStrategy.getAlignment(null)); boolean methodParametersBlock = true; @@ -1076,7 +1084,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo } else { final IElementType elementType = child.getElementType(); - Indent indentToUse = shouldEnforceParentIndent(child) ? internalIndentEnforcedToParent : internalIndent; + Indent indentToUse = shouldEnforceIndentToChildren(child) ? internalIndentEnforcedToChildren : internalIndent; processChild(result, child, alignmentStrategy.getAlignment(elementType), wrappingStrategy.getWrap(elementType), indentToUse); if (to == null) {//process only one statement return child; @@ -1091,7 +1099,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo return prev; } - private boolean shouldEnforceParentIndent(@NotNull ASTNode node) { + private boolean shouldEnforceIndentToChildren(@NotNull ASTNode node) { // Don't enforce indent if given node is the last argument, i.e. prefer the code below // void test() { // foo("test", new Runnable() { @@ -1129,7 +1137,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo // Enforce indent only if anonymous class instance expression doesn't start new line. ASTNode prev = node.getTreePrev(); - return prev == null || prev.getElementType() != JavaTokenType.WHITE_SPACE || !StringUtil.containsLineBreak(prev.getChars()); + return prev == null || prev.getElementType() != TokenType.WHITE_SPACE || !StringUtil.containsLineBreak(prev.getChars()); } @Nullable @@ -1193,7 +1201,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo } final int braceStyle = getBraceStyle(); - return braceStyle == CodeStyleSettings.NEXT_LINE_SHIFTED ? + return braceStyle == CommonCodeStyleSettings.NEXT_LINE_SHIFTED ? createNormalIndent(baseChildrenIndent - 1, enforceParentIndent) : createNormalIndent(baseChildrenIndent, enforceParentIndent); } @@ -1202,16 +1210,16 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo return createNormalIndent(baseChildrenIndent, false); } - protected static Indent createNormalIndent(final int baseChildrenIndent, boolean enforceParentIndent) { + protected static Indent createNormalIndent(final int baseChildrenIndent, boolean enforceIndentToChildren) { if (baseChildrenIndent == 1) { - return Indent.getIndent(Indent.Type.NORMAL, false, enforceParentIndent); + return Indent.getIndent(Indent.Type.NORMAL, false, enforceIndentToChildren); } else if (baseChildrenIndent <= 0) { return Indent.getNoneIndent(); } else { LOG.assertTrue(false); - return Indent.getIndent(Indent.Type.NORMAL, false, enforceParentIndent); + return Indent.getIndent(Indent.Type.NORMAL, false, enforceIndentToChildren); } } @@ -1222,8 +1230,8 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo protected Indent getCodeBlockExternalIndent() { final int braceStyle = getBraceStyle(); - if (braceStyle == CodeStyleSettings.END_OF_LINE || braceStyle == CodeStyleSettings.NEXT_LINE || - braceStyle == CodeStyleSettings.NEXT_LINE_IF_WRAPPED) { + if (braceStyle == CommonCodeStyleSettings.END_OF_LINE || braceStyle == CommonCodeStyleSettings.NEXT_LINE || + braceStyle == CommonCodeStyleSettings.NEXT_LINE_IF_WRAPPED) { return Indent.getNoneIndent(); } else { @@ -1236,9 +1244,9 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo if (!isAfterCodeBlock(newChildIndex)) { return Indent.getNormalIndent(); } - else if (braceStyle == CodeStyleSettings.NEXT_LINE || - braceStyle == CodeStyleSettings.NEXT_LINE_IF_WRAPPED || - braceStyle == CodeStyleSettings.END_OF_LINE) { + else if (braceStyle == CommonCodeStyleSettings.NEXT_LINE || + braceStyle == CommonCodeStyleSettings.NEXT_LINE_IF_WRAPPED || + braceStyle == CommonCodeStyleSettings.END_OF_LINE) { return Indent.getNoneIndent(); } else { @@ -1364,9 +1372,10 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo ); } final boolean rBrace = isRBrace(child); - Indent childIndent = rBrace ? Indent.getNoneIndent() : getCodeBlockInternalIndent(childrenIndent); + Indent childIndent = rBrace ? Indent.getNoneIndent() : getCodeBlockInternalIndent(childrenIndent, true); if (!rBrace && child.getElementType() == JavaElementType.CODE_BLOCK - && (getBraceStyle() == CodeStyleSettings.NEXT_LINE_SHIFTED || getBraceStyle() == CodeStyleSettings.NEXT_LINE_SHIFTED2)) + && (getBraceStyle() == CommonCodeStyleSettings.NEXT_LINE_SHIFTED + || getBraceStyle() == CommonCodeStyleSettings.NEXT_LINE_SHIFTED2)) { childIndent = Indent.getNormalIndent(); } diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/CodeBlockBlock.java b/java/java-impl/src/com/intellij/psi/formatter/java/CodeBlockBlock.java index b3963b53dd7e..2d93983cff5c 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/CodeBlockBlock.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/CodeBlockBlock.java @@ -18,12 +18,12 @@ package com.intellij.psi.formatter.java; import com.intellij.formatting.*; import com.intellij.lang.ASTNode; import com.intellij.psi.JavaTokenType; +import com.intellij.psi.TokenType; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.formatter.FormatterUtil; import com.intellij.psi.formatter.common.AbstractBlock; import com.intellij.formatting.alignment.AlignmentStrategy; import com.intellij.psi.impl.source.jsp.jspJava.JspClass; -import com.intellij.psi.impl.source.tree.ElementType; import com.intellij.psi.impl.source.tree.JavaDocElementType; import com.intellij.psi.impl.source.tree.JavaElementType; import com.intellij.psi.impl.source.tree.StdTokenSets; @@ -72,7 +72,7 @@ public class CodeBlockBlock extends AbstractJavaBlock { continue; } ASTNode lastChildNode = node.getLastChildNode(); - if (lastChildNode != null && lastChildNode.getElementType() == JavaTokenType.ERROR_ELEMENT) { + if (lastChildNode != null && lastChildNode.getElementType() == TokenType.ERROR_ELEMENT) { Alignment alignmentToUse = alignment; if (alignment == null) { alignmentToUse = Alignment.createAlignment(); @@ -87,7 +87,7 @@ public class CodeBlockBlock extends AbstractJavaBlock { } private boolean isSwitchCodeBlock() { - return myNode.getTreeParent().getElementType() == ElementType.SWITCH_STATEMENT; + return myNode.getTreeParent().getElementType() == JavaElementType.SWITCH_STATEMENT; } protected List buildChildren() { @@ -115,13 +115,13 @@ public class CodeBlockBlock extends AbstractJavaBlock { final Indent indent = calcCurrentIndent(child, state); state = calcNewState(child, state); - if (child.getElementType() == ElementType.SWITCH_LABEL_STATEMENT) { + if (child.getElementType() == JavaElementType.SWITCH_LABEL_STATEMENT) { child = processCaseAndStatementAfter(result, child, childAlignment, childWrap, indent); } - else if (myNode.getElementType() == ElementType.CLASS && child.getElementType() == ElementType.LBRACE) { + else if (myNode.getElementType() == JavaElementType.CLASS && child.getElementType() == JavaTokenType.LBRACE) { child = composeCodeBlock(result, child, getCodeBlockExternalIndent(), myChildrenIndent, null); } - else if (myNode.getElementType() == ElementType.CODE_BLOCK && child.getElementType() == ElementType.LBRACE + else if (myNode.getElementType() == JavaElementType.CODE_BLOCK && child.getElementType() == JavaTokenType.LBRACE && myNode.getTreeParent().getElementType() == JavaElementType.METHOD) { child = composeCodeBlock(result, child, indent, myChildrenIndent, childWrap); @@ -146,14 +146,14 @@ public class CodeBlockBlock extends AbstractJavaBlock { child = child.getTreeNext(); Indent childIndent = Indent.getNormalIndent(); while (child != null) { - if (child.getElementType() == ElementType.SWITCH_LABEL_STATEMENT || isRBrace(child)) { + if (child.getElementType() == JavaElementType.SWITCH_LABEL_STATEMENT || isRBrace(child)) { result.add(createCaseSectionBlock(localResult, childAlignment, indent, childWrap)); return child.getTreePrev(); } if (!FormatterUtil.containsWhiteSpacesOnly(child)) { - if (child.getElementType() == ElementType.BLOCK_STATEMENT) { + if (child.getElementType() == JavaElementType.BLOCK_STATEMENT) { childIndent = Indent.getNoneIndent(); } @@ -189,9 +189,9 @@ public class CodeBlockBlock extends AbstractJavaBlock { } } - if (prevElementType == ElementType.BLOCK_STATEMENT - || prevElementType == ElementType.BREAK_STATEMENT - || prevElementType == ElementType.RETURN_STATEMENT) { + if (prevElementType == JavaElementType.BLOCK_STATEMENT + || prevElementType == JavaElementType.BREAK_STATEMENT + || prevElementType == JavaElementType.RETURN_STATEMENT) { return new ChildAttributes(Indent.getNoneIndent(), null); } else { @@ -231,7 +231,7 @@ public class CodeBlockBlock extends AbstractJavaBlock { } private static boolean isLBrace(final ASTNode child) { - return child.getElementType() == ElementType.LBRACE; + return child.getElementType() == JavaTokenType.LBRACE; } private Indent calcCurrentIndent(final ASTNode child, final int state) { @@ -241,7 +241,7 @@ public class CodeBlockBlock extends AbstractJavaBlock { if (state == BEFORE_FIRST) return Indent.getNoneIndent(); - if (child.getElementType() == ElementType.SWITCH_LABEL_STATEMENT) { + if (child.getElementType() == JavaElementType.SWITCH_LABEL_STATEMENT) { return getCodeBlockInternalIndent(myChildrenIndent); } if (state == BEFORE_LBRACE) { diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/JavaFormatterUtil.java b/java/java-impl/src/com/intellij/psi/formatter/java/JavaFormatterUtil.java new file mode 100644 index 000000000000..930248ee8a94 --- /dev/null +++ b/java/java-impl/src/com/intellij/psi/formatter/java/JavaFormatterUtil.java @@ -0,0 +1,176 @@ +/* + * Copyright 2000-2011 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.psi.formatter.java; + +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiExpression; +import com.intellij.psi.PsiExpressionList; +import com.intellij.psi.impl.source.tree.ElementType; +import com.intellij.psi.impl.source.tree.JavaElementType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Denis Zhdanov + * @since 4/12/11 3:26 PM + */ +public class JavaFormatterUtil { + + private JavaFormatterUtil() { + } + + public static boolean isFirstMethodCallArgument(@NotNull ASTNode node) { + ASTNode firstArgCandidate = node; + ASTNode expressionList = node.getTreeParent(); + if (expressionList == null) { + return false; + } + + if (expressionList.getElementType() != JavaElementType.EXPRESSION_LIST + && expressionList.getElementType() == JavaElementType.NEW_EXPRESSION) + { + firstArgCandidate = expressionList; + expressionList = expressionList.getTreeParent(); + } + + if (expressionList == null || expressionList.getElementType() != JavaElementType.EXPRESSION_LIST) { + return false; + } + + ASTNode methodCallExpression = expressionList.getTreeParent(); + if (methodCallExpression == null || methodCallExpression.getElementType() != JavaElementType.METHOD_CALL_EXPRESSION) { + return false; + } + + ASTNode lbrace = expressionList.getFirstChildNode(); + ASTNode firstArg = lbrace.getTreeNext(); + if (firstArg != null && ElementType.WHITE_SPACE_BIT_SET.contains(firstArg.getElementType())) { + firstArg = firstArg.getTreeNext(); + } + + return firstArg == firstArgCandidate; + } + + /** + * Allows to check if given node references anonymous class instance used as a method call argument. The most important thing + * is that that method call expression should have other anonymous classes as well. + *

+ * Examples + *

+   *   test(new Runnable() {         <-- true is returned for this node
+   *          public void run() {
+   *          }
+   *        },
+   *        new Runnable() {          <-- false is returned for this node
+   *          public void run() {
+   *          }
+   *        }
+   *    );
+   *    
+   *    test(1234, "text", new Runnable() {         <-- true is returned for this node because there are no other anonymous
+   *          public void run() {                          class objects at method call expression before it
+   *          }
+   *        },
+   *        new Runnable() {                        <-- false is returned for this node
+   *          public void run() {
+   *          }
+   *        }
+   *    );    
+   *    
+   *    test(1234, "text", new Runnable() {         <-- false is returned for this node because there are no other anonymous
+   *        public void run() {                            class objects at method call expression after it
+   *        }
+   *    });
+   * 
+ * + * @param node node to process + * @return + */ + public static boolean isFirstAmongOthersAnonymousClassMethodCallArguments(@NotNull ASTNode node) { + ASTNode expressionList = node.getTreeParent(); + ASTNode firstAnonymousClassCandidate = node; + if (expressionList == null) { + return false; + } + + if (expressionList.getElementType() != JavaElementType.EXPRESSION_LIST + && expressionList.getElementType() == JavaElementType.NEW_EXPRESSION) + { + firstAnonymousClassCandidate = expressionList; + expressionList = expressionList.getTreeParent(); + } + + if (expressionList == null || expressionList.getElementType() != JavaElementType.EXPRESSION_LIST) { + return false; + } + + ASTNode methodCallExpression = expressionList.getTreeParent(); + if (methodCallExpression == null || methodCallExpression.getElementType() != JavaElementType.METHOD_CALL_EXPRESSION) { + return false; + } + + ASTNode lbrace = expressionList.getFirstChildNode(); + boolean firstAnonymousClass = false; + for (ASTNode arg = lbrace.getTreeNext(); arg != null; arg = FormattingAstUtil.getNextNonWhiteSpaceNode(arg)) { + if (!isAnonymousClass(arg)) { + continue; + } + if (firstAnonymousClass) { + // Other anonymous class is found at the method call expression after the target one. + return true; + } + else if (arg != firstAnonymousClassCandidate) { + return false; + } + else { + firstAnonymousClass = true; + } + } + return false; + } + + /** + * Allows to check if given expression list has given number of anonymous classes. + * + * @param count interested number of anonymous classes used at the given expression list + * @return true if given expression list contains given number of anonymous classes; + * false otherwise + */ + public static boolean hasAnonymousClassesArguments(@NotNull PsiExpressionList expressionList, int count) { + int found = 0; + for (PsiExpression expression : expressionList.getExpressions()) { + ASTNode node = expression.getNode(); + if (isAnonymousClass(node)) { + found++; + } + if (found >= count) { + return true; + } + } + return false; + } + + private static boolean isAnonymousClass(@Nullable final ASTNode node) { + if (node == null) { + return false; + } + ASTNode nodeToCheck = node; + if (node.getElementType() == JavaElementType.NEW_EXPRESSION) { + nodeToCheck = node.getLastChildNode(); + } + return nodeToCheck != null && nodeToCheck.getElementType() == JavaElementType.ANONYMOUS_CLASS; + } +} diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java b/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java index 746a89e87d02..cf6708138141 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java @@ -1100,8 +1100,13 @@ public class JavaSpacePropertyProcessor extends JavaElementVisitor { createParenthSpace(mySettings.CALL_PARAMETERS_LPAREN_ON_NEXT_LINE, false); } else if (myRole2 == ChildRole.RPARENTH) { - createParenthSpace(mySettings.CALL_PARAMETERS_RPAREN_ON_NEXT_LINE, - myRole1 == ChildRole.COMMA || mySettings.SPACE_WITHIN_METHOD_CALL_PARENTHESES); + if (JavaFormatterUtil.hasAnonymousClassesArguments(list, 2)) { + myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, 0); + } + else { + createParenthSpace(mySettings.CALL_PARAMETERS_RPAREN_ON_NEXT_LINE, + myRole1 == ChildRole.COMMA || mySettings.SPACE_WITHIN_METHOD_CALL_PARENTHESES); + } } else if (myRole1 == ChildRole.LPARENTH) { createParenthSpace(mySettings.CALL_PARAMETERS_LPAREN_ON_NEXT_LINE, mySettings.SPACE_WITHIN_METHOD_CALL_PARENTHESES); diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterIndentationTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterIndentationTest.java index ad75c2e0fed3..a11d8f922556 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterIndentationTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterIndentationTest.java @@ -16,7 +16,6 @@ package com.intellij.psi.formatter.java; import com.intellij.openapi.fileTypes.StdFileTypes; -import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.intellij.util.IncorrectOperationException; @@ -88,7 +87,7 @@ public class JavaFormatterIndentationTest extends AbstractJavaFormatterTest { } public void testShiftedChainedIfElse() throws Exception { - getSettings().BRACE_STYLE = CodeStyleSettings.NEXT_LINE_SHIFTED2; + getSettings().BRACE_STYLE = CommonCodeStyleSettings.NEXT_LINE_SHIFTED2; getSettings().ELSE_ON_NEW_LINE = true; getSettings().getIndentOptions(StdFileTypes.JAVA).INDENT_SIZE = 4; doMethodTest( @@ -331,6 +330,98 @@ public class JavaFormatterIndentationTest extends AbstractJavaFormatterTest { " } \n" + "); " ); + + doMethodTest( + "foo(1,\n" + + "2, new Runnable() {\n" + + "@Override\n" + + "public void run() {\n" + + "}\n" + + "});", + "foo(1,\n" + + " 2, new Runnable() {\n" + + " @Override\n" + + " public void run() {\n" + + " }\n" + + "}); " + ); + + doMethodTest( + "foo(new Runnable() {\n" + + "@Override\n" + + "public void run() {\n" + + "}\n" + + "},\n" + + "new Runnable() {\n" + + "@Override\n" + + "public void run() {\n" + + "}\n" + + "});", + "foo(new Runnable() {\n" + + " @Override\n" + + " public void run() {\n" + + " }\n" + + " },\n" + + " new Runnable() {\n" + + " @Override\n" + + " public void run() {\n" + + " }\n" + + " }\n" + + ");" + ); + } + + public void testAnonymousClassInstancesAsAlignedMethodCallArguments() throws Exception { + getSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true; + + doMethodTest( + "foo(new Runnable() {\n" + + "@Override\n" + + "public void run() {\n" + + "}\n" + + "},\n" + + "new Runnable() {\n" + + "@Override\n" + + "public void run() {\n" + + "}\n" + + "});", + "foo(new Runnable() {\n" + + " @Override\n" + + " public void run() {\n" + + " }\n" + + " },\n" + + " new Runnable() {\n" + + " @Override\n" + + " public void run() {\n" + + " }\n" + + " }\n" + + ");" + ); + + doMethodTest( + "foo(123456789, new Runnable() {\n" + + "@Override\n" + + "public void run() {\n" + + "}\n" + + "},\n" + + "new Runnable() {\n" + + "@Override\n" + + "public void run() {\n" + + "}\n" + + "});", + "foo(123456789, new Runnable() {\n" + + " @Override\n" + + " public void run() {\n" + + " }\n" + + " },\n" + + " new Runnable() {\n" + + " @Override\n" + + " public void run() {\n" + + " }\n" + + " }\n" + + ");" + ); + } public void testPackagePrivateAnnotation() { diff --git a/platform/lang-api/src/com/intellij/formatting/Indent.java b/platform/lang-api/src/com/intellij/formatting/Indent.java index b10cdc0eee44..a69a47bc08c7 100644 --- a/platform/lang-api/src/com/intellij/formatting/Indent.java +++ b/platform/lang-api/src/com/intellij/formatting/Indent.java @@ -58,7 +58,7 @@ import org.jetbrains.annotations.NotNull; * In contrast, it's possible to specify that direct parent block that starts on a line before target child block is used as an anchor. * Initial formatting example illustrates such approach. *

- * Parent indent enforcing + * Enforcing indent to children *

* It's possible to configure indent to enforce parent block indent to its children that start new line. Consider the following situation: *

@@ -74,7 +74,7 @@ import org.jetbrains.annotations.NotNull;
  * 
* We want the first {@code 'new Runnable() {...}'} block here to be indented to the method expression list element. However, formatter * uses indents only if the block starts new line. Here the block doesn't start new line ({@code 'new Runnable() ...'}), hence - * we need to define 'enforce parent indent' flag in order to instruct formatter to apply parent indent to the sub-blocks. + * we need to define 'enforce indent to children' flag in order to instruct formatter to apply parent indent to the sub-blocks. * * @see com.intellij.formatting.Block#getIndent() * @see com.intellij.formatting.ChildAttributes#getChildIndent() @@ -244,12 +244,12 @@ public abstract class Indent { * @param type indent type * @param relativeToDirectParent flag the indicates if current indent object anchors direct block parent (feel free * to get more information about that at class-level javadoc) - * @param enforceParentIndent flag the indicates if current indent object should be enforced for multiline block children + * @param enforceIndentToChildren flag the indicates if current indent object should be enforced for multiline block children * (feel free to get more information about that at class-level javadoc) * @return newly created indent configured in accordance with the given arguments */ - public static Indent getIndent(@NotNull Type type, boolean relativeToDirectParent, boolean enforceParentIndent) { - return myFactory.getIndent(type, relativeToDirectParent, enforceParentIndent); + public static Indent getIndent(@NotNull Type type, boolean relativeToDirectParent, boolean enforceIndentToChildren) { + return myFactory.getIndent(type, relativeToDirectParent, enforceIndentToChildren); } public static class Type { diff --git a/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java b/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java index 5ca57e20fc4a..cf0773617e46 100644 --- a/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java +++ b/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java @@ -21,20 +21,13 @@ import com.intellij.psi.codeStyle.CodeStyleSettings; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; -import java.util.HashSet; -import java.util.Set; - -import static java.util.Arrays.asList; +import java.util.List; /** * @author lesya */ public abstract class AbstractBlockWrapper { - private static final Set RELATIVE_INDENT_TYPES = new HashSet(asList( - Indent.Type.NORMAL, Indent.Type.CONTINUATION, Indent.Type.CONTINUATION_WITHOUT_FIRST - )); - protected WhiteSpace myWhiteSpace; protected CompositeBlockWrapper myParent; protected int myStart; @@ -165,13 +158,10 @@ public abstract class AbstractBlockWrapper { public IndentData getChildOffset(AbstractBlockWrapper child, CodeStyleSettings.IndentOptions options, int targetBlockStartOffset) { final boolean childStartsNewLine = child.getWhiteSpace().containsLineFeeds(); - IndentImpl.Type childIndentType = child.getIndent().getType(); IndentData childIndent; // Calculate child indent. - if (childStartsNewLine - || (!getWhiteSpace().containsLineFeeds() && RELATIVE_INDENT_TYPES.contains(childIndentType) && indentAlreadyUsedBefore(child))) - { + if (childStartsNewLine) { childIndent = getIndent(options, child, targetBlockStartOffset); } else { @@ -202,7 +192,38 @@ public abstract class AbstractBlockWrapper { // } // ); // } - if (child.getIndent().isEnforceParentIndent() && !child.getWhiteSpace().containsLineFeeds()) { + if (child.getIndent().isEnforceIndentToChildren() && !child.getWhiteSpace().containsLineFeeds()) { + AlignmentImpl alignment = child.getAlignment(); + if (alignment != null) { + // Generally, we want to handle situation like the one below: + // test("text", new Runnable() { + // @Override + // public void run() { + // } + // }, + // new Runnable() { + // @Override + // public void run() { + // } + // } + // ); + // I.e. we want 'run()' method from the first anonymous class to be aligned with the 'run()' method of the second anonymous class. + + AbstractBlockWrapper anchorBlock = alignment.getOffsetRespBlockBefore(child); + if (anchorBlock == null) { + anchorBlock = this; + if (anchorBlock instanceof CompositeBlockWrapper) { + List children = ((CompositeBlockWrapper)anchorBlock).getChildren(); + for (AbstractBlockWrapper c : children) { + if (c.getStartOffset() != getStartOffset()) { + anchorBlock = c; + break; + } + } + } + } + return anchorBlock.getNumberOfSymbolsBeforeBlock(); + } childIndent = childIndent.add(getIndent(options, child, getStartOffset())); } @@ -266,15 +287,6 @@ public abstract class AbstractBlockWrapper { } } - /** - * Allows to answer if current wrapped block has a child block that is located before given block and has line feed. - * - * @param child target child block to process - * @return true if current block has a child that is located before the given block and contains line feed; - * false otherwise - */ - protected abstract boolean indentAlreadyUsedBefore(final AbstractBlockWrapper child); - /** * Allows to retrieve object that encapsulates information about number of symbols before the current block starting * from the line start. I.e. all symbols (either white space or not) between start of the line where current block begins @@ -310,9 +322,7 @@ public abstract class AbstractBlockWrapper { if (childIndent == null) childIndent = (IndentImpl)Indent.getContinuationWithoutFirstIndent(indentOption.USE_RELATIVE_INDENTS); IndentData indent = getIndent(indentOption, index, childIndent); - if (myParent == null) { - return indent.add(getWhiteSpace()); - } else if ((myFlags & CAN_USE_FIRST_CHILD_INDENT_AS_BLOCK_INDENT) != 0 && getWhiteSpace().containsLineFeeds()) { + if (myParent == null || (myFlags & CAN_USE_FIRST_CHILD_INDENT_AS_BLOCK_INDENT) != 0 && getWhiteSpace().containsLineFeeds()) { return indent.add(getWhiteSpace()); } else { diff --git a/platform/lang-impl/src/com/intellij/formatting/CompositeBlockWrapper.java b/platform/lang-impl/src/com/intellij/formatting/CompositeBlockWrapper.java index dca827b624f4..aaec1d4902b1 100644 --- a/platform/lang-impl/src/com/intellij/formatting/CompositeBlockWrapper.java +++ b/platform/lang-impl/src/com/intellij/formatting/CompositeBlockWrapper.java @@ -57,15 +57,6 @@ public class CompositeBlockWrapper extends AbstractBlockWrapper{ } } - @Override - protected boolean indentAlreadyUsedBefore(final AbstractBlockWrapper child) { - for (AbstractBlockWrapper childBefore : myChildren) { - if (childBefore == child) return false; - if (childBefore.getWhiteSpace().containsLineFeeds()) return true; - } - return false; - } - @Override protected IndentData getNumberOfSymbolsBeforeBlock() { if (myChildren == null || myChildren.isEmpty()) { diff --git a/platform/lang-impl/src/com/intellij/formatting/IndentImpl.java b/platform/lang-impl/src/com/intellij/formatting/IndentImpl.java index 803de8ca63f8..04c806f3407f 100644 --- a/platform/lang-impl/src/com/intellij/formatting/IndentImpl.java +++ b/platform/lang-impl/src/com/intellij/formatting/IndentImpl.java @@ -24,18 +24,18 @@ class IndentImpl extends Indent { private final Type myType; private final int mySpaces; - private final boolean myEnforceParentIndent; + private final boolean myEnforceIndentToChildren; public IndentImpl(final Type type, boolean absolute, boolean relativeToDirectParent) { this(type, absolute, 0, relativeToDirectParent, false); } - public IndentImpl(final Type type, boolean absolute, final int spaces, boolean relativeToDirectParent, boolean enforceParentIndent) { + public IndentImpl(final Type type, boolean absolute, final int spaces, boolean relativeToDirectParent, boolean enforceIndentToChildren) { myType = type; myIsAbsolute = absolute; mySpaces = spaces; myRelativeToDirectParent = relativeToDirectParent; - myEnforceParentIndent = enforceParentIndent; + myEnforceIndentToChildren = enforceIndentToChildren; } Type getType() { @@ -74,8 +74,8 @@ class IndentImpl extends Indent { * @return true if current indent object is configured to enforce indent for sub-blocks of composite block * that doesn't start new line; false otherwise */ - public boolean isEnforceParentIndent() { - return myEnforceParentIndent; + public boolean isEnforceIndentToChildren() { + return myEnforceIndentToChildren; } @NonNls @@ -86,6 +86,6 @@ class IndentImpl extends Indent { } return ""; + + (myEnforceIndentToChildren ? " enforce indent to children" : "") + ">"; } } diff --git a/platform/lang-impl/src/com/intellij/formatting/LeafBlockWrapper.java b/platform/lang-impl/src/com/intellij/formatting/LeafBlockWrapper.java index 99b38484192a..4ee2f339dc46 100644 --- a/platform/lang-impl/src/com/intellij/formatting/LeafBlockWrapper.java +++ b/platform/lang-impl/src/com/intellij/formatting/LeafBlockWrapper.java @@ -126,11 +126,6 @@ class LeafBlockWrapper extends AbstractBlockWrapper { myNextBlock = nextBlock; } - @Override - protected boolean indentAlreadyUsedBefore(final AbstractBlockWrapper child) { - return false; - } - @Override protected IndentData getNumberOfSymbolsBeforeBlock() { int spaces = getWhiteSpace().getSpaces(); From 476cfa619aefaf23725cf2558ca1c658a7b45da8 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Wed, 13 Apr 2011 11:20:29 +0200 Subject: [PATCH 014/102] cleanup --- .../ig/migration/RawUseOfParameterizedTypeInspection.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/migration/RawUseOfParameterizedTypeInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/RawUseOfParameterizedTypeInspection.java index 49253cf0cbaa..cbe92fc8c8c1 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/migration/RawUseOfParameterizedTypeInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/RawUseOfParameterizedTypeInspection.java @@ -72,8 +72,8 @@ public class RawUseOfParameterizedTypeInspection extends BaseInspection { return "unchecked"; } - @Override - public BaseInspectionVisitor buildVisitor() { + @Override + public BaseInspectionVisitor buildVisitor() { return new RawUseOfParameterizedTypeVisitor(); } From 9270aaf54c2636504297ed61006ad4ec3c4b83aa Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Wed, 13 Apr 2011 11:21:43 +0200 Subject: [PATCH 015/102] IDEA-68012 ("Method can be variable arity method" inspection) --- .../siyeh/InspectionGadgetsBundle.properties | 3 + .../com/siyeh/ig/InspectionGadgetsPlugin.java | 1 + ...hodCanBeVariableArityMethodInspection.java | 127 ++++++++++++++++++ .../MethodCanBeVariableArityMethod.html | 11 ++ 4 files changed, 142 insertions(+) create mode 100644 plugins/InspectionGadgets/src/com/siyeh/ig/migration/MethodCanBeVariableArityMethodInspection.java create mode 100644 plugins/InspectionGadgets/src/inspectionDescriptions/MethodCanBeVariableArityMethod.html diff --git a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties index 635d94372604..8ec733d3a713 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties @@ -1875,3 +1875,6 @@ array.hash.code.display.name='hashCode()' called on array array.hash.code.problem.descriptor=#ref() called on array should probably be 'Arrays.hashCode()' #loc arrays.deep.hash.code.quickfix=Replace with 'Arrays.deepHashCode()' arrays.hash.code.quickfix=Replace with 'Arrays.hashCode()' +method.can.be.variable.arity.method.display.name=Method can be variable arity method +method.can.be.variable.arity.method.problem.descriptor=#ref() can be converted to variable arity method +convert.to.variable.arity.method.quickfix=Convert to variable arity method diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java b/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java index 0deceeba6822..8188adaf9c1a 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java @@ -633,6 +633,7 @@ public class InspectionGadgetsPlugin implements ApplicationComponent, m_inspectionClasses.add(ForCanBeForeachInspection.class); m_inspectionClasses.add(IfCanBeSwitchInspection.class); m_inspectionClasses.add(IndexOfReplaceableByContainsInspection.class); + m_inspectionClasses.add(MethodCanBeVariableArityMethodInspection.class); m_inspectionClasses.add(RawUseOfParameterizedTypeInspection.class); m_inspectionClasses.add(StringBufferReplaceableByStringBuilderInspection.class); m_inspectionClasses.add(TryFinallyCanBeTryWithResourcesInspection.class); diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/migration/MethodCanBeVariableArityMethodInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/MethodCanBeVariableArityMethodInspection.java new file mode 100644 index 000000000000..542d2de87f02 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/MethodCanBeVariableArityMethodInspection.java @@ -0,0 +1,127 @@ +/* + * Copyright 2011 Bas Leijdekkers + * + * 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.siyeh.ig.migration; + +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiUtil; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.InspectionGadgetsFix; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; + +public class MethodCanBeVariableArityMethodInspection extends BaseInspection { + + @Nls + @NotNull + @Override + public String getDisplayName() { + return InspectionGadgetsBundle.message( + "method.can.be.variable.arity.method.display.name"); + } + + @NotNull + @Override + protected String buildErrorString(Object... infos) { + return InspectionGadgetsBundle.message( + "method.can.be.variable.arity.method.problem.descriptor"); + } + + @Override + protected InspectionGadgetsFix buildFix(Object... infos) { + return new MethodCanBeVariableArityMethodFix(); + } + + private static class MethodCanBeVariableArityMethodFix + extends InspectionGadgetsFix { + + @NotNull + @Override + public String getName() { + return InspectionGadgetsBundle.message( + "convert.to.variable.arity.method.quickfix"); + } + + @Override + protected void doFix(Project project, ProblemDescriptor descriptor) + throws IncorrectOperationException { + final PsiElement element = descriptor.getPsiElement(); + final PsiElement parent = element.getParent(); + if (!(parent instanceof PsiMethod)) { + return; + } + final PsiMethod method = (PsiMethod) parent; + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList.getParametersCount() == 0) { + return; + } + final PsiParameter[] parameters = parameterList.getParameters(); + final PsiParameter lastParameter = + parameters[parameters.length - 1]; + final PsiType type = lastParameter.getType(); + if (!(type instanceof PsiArrayType)) { + return; + } + final PsiArrayType arrayType = (PsiArrayType) type; + final PsiType componentType = arrayType.getComponentType(); + final PsiElementFactory factory = + JavaPsiFacade.getElementFactory(project); + final PsiTypeElement newTypeElement = + factory.createTypeElementFromText( + componentType.getCanonicalText() + "...", method); + lastParameter.getTypeElement().replace(newTypeElement); + } + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new MethodCanBeVariableArityMethodVisitor(); + } + + private static class MethodCanBeVariableArityMethodVisitor + extends BaseInspectionVisitor { + + @Override + public void visitMethod(PsiMethod method) { + if (!PsiUtil.isLanguageLevel5OrHigher(method)) { + return; + } + super.visitMethod(method); + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList.getParametersCount() == 0) { + return; + } + final PsiParameter[] parameters = parameterList.getParameters(); + final PsiParameter lastParameter = + parameters[parameters.length - 1]; + final PsiType type = lastParameter.getType(); + if (!(type instanceof PsiArrayType)) { + return; + } + final PsiArrayType arrayType = (PsiArrayType) type; + final PsiType componentType = arrayType.getComponentType(); + if (componentType instanceof PsiArrayType) { + // don't report when it is multidimensional array + return; + } + registerMethodError(method); + } + } +} diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MethodCanBeVariableArityMethod.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MethodCanBeVariableArityMethod.html new file mode 100644 index 000000000000..ac5e248ddcc6 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MethodCanBeVariableArityMethod.html @@ -0,0 +1,11 @@ + + +This inspection reports methods with which can be converted to be a variable +arity/varargs method, available in Java 5 and newer. +

+This inspection only reports if the project or module is configured to use a +language level of 5.0 or higher. +

+New in 10.5, Powered by InspectionGadgets + + \ No newline at end of file From b87d8c47939e84a293bc7f8eab162a57d8b2d411 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Mon, 11 Apr 2011 13:51:04 +0400 Subject: [PATCH 016/102] @NotNulls --- .../intellij/codeInsight/template/TemplateBuilder.java | 9 +++++---- .../codeInsight/template/TemplateBuilderImpl.java | 8 ++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/platform/lang-api/src/com/intellij/codeInsight/template/TemplateBuilder.java b/platform/lang-api/src/com/intellij/codeInsight/template/TemplateBuilder.java index a9e27d9a28b1..a6b955f6b850 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/template/TemplateBuilder.java +++ b/platform/lang-api/src/com/intellij/codeInsight/template/TemplateBuilder.java @@ -18,6 +18,7 @@ package com.intellij.codeInsight.template; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; /** * Shows a live template-like chooser UI over a PSI element and offers the user to replace certain sub-elements of the @@ -34,9 +35,9 @@ public interface TemplateBuilder { * @param element the element to replace. * @param replacementText the initial value for the replacement. */ - void replaceElement(PsiElement element, String replacementText); + void replaceElement(@NotNull PsiElement element, String replacementText); - void replaceElement(PsiElement element, TextRange rangeWithinElement, String replacementText); + void replaceElement(@NotNull PsiElement element, TextRange rangeWithinElement, String replacementText); /** * Creates a replacement box for the specified element with the specified expression. @@ -44,9 +45,9 @@ public interface TemplateBuilder { * @param element the element to replace. * @param expression the replacement expression. */ - void replaceElement(PsiElement element, Expression expression); + void replaceElement(@NotNull PsiElement element, Expression expression); - void replaceElement(PsiElement element, TextRange rangeWithinElement, Expression expression); + void replaceElement(@NotNull PsiElement element, TextRange rangeWithinElement, Expression expression); /** * Creates a replacement box for the specified text range within the container element. diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateBuilderImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateBuilderImpl.java index 4e41928a7ba2..4855d980d53d 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateBuilderImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateBuilderImpl.java @@ -119,13 +119,13 @@ public class TemplateBuilderImpl implements TemplateBuilder { myElements.add(key); } - public void replaceElement(PsiElement element, Expression expression) { + public void replaceElement(@NotNull PsiElement element, Expression expression) { final RangeMarker key = wrapElement(element); replaceElement(key, expression); } @Override - public void replaceElement(PsiElement element, TextRange rangeWithinElement, Expression expression) { + public void replaceElement(@NotNull PsiElement element, TextRange rangeWithinElement, Expression expression) { final RangeMarker key = myDocument.createRangeMarker(rangeWithinElement.shiftRight(element.getTextRange().getStartOffset())); replaceElement(key, expression); } @@ -242,11 +242,11 @@ public class TemplateBuilderImpl implements TemplateBuilder { return myDocument.getCharsSequence().subSequence(startOffset, endOffset).toString(); } - public void replaceElement(PsiElement element, String replacementText) { + public void replaceElement(@NotNull PsiElement element, String replacementText) { replaceElement(element, new ConstantNode(replacementText)); } - public void replaceElement(PsiElement element, TextRange rangeWithinElement, String replacementText) { + public void replaceElement(@NotNull PsiElement element, TextRange rangeWithinElement, String replacementText) { final RangeMarker key = myDocument.createRangeMarker(rangeWithinElement.shiftRight(element.getTextRange().getStartOffset())); ConstantNode value = new ConstantNode(replacementText); replaceElement(key, value); From 2e5915029f97838c48142b9701877bed67d570d9 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Mon, 11 Apr 2011 13:51:25 +0400 Subject: [PATCH 017/102] EA-26173 - NPE: TemplateBuilderImpl.replaceElement --- .../src/com/intellij/xml/actions/GenerateXmlTagAction.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/xml/impl/src/com/intellij/xml/actions/GenerateXmlTagAction.java b/xml/impl/src/com/intellij/xml/actions/GenerateXmlTagAction.java index f300a7f537ef..d47721b197b4 100644 --- a/xml/impl/src/com/intellij/xml/actions/GenerateXmlTagAction.java +++ b/xml/impl/src/com/intellij/xml/actions/GenerateXmlTagAction.java @@ -218,7 +218,9 @@ public class GenerateXmlTagAction extends SimpleCodeInsightAction { private static void replaceElements(XmlTag tag, TemplateBuilder builder) { for (XmlAttribute attribute : tag.getAttributes()) { XmlAttributeValue value = attribute.getValueElement(); - builder.replaceElement(value, TextRange.from(1, 0), new MacroCallNode(new CompleteMacro())); + if (value != null) { + builder.replaceElement(value, TextRange.from(1, 0), new MacroCallNode(new CompleteMacro())); + } } if ("<".equals(tag.getText())) { builder.replaceElement(tag, TextRange.from(1, 0), new MacroCallNode(new CompleteSmartMacro())); From ce0940f3af0b7058455afa66542cd8b06fc4f2cc Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Tue, 12 Apr 2011 12:49:40 +0400 Subject: [PATCH 018/102] introducing AbstractDocumentationProvider --- .../regexp/RegExpDocumentationProvider.java | 4 +- .../fileTypes/ImageDocumentationProvider.java | 8 +-- .../lang/java/FileDocumentationProvider.java | 8 +-- .../AbstractDocumentationProvider.java | 52 +++++++++++++++++++ .../documentation/DocumentationProvider.java | 1 + .../QuickDocumentationProvider.java | 4 ++ .../PropertiesDocumentationProvider.java | 4 +- 7 files changed, 65 insertions(+), 16 deletions(-) create mode 100644 platform/lang-api/src/com/intellij/lang/documentation/AbstractDocumentationProvider.java diff --git a/RegExpSupport/src/org/intellij/lang/regexp/RegExpDocumentationProvider.java b/RegExpSupport/src/org/intellij/lang/regexp/RegExpDocumentationProvider.java index 40e89fc2e164..504a6752dbdd 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/RegExpDocumentationProvider.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/RegExpDocumentationProvider.java @@ -16,7 +16,7 @@ package org.intellij.lang.regexp; import com.intellij.lang.ASTNode; -import com.intellij.lang.documentation.QuickDocumentationProvider; +import com.intellij.lang.documentation.AbstractDocumentationProvider; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiManager; import org.intellij.lang.regexp.psi.RegExpElement; @@ -28,7 +28,7 @@ import org.jetbrains.annotations.Nullable; /** * @author vnikolaenko */ -public class RegExpDocumentationProvider extends QuickDocumentationProvider { +public class RegExpDocumentationProvider extends AbstractDocumentationProvider { @Override @Nullable public String generateDoc(PsiElement element, PsiElement originalElement) { diff --git a/images/src/org/intellij/images/fileTypes/ImageDocumentationProvider.java b/images/src/org/intellij/images/fileTypes/ImageDocumentationProvider.java index d1826fecb145..49199eb0da7e 100644 --- a/images/src/org/intellij/images/fileTypes/ImageDocumentationProvider.java +++ b/images/src/org/intellij/images/fileTypes/ImageDocumentationProvider.java @@ -15,7 +15,7 @@ */ package org.intellij.images.fileTypes; -import com.intellij.lang.documentation.QuickDocumentationProvider; +import com.intellij.lang.documentation.AbstractDocumentationProvider; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileWithId; @@ -30,13 +30,9 @@ import java.net.URISyntaxException; /** * @author spleaner */ -public class ImageDocumentationProvider extends QuickDocumentationProvider { +public class ImageDocumentationProvider extends AbstractDocumentationProvider { private static final int MAX_IMAGE_SIZE = 300; - public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) { - return null; - } - @Override public String generateDoc(PsiElement element, PsiElement originalElement) { final String[] result = new String[] {null}; diff --git a/java/java-impl/src/com/intellij/lang/java/FileDocumentationProvider.java b/java/java-impl/src/com/intellij/lang/java/FileDocumentationProvider.java index 22165ea4b7ef..d52530598263 100644 --- a/java/java-impl/src/com/intellij/lang/java/FileDocumentationProvider.java +++ b/java/java-impl/src/com/intellij/lang/java/FileDocumentationProvider.java @@ -17,17 +17,13 @@ package com.intellij.lang.java; import com.intellij.codeInsight.javadoc.JavaDocExternalFilter; import com.intellij.codeInsight.javadoc.JavaDocInfoGenerator; -import com.intellij.lang.documentation.QuickDocumentationProvider; +import com.intellij.lang.documentation.AbstractDocumentationProvider; import com.intellij.psi.PsiElement; /** * @author spleaner */ -public class FileDocumentationProvider extends QuickDocumentationProvider { - - public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) { - return null; - } +public class FileDocumentationProvider extends AbstractDocumentationProvider { @Override public String generateDoc(PsiElement element, PsiElement originalElement) { diff --git a/platform/lang-api/src/com/intellij/lang/documentation/AbstractDocumentationProvider.java b/platform/lang-api/src/com/intellij/lang/documentation/AbstractDocumentationProvider.java new file mode 100644 index 000000000000..91c903af7d41 --- /dev/null +++ b/platform/lang-api/src/com/intellij/lang/documentation/AbstractDocumentationProvider.java @@ -0,0 +1,52 @@ +/* + * Copyright 2000-2011 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.lang.documentation; + +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiManager; + +import java.util.List; + +/** + * @author Dmitry Avdeev + */ +public abstract class AbstractDocumentationProvider implements DocumentationProvider { + + @Override + public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) { + return null; + } + + @Override + public List getUrlFor(PsiElement element, PsiElement originalElement) { + return null; + } + + @Override + public String generateDoc(PsiElement element, PsiElement originalElement) { + return null; + } + + @Override + public PsiElement getDocumentationElementForLookupItem(PsiManager psiManager, Object object, PsiElement element) { + return null; + } + + @Override + public PsiElement getDocumentationElementForLink(PsiManager psiManager, String link, PsiElement context) { + return null; + } +} diff --git a/platform/lang-api/src/com/intellij/lang/documentation/DocumentationProvider.java b/platform/lang-api/src/com/intellij/lang/documentation/DocumentationProvider.java index 74e1ec5b7d5e..b889b30f7aff 100644 --- a/platform/lang-api/src/com/intellij/lang/documentation/DocumentationProvider.java +++ b/platform/lang-api/src/com/intellij/lang/documentation/DocumentationProvider.java @@ -25,6 +25,7 @@ import java.util.List; /** * @see com.intellij.lang.LanguageDocumentation + * @see AbstractDocumentationProvider */ public interface DocumentationProvider { diff --git a/platform/lang-api/src/com/intellij/lang/documentation/QuickDocumentationProvider.java b/platform/lang-api/src/com/intellij/lang/documentation/QuickDocumentationProvider.java index 45927d2cc97e..29901cb03d27 100644 --- a/platform/lang-api/src/com/intellij/lang/documentation/QuickDocumentationProvider.java +++ b/platform/lang-api/src/com/intellij/lang/documentation/QuickDocumentationProvider.java @@ -22,6 +22,10 @@ import org.jetbrains.annotations.Nullable; import java.util.List; +/** + * @see AbstractDocumentationProvider + */ +@Deprecated public abstract class QuickDocumentationProvider implements DocumentationProvider { @Nullable diff --git a/plugins/properties/src/com/intellij/lang/properties/PropertiesDocumentationProvider.java b/plugins/properties/src/com/intellij/lang/properties/PropertiesDocumentationProvider.java index 75be88e8c853..c0142a2a7566 100644 --- a/plugins/properties/src/com/intellij/lang/properties/PropertiesDocumentationProvider.java +++ b/plugins/properties/src/com/intellij/lang/properties/PropertiesDocumentationProvider.java @@ -19,7 +19,7 @@ */ package com.intellij.lang.properties; -import com.intellij.lang.documentation.QuickDocumentationProvider; +import com.intellij.lang.documentation.AbstractDocumentationProvider; import com.intellij.lang.properties.psi.Property; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.markup.TextAttributes; @@ -32,7 +32,7 @@ import org.jetbrains.annotations.Nullable; import java.awt.*; -public class PropertiesDocumentationProvider extends QuickDocumentationProvider { +public class PropertiesDocumentationProvider extends AbstractDocumentationProvider { @Nullable public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) { if (element instanceof Property) { From cd242d808a2035bccc4ce7a7af445f83b9f201a1 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Tue, 12 Apr 2011 13:31:49 +0400 Subject: [PATCH 019/102] javadoc --- .../com/intellij/lang/documentation/DocumentationProvider.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platform/lang-api/src/com/intellij/lang/documentation/DocumentationProvider.java b/platform/lang-api/src/com/intellij/lang/documentation/DocumentationProvider.java index b889b30f7aff..eacdb5538eb4 100644 --- a/platform/lang-api/src/com/intellij/lang/documentation/DocumentationProvider.java +++ b/platform/lang-api/src/com/intellij/lang/documentation/DocumentationProvider.java @@ -29,6 +29,9 @@ import java.util.List; */ public interface DocumentationProvider { + /** + * Please use {@link com.intellij.lang.LanguageDocumentation} instead of this for language-specific documentation + */ ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.documentationProvider"); @Nullable From 73ef2a8969ccbda8498125135e13b3b35b0b6a6a Mon Sep 17 00:00:00 2001 From: Kirill Kalishev Date: Wed, 13 Apr 2011 14:57:48 +0400 Subject: [PATCH 020/102] TreeUI: CCE fix --- .../com/intellij/ide/util/treeView/AbstractTreeUi.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java index 2927e0cc18da..6e86599db937 100644 --- a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java +++ b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java @@ -482,10 +482,13 @@ public class AbstractTreeUi { @Nullable private static NodeDescriptor getDescriptorFrom(Object node) { if (node instanceof DefaultMutableTreeNode) { - return (NodeDescriptor)((DefaultMutableTreeNode)node).getUserObject(); - } else { - return null; + Object userObject = ((DefaultMutableTreeNode)node).getUserObject(); + if (userObject instanceof NodeDescriptor) { + return (NodeDescriptor)userObject; + } } + + return null; } @Nullable From dc7343986c10f344a4fa203990489abf2bbf372b Mon Sep 17 00:00:00 2001 From: Alexey Pegov Date: Wed, 13 Apr 2011 15:28:50 +0400 Subject: [PATCH 021/102] IDEA-63663 Sort run configurations alphabetically if clean checkout (no workspace.xml were found) [r=ann] --- .../execution/impl/RunManagerImpl.java | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/execution/impl/RunManagerImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/RunManagerImpl.java index ceb8b8d985bc..361ccb059d16 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/RunManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/RunManagerImpl.java @@ -287,19 +287,28 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable, @Override public Collection getSortedConfigurations() { - if (!myOrdered && !myOrder.isEmpty()) { //compatibility + if (!myOrdered) { //compatibility final HashMap settings = - new HashMap(myConfigurations); //sort shared and local configurations + new HashMap(myConfigurations); //sort shared and local configurations myConfigurations.clear(); + final List order = new ArrayList(settings.keySet()); - Collections.sort(order, new Comparator() { - public int compare(final String o1, final String o2) { - return myOrder.indexOf(o1) - myOrder.indexOf(o2); - } - }); - for (String configName : order) { + if (myOrder.isEmpty()) { + // IDEA-63663 Sort run configurations alphabetically if clean checkout + Collections.sort(order); + } + else { + Collections.sort(order, new Comparator() { + public int compare(final String o1, final String o2) { + return myOrder.indexOf(o1) - myOrder.indexOf(o2); + } + }); + } + + for (final String configName : order) { myConfigurations.put(configName, settings.get(configName)); } + myOrdered = true; } return myConfigurations.values(); From e02e7562e8e9133482186ee282afba46f9dde0e4 Mon Sep 17 00:00:00 2001 From: Maxim Shafirov Date: Wed, 13 Apr 2011 15:27:05 +0400 Subject: [PATCH 022/102] IDEA-63971: mouse hits for marks inside folded ranges. --- .../editor/impl/EditorMarkupModelImpl.java | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java index dd41e8a8a8e4..c665fe5f779f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java @@ -187,11 +187,18 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark private void getNearestHighlighters(MarkupModelEx markupModel, MouseEvent e, final double width, final Collection nearest) { if (0 > e.getX() || e.getX() >= width) return; - int startOffset = yPositionToOffset(e.getY()-getMinHeight(), true); - int endOffset = yPositionToOffset(e.getY()+getMinHeight(), false); + final int y = e.getY(); + int startOffset = yPositionToOffset(y -getMinHeight(), true); + int endOffset = yPositionToOffset(y +getMinHeight(), false); markupModel.processHighlightsOverlappingWith(startOffset, endOffset, new Processor() { public boolean process(RangeHighlighterEx highlighter) { - if (highlighter.getErrorStripeMarkColor() != null) nearest.add(highlighter); + if (highlighter.getErrorStripeMarkColor() != null) { + ProperTextRange range = offsetToYPosition(highlighter.getStartOffset(), highlighter.getEndOffset()); + if (range.getStartOffset() >= y - getMinHeight() * 2 && + range.getEndOffset() <= y + getMinHeight() * 2) { + nearest.add(highlighter); + } + } return true; } }); @@ -797,6 +804,16 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark if (line < 0) return 0; if (line >= document.getLineCount()) return document.getTextLength(); - return beginLine ? document.getLineStartOffset(line) : document.getLineEndOffset(line); + final FoldingModelEx foldingModel = myEditor.getFoldingModel(); + if (beginLine) { + final int offset = document.getLineStartOffset(line); + final FoldRegion startCollapsed = foldingModel.getCollapsedRegionAtOffset(offset); + return startCollapsed != null ? Math.min(offset, startCollapsed.getStartOffset()) : offset; + } + else { + final int offset = document.getLineEndOffset(line); + final FoldRegion startCollapsed = foldingModel.getCollapsedRegionAtOffset(offset); + return startCollapsed != null ? Math.max(offset, startCollapsed.getEndOffset()) : offset; + } } } From 4784542e30211dea881aad4d5815072a8e10da11 Mon Sep 17 00:00:00 2001 From: Maxim Shafirov Date: Wed, 13 Apr 2011 15:28:39 +0400 Subject: [PATCH 023/102] Tolerate to missing searchableOptions.xml --- .../ide/ui/search/SearchableOptionsRegistrarImpl.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionsRegistrarImpl.java b/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionsRegistrarImpl.java index 9da67123c1b8..7c4d63da879b 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionsRegistrarImpl.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionsRegistrarImpl.java @@ -40,6 +40,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.event.DocumentEvent; +import java.net.URL; import java.util.*; import java.util.regex.Pattern; @@ -80,8 +81,14 @@ public class SearchableOptionsRegistrarImpl extends SearchableOptionsRegistrar { ContainerUtil.addAll(myStopWords, stopWords); //index + final URL indexResource = ResourceUtil.getResource(SearchableOptionsRegistrar.class, "/search/", "searchableOptions.xml"); + if (indexResource == null) { + LOG.info("No /search/searchableOptions.xml found, settings search won't work!"); + return; + } + Document document = - JDOMUtil.loadDocument(ResourceUtil.getResource(SearchableOptionsRegistrar.class, "/search/", "searchableOptions.xml")); + JDOMUtil.loadDocument(indexResource); Element root = document.getRootElement(); List configurables = root.getChildren("configurable"); for (final Object o : configurables) { From 37a88f9b3d6b6e258ba4288c0c7ad7c0a52b855d Mon Sep 17 00:00:00 2001 From: irengrig Date: Fri, 8 Apr 2011 17:53:17 +0400 Subject: [PATCH 024/102] progress for files --- .../changes/shelf/ShelveChangesManager.java | 5 +- .../com/intellij/vcsUtil/FilesProgress.java | 62 +++++++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 platform/vcs-impl/src/com/intellij/vcsUtil/FilesProgress.java diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java index 97ec0edcd960..f904fb734eb7 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java @@ -51,6 +51,7 @@ import com.intellij.util.continuation.*; import com.intellij.util.messages.MessageBus; import com.intellij.util.messages.Topic; import com.intellij.util.text.CharArrayCharSequence; +import com.intellij.vcsUtil.FilesProgress; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -237,9 +238,9 @@ public class ShelveChangesManager implements ProjectComponent, JDOMExternalizabl public List importChangeLists(final Collection files, final Consumer exceptionConsumer) { final List result = new ArrayList(files.size()); try { + final FilesProgress filesProgress = new FilesProgress(files.size(), "Processing "); for (VirtualFile file : files) { - ProgressManager.checkCanceled(); - + filesProgress.updateIndicator(file); final String description = file.getNameWithoutExtension().replace('_', ' '); final File patchPath = getPatchPath(description); final ShelvedChangeList list = new ShelvedChangeList(patchPath.getPath(), description, new SmartList(), diff --git a/platform/vcs-impl/src/com/intellij/vcsUtil/FilesProgress.java b/platform/vcs-impl/src/com/intellij/vcsUtil/FilesProgress.java new file mode 100644 index 000000000000..60dfc96bdf09 --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/vcsUtil/FilesProgress.java @@ -0,0 +1,62 @@ +/* + * Copyright 2000-2011 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.vcsUtil; + +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.vfs.VirtualFile; + +/** + * @author irengrig + * Date: 4/8/11 + * Time: 5:15 PM + */ +public class FilesProgress { + private final double myTotal; + private final String myPrefix; + private final ProgressIndicator myProgressIndicator; + private int myCnt; + private boolean myInText2; + + public FilesProgress(double total, final String prefix) { + myTotal = total; + myPrefix = prefix; + myProgressIndicator = ProgressManager.getInstance().getProgressIndicator(); + myCnt = 0; + myInText2 = false; + } + + public void updateIndicator(final VirtualFile vf) { + if (myProgressIndicator == null) return; + myProgressIndicator.checkCanceled(); + if (myInText2) { + myProgressIndicator.setText2(myPrefix + getFileDescriptionForProgress(vf)); + } else { + myProgressIndicator.setText(myPrefix + getFileDescriptionForProgress(vf)); + } + myProgressIndicator.setFraction(myCnt/myTotal); + ++ myCnt; + } + + private static String getFileDescriptionForProgress(final VirtualFile file) { + final VirtualFile parent = file.getParent(); + return file.getName() + " (" + (parent == null ? file.getPath() : parent.getPath()) + ")"; + } + + public void setInText2(boolean inText2) { + myInText2 = inText2; + } +} From ab9d0b32e3a215fa31e14297f692b96ec94a8965 Mon Sep 17 00:00:00 2001 From: irengrig Date: Wed, 13 Apr 2011 13:19:11 +0400 Subject: [PATCH 025/102] VCS: use VCS plugin name for notifications group id --- .../idea/svn/SvnAuthenticationNotifier.java | 3 +-- .../src/org/jetbrains/idea/svn/SvnVcs.java | 14 +++++++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationNotifier.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationNotifier.java index fd0e7e06eb24..8a2fdae3ed98 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationNotifier.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationNotifier.java @@ -45,14 +45,13 @@ import java.util.*; public class SvnAuthenticationNotifier extends GenericNotifierImpl { private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnAuthenticationNotifier"); - private static final String ourGroupId = "SubversionId"; private final SvnVcs myVcs; private final RootsToWorkingCopies myRootsToWorkingCopies; private final Map myCopiesPassiveResults; private Timer myTimer; public SvnAuthenticationNotifier(final SvnVcs svnVcs) { - super(svnVcs.getProject(), ourGroupId, "Not Logged In to Subversion", NotificationType.ERROR); + super(svnVcs.getProject(), svnVcs.getDisplayName(), "Not Logged In to Subversion", NotificationType.ERROR); myVcs = svnVcs; myRootsToWorkingCopies = myVcs.getRootsToWorkingCopies(); myCopiesPassiveResults = Collections.synchronizedMap(new HashMap()); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java index b7f6a5aaba33..8b8af3ba5ce8 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java @@ -21,6 +21,8 @@ import com.intellij.ide.FrameStateListener; import com.intellij.ide.FrameStateManager; import com.intellij.idea.RareLogger; import com.intellij.notification.*; +import com.intellij.notification.impl.NotificationSettings; +import com.intellij.notification.impl.NotificationsConfiguration; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; @@ -221,6 +223,10 @@ public class SvnVcs extends AbstractVcs { myFrameStateListener = new MyFrameStateListener(changeListManager, vcsDirtyScopeManager); myWorkingCopiesContent = new WorkingCopiesContent(this); + + // remove used some time before old notification group ids + NotificationsConfiguration.remove(new NotificationSettings[] {new NotificationSettings("SVN_NO_JNA", null), + new NotificationSettings("SVN_NO_CRYPT32", null), new NotificationSettings("SubversionId", null)}); } public void postStartup() { @@ -328,15 +334,13 @@ public class SvnVcs extends AbstractVcs { } } - private final static String UPGRADE_SUBVERSION_FORMAT = "Subversion"; - private void upgradeToRecentVersion(final SvnConfiguration.SvnSupportOptions supportOptions) { if (! supportOptions.upgradeTo16Asked()) { final SvnWorkingCopyChecker workingCopyChecker = new SvnWorkingCopyChecker(); if (workingCopyChecker.upgradeNeeded()) { - Notifications.Bus.notify(new Notification(UPGRADE_SUBVERSION_FORMAT, SvnBundle.message("upgrade.format.to16.question.title"), + Notifications.Bus.notify(new Notification(getDisplayName(), SvnBundle.message("upgrade.format.to16.question.title"), "Old format Subversion working copies could be upgraded to version 1.6.", NotificationType.INFORMATION, new NotificationListener() { public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) { @@ -374,10 +378,10 @@ public class SvnVcs extends AbstractVcs { if (SystemInfo.isWindows) { if (! SVNJNAUtil.isJNAPresent()) { - Notifications.Bus.notify(new Notification("SVN_NO_JNA", "Subversion plugin: no JNA", + Notifications.Bus.notify(new Notification(getDisplayName(), "Subversion plugin: no JNA", "A problem with JNA initialization for svnkit library. Encryption is not available.", NotificationType.WARNING), NotificationDisplayType.BALLOON, myProject); } else if (! SVNJNAUtil.isWinCryptEnabled()) { - Notifications.Bus.notify(new Notification("SVN_NO_CRYPT32", "Subversion plugin: no encryption", + Notifications.Bus.notify(new Notification(getDisplayName(), "Subversion plugin: no encryption", "A problem with encryption module (Crypt32.dll) initialization for svnkit library. Encryption is not available.", NotificationType.WARNING), NotificationDisplayType.BALLOON, myProject); } } From f008573b3fa6612ec3cca922887929ec1840b9f1 Mon Sep 17 00:00:00 2001 From: irengrig Date: Wed, 13 Apr 2011 14:04:25 +0400 Subject: [PATCH 026/102] SVN: when changing notification ids, also make Subversion group sticky balloon - since group was used before, but for other kinds (will be done once) --- .../src/org/jetbrains/idea/svn/SvnVcs.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java index 8b8af3ba5ce8..f4dd88bc9e23 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java @@ -225,8 +225,22 @@ public class SvnVcs extends AbstractVcs { myWorkingCopiesContent = new WorkingCopiesContent(this); // remove used some time before old notification group ids - NotificationsConfiguration.remove(new NotificationSettings[] {new NotificationSettings("SVN_NO_JNA", null), - new NotificationSettings("SVN_NO_CRYPT32", null), new NotificationSettings("SubversionId", null)}); + correctNotificationIds(); + } + + private void correctNotificationIds() { + boolean notEmpty = NotificationsConfiguration.getSettings("SVN_NO_JNA") != null || + NotificationsConfiguration.getSettings("SVN_NO_CRYPT32") != null || + NotificationsConfiguration.getSettings("SubversionId") != null; + if (notEmpty) { + NotificationsConfiguration.remove(new NotificationSettings[] {new NotificationSettings("SVN_NO_JNA", null), + new NotificationSettings("SVN_NO_CRYPT32", null), new NotificationSettings("SubversionId", null)}); + // if group ids is being changed, set highest level first + final NotificationSettings settings = NotificationsConfiguration.getSettings(getDisplayName()); + if (settings != null) { + settings.setDisplayType(NotificationDisplayType.STICKY_BALLOON); + } + } } public void postStartup() { From 223eba72a6f03a23233097b43c26eeb6fc51ad9b Mon Sep 17 00:00:00 2001 From: irengrig Date: Wed, 13 Apr 2011 16:01:23 +0400 Subject: [PATCH 027/102] P4: detect offline state. Offline notification. Also when offline state edited from settings --- .../intellij/openapi/vcs/impl/GenericNotifierImpl.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/GenericNotifierImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/GenericNotifierImpl.java index 245e377bc1ff..a2ca4b56f722 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/GenericNotifierImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/GenericNotifierImpl.java @@ -28,7 +28,7 @@ import java.util.*; public abstract class GenericNotifierImpl { private final static Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.impl.GenericNotifier"); - private final Project myProject; + protected final Project myProject; @NotNull private final String myGroupId; //+- here @NotNull @@ -181,4 +181,10 @@ public abstract class GenericNotifierImpl { private static void log(final String s) { LOG.debug(s); } + + public boolean isEmpty() { + synchronized (myLock) { + return myState.isEmpty(); + } + } } From 838f8f67fcdb1907f44cc370f316cf2851b9b016 Mon Sep 17 00:00:00 2001 From: Shaverdova Elena Date: Wed, 13 Apr 2011 16:02:36 +0400 Subject: [PATCH 028/102] Phing initial commit --- .../openapi/actionSystem/ActionPlaces.java | 9 +- .../buildfiles/ForcedBuildFileAttribute.java | 107 ++++++++++++++++++ .../intellij/openapi/util/io/FileUtil.java | 53 ++++++++- .../openapi/util/io/FileUtilFindFileTest.java | 89 +++++++++++++++ plugins/ant/ant.iml | 5 +- .../lang/ant/ForcedAntFileAttribute.java | 43 ++++--- .../lang/ant/dom/AntDomFileDescription.java | 7 +- 7 files changed, 279 insertions(+), 34 deletions(-) create mode 100644 platform/platform-impl/src/com/intellij/buildfiles/ForcedBuildFileAttribute.java create mode 100644 platform/util/testSrc/com/intellij/openapi/util/io/FileUtilFindFileTest.java diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java index bf31a84e1256..7b86e53a25d7 100644 --- a/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2011 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. @@ -103,10 +103,13 @@ public abstract class ActionPlaces { public static final String TFS_TREE_POPUP = "TfsTreePopup"; public static final String ACTION_PLACE_VCS_QUICK_LIST_POPUP_ACTION = "ActionPlace.VcsQuickListPopupAction"; + public static final String PHING_EXPLORER_POPUP = "PhingExplorerPopup"; + public static final String PHING_EXPLORER_TOOLBAR = "PhingExplorerToolbar"; + private static final String[] ourToolbarPlaces = new String[]{EDITOR_TOOLBAR, PROJECT_VIEW_TOOLBAR, TESTTREE_VIEW_TOOLBAR, MAIN_TOOLBAR, ANT_EXPLORER_TOOLBAR, ANT_MESSAGES_TOOLBAR, COMPILER_MESSAGES_TOOLBAR, TODO_VIEW_TOOLBAR, STRUCTURE_VIEW_TOOLBAR, USAGE_VIEW_TOOLBAR, DEBUGGER_TOOLBAR, CALL_HIERARCHY_VIEW_TOOLBAR, METHOD_HIERARCHY_VIEW_TOOLBAR, TYPE_HIERARCHY_VIEW_TOOLBAR, JAVADOC_TOOLBAR, - FILE_HISTORY_TOOLBAR, FILEHISTORY_VIEW_TOOLBAR, LVCS_DIRECTORY_HISTORY_TOOLBAR, CHANGES_VIEW_TOOLBAR, }; + FILE_HISTORY_TOOLBAR, FILEHISTORY_VIEW_TOOLBAR, LVCS_DIRECTORY_HISTORY_TOOLBAR, CHANGES_VIEW_TOOLBAR, PHING_EXPLORER_TOOLBAR }; public static boolean isToolbarPlace(@NotNull String place) { return ArrayUtil.find(ourToolbarPlaces, place) != -1; @@ -118,7 +121,7 @@ public abstract class ActionPlaces { STRUCTURE_VIEW_POPUP, TODO_VIEW_POPUP, COMPILER_MESSAGES_POPUP, ANT_MESSAGES_POPUP, ANT_EXPLORER_POPUP, UPDATE_POPUP, FILEVIEW_POPUP, CHECKOUT_POPUP, LVCS_DIRECTORY_HISTORY_POPUP, GUI_DESIGNER_EDITOR_POPUP, GUI_DESIGNER_COMPONENT_TREE_POPUP, GUI_DESIGNER_PROPERTY_INSPECTOR_POPUP, CREATE_EJB_POPUP, CHANGES_VIEW_POPUP, REMOTE_HOST_VIEW_POPUP, REMOTE_HOST_DIALOG_POPUP, TFS_TREE_POPUP, - ACTION_PLACE_VCS_QUICK_LIST_POPUP_ACTION + ACTION_PLACE_VCS_QUICK_LIST_POPUP_ACTION , PHING_EXPLORER_POPUP }; public static boolean isPopupPlace(@NotNull String place) { diff --git a/platform/platform-impl/src/com/intellij/buildfiles/ForcedBuildFileAttribute.java b/platform/platform-impl/src/com/intellij/buildfiles/ForcedBuildFileAttribute.java new file mode 100644 index 000000000000..9da3b5c2f09d --- /dev/null +++ b/platform/platform-impl/src/com/intellij/buildfiles/ForcedBuildFileAttribute.java @@ -0,0 +1,107 @@ +/* + * Copyright 2000-2011 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.buildfiles; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.newvfs.FileAttribute; +import com.intellij.openapi.vfs.newvfs.NewVirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Created by IntelliJ IDEA. + * User: lene + * Date: 04.04.11 + * Time: 17:40 + */ +public class ForcedBuildFileAttribute { + private static final Logger LOG = Logger.getInstance("#" + ForcedBuildFileAttribute.class.getName()); + + private static final FileAttribute FRAMEWORK_FILE_ATTRIBUTE = new FileAttribute("forcedBuildFileFrameworkAttribute", 1, false); + private static final Key FRAMEWORK_FILE_MARKER = Key.create("forcedBuildFileFrameworkAttribute"); + + + private ForcedBuildFileAttribute() { + } + + public static boolean belongsToFramework(VirtualFile file, @NotNull String frameworkId) { + return frameworkId.equals(getFrameworkIdOfBuildFile(file)); + } + + @Nullable + public static String getFrameworkIdOfBuildFile(VirtualFile file) { + if (file instanceof NewVirtualFile) { + final DataInputStream is = FRAMEWORK_FILE_ATTRIBUTE.readAttribute(file); + if (is != null) { + try { + try { + /* + //todo[lene] IOUtil throws java.io.EOFException + at java.io.DataInputStream.readFully(DataInputStream.java:180) + at java.io.DataInputStream.readFully(DataInputStream.java:152) + at com.intellij.util.io.IOUtil.readString(IOUtil.java:40) + at com.intellij.buildfiles.ForcedBuildFileAttribute.getFrameworkIdOfBuildFile(ForcedBuildFileAttribute.java:59) + */ + return is.readUTF(); + } + finally { + is.close(); + } + } + catch (IOException e) { + LOG.error(e); + } + } + return ""; + } + return file.getUserData(FRAMEWORK_FILE_MARKER); + } + + + public static void forceFileToFramework(VirtualFile file, String frameworkId, boolean value) { + if (!value && !frameworkId.equals(getFrameworkIdOfBuildFile(file))) {//belongs to other framework + return; + } + forceBuildFile(file, frameworkId); + } + + + private static void forceBuildFile(VirtualFile file, String value) { + if (file instanceof NewVirtualFile) { + final DataOutputStream os = FRAMEWORK_FILE_ATTRIBUTE.writeAttribute(file); + try { + try { + os.writeUTF(value); + } + finally { + os.close(); + } + } + catch (IOException e) { + LOG.error(e); + } + } + else { + file.putUserData(FRAMEWORK_FILE_MARKER, value); + } + } +} diff --git a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java index b6ee40302f1f..c406f88f1eee 100644 --- a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java +++ b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2011 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. @@ -120,7 +120,7 @@ public class FileUtil { * @param strict if {@code false} then this method returns {@code true} if {@code ancestor} * and {@code file} are equal * @return {@code true} if {@code ancestor} is parent of {@code file}; {@code false} otherwise - * @throws IOException this exception is never thrown and left here for backward compatibilty + * @throws IOException this exception is never thrown and left here for backward compatibilty */ public static boolean isAncestor(@NotNull File ancestor, @NotNull File file, boolean strict) throws IOException { File parent = strict ? getParentFile(file) : file; @@ -902,7 +902,7 @@ public class FileUtil { /** * Has duplicate: {@link com.intellij.coverage.listeners.CoverageListener#sanitize(java.lang.String, java.lang.String)} - * as FileUtil is not available in client's vm + * as FileUtil is not available in client's vm */ @NotNull public static String sanitizeFileName(@NotNull String name) { @@ -1016,4 +1016,51 @@ public class FileUtil { } return found; } + + /** + * Returns empty string for empty path. + * First checks whether provided path is a path of a file with sought-for name. + * Unless found, checks if provided file was a directory. In this case checks existance + * of child files with given names in order "as provided". Finally checks filename among + * brother-files of provided. Returns null if nothing found. + * + * @return path of the first of found files or empty string or null. + */ + @Nullable + public static String findFileInProvidedPath(String providedPath, String... fileNames) { + if (StringUtil.isEmpty(providedPath)) { + return ""; + } + + File providedFile = new File(providedPath); + if (providedFile.exists()) { + String name = providedFile.getName(); + for (String fileName : fileNames) { + if (name.equals(fileName)) { + return toSystemDependentName(providedFile.getPath()); + } + } + } + + if (providedFile.isDirectory()) { //user chose folder with file + for (String fileName : fileNames) { + File file = new File(providedFile, fileName); + if (fileName.equals(file.getName()) && file.exists()) { + return toSystemDependentName(file.getPath()); + } + } + } + + providedFile = providedFile.getParentFile(); //users chose wrong file in same directory + if (providedFile != null && providedFile.exists()) { + for (String fileName : fileNames) { + File file = new File(providedFile, fileName); + if (fileName.equals(file.getName()) && file.exists()) { + return toSystemDependentName(file.getPath()); + } + } + } + + return null; + } } diff --git a/platform/util/testSrc/com/intellij/openapi/util/io/FileUtilFindFileTest.java b/platform/util/testSrc/com/intellij/openapi/util/io/FileUtilFindFileTest.java new file mode 100644 index 000000000000..701128508a89 --- /dev/null +++ b/platform/util/testSrc/com/intellij/openapi/util/io/FileUtilFindFileTest.java @@ -0,0 +1,89 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.util.io; + +import com.intellij.openapi.util.text.StringUtil; +import junit.framework.TestCase; + +import java.io.File; +import java.io.IOException; + +/** + * Created by IntelliJ IDEA. + * User: lene + * Date: 29.03.11 + * Time: 17:16 + */ +public class FileUtilFindFileTest extends TestCase { + private final File myTempFile; + private final File myFirstFile; + private final File mySecondFile; + + @SuppressWarnings({"JUnitTestCaseWithNonTrivialConstructors"}) + public FileUtilFindFileTest() throws IOException { + myTempFile = FileUtil.createTempDirectory("tEF", ""); //NON-NLS + myFirstFile = new File(myTempFile, "first"); + mySecondFile = new File(myTempFile, "second"); //NON-NLS + assertTrue(myFirstFile.createNewFile()); + assertTrue(mySecondFile.createNewFile()); + } + + public void testNonExistingFileInNonExistentDirectory() throws Exception { + String path = FileUtil.findFileInProvidedPath("123", "zero");//NON-NLS + assertTrue(StringUtil.isEmpty(path)); + } + + public void testNonExistingFileInDirectory() throws Exception { + String path = FileUtil.findFileInProvidedPath(myTempFile.getAbsolutePath(), "zero");//NON-NLS + assertTrue(StringUtil.isEmpty(path)); + } + + public void testNonExistingFile() throws Exception { + String path = + FileUtil.findFileInProvidedPath(myFirstFile.getAbsolutePath() + "123", myFirstFile.getName() + "123"); + assertTrue(StringUtil.isEmpty(path)); + } + + public void testExistingFileInDirectory() throws Exception { + String path = FileUtil.findFileInProvidedPath(myTempFile.getAbsolutePath(), "first"); + assertEquals(path, myFirstFile.getAbsolutePath()); + } + + public void testExistingFile() throws Exception { + String path = FileUtil.findFileInProvidedPath(myFirstFile.getAbsolutePath(), "first"); + assertEquals(path, myFirstFile.getAbsolutePath()); + } + + public void testTwoFilesOrderInDirectory() throws Exception { + String path = FileUtil.findFileInProvidedPath(myTempFile.getAbsolutePath(), "first", "second"); //NON-NLS + assertEquals(path, myFirstFile.getAbsolutePath()); + } + + public void testTwoFilesOrderInDirectory2() throws Exception { + String path = FileUtil.findFileInProvidedPath(myTempFile.getAbsolutePath(), "second", "first"); //NON-NLS + assertEquals(path, mySecondFile.getAbsolutePath()); + } + + public void testTwoFilesOrder() throws Exception { + String path = FileUtil.findFileInProvidedPath(myFirstFile.getAbsolutePath(), "first", "second");//NON-NLS + assertEquals(path, myFirstFile.getAbsolutePath()); + } + + public void testTwoFilesOrder2() throws Exception { + String path = FileUtil.findFileInProvidedPath(myFirstFile.getAbsolutePath(), "second", "first"); //NON-NLS + assertEquals(path, myFirstFile.getAbsolutePath()); + } +} diff --git a/plugins/ant/ant.iml b/plugins/ant/ant.iml index 3ff75610bb1f..54328549d2b6 100644 --- a/plugins/ant/ant.iml +++ b/plugins/ant/ant.iml @@ -9,8 +9,8 @@ - - + + @@ -23,6 +23,7 @@ + diff --git a/plugins/ant/src/com/intellij/lang/ant/ForcedAntFileAttribute.java b/plugins/ant/src/com/intellij/lang/ant/ForcedAntFileAttribute.java index 0b538377e2ee..0f18fd1f793c 100644 --- a/plugins/ant/src/com/intellij/lang/ant/ForcedAntFileAttribute.java +++ b/plugins/ant/src/com/intellij/lang/ant/ForcedAntFileAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2011 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,14 +15,15 @@ */ package com.intellij.lang.ant; +import com.intellij.buildfiles.ForcedBuildFileAttribute; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.newvfs.FileAttribute; import com.intellij.openapi.vfs.newvfs.NewVirtualFile; import java.io.DataInputStream; -import java.io.DataOutputStream; import java.io.IOException; /** @@ -31,15 +32,27 @@ import java.io.IOException; */ public class ForcedAntFileAttribute extends FileAttribute { private static final Logger LOG = Logger.getInstance("#com.intellij.lang.ant.ForcedAntFileAttribute"); - + + private static final String ANT_ID = "ant"; + private static final ForcedAntFileAttribute ourAttribute = new ForcedAntFileAttribute(); private static final Key ourAntFileMarker = Key.create("_forced_ant_attribute_"); - + public ForcedAntFileAttribute() { super("_forced_ant_attribute_", 1, true); } - + public static boolean isAntFile(VirtualFile file) { + String id = ForcedBuildFileAttribute.getFrameworkIdOfBuildFile(file); + return ANT_ID.equals(id) || (StringUtil.isEmpty(id) && isAntFileOld(file)); + } + + public static boolean mayBeAntFile(VirtualFile file) { + String id = ForcedBuildFileAttribute.getFrameworkIdOfBuildFile(file); + return StringUtil.isEmpty(id) || ANT_ID.equals(id); + } + + private static boolean isAntFileOld(VirtualFile file) { if (file instanceof NewVirtualFile) { final DataInputStream is = ourAttribute.readAttribute(file); if (is != null) { @@ -59,24 +72,8 @@ public class ForcedAntFileAttribute extends FileAttribute { } return Boolean.TRUE.equals(file.getUserData(ourAntFileMarker)); } - + public static void forceAntFile(VirtualFile file, boolean value) { - if (file instanceof NewVirtualFile) { - final DataOutputStream os = ourAttribute.writeAttribute(file); - try { - try { - os.writeBoolean(value); - } - finally { - os.close(); - } - } - catch (IOException e) { - LOG.error(e); - } - } - else { - file.putUserData(ourAntFileMarker, Boolean.valueOf(value)); - } + ForcedBuildFileAttribute.forceFileToFramework(file, ANT_ID, value); } } diff --git a/plugins/ant/src/com/intellij/lang/ant/dom/AntDomFileDescription.java b/plugins/ant/src/com/intellij/lang/ant/dom/AntDomFileDescription.java index d538de8a1f54..feff55d1ef19 100644 --- a/plugins/ant/src/com/intellij/lang/ant/dom/AntDomFileDescription.java +++ b/plugins/ant/src/com/intellij/lang/ant/dom/AntDomFileDescription.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2011 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,12 +43,13 @@ public class AntDomFileDescription extends AntFileDescription { final XmlDocument document = xmlFile.getDocument(); if (document != null) { final XmlTag tag = document.getRootTag(); + final VirtualFile vFile = xmlFile.getOriginalFile().getVirtualFile(); if (tag != null && ROOT_TAG_NAME.equals(tag.getName()) && tag.getContext() instanceof XmlDocument) { - if (tag.getAttributeValue("name") != null && tag.getAttributeValue("default") != null) { + if (tag.getAttributeValue("name") != null && tag.getAttributeValue("default") != null + && vFile != null && ForcedAntFileAttribute.mayBeAntFile(vFile)) { return true; } } - final VirtualFile vFile = xmlFile.getOriginalFile().getVirtualFile(); if (vFile != null && ForcedAntFileAttribute.isAntFile(vFile)) { return true; } From e36f6fa507101d47ed41e0ed271b7a735b9b460e Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Wed, 13 Apr 2011 14:58:08 +0200 Subject: [PATCH 029/102] IDEA-67323 (New inspection: StringBuffer/StringBuilder is modified but never queried) --- .../siyeh/InspectionGadgetsBundle.properties | 3 + .../com/siyeh/ig/InspectionGadgetsPlugin.java | 1 + ...hedStringBuilderQueryUpdateInspection.java | 374 ++++++++++++++++++ .../MismatchedStringBuilderQueryUpdate.html | 9 + 4 files changed, 387 insertions(+) create mode 100644 plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MismatchedStringBuilderQueryUpdateInspection.java create mode 100644 plugins/InspectionGadgets/src/inspectionDescriptions/MismatchedStringBuilderQueryUpdate.html diff --git a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties index 8ec733d3a713..254c1458b284 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties @@ -1878,3 +1878,6 @@ arrays.hash.code.quickfix=Replace with 'Arrays.hashCode()' method.can.be.variable.arity.method.display.name=Method can be variable arity method method.can.be.variable.arity.method.problem.descriptor=#ref() can be converted to variable arity method convert.to.variable.arity.method.quickfix=Convert to variable arity method +mismatched.string.builder.query.update.display.name=Mismatched query and update of StringBuilder +mismatched.string.builder.updated.problem.descriptor=Contents of {0} #ref are updated, but never queried #loc +mismatched.string.builder.queried.problem.descriptor=Contents of {0} #ref are queried, but never updated #loc diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java b/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java index 8188adaf9c1a..59217967ddfd 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java @@ -552,6 +552,7 @@ public class InspectionGadgetsPlugin implements ApplicationComponent, } m_inspectionClasses.add(MismatchedArrayReadWriteInspection.class); m_inspectionClasses.add(MismatchedCollectionQueryUpdateInspection.class); + m_inspectionClasses.add(MismatchedStringBuilderQueryUpdateInspection.class); m_inspectionClasses.add(MisspelledCompareToInspection.class); m_inspectionClasses.add(MisspelledHashcodeInspection.class); m_inspectionClasses.add(MisspelledEqualsInspection.class); diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MismatchedStringBuilderQueryUpdateInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MismatchedStringBuilderQueryUpdateInspection.java new file mode 100644 index 000000000000..5cd627952100 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MismatchedStringBuilderQueryUpdateInspection.java @@ -0,0 +1,374 @@ +/* + * Copyright 2011 Bas Leijdekkers + * + * 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.siyeh.ig.bugs; + +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.psiutils.TypeUtils; +import com.siyeh.ig.psiutils.VariableAccessUtils; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import java.util.HashSet; +import java.util.Set; + +public class MismatchedStringBuilderQueryUpdateInspection extends BaseInspection { + + @NonNls + private static final Set returnSelfNames = new HashSet(); + static { + returnSelfNames.add("append"); + returnSelfNames.add("appendCodePoint"); + returnSelfNames.add("delete"); + returnSelfNames.add("deleteCharAt"); + returnSelfNames.add("insert"); + returnSelfNames.add("replace"); + returnSelfNames.add("reverse"); + } + + @Override + @NotNull + public String getID(){ + return "MismatchedQueryAndUpdateOfStringBuilder"; + } + + @Nls + @NotNull + @Override + public String getDisplayName() { + return InspectionGadgetsBundle.message( + "mismatched.string.builder.query.update.display.name"); + } + + @NotNull + @Override + protected String buildErrorString(Object... infos) { + final boolean updated = ((Boolean)infos[0]).booleanValue(); + final PsiType type = (PsiType)infos[1]; //"StringBuilder"; + if(updated){ + return InspectionGadgetsBundle.message( + "mismatched.string.builder.updated.problem.descriptor", + type.getPresentableText()); + } else{ + return InspectionGadgetsBundle.message( + "mismatched.string.builder.queried.problem.descriptor", + type.getPresentableText()); + } + } + + @Override + public boolean isEnabledByDefault() { + return true; + } + + @Override + public boolean runForWholeFile() { + return true; + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new MismatchedQueryAndUpdateOfStringBuilderVisitor(); + } + + private static class MismatchedQueryAndUpdateOfStringBuilderVisitor + extends BaseInspectionVisitor { + + @Override + public void visitField(PsiField field) { + super.visitField(field); + if (!field.hasModifierProperty(PsiModifier.PRIVATE)) { + return; + } + final PsiClass containingClass = PsiUtil.getTopLevelClass(field); + if (!checkVariable(field, containingClass)) { + return; + } + final boolean queried = + stringBuilderContentsAreQueried(field, containingClass); + final boolean updated = + stringBuilderContentsAreUpdated(field, containingClass); + if (queried == updated) { + return; + } + registerFieldError(field, Boolean.valueOf(updated), + field.getType()); + } + + @Override + public void visitLocalVariable(PsiLocalVariable variable) { + super.visitLocalVariable(variable); + final PsiCodeBlock codeBlock = + PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class); + if (!checkVariable(variable, codeBlock)) { + return; + } + final boolean queried = + stringBuilderContentsAreQueried(variable, codeBlock); + final boolean updated = + stringBuilderContentsAreUpdated(variable, codeBlock); + if (queried == updated) { + return; + } + registerVariableError(variable, Boolean.valueOf(updated), + variable.getType()); + } + + private static boolean checkVariable(PsiVariable variable, + PsiElement context) { + if(context == null){ + return false; + } + if (!TypeUtils.variableHasTypeOrSubtype(variable, + "java.lang.AbstractStringBuilder")) { + return false; + } + if(VariableAccessUtils.variableIsAssigned(variable, context)){ + return false; + } + if(VariableAccessUtils.variableIsAssignedFrom(variable, context)){ + return false; + } + if(VariableAccessUtils.variableIsReturned(variable, context)){ + return false; + } + return !VariableAccessUtils.variableIsUsedInArrayInitializer( + variable, context); + } + + private static boolean stringBuilderContentsAreUpdated( + PsiVariable variable, PsiElement context) { + final PsiExpression initializer = variable.getInitializer(); + if (initializer != null && !isDefaultConstructorCall(initializer)) { + return true; + } + return isStringBuilderUpdated(variable, context); + } + + private static boolean stringBuilderContentsAreQueried( + PsiVariable variable, PsiElement context) { + return isStringBuilderQueried(variable, context); + } + + private static boolean isDefaultConstructorCall( + PsiExpression initializer) { + if (!(initializer instanceof PsiNewExpression)) { + return false; + } + final PsiNewExpression newExpression = + (PsiNewExpression) initializer; + final PsiJavaCodeReferenceElement classReference = + newExpression.getClassReference(); + if (classReference == null) { + return false; + } + final PsiElement target = classReference.resolve(); + if (!(target instanceof PsiClass)) { + return false; + } + final PsiClass aClass = (PsiClass) target; + final String qualifiedName = aClass.getQualifiedName(); + if (!"java.lang.StringBuilder".equals(qualifiedName) && + !"java.lang.StringBuffer".equals(qualifiedName)) { + return false; + } + final PsiExpressionList argumentList = + newExpression.getArgumentList(); + if (argumentList == null) { + return false; + } + final PsiExpression[] arguments = argumentList.getExpressions(); + if (arguments.length == 0) { + return true; + } + final PsiExpression argument = arguments[0]; + final PsiType argumentType = argument.getType(); + return PsiType.INT.equals(argumentType); + } + } + + public static boolean isStringBuilderUpdated(PsiVariable variable, + PsiElement context) { + final StringBuilderUpdateCalledVisitor visitor = + new StringBuilderUpdateCalledVisitor(variable); + context.accept(visitor); + return visitor.isUpdated(); + } + + private static class StringBuilderUpdateCalledVisitor + extends JavaRecursiveElementVisitor { + + @NonNls + private static final Set updateNames = new HashSet(); + static { + updateNames.add("append"); + updateNames.add("appendCodePoint"); + updateNames.add("delete"); + updateNames.add("delete"); + updateNames.add("deleteCharAt"); + updateNames.add("insert"); + updateNames.add("replace"); + updateNames.add("setCharAt"); + } + + private final PsiVariable variable; + boolean updated = false; + + public StringBuilderUpdateCalledVisitor(PsiVariable variable) { + this.variable = variable; + } + + public boolean isUpdated() { + return updated; + } + + @Override + public void visitMethodCallExpression( + PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + if (updated) { + return; + } + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = + expression.getMethodExpression(); + final String name = methodExpression.getReferenceName(); + if (!updateNames.contains(name)) { + return; + } + final PsiExpression qualifierExpression = + methodExpression.getQualifierExpression(); + if (hasReferenceToVariable(variable, qualifierExpression)) { + updated = true; + } + } + } + + public static boolean isStringBuilderQueried(PsiVariable variable, + PsiElement context) { + final StringBuilderQueryCalledVisitor visitor = + new StringBuilderQueryCalledVisitor(variable); + context.accept(visitor); + return visitor.isQueried(); + } + + private static class StringBuilderQueryCalledVisitor + extends JavaRecursiveElementVisitor { + + @NonNls + private static final Set queryNames = new HashSet(); + static { + queryNames.add("toString"); + queryNames.add("indexOf"); + queryNames.add("lastIndexOf"); + queryNames.add("capacity"); + queryNames.add("charAt"); + queryNames.add("codePointAt"); + queryNames.add("codePointBefore"); + queryNames.add("codePointCount"); + queryNames.add("equals"); + queryNames.add("getChars"); + queryNames.add("hashCode"); + queryNames.add("length"); + queryNames.add("offsetByCodePoints"); + queryNames.add("subSequence"); + queryNames.add("substring"); + } + + private final PsiVariable variable; + private boolean queried = false; + + private StringBuilderQueryCalledVisitor(PsiVariable variable) { + this.variable = variable; + } + + public boolean isQueried() { + return queried; + } + + @Override public void visitElement(@NotNull PsiElement element){ + if (queried) { + return; + } + super.visitElement(element); + } + + @Override + public void visitMethodCallExpression( + PsiMethodCallExpression expression) { + if (queried) { + return; + } + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = + expression.getMethodExpression(); + final String name = methodExpression.getReferenceName(); + if (!queryNames.contains(name)) { + return; + } + final PsiExpression qualifierExpression = + methodExpression.getQualifierExpression(); + if (hasReferenceToVariable(variable, qualifierExpression)) { + queried = true; + } + } + } + + private static boolean hasReferenceToVariable(PsiVariable variable, + PsiElement element) { + if (element instanceof PsiReferenceExpression) { + final PsiReferenceExpression referenceExpression = + (PsiReferenceExpression) element; + final PsiElement target = referenceExpression.resolve(); + if (variable.equals(target)) { + return true; + } + } else if (element instanceof PsiParenthesizedExpression) { + final PsiParenthesizedExpression parenthesizedExpression = + (PsiParenthesizedExpression) element; + final PsiExpression expression = + parenthesizedExpression.getExpression(); + return hasReferenceToVariable(variable, expression); + } else if (element instanceof PsiMethodCallExpression) { + final PsiMethodCallExpression methodCallExpression = + (PsiMethodCallExpression) element; + final PsiReferenceExpression methodExpression = + methodCallExpression.getMethodExpression(); + final String name = methodExpression.getReferenceName(); + if (returnSelfNames.contains(name)) { + return hasReferenceToVariable(variable, + methodExpression.getQualifierExpression()); + } + } else if (element instanceof PsiConditionalExpression) { + final PsiConditionalExpression conditionalExpression = + (PsiConditionalExpression) element; + final PsiExpression thenExpression = + conditionalExpression.getThenExpression(); + if (hasReferenceToVariable(variable, thenExpression)) { + return true; + } + final PsiExpression elseExpression = + conditionalExpression.getElseExpression(); + return hasReferenceToVariable(variable, elseExpression); + } + return false; + } +} diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MismatchedStringBuilderQueryUpdate.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MismatchedStringBuilderQueryUpdate.html new file mode 100644 index 000000000000..e90bc982f551 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MismatchedStringBuilderQueryUpdate.html @@ -0,0 +1,9 @@ + + +This inspection reports any StringBuilder or StringBuffer fields or variables whose contents are read but not written, +or written but not read. Such mismatched reads and writes are pointless, and probably indicate +dead, incomplete or erroneous code. +

+New in 10.5, Powered by InspectionGadgets + + \ No newline at end of file From d93112a37734a59e110389113d43ca463629d29d Mon Sep 17 00:00:00 2001 From: anna Date: Tue, 12 Apr 2011 21:11:31 +0200 Subject: [PATCH 030/102] for groovy script without classes (EA-26890 - assert: UpdatePsiFileCopyright.checkComments) --- .../idea/copyright/psi/UpdatePsiFileCopyright.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/plugins/copyright/src/com/maddyhome/idea/copyright/psi/UpdatePsiFileCopyright.java b/plugins/copyright/src/com/maddyhome/idea/copyright/psi/UpdatePsiFileCopyright.java index 2f83668fe8d7..e8387bf0de14 100644 --- a/plugins/copyright/src/com/maddyhome/idea/copyright/psi/UpdatePsiFileCopyright.java +++ b/plugins/copyright/src/com/maddyhome/idea/copyright/psi/UpdatePsiFileCopyright.java @@ -232,14 +232,12 @@ public abstract class UpdatePsiFileCopyright extends AbstractUpdateCopyright { } } - final int pos; - if (point == null) { - pos = 0; - } - else { + int pos = 0; + if (point != null) { final TextRange textRange = point.getTextRange(); - assert textRange != null : point.getClass(); - pos = textRange.getStartOffset(); + if (textRange != null) { + pos = textRange.getStartOffset(); + } } addAction(new CommentAction(pos, prefix, suffix)); } From acac378713f9f84534e59f144333f7560dbcecfb Mon Sep 17 00:00:00 2001 From: anna Date: Wed, 13 Apr 2011 13:53:09 +0200 Subject: [PATCH 031/102] EA-26903 - NPE: NotInSuperOrThisCallFilterBase.isOK --- .../refactoring/introduceField/IntroduceConstantHandler.java | 2 +- .../refactoring/introduceField/IntroduceFieldHandler.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceConstantHandler.java b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceConstantHandler.java index 493bad86ca48..2f230c9def78 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceConstantHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceConstantHandler.java @@ -149,7 +149,7 @@ public class IntroduceConstantHandler extends BaseExpressionToFieldHandler { if (editor != null && editor.getSettings().isVariableInplaceRenameEnabled()) { new InplaceIntroduceConstantPopup(project, editor, parentClass, expr, localVariable, occurences, typeSelectorManager, anchorElement, anchorElementIfAll, - createOccurenceManager(expr, parentClass)).performInplaceIntroduce(); + expr != null ? createOccurenceManager(expr, parentClass) : null).performInplaceIntroduce(); return null; } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldHandler.java b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldHandler.java index 5ec92ee88f56..b70ec6cfb072 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldHandler.java @@ -108,7 +108,7 @@ public class IntroduceFieldHandler extends BaseExpressionToFieldHandler { if (editor != null && editor.getSettings().isVariableInplaceRenameEnabled()) { myInplaceIntroduceFieldPopup = new InplaceIntroduceFieldPopup(localVariable, parentClass, declareStatic, currentMethodConstructor, occurences, expr, typeSelectorManager, editor, - allowInitInMethod, allowInitInMethodIfAll, anchorElement, anchorElementIfAll, createOccurenceManager(expr, parentClass)); + allowInitInMethod, allowInitInMethodIfAll, anchorElement, anchorElementIfAll, expr != null ? createOccurenceManager(expr, parentClass) : null); myInplaceIntroduceFieldPopup.startTemplate(); return null; } From 5df673a98d16cd3d1028bf09075cb4c2943bbe14 Mon Sep 17 00:00:00 2001 From: anna Date: Wed, 13 Apr 2011 14:13:46 +0200 Subject: [PATCH 032/102] correct find for synthetic last parameter (e.g. GWT) --- .../find/findUsages/JavaFindUsagesHandler.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/java/java-impl/src/com/intellij/find/findUsages/JavaFindUsagesHandler.java b/java/java-impl/src/com/intellij/find/findUsages/JavaFindUsagesHandler.java index ac8ce9e62a65..418864150f3f 100644 --- a/java/java-impl/src/com/intellij/find/findUsages/JavaFindUsagesHandler.java +++ b/java/java-impl/src/com/intellij/find/findUsages/JavaFindUsagesHandler.java @@ -117,13 +117,16 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{ for (int i = 0; i < overrides.length; i++) { overrides[i] = (PsiMethod)overrides[i].getNavigationElement(); } - PsiElement[] elementsToSearch = new PsiElement[overrides.length + 1]; - elementsToSearch[0] = parameter; + List elementsToSearch = new ArrayList(overrides.length + 1); + elementsToSearch.add(parameter); int idx = method.getParameterList().getParameterIndex(parameter); - for (int i = 0; i < overrides.length; i++) { - elementsToSearch[i + 1] = overrides[i].getParameterList().getParameters()[idx]; + for (PsiMethod override : overrides) { + final PsiParameter[] parameters = override.getParameterList().getParameters(); + if (idx < parameters.length) { + elementsToSearch.add(parameters[idx]); + } } - return elementsToSearch; + return elementsToSearch.toArray(new PsiElement[elementsToSearch.size()]); } From f4603c5347700cd910490b6915e5ebfa1caff626 Mon Sep 17 00:00:00 2001 From: anna Date: Wed, 13 Apr 2011 14:18:04 +0200 Subject: [PATCH 033/102] EA-26853 - AIOOBE: UnusedParametersInspection$1.visitElement --- .../unusedParameters/UnusedParametersInspection.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/codeInspection/unusedParameters/UnusedParametersInspection.java b/java/java-impl/src/com/intellij/codeInspection/unusedParameters/UnusedParametersInspection.java index 72d563db0647..ee45346a18ed 100644 --- a/java/java-impl/src/com/intellij/codeInspection/unusedParameters/UnusedParametersInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/unusedParameters/UnusedParametersInspection.java @@ -122,7 +122,9 @@ public class UnusedParametersInspection extends GlobalJavaInspectionTool { final boolean[] found = {false}; for (int i = 0; i < derived.length && !found[0]; i++) { if (!scope.contains(derived[i])) { - PsiParameter psiParameter = derived[i].getParameterList().getParameters()[idx]; + final PsiParameter[] parameters = derived[i].getParameterList().getParameters(); + if (parameters.length >= idx) continue; + PsiParameter psiParameter = parameters[idx]; ReferencesSearch.search(psiParameter, helper.getUseScope(psiParameter), false).forEach(new PsiReferenceProcessorAdapter( new PsiReferenceProcessor() { public boolean execute(PsiReference element) { From dbc0319f166c081f7c5e5dceecd9b17e247ba712 Mon Sep 17 00:00:00 2001 From: anna Date: Wed, 13 Apr 2011 14:20:40 +0200 Subject: [PATCH 034/102] EA-26629 - IAE: JavaCodeStyleManagerImpl.shortenClassReferences --- .../com/intellij/codeInsight/intention/AddAnnotationFix.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/AddAnnotationFix.java b/java/java-impl/src/com/intellij/codeInsight/intention/AddAnnotationFix.java index b66970767844..0088f7be3f7f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/AddAnnotationFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/AddAnnotationFix.java @@ -175,7 +175,7 @@ public class AddAnnotationFix extends PsiElementBaseIntentionAction implements L } } - PsiAnnotation inserted = modifierList.addAnnotation(myAnnotation); + final @NotNull PsiAnnotation inserted = modifierList.addAnnotation(myAnnotation); if (myPairs != null) { for (PsiNameValuePair pair : myPairs) { inserted.setDeclaredAttributeValue(pair.getName(), pair.getValue()); From 9300034a9a237654330889b2e8049feb89d0a77b Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Wed, 13 Apr 2011 15:34:09 +0200 Subject: [PATCH 035/102] warn in more cases and optimization --- .../MismatchedArrayReadWriteInspection.java | 96 +++++++------------ .../MismatchedArrayReadWrite.java | 15 +++ .../mismatched_array_read_write/expected.xml | 29 ++++++ 3 files changed, 81 insertions(+), 59 deletions(-) diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MismatchedArrayReadWriteInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MismatchedArrayReadWriteInspection.java index 8865ef364677..0c2b00284509 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MismatchedArrayReadWriteInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MismatchedArrayReadWriteInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2010 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,6 @@ package com.siyeh.ig.bugs; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; -import com.siyeh.HardcodedMethodConstants; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; @@ -78,11 +77,7 @@ public class MismatchedArrayReadWriteInspection extends BaseInspection{ return; } final PsiClass containingClass = PsiUtil.getTopLevelClass(field); - if(containingClass == null){ - return; - } - final PsiType type = field.getType(); - if(type.getArrayDimensions() == 0){ + if(!checkVariable(field, containingClass)){ return; } final boolean written = @@ -99,11 +94,7 @@ public class MismatchedArrayReadWriteInspection extends BaseInspection{ super.visitLocalVariable(variable); final PsiCodeBlock codeBlock = PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class); - if(codeBlock == null){ - return; - } - final PsiType type = variable.getType(); - if(type.getArrayDimensions() == 0){ + if(!checkVariable(variable, codeBlock)){ return; } final boolean written = @@ -115,6 +106,28 @@ public class MismatchedArrayReadWriteInspection extends BaseInspection{ registerVariableError(variable, Boolean.valueOf(written)); } + private static boolean checkVariable(PsiVariable variable, + PsiElement context) { + if(context == null){ + return false; + } + final PsiType type = variable.getType(); + if(type.getArrayDimensions() == 0){ + return false; + } + if(VariableAccessUtils.variableIsAssigned(variable, context)){ + return false; + } + if(VariableAccessUtils.variableIsAssignedFrom(variable, context)){ + return false; + } + if(VariableAccessUtils.variableIsReturned(variable, context)){ + return false; + } + return !VariableAccessUtils.variableIsUsedInArrayInitializer( + variable, context); + } + private static boolean arrayContentsAreWritten(PsiVariable variable, PsiElement context){ if(VariableAccessUtils.arrayContentsAreAssigned(variable, context)){ @@ -124,20 +137,7 @@ public class MismatchedArrayReadWriteInspection extends BaseInspection{ if(initializer != null && !isDefaultArrayInitializer(initializer)){ return true; } - if(VariableAccessUtils.variableIsAssigned(variable, context)){ - return true; - } - if(VariableAccessUtils.variableIsAssignedFrom(variable, context)){ - return true; - } - if(VariableAccessUtils.variableIsReturned(variable, context)){ - return true; - } - if(variableIsWrittenAsMethodArgument(variable, context)) { - return true; - } - return VariableAccessUtils.variableIsUsedInArrayInitializer(variable, - context); + return variableIsWrittenAsMethodArgument(variable, context); } private static boolean arrayContentsAreRead(PsiVariable variable, @@ -145,24 +145,7 @@ public class MismatchedArrayReadWriteInspection extends BaseInspection{ if(VariableAccessUtils.arrayContentsAreAccessed(variable, context)){ return true; } - final PsiExpression initializer = variable.getInitializer(); - if(initializer != null && !isDefaultArrayInitializer(initializer)){ - return true; - } - if(VariableAccessUtils.variableIsAssigned(variable, context)){ - return true; - } - if(VariableAccessUtils.variableIsAssignedFrom(variable, context)){ - return true; - } - if(VariableAccessUtils.variableIsReturned(variable, context)){ - return true; - } - if(variableIsReadAsMethodArgument(variable, context)) { - return true; - } - return VariableAccessUtils.variableIsUsedInArrayInitializer(variable, - context); + return variableIsReadAsMethodArgument(variable, context); } private static boolean isDefaultArrayInitializer( @@ -170,21 +153,16 @@ public class MismatchedArrayReadWriteInspection extends BaseInspection{ if (initializer instanceof PsiNewExpression) { final PsiNewExpression newExpression = (PsiNewExpression) initializer; - return newExpression.getArrayInitializer() == null; - } else if (initializer instanceof PsiMethodCallExpression) { - final PsiMethodCallExpression methodCallExpression = - (PsiMethodCallExpression) initializer; - final PsiReferenceExpression methodExpression = - methodCallExpression.getMethodExpression(); - final String methodName = methodExpression.getReferenceName(); - if (!HardcodedMethodConstants.CLONE.equals(methodName)) { - return false; - } - final PsiExpressionList argumentList = - methodCallExpression.getArgumentList(); - final PsiExpression[] expressions = - argumentList.getExpressions(); - return expressions.length == 0; + final PsiArrayInitializerExpression arrayInitializer = + newExpression.getArrayInitializer(); + return arrayInitializer == null || + isDefaultArrayInitializer(arrayInitializer); + } else if (initializer instanceof PsiArrayInitializerExpression) { + final PsiArrayInitializerExpression arrayInitializerExpression = + (PsiArrayInitializerExpression) initializer; + final PsiExpression[] initializers = + arrayInitializerExpression.getInitializers(); + return initializers.length == 0; } return false; } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/mismatched_array_read_write/MismatchedArrayReadWrite.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/mismatched_array_read_write/MismatchedArrayReadWrite.java index 4feb02aadbb1..2084fd8cb339 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/mismatched_array_read_write/MismatchedArrayReadWrite.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/mismatched_array_read_write/MismatchedArrayReadWrite.java @@ -85,4 +85,19 @@ class Test{ array[0][1]++; System.out.println(array[0][1]); } + + void foo1() { + final int[] barzoom = {}; + barzoom[2] = 3; + } + + void foo2() { + final int[] barzoom = new int[]{}; + barzoom[2] = 3; + } + + void foo3(Object[] otherArr) { + Object[] arr = otherArr.clone(); + for (int i = 0; i < 10; i++) arr[i] = i; + } } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/mismatched_array_read_write/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/mismatched_array_read_write/expected.xml index c322f7e4b800..c1b9fc0fdffa 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/mismatched_array_read_write/expected.xml +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/mismatched_array_read_write/expected.xml @@ -42,4 +42,33 @@ Contents of array <code>foo</code> are written to, but never read #loc + + MismatchedArrayReadWrite.java + 90 + Mismatched read and write of array + Contents of array <code>barzoom</code> are written to, but never read #loc + + + + MismatchedArrayReadWrite.java + 100 + Mismatched read and write of array + Contents of array <code>arr</code> are written to, but never read #loc + + + + MismatchedArrayReadWrite.java + 95 + Mismatched read and write of array + Contents of array <code>barzoom</code> are written to, but never read #loc + + + + MismatchedArrayReadWrite.java + 61 + Mismatched read and write of array + Contents of array <code>rowData</code> are written to, but never read #loc + + + \ No newline at end of file From 6535876a2c1f35e05c3f8f703a55572f15320c2e Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Wed, 13 Apr 2011 15:34:55 +0200 Subject: [PATCH 036/102] warn in more cases, optimization and cleanup --- .../ig/bugs/CollectionQueryCalledVisitor.java | 3 +- .../bugs/CollectionUpdateCalledVisitor.java | 2 +- ...atchedCollectionQueryUpdateInspection.java | 91 ++++++++----------- 3 files changed, 40 insertions(+), 56 deletions(-) diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/CollectionQueryCalledVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/CollectionQueryCalledVisitor.java index 580371d7c38c..b41d34758def 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/CollectionQueryCalledVisitor.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/CollectionQueryCalledVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2010 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,6 @@ import com.intellij.psi.*; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import java.util.HashSet; import java.util.Set; class CollectionQueryCalledVisitor extends JavaRecursiveElementVisitor{ diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/CollectionUpdateCalledVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/CollectionUpdateCalledVisitor.java index 1e2f0e229d11..cc409378e10f 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/CollectionUpdateCalledVisitor.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/CollectionUpdateCalledVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2010 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MismatchedCollectionQueryUpdateInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MismatchedCollectionQueryUpdateInspection.java index 1e84180335f5..c083663e2188 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MismatchedCollectionQueryUpdateInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MismatchedCollectionQueryUpdateInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2010 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,9 +37,11 @@ import java.awt.*; public class MismatchedCollectionQueryUpdateInspection extends BaseInspection { + @SuppressWarnings({"PublicField"}) public final ExternalizableStringSet queryNames = new ExternalizableStringSet("copyInto", "drainTo", "propertyNames", "save", "store", "write"); + @SuppressWarnings({"PublicField"}) public final ExternalizableStringSet updateNames = new ExternalizableStringSet("add", "clear", "drainTo", "insert", "load", "offer", "poll", "push", "put", "remove", "replace", @@ -140,16 +142,16 @@ public class MismatchedCollectionQueryUpdateInspection if(argumentList == null){ return false; } - final PsiExpression[] expressions = argumentList.getExpressions(); - for(final PsiExpression arg : expressions){ - final PsiType argType = arg.getType(); - if(argType == null){ + final PsiExpression[] arguments = argumentList.getExpressions(); + for(final PsiExpression argument : arguments){ + final PsiType argumentType = argument.getType(); + if(argumentType == null){ return false; } - if(CollectionUtils.isCollectionClassOrInterface(argType)){ + if(CollectionUtils.isCollectionClassOrInterface(argumentType)){ return false; } - if(argType instanceof PsiArrayType){ + if(argumentType instanceof PsiArrayType){ return false; } } @@ -165,11 +167,7 @@ public class MismatchedCollectionQueryUpdateInspection return; } final PsiClass containingClass = PsiUtil.getTopLevelClass(field); - if(containingClass == null){ - return; - } - final PsiType type = field.getType(); - if(!CollectionUtils.isCollectionClassOrInterface(type)){ + if (!checkVariable(field, containingClass)) { return; } final boolean written = @@ -182,16 +180,13 @@ public class MismatchedCollectionQueryUpdateInspection registerFieldError(field, Boolean.valueOf(written)); } - @Override public void visitLocalVariable(@NotNull PsiLocalVariable variable){ + @Override public void visitLocalVariable( + @NotNull PsiLocalVariable variable){ super.visitLocalVariable(variable); final PsiCodeBlock codeBlock = PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class); - if(codeBlock == null){ - return; - } - final PsiType type = variable.getType(); - if(!CollectionUtils.isCollectionClassOrInterface(type)){ + if (!checkVariable(variable, codeBlock)) { return; } final boolean written = @@ -203,6 +198,29 @@ public class MismatchedCollectionQueryUpdateInspection } } + private boolean checkVariable(PsiVariable variable, + PsiElement context) { + if (context == null) { + return false; + } + final PsiType type = variable.getType(); + if(!CollectionUtils.isCollectionClassOrInterface(type)){ + return false; + } + if(VariableAccessUtils.variableIsAssignedFrom(variable, context)){ + return false; + } + if(VariableAccessUtils.variableIsReturned(variable, context)){ + return false; + } + if(VariableAccessUtils.variableIsPassedAsMethodArgument(variable, + context)){ + return false; + } + return !VariableAccessUtils.variableIsUsedInArrayInitializer( + variable, context); + } + private boolean collectionContentsAreUpdated( PsiVariable variable, PsiElement context){ if(collectionUpdateCalled(variable, context)){ @@ -224,21 +242,7 @@ public class MismatchedCollectionQueryUpdateInspection } } } - if(VariableAccessUtils.variableIsAssigned(variable, context)){ - return true; - } - if(VariableAccessUtils.variableIsAssignedFrom(variable, context)){ - return true; - } - if(VariableAccessUtils.variableIsReturned(variable, context)){ - return true; - } - if(VariableAccessUtils.variableIsPassedAsMethodArgument(variable, - context)){ - return true; - } - return VariableAccessUtils.variableIsUsedInArrayInitializer(variable, - context); + return VariableAccessUtils.variableIsAssigned(variable, context); } private boolean collectionContentsAreQueried( @@ -246,26 +250,7 @@ public class MismatchedCollectionQueryUpdateInspection if(collectionQueryCalled(variable, context)){ return true; } - final PsiExpression initializer = variable.getInitializer(); - if(initializer != null && - !isEmptyCollectionInitializer(initializer)){ - return true; - } - if(collectionQueriedByAssignment(variable, context)){ - return true; - } - if(VariableAccessUtils.variableIsAssignedFrom(variable, context)){ - return true; - } - if(VariableAccessUtils.variableIsReturned(variable, context)){ - return true; - } - if(VariableAccessUtils.variableIsPassedAsMethodArgument(variable, - context)){ - return true; - } - return VariableAccessUtils.variableIsUsedInArrayInitializer(variable, - context); + return collectionQueriedByAssignment(variable, context); } private boolean collectionQueryCalled(PsiVariable variable, From 4b752f21572ebd1989a4405f26a19c6916a3c772 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Tue, 12 Apr 2011 14:29:01 +0400 Subject: [PATCH 037/102] more robust tests --- .../codeInsight/daemon/impl/FileStatusMap.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/FileStatusMap.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/FileStatusMap.java index 2c5afda29564..f6f9725ec160 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/FileStatusMap.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/FileStatusMap.java @@ -150,13 +150,22 @@ public class FileStatusMap implements Disposable { } public void markAllFilesDirty() { - assert myAllowDirt; + assertAllowModifications(); LOG.debug("********************************* Mark all dirty"); synchronized (myDocumentToStatusMap) { myDocumentToStatusMap.clear(); } } + private void assertAllowModifications() { + try { + assert myAllowDirt; + } + finally { + myAllowDirt = true; //give next test a chance + } + } + public void markFileUpToDate(@NotNull Document document, @NotNull PsiFile file, int passId) { synchronized(myDocumentToStatusMap){ FileStatus status = myDocumentToStatusMap.get(document); @@ -204,7 +213,7 @@ public class FileStatusMap implements Disposable { } public void markFileScopeDirty(@NotNull Document document, int passId) { - assert myAllowDirt; + assertAllowModifications(); synchronized(myDocumentToStatusMap){ FileStatus status = myDocumentToStatusMap.get(document); if (status == null){ @@ -226,7 +235,7 @@ public class FileStatusMap implements Disposable { } public void markFileScopeDirtyDefensively(@NotNull PsiFile file) { - assert myAllowDirt; + assertAllowModifications(); if (LOG.isDebugEnabled()) { LOG.debug("********************************* Mark dirty file defensively: "+file.getName()); } @@ -242,7 +251,7 @@ public class FileStatusMap implements Disposable { } public void markFileScopeDirty(@NotNull Document document, @NotNull TextRange scope, int fileLength) { - assert myAllowDirt; + assertAllowModifications(); if (LOG.isDebugEnabled()) { LOG.debug("********************************* Mark dirty: "+scope); } From 5b6a43015df4285a8d2ecf029b6def97b80af33e Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Tue, 12 Apr 2011 15:18:03 +0400 Subject: [PATCH 038/102] IDEA-61333 --- .../intellij/psi/impl/source/PsiJavaFileBaseImpl.java | 10 +++++----- .../importDefaultPackage/x/InvalidUse.java | 5 +++++ .../codeInsight/daemon/AdvHighlightingTest.java | 1 + 3 files changed, 11 insertions(+), 5 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/importDefaultPackage/x/InvalidUse.java diff --git a/java/java-impl/src/com/intellij/psi/impl/source/PsiJavaFileBaseImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/PsiJavaFileBaseImpl.java index c9e5efb517cf..e3b86c672a69 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/PsiJavaFileBaseImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/PsiJavaFileBaseImpl.java @@ -304,11 +304,11 @@ public abstract class PsiJavaFileBaseImpl extends PsiFileImpl implements PsiJava } } - if(classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.PACKAGE)){ - final PsiPackage rootPackage = JavaPsiFacade.getInstance(getProject()).findPackage(""); - processor.handleEvent(JavaScopeProcessorEvent.SET_CURRENT_FILE_CONTEXT, rootPackage); - if(rootPackage != null) rootPackage.processDeclarations(processor, state, null, place); - } + //if(classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.PACKAGE)){ + // final PsiPackage rootPackage = JavaPsiFacade.getInstance(getProject()).findPackage(""); + // processor.handleEvent(JavaScopeProcessorEvent.SET_CURRENT_FILE_CONTEXT, rootPackage); + // if(rootPackage != null) rootPackage.processDeclarations(processor, state, null, place); + //} final PsiImportList importList = getImportList(); final PsiImportStaticStatement[] importStaticStatements = importList.getImportStaticStatements(); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/importDefaultPackage/x/InvalidUse.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/importDefaultPackage/x/InvalidUse.java new file mode 100644 index 000000000000..f02025936521 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/importDefaultPackage/x/InvalidUse.java @@ -0,0 +1,5 @@ +package x; + +class InvalidUse { + Test t = null; +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AdvHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AdvHighlightingTest.java index 00ddf6298151..de3baf9edbdb 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AdvHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AdvHighlightingTest.java @@ -79,6 +79,7 @@ public class AdvHighlightingTest extends DaemonAnalyzerTestCase { public void testAlreadyImportedClass() throws Exception { doTest(BASE_PATH+"/alreadyImportedClass/pack/AlreadyImportedClass.java", BASE_PATH+"/alreadyImportedClass", false, false); } public void testImportDefaultPackage() throws Exception { doTest(BASE_PATH+"/importDefaultPackage/x/Usage.java", BASE_PATH+"/importDefaultPackage", false, false); } public void testImportDefaultPackage2() throws Exception { doTest(BASE_PATH+"/importDefaultPackage/x/ImportOnDemandUsage.java", BASE_PATH+"/importDefaultPackage", false, false); } + public void testImportDefaultPackageInvalid() throws Exception { doTest(BASE_PATH+"/importDefaultPackage/x/InvalidUse.java", BASE_PATH+"/importDefaultPackage", false, false); } public void testScopeBased() throws Exception { NamedScope xScope = new NamedScope("xxx", new PatternPackageSet("x..*", PatternPackageSet.SCOPE_SOURCE, null)); From 46b0c56acb44cce2c526dee012288d1e07155b6a Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 13 Apr 2011 09:49:04 +0400 Subject: [PATCH 039/102] auto import broken again --- .../intellij/codeInsight/daemon/impl/DaemonListeners.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java index 0746219ef8f5..8ceff750faef 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java @@ -288,7 +288,7 @@ class DaemonListeners implements Disposable { LOG.assertTrue(((UserDataHolderEx)myProject).replace(DAEMON_INITIALIZED, Boolean.TRUE, null), "Daemon listeners already disposed for the project "+myProject); } - boolean canChangeFileSilently(PsiFileSystemItem file) { + boolean canChangeFileSilently(@NotNull PsiFileSystemItem file) { if (cutOperationJustHappened) return false; VirtualFile virtualFile = file.getVirtualFile(); if (virtualFile == null) return false; @@ -302,7 +302,7 @@ class DaemonListeners implements Disposable { return canUndo(virtualFile); } - private boolean canUndo(VirtualFile virtualFile) { + private boolean canUndo(@NotNull VirtualFile virtualFile) { for (FileEditor editor : FileEditorManager.getInstance(myProject).getEditors(virtualFile)) { if (UndoManager.getInstance(myProject).isUndoAvailable(editor)) return true; } @@ -312,13 +312,14 @@ class DaemonListeners implements Disposable { private static enum Result { CHANGED, UNCHANGED, NOT_SURE } + private Result vcsThinksItChanged(VirtualFile virtualFile, Project project) { AbstractVcs activeVcs = ProjectLevelVcsManager.getInstance(project).getVcsFor(virtualFile); if (activeVcs == null) return Result.NOT_SURE; FilePath path = new FilePathImpl(virtualFile); boolean vcsIsThinking = !VcsDirtyScopeManager.getInstance(myProject).whatFilesDirty(Arrays.asList(path)).isEmpty(); - if (vcsIsThinking) return Result.UNCHANGED; // do not modify file which is in the process of updating + if (vcsIsThinking) return Result.NOT_SURE; // do not modify file which is in the process of updating FileStatus status = FileStatusManager.getInstance(project).getStatus(virtualFile); if (status == FileStatus.UNKNOWN) return Result.NOT_SURE; From a077f083063ee1f60239f82c4b9d4a8c173d8c0a Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 13 Apr 2011 09:49:29 +0400 Subject: [PATCH 040/102] periodically purge internal file queues during batch processing --- .../psi/impl/PsiDocumentManagerImpl.java | 6 ++ .../openapi/command/impl/UndoableGroup.java | 97 ++++++++----------- .../impl/FileDocumentManagerImpl.java | 16 +++ 3 files changed, 64 insertions(+), 55 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java index f5c0475e4f46..3540a25aaf4c 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java @@ -33,6 +33,7 @@ import com.intellij.openapi.editor.ex.DocumentEx; import com.intellij.openapi.editor.impl.DocumentImpl; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.FileDocumentManagerAdapter; +import com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; @@ -630,8 +631,13 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec if (commitNecessary && ApplicationManager.getApplication().getCurrentWriteAction(ExternalChangeAction.class) != null){ commitDocument(document); } + // avoid documents piling up during batch processing + if (FileDocumentManagerImpl.areTooManyDocumentsInTheQueue(myUncommittedDocuments)) { + commitAllDocuments(); + } } + private boolean isRelevant(FileViewProvider viewProvider) { VirtualFile virtualFile = viewProvider.getVirtualFile(); return !virtualFile.getFileType().isBinary() && viewProvider.getManager() == myPsiManager && !myPsiManager.getProject().isDisposed(); diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoableGroup.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoableGroup.java index 6368daa54529..781af952a723 100644 --- a/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoableGroup.java +++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoableGroup.java @@ -33,9 +33,11 @@ import com.intellij.psi.PsiDocumentManager; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashSet; -import org.jetbrains.annotations.NotNull; -import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; class UndoableGroup { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.command.impl.UndoableGroup"); @@ -115,71 +117,56 @@ class UndoableGroup { } } - private static void doInBulkMode(@NotNull final Runnable action, @NotNull Collection documents) { - Runnable runnable = action; - for (final DocumentEx document : documents) { - final Runnable oldRunnable = runnable; - runnable = new Runnable() { - @Override - public void run() { - doInBulkMode(oldRunnable, document); - } - }; - } - runnable.run(); - } - private static void doInBulkMode(@NotNull Runnable action, @NotNull DocumentEx document) { - boolean wasInBulkUpdate = document.isInBulkUpdate(); - document.setInBulkUpdate(true); - try { - action.run(); - } - finally { - if (!wasInBulkUpdate) { - document.setInBulkUpdate(false); - } - } - } - - private void doUndoOrRedo(final boolean isUndo) { - Runnable runnable = new Runnable() { + final boolean wrapInBulkUpdate = myActions.size() > 50; + // perform undo action by action, setting bulk update flag if possible + // if multiple consecutive actions share a document, then set the bulk flag only once + final Set bulkDocuments = new THashSet(); + ApplicationManager.getApplication().runWriteAction(new Runnable() { public void run() { try { - for (UndoableAction each : isUndo ? ContainerUtil.iterateBackward(myActions) : myActions) { - if (isUndo) { - each.undo(); + for (final UndoableAction action : isUndo ? ContainerUtil.iterateBackward(myActions) : myActions) { + final Collection newDocuments; + if (wrapInBulkUpdate) { + newDocuments = new THashSet(); + Set documentsToRemoveFromBulk = new THashSet(bulkDocuments); + DocumentReference[] affectedDocuments = action.getAffectedDocuments(); + if (affectedDocuments != null) { + for (DocumentReference affectedDocument : affectedDocuments) { + DocumentEx document = (DocumentEx)affectedDocument.getDocument(); + if (document == null) continue; + documentsToRemoveFromBulk.remove(document); + if (bulkDocuments.contains(document)) continue; + newDocuments.add(document); + document.setInBulkUpdate(true); + } + } + for (DocumentEx document : documentsToRemoveFromBulk) { + document.setInBulkUpdate(false); + } + bulkDocuments.removeAll(documentsToRemoveFromBulk); + bulkDocuments.addAll(newDocuments); } else { - each.redo(); + newDocuments = Collections.emptyList(); } + + if (isUndo) { + action.undo(); + } + else { + action.redo(); + } + } + for (DocumentEx bulkDocument : bulkDocuments) { + bulkDocument.setInBulkUpdate(false); } } catch (UnexpectedUndoException e) { reportUndoProblem(e, isUndo); } } - }; - if (myActions.size() > 50) { - final Collection documents = new THashSet(); - for (UndoableAction action : myActions) { - DocumentReference[] affectedDocuments = action.getAffectedDocuments(); - if (affectedDocuments != null) { - for (DocumentReference affectedDocument : affectedDocuments) { - documents.add((DocumentEx)affectedDocument.getDocument()); - } - } - } - final Runnable oldRunnable = runnable; - runnable = new Runnable() { - @Override - public void run() { - doInBulkMode(oldRunnable, documents); - } - }; - } - - ApplicationManager.getApplication().runWriteAction(runnable); + }); commitAllDocuments(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java index 294f15809460..be73a336fc01 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java @@ -44,6 +44,7 @@ import com.intellij.openapi.ui.DialogBuilder; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.*; import com.intellij.openapi.vfs.ex.dummy.DummyFileSystem; @@ -135,6 +136,11 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl Project project = currentCommand == null ? null : CommandProcessor.getInstance().getCurrentCommandProject(); String lineSeparator = CodeStyleFacade.getInstance(project).getLineSeparator(); document.putUserData(LINE_SEPARATOR_KEY, lineSeparator); + + // avoid documents piling up during batch processing + if (areTooManyDocumentsInTheQueue(myUnsavedDocuments)) { + saveAllDocuments(); + } } } ); @@ -148,6 +154,16 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl return document; } + public static boolean areTooManyDocumentsInTheQueue(Collection documents) { + if (documents.size() > 100) return true; + int totalSize = 0; + for (Document document : documents) { + totalSize += document.getTextLength(); + if (totalSize > 10 * FileUtil.MEGABYTE) return true; + } + return false; + } + private static Document createDocument(final CharSequence text) { return EditorFactory.getInstance().createDocument(text); } From 111b9c255f8c39afff4374736d9f7ba1161d146d Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 13 Apr 2011 15:23:12 +0400 Subject: [PATCH 041/102] read action --- .../src/com/intellij/slicer/DuplicateMap.java | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/java/java-impl/src/com/intellij/slicer/DuplicateMap.java b/java/java-impl/src/com/intellij/slicer/DuplicateMap.java index f22cd07fc0a7..ea8d0ec455cf 100644 --- a/java/java-impl/src/com/intellij/slicer/DuplicateMap.java +++ b/java/java-impl/src/com/intellij/slicer/DuplicateMap.java @@ -15,6 +15,8 @@ */ package com.intellij.slicer; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.util.Computable; import com.intellij.usageView.UsageInfo; import gnu.trove.THashMap; import gnu.trove.TObjectHashingStrategy; @@ -37,13 +39,17 @@ public class DuplicateMap { }; private final Map myDuplicates = new THashMap(USAGEINFO_EQUALITY); - public SliceNode putNodeCheckDupe(SliceNode node) { - SliceUsage usage = node.getValue(); - SliceNode eq = myDuplicates.get(usage); - if (eq == null) { - myDuplicates.put(usage, node); - } - return eq; + public SliceNode putNodeCheckDupe(final SliceNode node) { + return ApplicationManager.getApplication().runReadAction(new Computable() { + public SliceNode compute() { + SliceUsage usage = node.getValue(); + SliceNode eq = myDuplicates.get(usage); + if (eq == null) { + myDuplicates.put(usage, node); + } + return eq; + } + }); } public void clear() { From 45b06de6bdc9da8b1165f38edd7e0839181fabbf Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 13 Apr 2011 15:51:55 +0400 Subject: [PATCH 042/102] NPE --- .../src/com/intellij/usages/impl/UsagePreviewPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/usageView/src/com/intellij/usages/impl/UsagePreviewPanel.java b/platform/usageView/src/com/intellij/usages/impl/UsagePreviewPanel.java index aa8e508889d4..aa754c421b36 100644 --- a/platform/usageView/src/com/intellij/usages/impl/UsagePreviewPanel.java +++ b/platform/usageView/src/com/intellij/usages/impl/UsagePreviewPanel.java @@ -110,7 +110,7 @@ public class UsagePreviewPanel extends JPanel implements Disposable { TextRange elementRange = psiElement.getTextRange(); TextRange infoRange = info.getRangeInElement(); - TextRange textRange = elementRange.intersection(infoRange); + TextRange textRange = infoRange == null ? null : elementRange.intersection(infoRange); if (textRange == null) textRange = elementRange; // hack to determine element range to highlight if (psiElement instanceof PsiNamedElement && !(psiElement instanceof PsiFile)) { From 6e02aab0ad30a7a93c175d4eb0bedf2c322e8ee9 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 13 Apr 2011 16:20:34 +0400 Subject: [PATCH 043/102] cleanup --- .../daemon/impl/actions/SuppressFix.java | 16 +++++++++------- .../generation/OverrideImplementUtil.java | 2 +- .../intention/PsiElementBaseIntentionAction.java | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/actions/SuppressFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/actions/SuppressFix.java index 98d76211c9a2..f647d669e1ca 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/actions/SuppressFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/actions/SuppressFix.java @@ -20,7 +20,10 @@ import com.intellij.codeInsight.CodeInsightUtilBase; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.codeInsight.daemon.HighlightDisplayKey; import com.intellij.codeInsight.intention.AddAnnotationFix; -import com.intellij.codeInspection.*; +import com.intellij.codeInspection.InspectionsBundle; +import com.intellij.codeInspection.SuppressIntentionAction; +import com.intellij.codeInspection.SuppressManager; +import com.intellij.codeInspection.SuppressionUtil; import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; @@ -33,7 +36,6 @@ import com.intellij.psi.*; import com.intellij.psi.impl.source.jsp.jspJava.JspHolderMethod; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.javadoc.PsiDocTag; -import com.intellij.psi.javadoc.PsiDocTagValue; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; @@ -133,14 +135,14 @@ public class SuppressFix extends SuppressIntentionAction { final PsiElement container, final PsiModifierListOwner modifierOwner, final String id) throws IncorrectOperationException { - PsiAnnotation annotation = AnnotationUtil.findAnnotation(modifierOwner, SuppressManagerImpl.SUPPRESS_INSPECTIONS_ANNOTATION_NAME); + PsiAnnotation annotation = AnnotationUtil.findAnnotation(modifierOwner, SuppressManager.SUPPRESS_INSPECTIONS_ANNOTATION_NAME); final PsiAnnotation newAnnotation = createNewAnnotation(project, editor, container, annotation, id); if (newAnnotation != null) { if (annotation != null && annotation.isPhysical()) { annotation.replace(newAnnotation); } else { final PsiNameValuePair[] attributes = newAnnotation.getParameterList().getAttributes(); - new AddAnnotationFix(SuppressManagerImpl.SUPPRESS_INSPECTIONS_ANNOTATION_NAME, modifierOwner, attributes).invoke(project, editor, container.getContainingFile()); + new AddAnnotationFix(SuppressManager.SUPPRESS_INSPECTIONS_ANNOTATION_NAME, modifierOwner, attributes).invoke(project, editor, container.getContainingFile()); } } } @@ -156,8 +158,8 @@ public class SuppressFix extends SuppressIntentionAction { final PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes(); if (attributes.length == 1) { final String suppressedWarnings = attributes[0].getText(); - return JavaPsiFacade.getInstance(project).getElementFactory().createAnnotationFromText("@" + SuppressManagerImpl - .SUPPRESS_INSPECTIONS_ANNOTATION_NAME + "({" + suppressedWarnings + ", \"" + id + "\"})", container); + return JavaPsiFacade.getInstance(project).getElementFactory().createAnnotationFromText("@" + + SuppressManager.SUPPRESS_INSPECTIONS_ANNOTATION_NAME + "({" + suppressedWarnings + ", \"" + id + "\"})", container); } } else { @@ -174,7 +176,7 @@ public class SuppressFix extends SuppressIntentionAction { } else { return JavaPsiFacade.getInstance(project).getElementFactory() - .createAnnotationFromText("@" + SuppressManagerImpl.SUPPRESS_INSPECTIONS_ANNOTATION_NAME + "({\"" + id + "\"})", container); + .createAnnotationFromText("@" + SuppressManager.SUPPRESS_INSPECTIONS_ANNOTATION_NAME + "({\"" + id + "\"})", container); } return null; } diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java b/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java index 078751201768..043b95770f67 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java @@ -327,7 +327,7 @@ public class OverrideImplementUtil { } } - public static void annotate(PsiMethod result, String fqn, String... annosToRemove) throws IncorrectOperationException { + public static void annotate(@NotNull PsiMethod result, String fqn, String... annosToRemove) throws IncorrectOperationException { Project project = result.getProject(); AddAnnotationFix fix = new AddAnnotationFix(fqn, result, annosToRemove); if (fix.isAvailable(project, null, result.getContainingFile())) { diff --git a/platform/lang-api/src/com/intellij/codeInsight/intention/PsiElementBaseIntentionAction.java b/platform/lang-api/src/com/intellij/codeInsight/intention/PsiElementBaseIntentionAction.java index 45b68cc920c9..ae3094770312 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/intention/PsiElementBaseIntentionAction.java +++ b/platform/lang-api/src/com/intellij/codeInsight/intention/PsiElementBaseIntentionAction.java @@ -46,7 +46,7 @@ public abstract class PsiElementBaseIntentionAction extends BaseIntentionAction public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { final PsiElement element = getElement(editor, file); - return element == null ? false : isAvailable(project, editor, element); + return element != null && isAvailable(project, editor, element); } @Nullable From e3b1adc82b98d59e5cf63a0720f468f98f9cd812 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 13 Apr 2011 17:38:32 +0400 Subject: [PATCH 044/102] trackInvalidation --- .../injected/editor/RangeMarkerWindow.java | 5 +++ .../openapi/editor/ex/RangeMarkerEx.java | 2 +- .../openapi/editor/impl/IntervalTreeImpl.java | 10 +++--- .../impl/PersistentRangeHighlighterImpl.java | 2 +- .../editor/impl/PersistentRangeMarker.java | 16 ++++----- .../openapi/editor/impl/RangeMarkerImpl.java | 36 +++++++++++++------ .../openapi/editor/impl/RangeMarkerTree.java | 10 +++--- 7 files changed, 50 insertions(+), 31 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/injected/editor/RangeMarkerWindow.java b/platform/lang-impl/src/com/intellij/injected/editor/RangeMarkerWindow.java index 82e9098b5200..1bdb50f08bec 100644 --- a/platform/lang-impl/src/com/intellij/injected/editor/RangeMarkerWindow.java +++ b/platform/lang-impl/src/com/intellij/injected/editor/RangeMarkerWindow.java @@ -65,6 +65,11 @@ public class RangeMarkerWindow implements RangeMarkerEx { myHostMarker.trackInvalidation(track); } + @Override + public boolean isTrackInvalidation() { + return myHostMarker.isTrackInvalidation(); + } + ////////////////////////////delegates public void setGreedyToLeft(final boolean greedy) { myHostMarker.setGreedyToLeft(greedy); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/ex/RangeMarkerEx.java b/platform/platform-impl/src/com/intellij/openapi/editor/ex/RangeMarkerEx.java index 190d6c6c28bb..413a9b6ccdc1 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/ex/RangeMarkerEx.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/ex/RangeMarkerEx.java @@ -35,5 +35,5 @@ public interface RangeMarkerEx extends RangeMarker, MutableInterval, Segment { long getId(); void trackInvalidation(boolean track); - + boolean isTrackInvalidation(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java index a120b780dbb9..a314c8201b4e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java @@ -45,7 +45,7 @@ public abstract class IntervalTreeImpl extends RedBla private final ReferenceQueue myReferenceQueue = new ReferenceQueue(); private int deadReferenceCount; - protected class IntervalNode extends Node implements MutableInterval/*, Iterable, Iterator*/ { + protected class IntervalNode extends Node implements MutableInterval { private volatile int myStart; private volatile int myEnd; private volatile boolean isValid = true; @@ -181,11 +181,11 @@ public abstract class IntervalTreeImpl extends RedBla return myEnd; } - public IntervalTreeImpl getTree() { + public IntervalTreeImpl getTree() { return IntervalTreeImpl.this; } - } + private void pushDeltaFromRoot(IntervalNode node) { if (normalized) return; if (node != null) { @@ -437,7 +437,7 @@ public abstract class IntervalTreeImpl extends RedBla } } - public IntervalNode addInterval(@NotNull T interval, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) { + public IntervalTreeImpl.IntervalNode addInterval(@NotNull T interval, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) { try { l.writeLock().lock(); checkMax(true); @@ -502,7 +502,7 @@ public abstract class IntervalTreeImpl extends RedBla int maxRightStart = r.second; if (!root.isValid()) { allValid.set(false); - if (assertInvalid) assert false : (T)root; + if (assertInvalid) assert false : root; return Trinity.create(Math.min(minLeftStart, minRightStart), Math.max(maxLeftStart, maxRightStart), Math.max(maxRightEnd, maxLeftEnd)); } IntervalNode parent = root.getParent(); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/PersistentRangeHighlighterImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/PersistentRangeHighlighterImpl.java index 55b3bb8c3d9a..c74afce3ccff 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/PersistentRangeHighlighterImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/PersistentRangeHighlighterImpl.java @@ -45,7 +45,7 @@ class PersistentRangeHighlighterImpl extends RangeHighlighterImpl implements Ran if (PersistentRangeMarkerUtil.shouldTranslateViaDiff(event, this)) { setLine(event.translateLineViaDiff(getLine())); if (getLine() < 0 || getLine() >= getDocument().getLineCount()) { - invalidate(); + invalidate(e); } else { DocumentEx document = getDocument(); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarker.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarker.java index 1c7d4a464300..61f9a3e365c2 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarker.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarker.java @@ -36,23 +36,23 @@ class PersistentRangeMarker extends RangeMarkerImpl { PersistentRangeMarker(DocumentEx document, int startOffset, int endOffset, boolean register) { super(document, startOffset, endOffset, register); - storeLinesAndCols(); + storeLinesAndCols(null); } - private void storeLinesAndCols() { + private void storeLinesAndCols(DocumentEvent e) { // document might have been changed already if (getStartOffset() < myDocument.getTextLength()) { myStartLine = myDocument.getLineNumber(getStartOffset()); myStartColumn = getStartOffset() - myDocument.getLineStartOffset(myStartLine); if (myStartColumn < 0) { - invalidate(); + invalidate(e); } } if (getEndOffset() < myDocument.getTextLength()) { myEndLine = myDocument.getLineNumber(getEndOffset()); myEndColumn = getEndOffset() - myDocument.getLineStartOffset(myEndLine); if (myEndColumn < 0) { - invalidate(); + invalidate(e); } } } @@ -63,7 +63,7 @@ class PersistentRangeMarker extends RangeMarkerImpl { if (PersistentRangeMarkerUtil.shouldTranslateViaDiff(event, this)){ myStartLine = event.translateLineViaDiffStrict(myStartLine); if (myStartLine < 0 || myStartLine >= getDocument().getLineCount()){ - invalidate(); + invalidate(e); } else{ setIntervalStart(getDocument().getLineStartOffset(myStartLine) + myStartColumn); @@ -71,7 +71,7 @@ class PersistentRangeMarker extends RangeMarkerImpl { myEndLine = event.translateLineViaDiffStrict(myEndLine); if (myEndLine < 0 || myEndLine >= getDocument().getLineCount()){ - invalidate(); + invalidate(e); } else{ setIntervalEnd(getDocument().getLineStartOffset(myEndLine) + myEndColumn); @@ -80,11 +80,11 @@ class PersistentRangeMarker extends RangeMarkerImpl { else { super.changedUpdateImpl(e); if (isValid()){ - storeLinesAndCols(); + storeLinesAndCols(e); } } if (getEndOffset() < getStartOffset() || getEndOffset() > getDocument().getTextLength()) { - invalidate(); + invalidate(e); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeMarkerImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeMarkerImpl.java index 2f52d3a489e9..c00edb2180d8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeMarkerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeMarkerImpl.java @@ -19,7 +19,9 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.event.DocumentEvent; import com.intellij.openapi.editor.ex.DocumentEx; import com.intellij.openapi.editor.ex.RangeMarkerEx; +import com.intellij.openapi.util.Key; import com.intellij.openapi.util.UserDataHolderBase; +import com.intellij.util.Processor; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -30,7 +32,6 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx protected final DocumentEx myDocument; RangeMarkerTree.RMNode myNode; - private boolean myTrackInvalidation; private final long myId; //private static long counter; @@ -91,8 +92,21 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx return intervalEnd() + (node == null ? 0 : node.computeDeltaUpToRoot()); } - public void invalidate() { + public void invalidate(final DocumentEvent e) { setValid(false); + RangeMarkerTree.RMNode node = myNode; + + if (node != null) { + node.processAliveKeys(new Processor() { + @Override + public boolean process(RangeMarkerEx markerEx) { + if (markerEx.isTrackInvalidation()) { + LOG.error("Range marker invalidated: "+markerEx +"; say thanks to the "+e); + } + return true; + } + }); + } } @NotNull @@ -133,7 +147,7 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx if (intervalStart() > intervalEnd() || intervalStart() < 0 || intervalEnd() > docLength - e.getNewLength() + e.getOldLength()) { LOG.error("RangeMarker" + (isGreedyToLeft() ? "[" : "(") + oldStart + ", " + oldEnd + (isGreedyToRight() ? "]" : ")") + " is invalid before update. Event = " + e + ". Doc length=" + docLength + "; "+getClass()); - invalidate(); + invalidate(e); return; } changedUpdateImpl(e); @@ -143,7 +157,7 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx "old doc length=" + docLength + "; real doc length = "+myDocument.getTextLength()+ "; "+getClass()+"." + " Before update: '"+markerBefore+"'; After update: '"+this+"'"); - invalidate(); + invalidate(e); } } @@ -192,7 +206,7 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx return; } - invalidate(); + invalidate(e); } private void processIfOnePoint(DocumentEvent e) { @@ -200,7 +214,7 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx int oldLength = e.getOldLength(); int oldEnd = offset + oldLength; if (offset < intervalStart() && intervalStart() < oldEnd) { - invalidate(); + invalidate(e); return; } @@ -237,17 +251,17 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx return node != null && node.isValid(); } + private static final Key TRACK_INVALIDATION_KEY = new Key("TRACK_INVALIDATION_KEY"); @Override public void trackInvalidation(boolean track) { - myTrackInvalidation = track; + putUserData(TRACK_INVALIDATION_KEY, track ? Boolean.TRUE : null); + } + public boolean isTrackInvalidation() { + return getUserData(TRACK_INVALIDATION_KEY) == Boolean.TRUE; } @Override public boolean setValid(boolean value) { - if (!value && myTrackInvalidation) { - LOG.error("Range marker invalidated"); - } - RangeMarkerTree.RMNode node = myNode; return node == null || node.setValid(value); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java index 5a15cb0e0fa2..a5ba44e06006 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java @@ -82,10 +82,10 @@ public class RangeMarkerTree extends IntervalTreeImpl.RMNode addInterval(@NotNull T interval, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) { RangeMarkerImpl marker = (RangeMarkerImpl)interval; marker.setValid(true); - RMNode node = (RMNode)super.addInterval(interval, start, end, greedyToLeft, greedyToRight, layer); + RangeMarkerTree.RMNode node = (RMNode)super.addInterval(interval, start, end, greedyToLeft, greedyToRight, layer); ((RangeMarkerImpl)interval).myNode = node; checkBelongsToTheTree(interval, true); @@ -106,8 +106,8 @@ public class RangeMarkerTree extends IntervalTreeImpl.RMNode lookupNode(@NotNull T key) { + return (RMNode)((RangeMarkerImpl)key).myNode; } public class RMNode extends IntervalNode { @@ -131,7 +131,7 @@ public class RangeMarkerTree extends IntervalTreeImpl Date: Wed, 13 Apr 2011 17:54:40 +0400 Subject: [PATCH 045/102] TreeUI: file status fast update fix --- .../src/com/intellij/ide/util/treeView/AbstractTreeUi.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java index 6e86599db937..3453c92d5016 100644 --- a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java +++ b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java @@ -1017,7 +1017,7 @@ public class AbstractTreeUi { invokeLaterIfNeeded(new Runnable() { @Override public void run() { - if (row >= getTree().getVisibleRowCount()) return; + if (row >= getTree().getRowCount()) return; TreePath path = getTree().getPathForRow(row); if (path != null) { From 53c5aea8323672d3464c869a5026e7d709be482e Mon Sep 17 00:00:00 2001 From: Alexey Pegov Date: Wed, 13 Apr 2011 18:09:37 +0400 Subject: [PATCH 046/102] collapse project path to ~/path if project is placed under user home dir [mac & linux] in frame title & project view --- .../intellij/openapi/project/ProjectUtil.java | 35 +++++++++++++++++++ .../impl/nodes/PsiDirectoryNode.java | 7 +++- .../wm/impl/PlatformFrameTitleBuilder.java | 3 +- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/platform/lang-api/src/com/intellij/openapi/project/ProjectUtil.java b/platform/lang-api/src/com/intellij/openapi/project/ProjectUtil.java index 20effd6324ea..dec2bfb9fdb1 100644 --- a/platform/lang-api/src/com/intellij/openapi/project/ProjectUtil.java +++ b/platform/lang-api/src/com/intellij/openapi/project/ProjectUtil.java @@ -21,14 +21,49 @@ package com.intellij.openapi.project; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtil; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFilePathWrapper; +import com.intellij.util.SystemProperties; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.File; +import java.io.IOException; + public class ProjectUtil { private ProjectUtil() { } + @Nullable + public static String getProjectLocationString(@NotNull final Project project) { + String projectPath = project.getLocation(); + return getLocationRelativeToUserHome(projectPath); + } + + @Nullable + public static String getLocationRelativeToUserHome(final String path) { + if (path == null) return null; + + String _path = path; + + if ((SystemInfo.isLinux || SystemInfo.isMac)) { + final File projectDir = new File(path); + final File userHomeDir = new File(SystemProperties.getUserHome()); + try { + if (FileUtil.isAncestor(userHomeDir, projectDir, true)) { + _path = "~/" + FileUtil.getRelativePath(userHomeDir, projectDir); + } + } + catch (IOException e) { + // nothing + } + } + + return _path; + } + public static String calcRelativeToProjectPath(final VirtualFile file, final Project project) { if (file instanceof VirtualFilePathWrapper) { return ((VirtualFilePathWrapper)file).getPresentablePath(); diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/PsiDirectoryNode.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/PsiDirectoryNode.java index c31486f261e7..841518078327 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/PsiDirectoryNode.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/PsiDirectoryNode.java @@ -27,6 +27,7 @@ import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtil; import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectUtil; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.roots.ui.configuration.ProjectSettingsService; @@ -81,7 +82,11 @@ public class PsiDirectoryNode extends BasePsiNode implements Navig } if (parentValue instanceof Project || parentValue instanceof Module) { - data.addText(" (" + directoryFile.getPresentableUrl() + ")", SimpleTextAttributes.GRAYED_ATTRIBUTES); + if (parentValue instanceof Project) { + data.addText(" (" + ProjectUtil.getLocationRelativeToUserHome(directoryFile.getPresentableUrl()) + ")", SimpleTextAttributes.GRAYED_ATTRIBUTES); + } else { + data.addText(" (" + directoryFile.getPresentableUrl() + ")", SimpleTextAttributes.GRAYED_ATTRIBUTES); + } } else if (ProjectRootsUtil.isSourceOrTestRoot(directoryFile, project)) { if (ProjectRootsUtil.isInTestSource(directoryFile, project)) { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/PlatformFrameTitleBuilder.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/PlatformFrameTitleBuilder.java index 831969c7a75b..a4a23b5732fc 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/PlatformFrameTitleBuilder.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/PlatformFrameTitleBuilder.java @@ -16,6 +16,7 @@ package com.intellij.openapi.wm.impl; import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFilePathWrapper; import com.intellij.platform.ProjectBaseDirectory; @@ -27,7 +28,7 @@ public class PlatformFrameTitleBuilder extends FrameTitleBuilder { public String getProjectTitle(final Project project) { final VirtualFile baseDir = project.getBaseDir(); if (baseDir != null) { - return project.getName() + " - [" + baseDir.getPresentableUrl() + "]"; + return project.getName() + " - [" + ProjectUtil.getLocationRelativeToUserHome(baseDir.getPresentableUrl()) + "]"; } return project.getName(); } From 52b02298129a81db397a10f1f811b30a15a7d76d Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 13 Apr 2011 18:15:09 +0400 Subject: [PATCH 047/102] support smart pointers in multiroot files --- .../MultiRootSelfElementInfo.java | 45 +++++++++++++++++++ .../impl/smartPointers/SelfElementInfo.java | 6 ++- .../SmartPsiElementPointerImpl.java | 6 +++ 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 platform/lang-impl/src/com/intellij/psi/impl/smartPointers/MultiRootSelfElementInfo.java diff --git a/platform/lang-impl/src/com/intellij/psi/impl/smartPointers/MultiRootSelfElementInfo.java b/platform/lang-impl/src/com/intellij/psi/impl/smartPointers/MultiRootSelfElementInfo.java new file mode 100644 index 000000000000..77a650a565f8 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/psi/impl/smartPointers/MultiRootSelfElementInfo.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2011 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.psi.impl.smartPointers; + +import com.intellij.lang.Language; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; + +/** + * User: cdr + */ +public class MultiRootSelfElementInfo extends SelfElementInfo { + private final Language myLanguage; + + public MultiRootSelfElementInfo(@NotNull Project project, + @NotNull TextRange anchor, + @NotNull Class anchorClass, + @NotNull PsiFile containingFile, + @NotNull Language language) { + super(project, anchor, anchorClass, containingFile); + myLanguage = language; + } + + @Override + protected PsiFile restoreFile() { + PsiFile mainRoot = super.restoreFile(); + if (mainRoot == null) return null; + return mainRoot.getViewProvider().getPsi(myLanguage); + } +} diff --git a/platform/lang-impl/src/com/intellij/psi/impl/smartPointers/SelfElementInfo.java b/platform/lang-impl/src/com/intellij/psi/impl/smartPointers/SelfElementInfo.java index f347c6b0cd15..17d4f454f1c9 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/smartPointers/SelfElementInfo.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/smartPointers/SelfElementInfo.java @@ -151,7 +151,7 @@ public class SelfElementInfo implements SmartPointerElementInfo { public PsiElement restoreElement() { if (!mySyncMarkerIsValid) return null; - PsiFile file = restoreFileFromVirtual(myVirtualFile, myProject); + PsiFile file = restoreFile(); if (file == null || !file.isValid()) return null; final int syncStartOffset = getSyncStartOffset(); @@ -160,6 +160,10 @@ public class SelfElementInfo implements SmartPointerElementInfo { return findElementInside(file, syncStartOffset, syncEndOffset, myType); } + protected PsiFile restoreFile() { + return restoreFileFromVirtual(myVirtualFile, myProject); + } + protected static PsiElement findElementInside(PsiFile file, int syncStartOffset, int syncEndOffset, Class type) { PsiElement anchor = file.getViewProvider().findElementAt(syncStartOffset, file.getLanguage()); if (anchor == null) return null; diff --git a/platform/lang-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java index 7401a1664a07..09eb11b42a5b 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java @@ -164,6 +164,12 @@ class SmartPsiElementPointerImpl implements SmartPointerEx LOG.assertTrue(element.isPhysical()); LOG.assertTrue(element.isValid()); + boolean isMultiRoot = viewProvider.getAllFiles().size() > 1; + VirtualFile virtualFile = containingFile.getVirtualFile(); + boolean isElementInMainRoot = virtualFile == null || containingFile.getManager().findFile(virtualFile) == containingFile; + if (isMultiRoot && !isElementInMainRoot) { + return new MultiRootSelfElementInfo(project, element.getTextRange(), element.getClass(), containingFile, containingFile.getLanguage()); + } return new SelfElementInfo(project, element.getTextRange(), element.getClass(), containingFile); } From 877299dad0d91618205dec71a083e03412b91647 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Wed, 13 Apr 2011 18:20:05 +0400 Subject: [PATCH 048/102] update attrs.xml from new sdk --- .../android-1.5/data/res/values/attrs.xml | 1171 ++++++++++++++++- 1 file changed, 1108 insertions(+), 63 deletions(-) diff --git a/plugins/android/testData/sdk1.5/platforms/android-1.5/data/res/values/attrs.xml b/plugins/android/testData/sdk1.5/platforms/android-1.5/data/res/values/attrs.xml index 6370696708a2..f9809709fa55 100644 --- a/plugins/android/testData/sdk1.5/platforms/android-1.5/data/res/values/attrs.xml +++ b/plugins/android/testData/sdk1.5/platforms/android-1.5/data/res/values/attrs.xml @@ -14,8 +14,8 @@ limitations under the License. --> - @@ -34,9 +34,11 @@ + rendered views. This should be the color of the background when + there is a solid background color; it should be null when the + background is a texture or translucent. When a device is able + to use accelerated drawing (thus setting state_accelerated), the + cache hint is ignored and always assumed to be transparent. --> @@ -95,6 +97,15 @@ + + + + + + + + + @@ -117,10 +128,25 @@ - + + + + + + + + + + + + + + + + + + + + + + @@ -174,6 +206,8 @@ + + + + + - + user's current wallpaper. --> @@ -244,6 +286,19 @@ {@link android.R.styleable#WindowAnimation}. --> + + + + + + + + + @@ -285,6 +340,9 @@ need to close the input area to get at and interact with parts of the window. --> + + + + + + + + + + + + + + + + + + @@ -390,6 +482,12 @@ + + + + + + @@ -410,8 +508,8 @@ - - + + @@ -427,6 +525,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -453,6 +639,8 @@ + + @@ -468,6 +656,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -514,6 +778,10 @@ + + + @@ -622,8 +890,17 @@ {@link android.text.InputType#TYPE_CLASS_TEXT} | {@link android.text.InputType#TYPE_TEXT_VARIATION_PHONETIC}. --> + + + + + {@link android.text.InputType#TYPE_CLASS_NUMBER} | + {@link android.text.InputType#TYPE_NUMBER_VARIATION_NORMAL}. --> + + @@ -696,6 +977,40 @@ Corresponds to {@link android.view.inputmethod.EditorInfo#IME_ACTION_DONE}. --> + + + + + + + + @@ -981,6 +1373,21 @@ + + + + + + + + + @@ -995,6 +1402,21 @@ + + + + + + + + + + + + + + + @@ -1007,7 +1429,7 @@ - + @@ -1048,7 +1470,7 @@ animation that is run on the top activity of the current task (which is exiting the screen). --> - + @@ -1065,7 +1487,7 @@ currently showing the wallpaper, this is the animation that is run on the old wallpaper activity (which is exiting the screen). --> - + + + + @@ -1364,12 +1794,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1573,6 +2102,30 @@ will use only the number of items in the adapter and the number of items visible on screen to determine the scrollbar's properties. --> + + + + + + + + + + + + + + + + @@ -1768,7 +2324,18 @@ - + + + + + + + + + + + + - - - - - - - - - @@ -1802,6 +2357,20 @@ + + + + + + + + + + + + + + @@ -1817,6 +2386,8 @@ + + @@ -1864,6 +2435,8 @@ + + @@ -1929,6 +2502,8 @@ + + @@ -2181,6 +2756,19 @@ + + + + + + + + + + + @@ -2243,14 +2831,36 @@ + + + + + + + + + + + + + + + + + + + @@ -2264,12 +2874,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2432,8 +3079,60 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2467,6 +3166,10 @@ same pixel configuration as the screen (for instance: a ARGB 8888 bitmap with an RGB 565 screen). --> + + + + @@ -2557,6 +3260,14 @@ + + + + + + + + @@ -2574,6 +3285,10 @@ + + + + @@ -2691,6 +3406,10 @@ + + @@ -2793,10 +3512,10 @@ - - - - + + + + @@ -2896,6 +3615,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2918,6 +3697,7 @@

  • "state_last"
  • "state_only"
  • "state_pressed" +
  • "state_activated"
  • "state_error"
  • "state_circle"
  • "state_rect" @@ -2925,35 +3705,53 @@
  • "state_move" --> - + - + - + - + - + - + - - - - - - - - - - - + + + + + + + + + + + + + + + @@ -2961,6 +3759,8 @@ + + @@ -2998,6 +3798,10 @@ + + + + @@ -3305,6 +4109,39 @@ + + + + + + + + + + + + + + + + + + + + + @@ -3320,6 +4157,25 @@ + + + + + + + + + + + + + + + + + + @@ -3327,15 +4183,20 @@ + + - + + + @@ -3407,6 +4268,16 @@ + + + + + + + @@ -3558,7 +4429,7 @@ - + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + - + @@ -3636,13 +4558,17 @@ + + - + @@ -3652,13 +4578,25 @@ + + + + - + @@ -3684,6 +4622,9 @@ + + @@ -3715,4 +4656,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 555514ad2304e4e07e4533280250b8d54b8f3dce Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Wed, 13 Apr 2011 18:20:54 +0400 Subject: [PATCH 049/102] IDEA-67650 support for fragments in layout xml files --- .../android/dom/AndroidDomExtender.java | 22 +++++++---- .../dom/converters/PackageClassConverter.java | 30 +++++++------- .../android/dom/layout/Fragment.java | 39 +++++++++++++++++++ .../android/dom/layout/LayoutViewElement.java | 2 + .../android/testData/dom/layout/Fragment.java | 3 ++ .../dom/layout/MyFragmentActivity.java | 6 +++ .../dom/layout/fragmentCompletion1.xml | 7 ++++ .../dom/layout/fragmentCompletion1_after.xml | 7 ++++ .../dom/layout/fragmentCompletion2.xml | 7 ++++ .../dom/layout/fragmentCompletion2_after.xml | 7 ++++ .../dom/layout/fragmentCompletion3.xml | 7 ++++ .../dom/layout/fragmentCompletion3_after.xml | 7 ++++ .../dom/layout/fragmentHighlighting.xml | 19 +++++++++ .../android/dom/AndroidLayoutDomTest.java | 22 +++++++++++ 14 files changed, 163 insertions(+), 22 deletions(-) create mode 100644 plugins/android/src/org/jetbrains/android/dom/layout/Fragment.java create mode 100644 plugins/android/testData/dom/layout/Fragment.java create mode 100644 plugins/android/testData/dom/layout/MyFragmentActivity.java create mode 100644 plugins/android/testData/dom/layout/fragmentCompletion1.xml create mode 100644 plugins/android/testData/dom/layout/fragmentCompletion1_after.xml create mode 100644 plugins/android/testData/dom/layout/fragmentCompletion2.xml create mode 100644 plugins/android/testData/dom/layout/fragmentCompletion2_after.xml create mode 100644 plugins/android/testData/dom/layout/fragmentCompletion3.xml create mode 100644 plugins/android/testData/dom/layout/fragmentCompletion3_after.xml create mode 100644 plugins/android/testData/dom/layout/fragmentHighlighting.xml diff --git a/plugins/android/src/org/jetbrains/android/dom/AndroidDomExtender.java b/plugins/android/src/org/jetbrains/android/dom/AndroidDomExtender.java index 6e0d3f04cbb9..b20daac5e010 100644 --- a/plugins/android/src/org/jetbrains/android/dom/AndroidDomExtender.java +++ b/plugins/android/src/org/jetbrains/android/dom/AndroidDomExtender.java @@ -38,6 +38,7 @@ import org.jetbrains.android.dom.attrs.AttributeFormat; import org.jetbrains.android.dom.attrs.StyleableDefinition; import org.jetbrains.android.dom.converters.CompositeConverter; import org.jetbrains.android.dom.converters.ResourceReferenceConverter; +import org.jetbrains.android.dom.layout.Fragment; import org.jetbrains.android.dom.layout.Include; import org.jetbrains.android.dom.layout.LayoutElement; import org.jetbrains.android.dom.layout.LayoutViewElement; @@ -375,7 +376,8 @@ public class AndroidDomExtender extends DomExtender { private static final MyAttributeProcessor ourLayoutAttrsProcessor = new MyAttributeProcessor() { @Override public void process(@NotNull XmlName attrName, @NotNull DomExtension extension, @NotNull DomElement element) { - if (element instanceof LayoutViewElement && SdkConstants.NS_RESOURCES.equals(attrName.getNamespaceKey())) { + if ((element instanceof LayoutViewElement || element instanceof Fragment) && + SdkConstants.NS_RESOURCES.equals(attrName.getNamespaceKey())) { XmlElement xmlElement = element.getXmlElement(); XmlTag tag = xmlElement instanceof XmlTag ? (XmlTag)xmlElement : null; String tagName = tag != null ? tag.getName() : null; @@ -422,15 +424,21 @@ public class AndroidDomExtender extends DomExtender { } return; } - String tagName = tag.getName(); - if (!tagName.equals("view")) { - PsiClass c = map.get(tagName); - registerAttributesForClassAndSuperclasses(facet, element, c, registrar, ourLayoutAttrsProcessor); + else if (element instanceof Fragment) { + registerAttributes(facet, element, new String[]{"Fragment"}, registrar, ourLayoutAttrsProcessor); } else { - String[] styleableNames = getClassNames(map.values()); - registerAttributes(facet, element, styleableNames, registrar, ourLayoutAttrsProcessor); + String tagName = tag.getName(); + if (!tagName.equals("view")) { + PsiClass c = map.get(tagName); + registerAttributesForClassAndSuperclasses(facet, element, c, registrar, ourLayoutAttrsProcessor); + } + else { + String[] styleableNames = getClassNames(map.values()); + registerAttributes(facet, element, styleableNames, registrar, ourLayoutAttrsProcessor); + } } + registerLayoutAttributes(facet, element, tag, registrar, ourLayoutAttrsProcessor); for (String viewClassName : map.keySet()) { diff --git a/plugins/android/src/org/jetbrains/android/dom/converters/PackageClassConverter.java b/plugins/android/src/org/jetbrains/android/dom/converters/PackageClassConverter.java index 1455df54150b..0e036fd3d4e6 100644 --- a/plugins/android/src/org/jetbrains/android/dom/converters/PackageClassConverter.java +++ b/plugins/android/src/org/jetbrains/android/dom/converters/PackageClassConverter.java @@ -66,28 +66,28 @@ public class PackageClassConverter extends ResolvingConverter implemen if (s == null) return null; DomElement domElement = context.getInvocationElement(); Manifest manifest = domElement.getParentOfType(Manifest.class, true); - if (manifest != null) { - s = s.replace('$', '.'); - String packageName = manifest.getPackage().getValue(); - String className; + s = s.replace('$', '.'); + String packageName = manifest != null ? manifest.getPackage().getValue() : null; + String className = null; + + if (packageName != null) { if (s.startsWith(".")) { className = packageName + s; } else { className = packageName + "." + s; } - JavaPsiFacade facade = JavaPsiFacade.getInstance(context.getPsiManager().getProject()); - final Module module = context.getModule(); - GlobalSearchScope scope = module != null - ? GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module) - : context.getInvocationElement().getResolveScope(); - PsiClass psiClass = facade.findClass(className, scope); - if (psiClass == null) { - psiClass = facade.findClass(s, scope); - } - return psiClass; } - return null; + JavaPsiFacade facade = JavaPsiFacade.getInstance(context.getPsiManager().getProject()); + final Module module = context.getModule(); + GlobalSearchScope scope = module != null + ? GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module) + : context.getInvocationElement().getResolveScope(); + PsiClass psiClass = className != null ? facade.findClass(className, scope) : null; + if (psiClass == null) { + psiClass = facade.findClass(s, scope); + } + return psiClass; } @NotNull diff --git a/plugins/android/src/org/jetbrains/android/dom/layout/Fragment.java b/plugins/android/src/org/jetbrains/android/dom/layout/Fragment.java new file mode 100644 index 000000000000..4f4ca53af2f2 --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/dom/layout/Fragment.java @@ -0,0 +1,39 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.android.dom.layout; + +import com.intellij.psi.PsiClass; +import com.intellij.util.xml.Attribute; +import com.intellij.util.xml.Convert; +import com.intellij.util.xml.ExtendClass; +import com.intellij.util.xml.GenericAttributeValue; +import org.jetbrains.android.dom.AndroidAttributeValue; +import org.jetbrains.android.dom.converters.PackageClassConverter; + +/** + * @author Eugene.Kudelevsky + */ +public interface Fragment extends LayoutElement { + @Attribute("name") + @Convert(PackageClassConverter.class) + @ExtendClass("android.app.Fragment") + AndroidAttributeValue getFragmentName(); + + @Attribute("class") + @Convert(PackageClassConverter.class) + @ExtendClass("android.app.Fragment") + GenericAttributeValue getFragmentClass(); +} diff --git a/plugins/android/src/org/jetbrains/android/dom/layout/LayoutViewElement.java b/plugins/android/src/org/jetbrains/android/dom/layout/LayoutViewElement.java index c1873197c47e..ac810990b7c1 100644 --- a/plugins/android/src/org/jetbrains/android/dom/layout/LayoutViewElement.java +++ b/plugins/android/src/org/jetbrains/android/dom/layout/LayoutViewElement.java @@ -46,4 +46,6 @@ public interface LayoutViewElement extends LayoutElement { GenericAttributeValue getViewClass(); List getIncludes(); + + List getFragments(); } diff --git a/plugins/android/testData/dom/layout/Fragment.java b/plugins/android/testData/dom/layout/Fragment.java new file mode 100644 index 000000000000..4be42783eda2 --- /dev/null +++ b/plugins/android/testData/dom/layout/Fragment.java @@ -0,0 +1,3 @@ +package android.app; + +public class Fragment {} \ No newline at end of file diff --git a/plugins/android/testData/dom/layout/MyFragmentActivity.java b/plugins/android/testData/dom/layout/MyFragmentActivity.java new file mode 100644 index 000000000000..01c27ea6f61a --- /dev/null +++ b/plugins/android/testData/dom/layout/MyFragmentActivity.java @@ -0,0 +1,6 @@ +package p1.p2; + +public class MyFragmentActivity extends android.app.Activity { + public static class MyFragment extends android.app.Fragment { + } +} \ No newline at end of file diff --git a/plugins/android/testData/dom/layout/fragmentCompletion1.xml b/plugins/android/testData/dom/layout/fragmentCompletion1.xml new file mode 100644 index 000000000000..d85e062d528b --- /dev/null +++ b/plugins/android/testData/dom/layout/fragmentCompletion1.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/plugins/android/testData/dom/layout/fragmentCompletion1_after.xml b/plugins/android/testData/dom/layout/fragmentCompletion1_after.xml new file mode 100644 index 000000000000..49fb40f862e7 --- /dev/null +++ b/plugins/android/testData/dom/layout/fragmentCompletion1_after.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/plugins/android/testData/dom/layout/fragmentCompletion2.xml b/plugins/android/testData/dom/layout/fragmentCompletion2.xml new file mode 100644 index 000000000000..3d608d927e6b --- /dev/null +++ b/plugins/android/testData/dom/layout/fragmentCompletion2.xml @@ -0,0 +1,7 @@ + + + /> + + \ No newline at end of file diff --git a/plugins/android/testData/dom/layout/fragmentCompletion2_after.xml b/plugins/android/testData/dom/layout/fragmentCompletion2_after.xml new file mode 100644 index 000000000000..448cd4bd5c4a --- /dev/null +++ b/plugins/android/testData/dom/layout/fragmentCompletion2_after.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/plugins/android/testData/dom/layout/fragmentCompletion3.xml b/plugins/android/testData/dom/layout/fragmentCompletion3.xml new file mode 100644 index 000000000000..195838f3dce9 --- /dev/null +++ b/plugins/android/testData/dom/layout/fragmentCompletion3.xml @@ -0,0 +1,7 @@ + + + /> + + \ No newline at end of file diff --git a/plugins/android/testData/dom/layout/fragmentCompletion3_after.xml b/plugins/android/testData/dom/layout/fragmentCompletion3_after.xml new file mode 100644 index 000000000000..bf8af317d788 --- /dev/null +++ b/plugins/android/testData/dom/layout/fragmentCompletion3_after.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/plugins/android/testData/dom/layout/fragmentHighlighting.xml b/plugins/android/testData/dom/layout/fragmentHighlighting.xml new file mode 100644 index 000000000000..6cac7a50be61 --- /dev/null +++ b/plugins/android/testData/dom/layout/fragmentHighlighting.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + <fragment class="p1.p2.MyFragmentActivity$MyFragment"/> + + \ No newline at end of file diff --git a/plugins/android/testSrc/org/jetbrains/android/dom/AndroidLayoutDomTest.java b/plugins/android/testSrc/org/jetbrains/android/dom/AndroidLayoutDomTest.java index c6fe3894580a..3ae359731c6b 100644 --- a/plugins/android/testSrc/org/jetbrains/android/dom/AndroidLayoutDomTest.java +++ b/plugins/android/testSrc/org/jetbrains/android/dom/AndroidLayoutDomTest.java @@ -22,6 +22,10 @@ public class AndroidLayoutDomTest extends AndroidDomTest { public void setUp() throws Exception { super.setUp(); myFixture.copyFileToProject(SdkConstants.FN_ANDROID_MANIFEST_XML, SdkConstants.FN_ANDROID_MANIFEST_XML); + + // copy mock fragment, because it is not included to old android.jar + // todo: create normal mock Android sdk + copyFileToProject("Fragment.java", "src/android/app/Fragment.java"); } @Override @@ -206,6 +210,24 @@ public class AndroidLayoutDomTest extends AndroidDomTest { doTestHighlighting("merge.xml"); } + public void testFragmentHighlighting() throws Throwable { + copyFileToProject("MyFragmentActivity.java", "src/p1/p2/MyFragmentActivity.java"); + doTestHighlighting(getTestName(true) + ".xml"); + } + + public void testFragmentCompletion1() throws Throwable { + copyFileToProject("MyFragmentActivity.java", "src/p1/p2/MyFragmentActivity.java"); + toTestCompletion(getTestName(true) + ".xml", getTestName(true) + "_after.xml"); + } + + public void testFragmentCompletion2() throws Throwable { + toTestCompletion(getTestName(true) + ".xml", getTestName(true) + "_after.xml"); + } + + public void testFragmentCompletion3() throws Throwable { + toTestCompletion(getTestName(true) + ".xml", getTestName(true) + "_after.xml"); + } + /*public void testCustomAttrsPerformance() throws Throwable { myFixture.copyFileToProject("dom/resources/bigfile.xml", "res/values/bigfile.xml"); myFixture.copyFileToProject("dom/resources/bigattrs.xml", "res/values/bigattrs.xml"); From faa0147a47e3f52ee0658655983827a32eb4f9f8 Mon Sep 17 00:00:00 2001 From: irengrig Date: Wed, 13 Apr 2011 18:33:51 +0400 Subject: [PATCH 050/102] 1) warn if Task.Backgroundable is created without a title 2) assert if GitBranches refreshes are invoked in parallel 3) monitor BackgroundTaskQueue load if property is passed --- .../com/intellij/openapi/progress/Task.java | 8 +- .../openapi/progress/BackgroundTaskQueue.java | 18 +++- .../progress/BackgroundTasksMonitor.java | 92 +++++++++++++++++++ .../src/com/intellij/util}/PlusMinus.java | 11 ++- .../vcs/changes/ChangeListManagerImpl.java | 5 +- .../openapi/vcs/changes/ChangeListWorker.java | 1 + .../openapi/vcs/changes/ChangesDelta.java | 2 +- .../vcs/changes/ChangesOnServerTracker.java | 1 + .../vcs/changes/RemoteRevisionsCache.java | 1 + .../src/git4idea/branch/GitBranches.java | 17 +++- 10 files changed, 142 insertions(+), 14 deletions(-) create mode 100644 platform/platform-impl/src/com/intellij/openapi/progress/BackgroundTasksMonitor.java rename platform/{vcs-impl/src/com/intellij/openapi/vcs/changes => util/src/com/intellij/util}/PlusMinus.java (79%) diff --git a/platform/platform-api/src/com/intellij/openapi/progress/Task.java b/platform/platform-api/src/com/intellij/openapi/progress/Task.java index 9aacc6a03b8a..b956b48c3c33 100644 --- a/platform/platform-api/src/com/intellij/openapi/progress/Task.java +++ b/platform/platform-api/src/com/intellij/openapi/progress/Task.java @@ -17,10 +17,13 @@ package com.intellij.openapi.progress; import com.intellij.CommonBundle; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.DumbModeAction; +import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import sun.util.LocaleServiceProviderPool; /** * Intended to run tasks, both modal and non-modal (backgroundable) @@ -39,7 +42,7 @@ import org.jetbrains.annotations.Nullable; * @see com.intellij.openapi.progress.ProgressManager#run(Task) */ public abstract class Task implements TaskInfo, Progressive { - + private final static Logger LOG = Logger.getInstance("#com.intellij.openapi.progress.Task"); protected final Project myProject; protected String myTitle; private final boolean myCanBeCancelled; @@ -134,6 +137,9 @@ public abstract class Task implements TaskInfo, Progressive { public Backgroundable(@Nullable final Project project, @NotNull final String title, final boolean canBeCancelled, @Nullable final PerformInBackgroundOption backgroundOption) { super(project, title, canBeCancelled); myBackgroundOption = backgroundOption; + if (StringUtil.isEmptyOrSpaces(title)) { + LOG.warn("Empty title for backgroundable task.", new Throwable()); + } } public Backgroundable(@Nullable final Project project, @NotNull final String title, final boolean canBeCancelled) { diff --git a/platform/platform-impl/src/com/intellij/openapi/progress/BackgroundTaskQueue.java b/platform/platform-impl/src/com/intellij/openapi/progress/BackgroundTaskQueue.java index 7c50d43de762..8f052e97839d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/progress/BackgroundTaskQueue.java +++ b/platform/platform-impl/src/com/intellij/openapi/progress/BackgroundTaskQueue.java @@ -27,6 +27,7 @@ import com.intellij.openapi.util.Getter; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.PairConsumer; +import com.intellij.util.PlusMinus; import com.intellij.util.concurrency.QueueProcessor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -41,21 +42,24 @@ import org.jetbrains.annotations.Nullable; */ @SomeQueue public class BackgroundTaskQueue { + private final static String ourMonitorFlag = "monitor.background.queue.load"; private static final Logger LOG = Logger.getInstance(BackgroundTaskQueue.class.getName()); //private final Project myProject; private final QueueProcessor>> myProcessor; private Boolean myForcedTestMode; + private final PlusMinus myMonitor; public BackgroundTaskQueue(@Nullable Project project, @NotNull String title) { this(project, title, null); } public BackgroundTaskQueue(@Nullable final Project project, @NotNull String title, final Boolean forcedHeadlessMode) { + myMonitor = Boolean.TRUE.equals(Boolean.getBoolean(ourMonitorFlag)) ? new BackgroundTasksMonitor(title) : new PlusMinus.Empty(); final boolean headless = forcedHeadlessMode != null ? forcedHeadlessMode : ApplicationManager.getApplication().isHeadlessEnvironment(); final QueueProcessor.ThreadToUse threadToUse = headless ? QueueProcessor.ThreadToUse.POOLED : QueueProcessor.ThreadToUse.AWT; final PairConsumer>, Runnable> consumer - = headless ? new BackgroundableHeadlessRunner() : new BackgroundableUnderProgressRunner(title, project); + = headless ? new BackgroundableHeadlessRunner() : new BackgroundableUnderProgressRunner(title, project, myMonitor); myProcessor = new QueueProcessor>>(consumer, true, threadToUse, new Condition() { @@ -83,6 +87,7 @@ public class BackgroundTaskQueue { } public void run(Task.Backgroundable task, final ModalityState state, final Getter pi) { + myMonitor.plus(task.getTitle()); if (isTestMode()) { // test tasks are executed in this thread without the progress manager RunBackgroundable.runIfBackgroundThread(task, new EmptyProgressIndicator(), null); } else { @@ -103,14 +108,17 @@ public class BackgroundTaskQueue { private static class BackgroundableUnderProgressRunner implements PairConsumer>, Runnable> { private final String myTitle; private final Project myProject; + private final PlusMinus myMonitor; - public BackgroundableUnderProgressRunner(String title, final Project project) { + public BackgroundableUnderProgressRunner(String title, final Project project, PlusMinus monitor) { myTitle = title; myProject = project; + myMonitor = monitor; } @Override public void consume(final Pair> pair, final Runnable runnable) { + myMonitor.minus(pair.getFirst().getTitle()); final Task.Backgroundable backgroundable = pair.getFirst(); final ProgressIndicator[] pi = new ProgressIndicator[1]; final boolean taskTitleIsEmpty = StringUtil.isEmptyOrSpaces(backgroundable.getTitle()); @@ -133,11 +141,11 @@ public class BackgroundTaskQueue { pi[0] = pair.getSecond().get(); } if (pi[0] == null) { + if (taskTitleIsEmpty) { + backgroundable.setTitle(myTitle); + } pi[0] = new BackgroundableProcessIndicator(backgroundable); } - if (taskTitleIsEmpty) { - ((BackgroundableProcessIndicator) pi[0]).setTitle(myTitle); - } ProgressManagerImpl.runProcessWithProgressAsynchronously(backgroundable, pi[0], runnable); } diff --git a/platform/platform-impl/src/com/intellij/openapi/progress/BackgroundTasksMonitor.java b/platform/platform-impl/src/com/intellij/openapi/progress/BackgroundTasksMonitor.java new file mode 100644 index 000000000000..ab1040eb3f7e --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/progress/BackgroundTasksMonitor.java @@ -0,0 +1,92 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.progress; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.util.PlusMinus; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author irengrig + * Date: 4/13/11 + * Time: 5:32 PM + */ +public class BackgroundTasksMonitor implements PlusMinus { + private final static Logger LOG = Logger.getInstance("#com.intellij.openapi.progress.BackgroundTasksMonitor"); + private static final long ourStatInterval = 300000; + private long myRecentTime; + private final Map myMap; + private final Map myMaxMap; + private final Object myLock; + private final String myQueueTitle; + + public BackgroundTasksMonitor(final String queueTitle) { + myQueueTitle = queueTitle; + myMap = new HashMap(); + myMaxMap = new HashMap(); + myLock = new Object(); + myRecentTime = 0; + } + + @Override + public void plus(String title) { + synchronized (myLock) { + final Integer previous = myMap.get(title); + final int newVal = previous == null ? 1 : (previous + 1); + myMap.put(title, newVal); + final Integer max = myMaxMap.get(title); + if (max == null || max < newVal) { + myMaxMap.put(title, newVal); + } + reportStatistics(); + } + } + + + @Override + public void minus(String title) { + synchronized (myLock) { + final Integer integer = myMap.get(title); + assert integer != null; + if (integer == 1) { + myMap.remove(title); + } else { + myMap.put(title, integer - 1); + } + reportStatistics(); + } + } + + private void reportStatistics() { + final long time = System.currentTimeMillis(); + if (time - ourStatInterval < myRecentTime) return; + final StringBuilder sb = new StringBuilder("BackgroundTaskQueue '" + myQueueTitle + "' usage statistics\n"); + sb.append("----------------------------------------------------\n"); + sb.append("Current Values:"); + for (Map.Entry entry : myMap.entrySet()) { + sb.append(entry.getKey()).append(": ").append(entry.getValue()); + } + sb.append("\nMaximum Values:"); + for (Map.Entry entry : myMaxMap.entrySet()) { + sb.append('\n').append(entry.getKey()).append(": ").append(entry.getValue()); + } + sb.append("----------------------------------------------------\n"); + LOG.info(sb.toString()); + myRecentTime = time; + } +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/PlusMinus.java b/platform/util/src/com/intellij/util/PlusMinus.java similarity index 79% rename from platform/vcs-impl/src/com/intellij/openapi/vcs/changes/PlusMinus.java rename to platform/util/src/com/intellij/util/PlusMinus.java index 47779e91da9e..7971dfd2f19e 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/PlusMinus.java +++ b/platform/util/src/com/intellij/util/PlusMinus.java @@ -13,9 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.openapi.vcs.changes; +package com.intellij.util; public interface PlusMinus { + class Empty implements PlusMinus { + @Override + public void plus(T t) { + } + @Override + public void minus(T t) { + } + } + void plus(final T t); void minus(final T t); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java index 0517740f2f0c..5e73e2795f4a 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java @@ -44,10 +44,7 @@ import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.EditorNotifications; -import com.intellij.util.ConcurrencyUtil; -import com.intellij.util.Consumer; -import com.intellij.util.EventDispatcher; -import com.intellij.util.NullableFunction; +import com.intellij.util.*; import com.intellij.util.containers.MultiMap; import com.intellij.util.messages.Topic; import com.intellij.vcsUtil.Rethrow; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListWorker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListWorker.java index 2236cd0fd2cd..10f9b4893c29 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListWorker.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListWorker.java @@ -23,6 +23,7 @@ import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.vcs.*; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.PlusMinus; import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesDelta.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesDelta.java index fcb32c5f88d6..5106db481e47 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesDelta.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesDelta.java @@ -20,7 +20,7 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vcs.VcsKey; -import com.intellij.openapi.vcs.impl.CollectionsDelta; +import com.intellij.util.PlusMinus; import java.util.Collection; import java.util.HashSet; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesOnServerTracker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesOnServerTracker.java index 3690ba3ee9cd..519a251de0bb 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesOnServerTracker.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesOnServerTracker.java @@ -19,6 +19,7 @@ import com.intellij.lifecycle.AtomicSectionsAware; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vcs.VcsListener; +import com.intellij.util.PlusMinus; import java.util.Collection; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/RemoteRevisionsCache.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/RemoteRevisionsCache.java index 4d7be3aeefe9..73c70c4a9fb5 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/RemoteRevisionsCache.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/RemoteRevisionsCache.java @@ -30,6 +30,7 @@ import com.intellij.openapi.vcs.impl.VcsInitObject; import com.intellij.openapi.vcs.update.UpdateFilesHelper; import com.intellij.openapi.vcs.update.UpdatedFiles; import com.intellij.util.Consumer; +import com.intellij.util.PlusMinus; import com.intellij.util.messages.Topic; import java.util.Collection; diff --git a/plugins/git4idea/src/git4idea/branch/GitBranches.java b/plugins/git4idea/src/git4idea/branch/GitBranches.java index 9c576cdfb290..f8d2760a029a 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranches.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranches.java @@ -38,6 +38,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; /** * Container and tracker of git branches information. @@ -55,11 +56,13 @@ public class GitBranches implements GitReferenceListener { private final Object myCurrentBranchesLock = new Object(); private ChangeListManager myChangeListManager; private GitVcs myVcs; + private final AtomicBoolean mySoleUseControl; public GitBranches(Project project, ChangeListManager changeListManager, ProjectLevelVcsManager vcsManager) { myProject = project; myChangeListManager = changeListManager; myVcsManager = vcsManager; + mySoleUseControl = new AtomicBoolean(false); } public static GitBranches getInstance(Project project) { @@ -121,8 +124,10 @@ public class GitBranches implements GitReferenceListener { return; } - final Task.Backgroundable task = new Task.Backgroundable(myProject, "") { + final Task.Backgroundable task = new Task.Backgroundable(myProject, "Git: refresh current branch") { @Override public void run(@NotNull ProgressIndicator indicator) { + assert ! mySoleUseControl.get(); + mySoleUseControl.set(true); try { GitBranch currentBranch = GitBranch.current(myProject, root); synchronized (myCurrentBranchesLock) { @@ -132,6 +137,8 @@ public class GitBranches implements GitReferenceListener { } catch (VcsException e) { LOG.info("Exception while trying to get current branch for root " + root, e); // doing nothing - null will be set to myCurrentBranchName + } finally { + mySoleUseControl.set(false); } } }; @@ -140,8 +147,11 @@ public class GitBranches implements GitReferenceListener { private void fullyUpdateBranchesInfo(final Collection roots) { if (roots == null) { return; } - final Task.Backgroundable task = new Task.Backgroundable(myProject, "") { + final Task.Backgroundable task = new Task.Backgroundable(myProject, "Git: refresh current branches") { @Override public void run(@NotNull ProgressIndicator indicator) { + assert ! mySoleUseControl.get(); + mySoleUseControl.set(true); + try { Map currentBranches = new HashMap(); for (VirtualFile root : roots) { try { @@ -156,6 +166,9 @@ public class GitBranches implements GitReferenceListener { synchronized (myCurrentBranchesLock) { myCurrentBranches = currentBranches; } + } finally { + mySoleUseControl.set(false); + } } }; GitVcs.runInBackground(task); From 8857cede42252ee2c36e07ffcf3bfbd43b10f896 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Wed, 13 Apr 2011 18:36:35 +0400 Subject: [PATCH 051/102] IDEA-62546 support for creating xml drawable resources --- .../jetbrains/android/actions/CreateResourceFileActionGroup.java | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/android/src/org/jetbrains/android/actions/CreateResourceFileActionGroup.java b/plugins/android/src/org/jetbrains/android/actions/CreateResourceFileActionGroup.java index 7ed9f4738380..cf180469efc6 100644 --- a/plugins/android/src/org/jetbrains/android/actions/CreateResourceFileActionGroup.java +++ b/plugins/android/src/org/jetbrains/android/actions/CreateResourceFileActionGroup.java @@ -33,6 +33,7 @@ public class CreateResourceFileActionGroup extends DefaultActionGroup { CreateResourceFileAction a = new CreateResourceFileAction(); a.add(new CreateTypedResourceFileAction("Layout", "layout", "LinearLayout")); a.add(new CreateTypedResourceFileAction("XML", "xml", "PreferenceScreen")); + a.add(new CreateTypedResourceFileAction("Drawable", "drawable", "selector")); a.add(new CreateTypedResourceFileAction("Values", "values", "resources", true, false)); a.add(new CreateTypedResourceFileAction("Menu", "menu", "menu", false, false)); a.add(new CreateTypedResourceFileAction("Animation", "anim", "set")); From edd537b57453460f872e76cff519552a6e02d39d Mon Sep 17 00:00:00 2001 From: Kirill Kalishev Date: Wed, 13 Apr 2011 19:09:35 +0400 Subject: [PATCH 052/102] tabs: closing editor with multirow mode fix --- .../platform-api/src/com/intellij/ui/tabs/impl/TabLabel.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platform/platform-api/src/com/intellij/ui/tabs/impl/TabLabel.java b/platform/platform-api/src/com/intellij/ui/tabs/impl/TabLabel.java index 745a84d233e8..96c1e47b07a7 100644 --- a/platform/platform-api/src/com/intellij/ui/tabs/impl/TabLabel.java +++ b/platform/platform-api/src/com/intellij/ui/tabs/impl/TabLabel.java @@ -21,6 +21,7 @@ import com.intellij.openapi.actionSystem.ActionPlaces; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.util.Pass; import com.intellij.openapi.util.SystemInfo; +import com.intellij.ui.InplaceButton; import com.intellij.ui.LayeredIcon; import com.intellij.ui.SimpleColoredComponent; import com.intellij.ui.SimpleColoredText; @@ -78,6 +79,8 @@ public class TabLabel extends JPanel { addMouseListener(new MouseAdapter() { public void mousePressed(final MouseEvent e) { if (myTabs.isSelectionClick(e, false) && myInfo.isEnabled()) { + Component c = SwingUtilities.getDeepestComponentAt(e.getComponent(), e.getX(), e.getY()); + if (c instanceof InplaceButton) return; myTabs.select(info, true); } else { From 7d3a93e6e7cb1d0416ba80453eb63e573f802073 Mon Sep 17 00:00:00 2001 From: Alexey Pegov Date: Wed, 13 Apr 2011 19:24:50 +0400 Subject: [PATCH 053/102] EA-26724 - assert: MessageBusImpl.checkNotDisposed --- .../openapi/components/impl/stores/FileBasedStorage.java | 2 +- .../openapi/components/impl/stores/XmlElementStorage.java | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/FileBasedStorage.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/FileBasedStorage.java index 7ba1de8a9057..1936b4855700 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/FileBasedStorage.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/FileBasedStorage.java @@ -96,7 +96,7 @@ public class FileBasedStorage extends XmlElementStorage { final Listener listener = messageBus.syncPublisher(STORAGE_TOPIC); virtualFileTracker.addTracker(fileUrl, new VirtualFileAdapter() { public void contentsChanged(final VirtualFileEvent event) { - listener.storageFileChanged(event, FileBasedStorage.this); + if (!isDisposed()) listener.storageFileChanged(event, FileBasedStorage.this); } }, false, this); } 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 0419e7856058..b8d7b72b8ecf 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 @@ -75,6 +75,8 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { myLocalVersionProvider.changeVersion(componentName, System.currentTimeMillis()); } }; + + private boolean myDisposed; protected XmlElementStorage(@Nullable final TrackingPathMacroSubstitutor pathMacroSubstitutor, @@ -113,6 +115,10 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { }; } + protected boolean isDisposed() { + return myDisposed; + } + @Nullable protected abstract Document loadDocument() throws StateStorageException; @@ -536,6 +542,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { } public void dispose() { + myDisposed = true; } protected static class StorageData { From 588afceb7f6c69e611dc8a15ca0cd3dcd817983d Mon Sep 17 00:00:00 2001 From: Alexey Pegov Date: Wed, 13 Apr 2011 19:27:37 +0400 Subject: [PATCH 054/102] EA-26244 - NPE: ContentEntryEditor.getContentEntry --- .../roots/ui/configuration/ContentEntryEditor.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentEntryEditor.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentEntryEditor.java index 43ac1f39631a..759183d274b0 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentEntryEditor.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentEntryEditor.java @@ -93,9 +93,12 @@ public abstract class ContentEntryEditor implements ContentRootPanel.ActionCallb @Nullable protected ContentEntry getContentEntry() { - final ContentEntry[] entries = getModel().getContentEntries(); - for (ContentEntry entry : entries) { - if (entry.getUrl().equals(myContentEntryUrl)) return entry; + final ModifiableRootModel model = getModel(); + if (model != null) { + final ContentEntry[] entries = model.getContentEntries(); + for (ContentEntry entry : entries) { + if (entry.getUrl().equals(myContentEntryUrl)) return entry; + } } return null; From fe3c00400715f7fc1c287d7a488452bcbf26af66 Mon Sep 17 00:00:00 2001 From: Alexey Pegov Date: Wed, 13 Apr 2011 19:40:08 +0400 Subject: [PATCH 055/102] EA-25564 - NPE: CommonContentEntriesEditor.createComponentImpl --- .../configuration/CommonContentEntriesEditor.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/CommonContentEntriesEditor.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/CommonContentEntriesEditor.java index c36083ce9e83..06821c652915 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/CommonContentEntriesEditor.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/CommonContentEntriesEditor.java @@ -175,12 +175,15 @@ public class CommonContentEntriesEditor extends ModuleElementsEditor { mainPanel.add(innerPanel, BorderLayout.SOUTH); } - final ContentEntry[] contentEntries = getModel().getContentEntries(); - if (contentEntries.length > 0) { - for (final ContentEntry contentEntry : contentEntries) { - addContentEntryPanel(contentEntry.getUrl()); + final ModifiableRootModel model = getModel(); + if (model != null) { + final ContentEntry[] contentEntries = model.getContentEntries(); + if (contentEntries.length > 0) { + for (final ContentEntry contentEntry : contentEntries) { + addContentEntryPanel(contentEntry.getUrl()); + } + selectContentEntry(contentEntries[0].getUrl()); } - selectContentEntry(contentEntries[0].getUrl()); } return mainPanel; From dab8de9f55d7f22cc782ca0bd35ab2442e612bb4 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Wed, 13 Apr 2011 20:32:20 +0400 Subject: [PATCH 056/102] slightly change DiffPanel interface --- .../src/com/intellij/openapi/diff/DiffPanel.java | 10 ++++++---- .../com/intellij/openapi/diff/impl/DiffPanelImpl.java | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/platform/platform-api/src/com/intellij/openapi/diff/DiffPanel.java b/platform/platform-api/src/com/intellij/openapi/diff/DiffPanel.java index 6af7bcc44655..1c9734df8911 100644 --- a/platform/platform-api/src/com/intellij/openapi/diff/DiffPanel.java +++ b/platform/platform-api/src/com/intellij/openapi/diff/DiffPanel.java @@ -15,13 +15,15 @@ */ package com.intellij.openapi.diff; -public interface DiffPanel extends DiffViewer { +import com.intellij.openapi.Disposable; +/** + * @author Konstantin Bulenkov + */ +public interface DiffPanel extends DiffViewer, Disposable { void setTitle1(String title); void setTitle2(String title); void setContents(DiffContent content1, DiffContent content2); - + void setRequestFocus(boolean requestFocus); boolean hasDifferences(); - - void dispose(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java index b456c62c6a5c..717b836374ea 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java @@ -386,7 +386,7 @@ public class DiffPanelImpl implements DiffPanelEx, ContentChangeListener, TwoSid } } - public void setIsRequestFocus(boolean isRequestFocus) { + public void setRequestFocus(boolean isRequestFocus) { myIsRequestFocus = isRequestFocus; } From 68881202249c2decc0b2ca831c7ddf719e776920 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Wed, 13 Apr 2011 20:35:13 +0400 Subject: [PATCH 057/102] default Editor and DiffPanel creation in DiffElement + file type recognizer --- .../com/intellij/ide/diff/DiffElement.java | 101 ++++++++++++++++-- .../ide/diff/VirtualFileDiffElement.java | 76 +------------ .../openapi/diff/impl/dir/DirDiffPanel.java | 19 ++-- 3 files changed, 101 insertions(+), 95 deletions(-) diff --git a/platform/platform-api/src/com/intellij/ide/diff/DiffElement.java b/platform/platform-api/src/com/intellij/ide/diff/DiffElement.java index 5c55cca18f73..f06fe968c3d1 100644 --- a/platform/platform-api/src/com/intellij/ide/diff/DiffElement.java +++ b/platform/platform-api/src/com/intellij/ide/diff/DiffElement.java @@ -15,8 +15,17 @@ */ package com.intellij.ide.diff; +import com.intellij.openapi.diff.*; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.EditorFactory; +import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -27,21 +36,24 @@ import java.io.IOException; * @author Konstantin Bulenkov */ public abstract class DiffElement { + private DiffPanel myDiffPanel; + private Editor myEditor; + public abstract String getPath(); + @NotNull public abstract String getName(); public abstract long getSize(); public abstract long getModificationStamp(); - public abstract FileType getFileType(); + public FileType getFileType() { + return FileTypeManager.getInstance().getFileTypeByFileName(getName()); + } public abstract boolean isContainer(); - @Nullable - public abstract DiffElement getParent(); - public abstract DiffElement[] getChildren(); @Nullable @@ -50,19 +62,90 @@ public abstract class DiffElement { /** * Returns content data as byte array. Can be null, if element for example is a container * @return content byte array + * @throws java.io.IOException when reading */ @Nullable public abstract byte[] getContent() throws IOException; - public abstract boolean canCompareWith(DiffElement element); + @Nullable + public JComponent getViewComponent(Project project) { + disposeViewComponent(); + try { + final T value = getValue(); + final byte[] content = getContent(); + final EditorFactory editorFactory = EditorFactory.getInstance(); + final Document document = value instanceof VirtualFile + ? FileDocumentManager.getInstance().getDocument((VirtualFile)value) + : editorFactory.createDocument(new String(content)); + if (document != null && getFileType() != null) { + myEditor = editorFactory.createEditor(document, project, getFileType(), true); + myEditor.getSettings().setFoldingOutlineShown(false); + return myEditor.getComponent(); + } + } + catch (IOException e) {// + } + return null; + } @Nullable - public abstract JComponent getViewComponent(Project project); + public JComponent getDiffComponent(DiffElement element, Project project, Window parentWindow) { + disposeDiffComponent(); + + final DiffRequest request = createRequest(project, element); + if (request != null) { + myDiffPanel = DiffManager.getInstance().createDiffPanel(parentWindow, project); + myDiffPanel.setRequestFocus(false); + myDiffPanel.setDiffRequest(request); + return myDiffPanel.getComponent(); + } + + return null; + } + @Nullable - public abstract JComponent getDiffComponent(DiffElement element, Project project, Window parentWindow); + protected DiffRequest createRequest(Project project, DiffElement element) { + final T src = getValue(); + if (src instanceof VirtualFile) { + final Object trg = element.getValue(); + if (trg instanceof VirtualFile) { + return SimpleDiffRequest.compareFiles((VirtualFile)src, (VirtualFile)trg, project); + } + } + final DiffContent srcContent = createDiffContent(); + final DiffContent trgContent = element.createDiffContent(); + + if (srcContent != null && trgContent != null) { + final SimpleDiffRequest request = new SimpleDiffRequest(project, ""); + request.setContents(srcContent, trgContent); + return request; + } + return null; + } + + @Nullable + protected DiffContent createDiffContent() { + try { + return new SimpleContent(new String(getContent()), getFileType()); + } + catch (IOException e) {// + } + return null; + } public abstract T getValue(); - public void disposeViewComponent() {} - public void disposeDiffComponent() {} + public void disposeViewComponent() { + if (myEditor != null) { + EditorFactory.getInstance().releaseEditor(myEditor); + myEditor = null; + } + } + + public void disposeDiffComponent() { + if (myDiffPanel != null) { + Disposer.dispose(myDiffPanel); + myDiffPanel = null; + } + } } diff --git a/platform/platform-impl/src/com/intellij/ide/diff/VirtualFileDiffElement.java b/platform/platform-impl/src/com/intellij/ide/diff/VirtualFileDiffElement.java index 433e4dc1e7c9..3b165023b1df 100644 --- a/platform/platform-impl/src/com/intellij/ide/diff/VirtualFileDiffElement.java +++ b/platform/platform-impl/src/com/intellij/ide/diff/VirtualFileDiffElement.java @@ -15,22 +15,9 @@ */ package com.intellij.ide.diff; -import com.intellij.openapi.diff.DiffManager; -import com.intellij.openapi.diff.DiffRequest; -import com.intellij.openapi.diff.SimpleDiffRequest; -import com.intellij.openapi.diff.impl.DiffPanelImpl; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.EditorFactory; -import com.intellij.openapi.fileEditor.FileDocumentManager; -import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Disposer; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; -import javax.swing.*; -import java.awt.*; import java.io.IOException; /** @@ -38,8 +25,6 @@ import java.io.IOException; */ public class VirtualFileDiffElement extends DiffElement { private final VirtualFile myFile; - private Editor myEditor; - private DiffPanelImpl myDiffPanel; public VirtualFileDiffElement(@NotNull VirtualFile file) { myFile = file; @@ -50,6 +35,7 @@ public class VirtualFileDiffElement extends DiffElement { return myFile.getPath(); } + @NotNull @Override public String getName() { return myFile.getName(); @@ -65,22 +51,10 @@ public class VirtualFileDiffElement extends DiffElement { return myFile.getModificationStamp(); } - @Override - public FileType getFileType() { - return myFile.getFileType(); - } - @Override public boolean isContainer() { return myFile.isDirectory(); } - - @Override - public DiffElement getParent() { - final VirtualFile parent = myFile.getParent(); - return parent == null ? null : new VirtualFileDiffElement(parent); - } - @Override public VirtualFileDiffElement[] getChildren() { final VirtualFile[] children = myFile.getChildren(); @@ -102,56 +76,8 @@ public class VirtualFileDiffElement extends DiffElement { return myFile.contentsToByteArray(); } - @Override - public boolean canCompareWith(DiffElement element) { - return element instanceof VirtualFileDiffElement; - } - - @Override - public JComponent getViewComponent(Project project) { - disposeViewComponent(); - final Document document = FileDocumentManager.getInstance().getDocument(myFile); - if (document != null) { - myEditor = EditorFactory.getInstance().createEditor(document, project, myFile, true); - myEditor.getSettings().setFoldingOutlineShown(false); - return myEditor.getComponent(); - } - return null; - } - - @Override - public JComponent getDiffComponent(DiffElement element, Project project, Window parentWindow) { - disposeDiffComponent(); - if (element instanceof VirtualFileDiffElement) { - final VirtualFileDiffElement diffElement = (VirtualFileDiffElement)element; - final DiffRequest request = SimpleDiffRequest.compareFiles(myFile, diffElement.getValue(), project); - myDiffPanel = (DiffPanelImpl)DiffManager.getInstance().createDiffPanel(parentWindow, project); - myDiffPanel.setIsRequestFocus(false); - myDiffPanel.setDiffRequest(request); - return myDiffPanel.getComponent(); - } - - return null; - } - @Override public VirtualFile getValue() { return myFile; } - - @Override - public void disposeViewComponent() { - if (myEditor != null) { - EditorFactory.getInstance().releaseEditor(myEditor); - myEditor = null; - } - } - - @Override - public void disposeDiffComponent() { - if (myDiffPanel != null) { - Disposer.dispose(myDiffPanel); - myDiffPanel = null; - } - } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffPanel.java b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffPanel.java index 527faa8a832e..3208d4a30ef3 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffPanel.java +++ b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffPanel.java @@ -37,7 +37,6 @@ import java.awt.event.KeyEvent; * @author Konstantin Bulenkov */ public class DirDiffPanel { - public static final JBLabel CANT_OPEN_LABEL = new JBLabel("Can't open file content", SwingConstants.CENTER); private JPanel myDiffPanel; private JBTable myTable; private JPanel myComponent; @@ -51,6 +50,7 @@ public class DirDiffPanel { private JComboBox myFileFilter; private JPanel myToolBarPanel; private final DirDiffTableModel myModel; + public JLabel myErrorLabel; private final DirDiffDialog myDialog; private JComponent myDiffPanelComponent; private JComponent myViewComponent; @@ -96,13 +96,10 @@ public class DirDiffPanel { if (myViewComponent != null) { myCurrentElement = object; myDiffPanel.add(myViewComponent, BorderLayout.CENTER); - } else { - myDiffPanel.add(CANT_OPEN_LABEL, BorderLayout.CENTER); - } - - if (myViewComponent != null) { myViewComponent.revalidate(); } else { + myDiffPanel.add(getErrorLabel(), BorderLayout.CENTER); + myDiffPanel.revalidate(); myDiffPanel.repaint(); } } @@ -142,6 +139,10 @@ public class DirDiffPanel { myToolBarPanel.add(toolbar.getComponent(), BorderLayout.CENTER); } + private JLabel getErrorLabel() { + return myErrorLabel == null ? myErrorLabel = new JLabel("Can't recognize file type", SwingConstants.CENTER) : myErrorLabel; + } + private void clearDiffPanel() { if (myDiffPanelComponent != null) { myDiffPanel.remove(myDiffPanelComponent); @@ -158,7 +159,7 @@ public class DirDiffPanel { } } myCurrentElement = null; - myDiffPanel.remove(CANT_OPEN_LABEL); + myDiffPanel.remove(getErrorLabel()); } private void createUIComponents() { @@ -172,10 +173,6 @@ public class DirDiffPanel { return myTable; } - public JSplitPane getSplitPanel() { - return mySplitPanel; - } - public void dispose() { clearDiffPanel(); } From b4e5f3d78febbad4e6da175b2bf0d8c8ada3c0c0 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 12 Apr 2011 15:54:49 +0200 Subject: [PATCH 058/102] correctly stop at the breakpoint in groovy classes not in source (IDEA-64023) --- .../debugger/GroovyPositionManager.java | 73 ++----------------- .../psi/impl/javaView/GroovyClassFinder.java | 4 +- .../lang/stubs/GroovyShortNamesCache.java | 26 +++++-- .../groovy/compiler/GroovyDebuggerTest.groovy | 71 ++++++++++++++++-- 4 files changed, 92 insertions(+), 82 deletions(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyPositionManager.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyPositionManager.java index f0b807067088..26d8d5037a93 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyPositionManager.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyPositionManager.java @@ -30,28 +30,20 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.ProjectFileIndex; -import com.intellij.openapi.roots.ProjectRootManager; -import com.intellij.openapi.roots.impl.DirectoryIndex; import com.intellij.openapi.util.Computable; -import com.intellij.openapi.util.Ref; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.*; -import com.intellij.psi.search.FilenameIndex; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.Function; -import com.intellij.util.Processor; -import com.intellij.util.Query; -import com.intellij.util.containers.HashSet; import com.sun.jdi.AbsentInformationException; import com.sun.jdi.Location; import com.sun.jdi.ReferenceType; import com.sun.jdi.request.ClassPrepareRequest; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.groovy.GroovyFileTypeLoader; import org.jetbrains.plugins.groovy.extensions.debugger.ScriptPositionManagerHelper; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase; @@ -63,7 +55,6 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Set; public class GroovyPositionManager implements PositionManager { private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.PositionManagerImpl"); @@ -250,8 +241,8 @@ public class GroovyPositionManager implements PositionManager { final GlobalSearchScope searchScope = myDebugProcess.getSearchScope(); try { - final PsiClass[] classes = GroovyPsiManager.getInstance(project).getNamesCache().getClassesByFQName(qName, searchScope); - PsiClass clazz = classes.length == 1 ? classes[0] : null; + final List classes = GroovyPsiManager.getInstance(project).getNamesCache().getClassesByFQName(qName, searchScope); + PsiClass clazz = classes.size() == 1 ? classes.get(0) : null; if (clazz != null) return clazz.getContainingFile(); } catch (ProcessCanceledException e) { @@ -261,51 +252,6 @@ public class GroovyPositionManager implements PositionManager { return null; } - DirectoryIndex directoryIndex = DirectoryIndex.getInstance(project); - int dotIndex = qName.lastIndexOf("."); - String packageName = dotIndex > 0 ? qName.substring(0, dotIndex) : ""; - Query query = directoryIndex.getDirectoriesByPackageName(packageName, true); - final String fileNameWithoutExtension = dotIndex > 0 ? qName.substring(dotIndex + 1) : qName; - final Set extensions = getAllGroovyFileExtensions(); - final Ref result = new Ref(); - query.forEach(new Processor() { - public boolean process(VirtualFile vDir) { - for (final String extension : extensions) { - VirtualFile vFile = vDir.findChild(fileNameWithoutExtension + "." + extension); - if (vFile != null) { - PsiFile psiFile = PsiManager.getInstance(project).findFile(vFile); - if (psiFile instanceof GroovyFileBase) { - result.set(psiFile); - return false; - } - } - } - return true; - } - }); - - PsiFile res = result.get(); - if (res != null) { - return res; - } - - if (StringUtil.isEmpty(packageName)) { - final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex(); - for (final String extension : extensions) { - for (final PsiFile file : FilenameIndex.getFilesByName(project, runtimeName + "." + extension, GlobalSearchScope.projectScope(project))) { - final VirtualFile vFile = file.getVirtualFile(); - if (file instanceof GroovyFile && vFile != null && !fileIndex.isInSource(vFile)) { - for (PsiClass aClass : ((GroovyFile)file).getClasses()) { - if (qName.equals(aClass.getQualifiedName())) { - return file; - } - } - } - } - } - } - - for (ScriptPositionManagerHelper helper : ScriptPositionManagerHelper.EP_NAME.getExtensions()) { if (helper.isAppropriateRuntimeName(runtimeName)) { PsiFile file = helper.getExtraScriptIfNotFound(refType, runtimeName, project); @@ -315,15 +261,6 @@ public class GroovyPositionManager implements PositionManager { return null; } - private static Set getAllGroovyFileExtensions() { - final Set extensions = new HashSet(); - extensions.addAll(GroovyFileTypeLoader.getAllGroovyExtensions()); - extensions.add("gvy"); - extensions.add("gy"); - extensions.add("gsh"); - return extensions; - } - @NotNull public List getAllClasses(final SourcePosition position) throws NoDataException { List result = ApplicationManager.getApplication().runReadAction(new Computable>() { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/javaView/GroovyClassFinder.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/javaView/GroovyClassFinder.java index 48903bcfa376..03c1e4b41869 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/javaView/GroovyClassFinder.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/javaView/GroovyClassFinder.java @@ -38,13 +38,13 @@ public class GroovyClassFinder extends PsiElementFinder { @Nullable public PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) { - final List classes = myGroovyPsiManager.getNamesCache().getScriptClassesByFQName(qualifiedName, scope); + final List classes = myGroovyPsiManager.getNamesCache().getScriptClassesByFQName(qualifiedName, scope, true); return classes.isEmpty() ? null : classes.get(0); } @NotNull public PsiClass[] findClasses(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) { - final Collection classes = myGroovyPsiManager.getNamesCache().getScriptClassesByFQName(qualifiedName, scope); + final Collection classes = myGroovyPsiManager.getNamesCache().getScriptClassesByFQName(qualifiedName, scope, true); return classes.isEmpty() ? PsiClass.EMPTY_ARRAY : classes.toArray(new PsiClass[classes.size()]); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/stubs/GroovyShortNamesCache.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/stubs/GroovyShortNamesCache.java index 789e8fe0f609..ddb8dca5117e 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/stubs/GroovyShortNamesCache.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/stubs/GroovyShortNamesCache.java @@ -57,8 +57,9 @@ public class GroovyShortNamesCache extends PsiShortNamesCache { return allClasses.toArray(new PsiClass[allClasses.size()]); } - public List getScriptClassesByFQName(final String name, final GlobalSearchScope scope) { - final Collection files = StubIndex.getInstance().get(GrFullScriptNameIndex.KEY, name.hashCode(), myProject, new GrSourceFilterScope(scope)); + public List getScriptClassesByFQName(final String name, final GlobalSearchScope scope, final boolean srcOnly) { + GlobalSearchScope actualScope = srcOnly ? new GrSourceFilterScope(scope) : scope; + final Collection files = StubIndex.getInstance().get(GrFullScriptNameIndex.KEY, name.hashCode(), myProject, actualScope); if (files.isEmpty()) { return Collections.emptyList(); } @@ -76,10 +77,22 @@ public class GroovyShortNamesCache extends PsiShortNamesCache { } @NotNull - public PsiClass[] getClassesByFQName(@NotNull @NonNls String name, @NotNull GlobalSearchScope scope) { - final Collection result = new ArrayList(getScriptClassesByFQName(name, scope)); + public List getClassesByFQName(@NotNull @NonNls String name, @NotNull GlobalSearchScope scope) { + final List result = addClasses(name, scope, true); + if (result.isEmpty()) { + result.addAll(addClasses(name, scope, false)); + } + if (result.isEmpty()) { + result.addAll(addClasses(name, GlobalSearchScope.projectScope(myProject), false)); + } + return result; + } - final Collection classes = StubIndex.getInstance().get(GrFullClassNameIndex.KEY, name.hashCode(), myProject, new GrSourceFilterScope(scope)); + private List addClasses(String name, GlobalSearchScope scope, boolean inSource) { + final List result = new ArrayList(getScriptClassesByFQName(name, scope, inSource)); + + final Collection classes = StubIndex + .getInstance().get(GrFullClassNameIndex.KEY, name.hashCode(), myProject, inSource ? new GrSourceFilterScope(scope) : scope); if (!classes.isEmpty()) { //hashcode doesn't guarantee equals for (PsiElement psiClass : classes) { @@ -88,8 +101,7 @@ public class GroovyShortNamesCache extends PsiShortNamesCache { } } } - - return result.isEmpty() ? PsiClass.EMPTY_ARRAY : result.toArray(new PsiClass[result.size()]); + return result; } private Collection getAllScriptClasses(String shortName, GlobalSearchScope scope) { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyDebuggerTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyDebuggerTest.groovy index 2d86c68d3bfd..ee610af0a2b4 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyDebuggerTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyDebuggerTest.groovy @@ -37,6 +37,13 @@ import com.intellij.util.concurrency.Semaphore import org.jetbrains.plugins.groovy.debugger.GroovyPositionManager import com.intellij.execution.runners.ProgramRunner import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.testFramework.fixtures.impl.TempDirTestFixtureImpl +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.Disposable +import com.intellij.openapi.roots.ModuleRootManager +import com.intellij.openapi.application.ApplicationManager +import com.intellij.debugger.engine.ContextUtil +import com.intellij.debugger.SourcePosition /** * @author peter @@ -136,9 +143,61 @@ println 2""") } } + public void testClassOutOfSourceRoots() { + def tempDir = new TempDirTestFixtureImpl() + edt { + tempDir.setUp() + disposeOnTearDown({ tempDir.tearDown() } as Disposable) + ApplicationManager.application.runWriteAction { + def model = ModuleRootManager.getInstance(myModule).modifiableModel + model.addContentEntry(tempDir.getFile('')) + model.commit() + } + } + + VirtualFile myClass = null + + def mcText = """ +package foo //1 + +class MyClass { //3 +static def foo(def a) { + println a //5 +} +} +""" + + + edt { + myClass = tempDir.createFile("MyClass.groovy", mcText) + } + + addBreakpoint(myClass, 5) + + myFixture.addFileToProject("Foo.groovy", """ +def cl = new GroovyClassLoader() +cl.parseClass('''$mcText''', 'MyClass.groovy').foo(2) + """) + make() + + runDebugger 'Foo', { + waitForBreakpoint() + SourcePosition position = managed { ContextUtil.getSourcePosition(evaluationContext()) } + assert myClass == position.file.virtualFile + eval 'a', '2' + } + } + private def addBreakpoint(String fileName, int line) { + VirtualFile file = null + edt { + file = myFixture.tempDirFixture.getFile(fileName) + } + addBreakpoint(file, line) + } + + private def addBreakpoint(VirtualFile file, int line) { edt { - def file = myFixture.tempDirFixture.getFile(fileName) DebuggerManagerImpl.getInstanceEx(project).breakpointManager.addLineBreakpoint(FileDocumentManager.instance.getDocument(file), line) } } @@ -180,7 +239,6 @@ println 2""") } private String eval(final String codeText, String expected) throws EvaluateException { - final SuspendContextImpl suspendContext = debugProcess.suspendManager.pausedContext Semaphore semaphore = new Semaphore() semaphore.down() @@ -189,15 +247,18 @@ println 2""") EvaluationContextImpl ctx def item = new WatchItemDescriptor(project, new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, codeText)) managed { - ctx = new EvaluationContextImpl(suspendContext, suspendContext.frameProxy, suspendContext.frameProxy.thisObject()) + ctx = evaluationContext() item.setContext(ctx) item.updateRepresentation(ctx, { semaphore.up() } as DescriptorLabelListener) } - semaphore.waitFor() + assert semaphore.waitFor(10000): "too long evaluation: $item.label" String result = managed { DebuggerUtils.getValueAsString(ctx, item.value) } assert result == expected } - + private EvaluationContextImpl evaluationContext() { + final SuspendContextImpl suspendContext = debugProcess.suspendManager.pausedContext + new EvaluationContextImpl(suspendContext, suspendContext.frameProxy, suspendContext.frameProxy.thisObject()) + } } From ab638476d17d88fffbcc8e7be0be7e89161c186b Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 12 Apr 2011 16:54:34 +0200 Subject: [PATCH 059/102] IDEA-67879 Groovy Inspection: false 'unused code' warning --- .../statements/branch/GrAssertStatement.java | 4 ++ .../controlFlow/impl/ControlFlowBuilder.java | 40 ++----------------- .../branch/GrAssertStatementImpl.java | 6 +++ .../groovy/lang/GroovyHighlightingTest.java | 4 +- .../highlighting/UsageInInjection.groovy | 5 +++ 5 files changed, 22 insertions(+), 37 deletions(-) create mode 100644 plugins/groovy/testdata/highlighting/UsageInInjection.groovy diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/branch/GrAssertStatement.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/branch/GrAssertStatement.java index 8aa2dd5edc83..852940aa35ff 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/branch/GrAssertStatement.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/branch/GrAssertStatement.java @@ -16,6 +16,7 @@ package org.jetbrains.plugins.groovy.lang.psi.api.statements.branch; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; @@ -24,4 +25,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpres */ public interface GrAssertStatement extends GrStatement { GrExpression getAssertion(); + + @Nullable + GrExpression getErrorMessage(); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java index baa859d3371a..0d8005882c0e 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java @@ -252,6 +252,10 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { if (assertion != null) { assertion.accept(this); final InstructionImpl assertInstruction = startNode(assertStatement); + GrExpression errorMessage = assertStatement.getErrorMessage(); + if (errorMessage != null) { + errorMessage.accept(this); + } final PsiType type = TypesUtil.createTypeByFQClassName("java.lang.AssertionError", assertStatement); ExceptionInfo info = findCatch(type); if (info != null) { @@ -419,41 +423,6 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { if (elseEnd != null) addEdge(elseEnd, end); } finishNode(ifInstruction); - - - - /*InstructionImpl ifInstruction = startNode(ifStatement); - final GrCondition condition = ifStatement.getCondition(); - - final InstructionImpl head = myHead; - final GrStatement thenBranch = ifStatement.getThenBranch(); - if (thenBranch != null) { - if (condition != null) { - condition.accept(this); - } - thenBranch.accept(this); - handlePossibleReturn(thenBranch); - addPendingEdge(ifStatement, myHead); - } - - myHead = head; - if (condition != null) { - myNegate = !myNegate; - final boolean old = myAssertionsOnly; - myAssertionsOnly = true; - condition.accept(this); - myNegate = !myNegate; - myAssertionsOnly = old; - } - - final GrStatement elseBranch = ifStatement.getElseBranch(); - if (elseBranch != null) { - elseBranch.accept(this); - handlePossibleReturn(elseBranch); - addPendingEdge(ifStatement, myHead); - } - - finishNode(ifInstruction);*/ } public void visitForStatement(GrForStatement forStatement) { @@ -706,7 +675,6 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { private void finishNode(InstructionImpl instruction) { assert instruction.equals(myProcessingStack.pop()); -/* myHead = myProcessingStack.peek();*/ } public void visitField(GrField field) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/branch/GrAssertStatementImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/branch/GrAssertStatementImpl.java index 7656938c9c4f..7f86a473f3f7 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/branch/GrAssertStatementImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/branch/GrAssertStatementImpl.java @@ -42,4 +42,10 @@ public class GrAssertStatementImpl extends GroovyPsiElementImpl implements GrAss public GrExpression getAssertion() { return findChildByClass(GrExpression.class); } + + @Override + public GrExpression getErrorMessage() { + GrExpression[] exprs = findChildrenByClass(GrExpression.class); + return exprs.length >= 2 ? exprs[1] : null; + } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java index 1fe08ab782b3..e2a9829b3395 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java @@ -306,7 +306,7 @@ public class GroovyHighlightingTest extends LightCodeInsightFixtureTestCase { public void testMapParamWithNoArgs() {doTest(new GroovyAssignabilityCheckInspection());} public void testGroovyEnumInJavaFile() { - myFixture.copyFileToProject(getTestName(false)+".groovy"); + myFixture.copyFileToProject(getTestName(false) + ".groovy"); myFixture.testHighlighting(true, false, false, getTestName(false) + ".java"); } @@ -359,6 +359,8 @@ public class GroovyHighlightingTest extends LightCodeInsightFixtureTestCase { doTest(new GroovyUnresolvedAccessInspection(), new GroovyUntypedAccessInspection()); } + public void testUsageInInjection() { doTest(new UnusedDefInspection()); } + public void testDuplicatedNamedArgs() {doTest();} public void testAnonymousClassArgList() { diff --git a/plugins/groovy/testdata/highlighting/UsageInInjection.groovy b/plugins/groovy/testdata/highlighting/UsageInInjection.groovy new file mode 100644 index 000000000000..2d222f6d5511 --- /dev/null +++ b/plugins/groovy/testdata/highlighting/UsageInInjection.groovy @@ -0,0 +1,5 @@ +def x = new Date() +def y = new Date() +def z = new Date() +assert false : "should have thrown exception, but returned $x" +assert false : "should have thrown exception, but returned ${y}" \ No newline at end of file From e83810e3580e3f473ef7a27570ffa3cacff65ebd Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 12 Apr 2011 20:29:08 +0200 Subject: [PATCH 060/102] IDEA-67939 Smart completion completes private field from parent class inside a static inner inheritor --- .../completion/scope/JavaCompletionProcessor.java | 7 ++++++- .../completion/smartType/NonStaticField.java | 15 +++++++++++++++ .../completion/SmartTypeCompletionTest.java | 2 ++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 java/java-tests/testData/codeInsight/completion/smartType/NonStaticField.java diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java b/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java index 16f10641c9db..2ed592b88479 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java @@ -48,6 +48,7 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme public static final Key JAVA_COMPLETION = Key.create("JAVA_COMPLETION"); private boolean myStatic = false; + private PsiElement myDeclarationHolder = null; private final Set myResultNames = new THashSet(); private final List myResults; private final PsiElement myElement; @@ -182,6 +183,9 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme if(event == JavaScopeProcessorEvent.CHANGE_LEVEL){ myMembersFlag = true; } + if (event == JavaScopeProcessorEvent.SET_CURRENT_FILE_CONTEXT) { + myDeclarationHolder = (PsiElement)associated; + } } public boolean execute(PsiElement element, ResolveState state) { @@ -242,7 +246,8 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme if (!myCheckAccess) return true; if (!(element instanceof PsiMember)) return true; - return JavaPsiFacade.getInstance(element.getProject()).getResolveHelper().isAccessible((PsiMember)element, myElement, myQualifierClass); + PsiMember member = (PsiMember)element; + return JavaPsiFacade.getInstance(element.getProject()).getResolveHelper().isAccessible(member, member.getModifierList(), myElement, myQualifierClass, myDeclarationHolder); } public void setCompletionElements(@NotNull Object[] elements) { diff --git a/java/java-tests/testData/codeInsight/completion/smartType/NonStaticField.java b/java/java-tests/testData/codeInsight/completion/smartType/NonStaticField.java new file mode 100644 index 000000000000..cfa4af045478 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/NonStaticField.java @@ -0,0 +1,15 @@ +public class SmartCompletionTest { + interface SmartCompletionType {} + + private SmartCompletionType myNonStaticField; + + private static void staticMethod(SmartCompletionType type) {} + + private static class StaticInnerClass extends SmartCompletionTest { + + private void method() { + staticMethod(myNon); + } + + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java index d58532489034..9e77c2091a63 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java @@ -1029,6 +1029,8 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase { doFirstItemTest('\t'); } + public void testNonStaticField() throws Exception { doAntiTest(); } + private void doActionTest() throws Exception { configureByTestName(); checkResultByTestName(); From 4628479ee0e77b50d09ea82ddc314863135f65c9 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 13 Apr 2011 12:49:21 +0200 Subject: [PATCH 061/102] more sensible java class reference separator names --- .../impl/providers/JavaClassReferenceSet.java | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/JavaClassReferenceSet.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/JavaClassReferenceSet.java index 18063e636247..853b381b4b54 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/JavaClassReferenceSet.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/JavaClassReferenceSet.java @@ -32,10 +32,10 @@ import java.util.Map; * @author peter */ public class JavaClassReferenceSet { - public static final char SEPARATOR = '.'; - public static final char SEPARATOR2 = '$'; - private static final char SEPARATOR3 = '<'; - private static final char SEPARATOR4 = ','; + public static final char DOT = '.'; + public static final char DOLLAR = '$'; + private static final char LT = '<'; + private static final char COMMA = ','; private JavaClassReference[] myReferences; private List myNestedGenericParameterReferences; @@ -75,14 +75,12 @@ public class JavaClassReferenceSet { for(int curIndex = currentDot + 1; curIndex < str.length(); ++curIndex) { final char ch = str.charAt(curIndex); - if (ch == SEPARATOR || - (ch == SEPARATOR2 && allowDollarInNames) - ) { + if (ch == DOT || ch == DOLLAR && allowDollarInNames) { nextDotOrDollar = curIndex; break; } - if (((ch == SEPARATOR3 || ch == SEPARATOR4))) { + if (ch == LT || ch == COMMA) { if (!allowGenericsCalculated) { allowGenerics = !isStaticImport && PsiUtil.getLanguageLevel(element).hasEnumKeywordAndAutoboxing(); allowGenericsCalculated = true; @@ -131,7 +129,7 @@ public class JavaClassReferenceSet { if (nextDotOrDollar != -1 && nextDotOrDollar < str.length()) { final char c = str.charAt(nextDotOrDollar); - if (c == SEPARATOR3) { + if (c == LT) { int end = str.lastIndexOf('>'); if (end != -1 && end > nextDotOrDollar) { if (myNestedGenericParameterReferences == null) myNestedGenericParameterReferences = new ArrayList(1); @@ -149,7 +147,7 @@ public class JavaClassReferenceSet { } else { nextDotOrDollar = -1; // nonsensible characters anyway, don't do resolve } - } else if (SEPARATOR4 == c && myContext != null) { + } else if (COMMA == c && myContext != null) { if (myContext.myNestedGenericParameterReferences == null) myContext.myNestedGenericParameterReferences = new ArrayList(1); myContext.myNestedGenericParameterReferences.add( new JavaClassReferenceSet( @@ -194,7 +192,7 @@ public class JavaClassReferenceSet { } protected boolean isStaticSeparator(char c, boolean strict) { - return isAllowDollarInNames() ? c == SEPARATOR2 : c == SEPARATOR; + return isAllowDollarInNames() ? c == DOLLAR : c == DOT; } public void reparse(PsiElement element, final TextRange range) { From 7cf41dd6682399fc4ff52c2a9e7c7b687163568c Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 13 Apr 2011 15:54:07 +0200 Subject: [PATCH 062/102] IDEA-67448 Exception for class name completion in Spring xml --- .../codeInsight/completion/AllClassesGetter.java | 1 + .../impl/providers/JavaClassReference.java | 13 +++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java b/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java index 4d8668a09268..8f921827737f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java @@ -85,6 +85,7 @@ public class AllClassesGetter { } else if (psiClass.isValid()) { try { + context.setTailOffset(psiReference.getRangeInElement().getEndOffset() + psiReference.getElement().getTextRange().getStartOffset()); final PsiElement newUnderlying = psiReference.bindToElement(psiClass); if (newUnderlying != null) { final PsiElement psiElement = CodeInsightUtilBase.forcePsiPostprocessAndRestoreElement(newUnderlying); diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/JavaClassReference.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/JavaClassReference.java index c2e63e57f957..b0f896fccced 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/JavaClassReference.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/JavaClassReference.java @@ -52,6 +52,7 @@ import com.intellij.psi.util.PsiUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.text.CharArrayUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -194,13 +195,17 @@ public class JavaClassReference extends GenericReference implements PsiJavaRefer } assert newName != null; - TextRange range = - new TextRange(myJavaClassReferenceSet.getReference(0).getRangeInElement().getStartOffset(), getRangeInElement().getEndOffset()); + int end = getRangeInElement().getEndOffset(); + String text = getElement().getText(); + int lt = text.indexOf('<', getRangeInElement().getStartOffset()); + if (lt >= 0) { + end = CharArrayUtil.shiftBackward(text, lt - 1, "\n\t ") + 1; + } + TextRange range = new TextRange(myJavaClassReferenceSet.getReference(0).getRangeInElement().getStartOffset(), end); final ElementManipulator manipulator = getManipulator(getElement()); if (manipulator != null) { final PsiElement finalElement = manipulator.handleContentChange(getElement(), range, newName); - range = new TextRange(range.getStartOffset(), range.getStartOffset() + newName.length()); - myJavaClassReferenceSet.reparse(finalElement, range); + myJavaClassReferenceSet.reparse(finalElement, TextRange.from(range.getStartOffset(), newName.length())); return finalElement; } return element; From e77c088663d1193c7344d8afc818806493892940 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 13 Apr 2011 18:23:32 +0200 Subject: [PATCH 063/102] fix NormalCompletionTest --- .../intellij/codeInsight/completion/AllClassesGetter.java | 2 +- .../intellij/codeInsight/completion/JavaCompletionUtil.java | 6 +++--- .../groovy/lang/completion/GroovyCompletionUtil.java | 4 +--- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java b/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java index 8f921827737f..3aaaf5f32741 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java @@ -73,7 +73,7 @@ public class AllClassesGetter { LOG.error(endOffset + " became invalid: " + context.getOffsetMap() + "; inserting " + qname); } - final RangeMarker toDelete = JavaCompletionUtil.insertSpace(endOffset, document); + final RangeMarker toDelete = JavaCompletionUtil.insertTemporary(endOffset, document, " "); psiDocumentManager.commitAllDocuments(); PsiReference psiReference = file.findReferenceAt(endOffset - 1); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java index da527247e91f..88742a06b232 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java @@ -763,7 +763,7 @@ public class JavaCompletionUtil { String name = psiClass.getName(); document.replaceString(startOffset, endOffset, name); - final RangeMarker toDelete = insertSpace(startOffset + name.length(), document); + final RangeMarker toDelete = insertTemporary(startOffset + name.length(), document, ";"); PsiDocumentManager.getInstance(project).commitAllDocuments(); @@ -812,12 +812,12 @@ public class JavaCompletionUtil { return psiReference.resolve(); } - public static RangeMarker insertSpace(final int endOffset, final Document document) { + public static RangeMarker insertTemporary(final int endOffset, final Document document, final String temporary) { final CharSequence chars = document.getCharsSequence(); final int length = chars.length(); final RangeMarker toDelete; if (endOffset < length && Character.isJavaIdentifierPart(chars.charAt(endOffset))){ - document.insertString(endOffset, " "); + document.insertString(endOffset, temporary); toDelete = document.createRangeMarker(endOffset, endOffset + 1); } else if (endOffset >= length) { toDelete = document.createRangeMarker(length, length); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java index 46a6354b26f5..4f6dfbc1aa76 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java @@ -48,8 +48,6 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.GroovyFileType; import org.jetbrains.plugins.groovy.GroovyIcons; -import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; -import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; @@ -425,7 +423,7 @@ public class GroovyCompletionUtil { String name = aClass.getName(); document.replaceString(startOffset, endOffset, name); - final RangeMarker toDelete = JavaCompletionUtil.insertSpace(endOffset, document); + final RangeMarker toDelete = JavaCompletionUtil.insertTemporary(endOffset, document, " "); PsiDocumentManager.getInstance(manager.getProject()).commitAllDocuments(); From cc8eb23f33a41397372be23e338063b788ada144 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 13 Apr 2011 18:29:58 +0200 Subject: [PATCH 064/102] don't choose template items by space if normally they're not configured to do so --- .../completion/JavaAutoPopupTest.groovy | 17 ++++++++++++++++- .../template/impl/LiveTemplateCharFilter.java | 7 ++++++- .../impl/LiveTemplateCompletionContributor.java | 4 ++-- .../impl/LiveTemplateLookupElement.java | 8 ++++++-- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy index 0fb5bb923416..fee8a61ac4c1 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy @@ -631,7 +631,7 @@ public interface Test { assert !lookup } - public void testTemplateSelection() { + public void testTemplateSelectionByComma() { myFixture.configureByText("a.java", """ class Foo { int ITER = 2; @@ -651,4 +651,19 @@ class Foo { assert myFixture.editor.document.text.contains('iter,') } + public void testTemplateSelectionBySpace() { + myFixture.configureByText("a.java", """ +class Foo { + int ITER = 2; + int itea = 2; + + { + it + } +} +""") + type 'er ' + assert myFixture.editor.document.text.contains('iter ') + } + } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateCharFilter.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateCharFilter.java index a34084de0e0f..12c18d53385d 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateCharFilter.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateCharFilter.java @@ -17,6 +17,7 @@ package com.intellij.codeInsight.template.impl; import com.intellij.codeInsight.lookup.CharFilter; import com.intellij.codeInsight.lookup.Lookup; +import com.intellij.codeInsight.lookup.LookupElement; /** * @author peter @@ -24,7 +25,11 @@ import com.intellij.codeInsight.lookup.Lookup; public class LiveTemplateCharFilter extends CharFilter { @Override public Result acceptChar(char c, int prefixLength, Lookup lookup) { - if (lookup.getCurrentItem() instanceof LiveTemplateLookupElement && c != ' ') { + LookupElement item = lookup.getCurrentItem(); + if (item instanceof LiveTemplateLookupElement) { + if (c == ((LiveTemplateLookupElement)item).getTemplate().getShortcutChar()) { + return Result.SELECT_ITEM_AND_FINISH_LOOKUP; + } return Result.HIDE_LOOKUP; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateCompletionContributor.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateCompletionContributor.java index 8638cd9a7ad5..d3a29aa09c16 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateCompletionContributor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateCompletionContributor.java @@ -45,7 +45,7 @@ public class LiveTemplateCompletionContributor extends CompletionContributor { final int offset = parameters.getOffset(); if (Registry.is("show.live.templates.in.completion")) { for (final TemplateImpl possible : listApplicableTemplates(file, offset)) { - result.addElement(new LiveTemplateLookupElement(possible.getKey(), possible)); + result.addElement(new LiveTemplateLookupElement(possible)); } return; } @@ -53,7 +53,7 @@ public class LiveTemplateCompletionContributor extends CompletionContributor { final String prefix = result.getPrefixMatcher().getPrefix(); final TemplateImpl template = findApplicableTemplate(file, offset, prefix); if (template != null) { - result.addElement(new LiveTemplateLookupElement(prefix, template)); + result.addElement(new LiveTemplateLookupElement(template)); } else { for (final TemplateImpl possible : listApplicableTemplates(file, offset)) { result.restartCompletionOnPrefixChange(possible.getKey()); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateLookupElement.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateLookupElement.java index 9257262c328c..2a53b3e03c8a 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateLookupElement.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateLookupElement.java @@ -28,8 +28,8 @@ public class LiveTemplateLookupElement extends LookupElement { private final String myPrefix; private final TemplateImpl myTemplate; - public LiveTemplateLookupElement(String prefix, TemplateImpl template) { - myPrefix = prefix; + public LiveTemplateLookupElement(TemplateImpl template) { + myPrefix = template.getKey(); myTemplate = template; } @NotNull @@ -38,6 +38,10 @@ public class LiveTemplateLookupElement extends LookupElement { return myPrefix; } + public TemplateImpl getTemplate() { + return myTemplate; + } + @Override public void renderElement(LookupElementPresentation presentation) { super.renderElement(presentation); From 0acf0df76e19c89972f17fa3f9c955d5aa40790d Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 13 Apr 2011 18:48:08 +0200 Subject: [PATCH 065/102] don't classes by ( not after new, don't insert space when completing an already typed variable name by comma --- .../completion/JavaCharFilter.java | 23 +++++++++++++++--- .../completion/JavaAutoPopupTest.groovy | 24 +++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCharFilter.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCharFilter.java index 769476ab91d4..c978caec7131 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCharFilter.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCharFilter.java @@ -27,6 +27,8 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.lookup.CharFilter; import com.intellij.codeInsight.lookup.Lookup; import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.impl.LookupImpl; +import com.intellij.patterns.PsiJavaPatterns; import com.intellij.psi.*; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.util.PsiTreeUtil; @@ -48,8 +50,8 @@ public class JavaCharFilter extends CharFilter { LookupElement item = lookup.getCurrentItem(); if (item == null) return null; + final Object o = item.getObject(); if (c == '!') { - final Object o = item.getObject(); if (o instanceof PsiVariable) { if (PsiType.BOOLEAN.isAssignableFrom(((PsiVariable)o).getType())) return Result.SELECT_ITEM_AND_FINISH_LOOKUP; } @@ -62,10 +64,25 @@ public class JavaCharFilter extends CharFilter { } if (c == '.' && isWithinLiteral(lookup)) return Result.ADD_TO_PREFIX; if (c == '[') return CharFilter.Result.SELECT_ITEM_AND_FINISH_LOOKUP; - if (c == '<' && item.getObject() instanceof PsiClass) return Result.SELECT_ITEM_AND_FINISH_LOOKUP; + if (c == '<' && o instanceof PsiClass) return Result.SELECT_ITEM_AND_FINISH_LOOKUP; + if (c == '(' && o instanceof PsiClass) { + if (PsiJavaPatterns.psiElement().afterLeaf(PsiKeyword.NEW).accepts(lookup.getPsiElement())) { + return Result.SELECT_ITEM_AND_FINISH_LOOKUP; + } + return Result.HIDE_LOOKUP; + } + if (c == ',' && o instanceof PsiVariable) { + int lookupStart = ((LookupImpl)lookup).getLookupStart(); + String name = ((PsiVariable)o).getName(); + if (lookupStart >= 0 && + name != null && + name.equals(item.getPrefixMatcher().getPrefix() + ((LookupImpl)lookup).getAdditionalPrefix())) { + return Result.HIDE_LOOKUP; + } + } if (c == '#' && PsiTreeUtil.getParentOfType(lookup.getPsiElement(), PsiDocComment.class) != null) { - if (item.getObject() instanceof PsiClass) { + if (o instanceof PsiClass) { return Result.SELECT_ITEM_AND_FINISH_LOOKUP; } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy index fee8a61ac4c1..22d144e12c6e 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy @@ -666,4 +666,28 @@ class Foo { assert myFixture.editor.document.text.contains('iter ') } + public void testNewClassParenthesis() { + myFixture.configureByText("a.java", """ class Foo { { new } } """) + type 'fil(' + assert myFixture.editor.document.text.contains('new File()') + } + + public void testUnknownMethodParenthesis() { + myFixture.configureByText("a.java", """ class Foo { { } } """) + type 'filinpstr(' + assert myFixture.editor.document.text.contains('filinpstr()') + } + + public void testNonFinishedParameterComma() { + myFixture.configureByText("a.java", """ class Foo { void foo(int aaa, int aaaaa) { foo() } } """) + type 'a,' + assert myFixture.editor.document.text.contains('foo(aaa, )') + } + + public void testFinishedParameterComma() { + myFixture.configureByText("a.java", """ class Foo { void foo(int aaa, int aaaaa) { foo() } } """) + type 'aaa,' + assert myFixture.editor.document.text.contains('foo(aaa,)') + } + } From 568c7e813aa17679248b144883cf6faf961cecda Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 13 Apr 2011 19:22:26 +0200 Subject: [PATCH 066/102] method signature validity assertions for EA-26920 --- .../src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java b/java/java-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java index 170a40d624c2..e58f3efc5946 100644 --- a/java/java-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java +++ b/java/java-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java @@ -207,11 +207,14 @@ public class PsiSuperMethodImplUtil { if (!PsiUtil.isAccessible(hierarchicalMethodSignature.getMethod(), aClass, aClass)) return; HierarchicalMethodSignatureImpl existing = map.get(signature); if (existing == null) { - map.put(signature, copy(hierarchicalMethodSignature)); + HierarchicalMethodSignatureImpl copy = copy(hierarchicalMethodSignature); + LOG.assertTrue(copy.getMethod().isValid()); + map.put(signature, copy); } else if (isReturnTypeIsMoreSpecificThan(hierarchicalMethodSignature, existing) && isSuperMethod(aClass, hierarchicalMethodSignature, existing)) { HierarchicalMethodSignatureImpl newSuper = copy(hierarchicalMethodSignature); mergeSupers(newSuper, existing); + LOG.assertTrue(newSuper.getMethod().isValid()); map.put(signature, newSuper); } else if (isSuperMethod(aClass, existing, hierarchicalMethodSignature)) { From acd87cb4c55786daebf695b8cd7a821f205c8873 Mon Sep 17 00:00:00 2001 From: Anton Makeev Date: Wed, 13 Apr 2011 19:47:58 +0200 Subject: [PATCH 067/102] SMTestRunner: invokeLaterIfNeeded in tests --- .../intellij/execution/testframework/sm/SMRunnerUtil.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/SMRunnerUtil.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/SMRunnerUtil.java index 1d04ae666beb..acd9b7ca5e3a 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/SMRunnerUtil.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/SMRunnerUtil.java @@ -19,6 +19,7 @@ import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.util.ui.UIUtil; import javax.swing.*; import java.awt.event.ActionEvent; @@ -39,11 +40,10 @@ public class SMRunnerUtil { */ public static void addToInvokeLater(final Runnable runnable) { final Application application = ApplicationManager.getApplication(); - if (application.isHeadlessEnvironment() || application.isUnitTestMode() - || SwingUtilities.isEventDispatchThread()) { + if (application.isHeadlessEnvironment() && !application.isUnitTestMode()) { runnable.run(); } else { - SwingUtilities.invokeLater(runnable); + UIUtil.invokeLaterIfNeeded(runnable); } } From 375dd2ae87021fc28e85d47fdccc94a0db7e6a03 Mon Sep 17 00:00:00 2001 From: Maxim Shafirov Date: Wed, 13 Apr 2011 21:56:37 +0400 Subject: [PATCH 068/102] IDEA-67777: Open files by dragging them onto icon in the dock. --- build/conf/mac/Contents/Info.plist | 21 ++++++++++++++++++- .../PlatformProjectOpenProcessor.java | 2 +- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/build/conf/mac/Contents/Info.plist b/build/conf/mac/Contents/Info.plist index ff4e84643833..e8d847f0cb03 100644 --- a/build/conf/mac/Contents/Info.plist +++ b/build/conf/mac/Contents/Info.plist @@ -4,7 +4,26 @@ CFBundleDevelopmentRegion English - @@doc_types@@ + CFBundleDocumentTypes + + @@doc_types@@ + + CFBundleTypeExtensions + + * + + CFBundleTypeName + All documents + CFBundleTypeOSTypes + + **** + + CFBundleTypeRole + Editor + LSTypeIsPackage + + + CFBundleExecutable @@executable@@ CFBundleIconFile diff --git a/platform/platform-impl/src/com/intellij/platform/PlatformProjectOpenProcessor.java b/platform/platform-impl/src/com/intellij/platform/PlatformProjectOpenProcessor.java index 701921fdcd72..a3e40233cf08 100644 --- a/platform/platform-impl/src/com/intellij/platform/PlatformProjectOpenProcessor.java +++ b/platform/platform-impl/src/com/intellij/platform/PlatformProjectOpenProcessor.java @@ -58,7 +58,7 @@ public class PlatformProjectOpenProcessor extends ProjectOpenProcessor { } public boolean canOpenProject(final VirtualFile file) { - return file.isDirectory() || ! file.getFileType().isBinary(); + return file.isDirectory(); } @Override From 7f1400d62f91f7984e2049e0e91ad33402b572d7 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Wed, 13 Apr 2011 21:59:23 +0400 Subject: [PATCH 069/102] IDEA-65775 support for state lists in dom model --- plugins/android/src/META-INF/plugin.xml | 3 + .../android/dom/AndroidDomExtender.java | 45 ++++++++++++++- .../dom/attrs/AttributeDefinitions.java | 11 ++++ .../android/dom/color/ColorDomElement.java | 24 ++++++++ .../dom/color/ColorDomFileDescription.java | 43 ++++++++++++++ .../android/dom/color/ColorSelector.java | 28 +++++++++ .../android/dom/color/ColorStateListItem.java | 33 +++++++++++ .../dom/drawable/DrawableDomElement.java | 4 +- .../drawable/DrawableDomFileDescription.java | 39 ++++++++++++- .../dom/drawable/DrawableSelector.java | 28 +++++++++ .../DrawableStateListDomFileDescription.java | 55 ++++++++++++++++++ .../dom/drawable/DrawableStateListItem.java | 33 +++++++++++ .../dom/drawable/UnknownDrawableElement.java | 26 +++++++++ plugins/android/testData/dom/color/colors.xml | 3 + .../2.xml => color/stateListCompletion1.xml} | 3 +- .../dom/color/stateListCompletion1_after.xml | 5 ++ .../dom/color/stateListCompletion2.xml | 5 ++ .../dom/color/stateListCompletion2_after.xml | 5 ++ .../dom/color/stateListCompletion3.xml | 5 ++ .../dom/color/stateListCompletion3_after.xml | 5 ++ .../dom/color/stateListCompletion4.xml | 5 ++ .../dom/color/stateListCompletion4_after.xml | 5 ++ .../dom/color/stateListCompletion5.xml | 3 + .../dom/color/stateListCompletion5_after.xml | 3 + .../dom/color/stateListHighlighting.xml | 9 +++ .../testData/dom/drawable/myDrawable.png | 0 .../dom/drawable/stateListCompletion1.xml | 5 ++ .../drawable/stateListCompletion1_after.xml | 5 ++ .../dom/drawable/stateListCompletion2.xml | 5 ++ .../drawable/stateListCompletion2_after.xml | 5 ++ .../dom/drawable/stateListCompletion3.xml | 5 ++ .../drawable/stateListCompletion3_after.xml | 5 ++ .../dom/drawable/stateListCompletion4.xml | 5 ++ .../drawable/stateListCompletion4_after.xml | 5 ++ .../dom/drawable/stateListCompletion5.xml | 3 + .../drawable/stateListCompletion5_after.xml | 3 + .../dom/drawable/stateListHighlighting.xml | 9 +++ plugins/android/testData/dom/other/1.xml | 8 ++- .../dom/AndroidColorStateListDomTest.java | 57 +++++++++++++++++++ .../jetbrains/android/dom/AndroidDomTest.java | 8 +++ .../dom/AndroidDrawableResourcesDomTest.java | 56 ++++++++++++++++++ .../dom/AndroidDrawableResourcesTest.java | 10 +--- .../android/dom/AndroidManifestDomTest.java | 4 -- 43 files changed, 602 insertions(+), 24 deletions(-) create mode 100644 plugins/android/src/org/jetbrains/android/dom/color/ColorDomElement.java create mode 100644 plugins/android/src/org/jetbrains/android/dom/color/ColorDomFileDescription.java create mode 100644 plugins/android/src/org/jetbrains/android/dom/color/ColorSelector.java create mode 100644 plugins/android/src/org/jetbrains/android/dom/color/ColorStateListItem.java create mode 100644 plugins/android/src/org/jetbrains/android/dom/drawable/DrawableSelector.java create mode 100644 plugins/android/src/org/jetbrains/android/dom/drawable/DrawableStateListDomFileDescription.java create mode 100644 plugins/android/src/org/jetbrains/android/dom/drawable/DrawableStateListItem.java create mode 100644 plugins/android/src/org/jetbrains/android/dom/drawable/UnknownDrawableElement.java create mode 100644 plugins/android/testData/dom/color/colors.xml rename plugins/android/testData/dom/{other/2.xml => color/stateListCompletion1.xml} (69%) create mode 100644 plugins/android/testData/dom/color/stateListCompletion1_after.xml create mode 100644 plugins/android/testData/dom/color/stateListCompletion2.xml create mode 100644 plugins/android/testData/dom/color/stateListCompletion2_after.xml create mode 100644 plugins/android/testData/dom/color/stateListCompletion3.xml create mode 100644 plugins/android/testData/dom/color/stateListCompletion3_after.xml create mode 100644 plugins/android/testData/dom/color/stateListCompletion4.xml create mode 100644 plugins/android/testData/dom/color/stateListCompletion4_after.xml create mode 100644 plugins/android/testData/dom/color/stateListCompletion5.xml create mode 100644 plugins/android/testData/dom/color/stateListCompletion5_after.xml create mode 100644 plugins/android/testData/dom/color/stateListHighlighting.xml create mode 100644 plugins/android/testData/dom/drawable/myDrawable.png create mode 100644 plugins/android/testData/dom/drawable/stateListCompletion1.xml create mode 100644 plugins/android/testData/dom/drawable/stateListCompletion1_after.xml create mode 100644 plugins/android/testData/dom/drawable/stateListCompletion2.xml create mode 100644 plugins/android/testData/dom/drawable/stateListCompletion2_after.xml create mode 100644 plugins/android/testData/dom/drawable/stateListCompletion3.xml create mode 100644 plugins/android/testData/dom/drawable/stateListCompletion3_after.xml create mode 100644 plugins/android/testData/dom/drawable/stateListCompletion4.xml create mode 100644 plugins/android/testData/dom/drawable/stateListCompletion4_after.xml create mode 100644 plugins/android/testData/dom/drawable/stateListCompletion5.xml create mode 100644 plugins/android/testData/dom/drawable/stateListCompletion5_after.xml create mode 100644 plugins/android/testData/dom/drawable/stateListHighlighting.xml create mode 100644 plugins/android/testSrc/org/jetbrains/android/dom/AndroidColorStateListDomTest.java create mode 100644 plugins/android/testSrc/org/jetbrains/android/dom/AndroidDrawableResourcesDomTest.java diff --git a/plugins/android/src/META-INF/plugin.xml b/plugins/android/src/META-INF/plugin.xml index e5c55c12af0b..7076f17b9a47 100644 --- a/plugins/android/src/META-INF/plugin.xml +++ b/plugins/android/src/META-INF/plugin.xml @@ -59,6 +59,9 @@ + + + diff --git a/plugins/android/src/org/jetbrains/android/dom/AndroidDomExtender.java b/plugins/android/src/org/jetbrains/android/dom/AndroidDomExtender.java index b20daac5e010..760910b48d64 100644 --- a/plugins/android/src/org/jetbrains/android/dom/AndroidDomExtender.java +++ b/plugins/android/src/org/jetbrains/android/dom/AndroidDomExtender.java @@ -36,8 +36,11 @@ import org.jetbrains.android.dom.attrs.AttributeDefinition; import org.jetbrains.android.dom.attrs.AttributeDefinitions; import org.jetbrains.android.dom.attrs.AttributeFormat; import org.jetbrains.android.dom.attrs.StyleableDefinition; +import org.jetbrains.android.dom.color.ColorDomElement; +import org.jetbrains.android.dom.color.ColorStateListItem; import org.jetbrains.android.dom.converters.CompositeConverter; import org.jetbrains.android.dom.converters.ResourceReferenceConverter; +import org.jetbrains.android.dom.drawable.*; import org.jetbrains.android.dom.layout.Fragment; import org.jetbrains.android.dom.layout.Include; import org.jetbrains.android.dom.layout.LayoutElement; @@ -185,6 +188,15 @@ public class AndroidDomExtender extends DomExtender { AttributeDefinitions attrDefs = manager.getAttributeDefinitions(); if (attrDefs == null) return; StyleableDefinition[] styleables = getStyleables(attrDefs, styleableNames); + registerAttributes(facet, element, styleables, resPackage, registrar, processor, skipNames); + } + + private static void registerAttributes(AndroidFacet facet, + DomElement element, + StyleableDefinition[] styleables, String resPackage, + DomExtensionsRegistrar registrar, + MyAttributeProcessor processor, + String... skipNames) { String namespace = getNamespaceKeyByResourcePackage(facet, resPackage); registerStyleableAttributes(element, styleables, namespace, registrar, processor, skipNames); } @@ -504,8 +516,14 @@ public class AndroidDomExtender extends DomExtender { else if (element instanceof XmlResourceElement) { registerExtensionsForXmlResources(facet, tagName, (XmlResourceElement)element, registrar, registeredSubtags); } + else if (element instanceof DrawableDomElement || element instanceof ColorDomElement) { + registerExtensionsForDrawable(facet, tagName, element, registrar); + } Collections.addAll(registeredSubtags, AndroidDomUtil.getStaticallyDefinedSubtags(element)); - if (!(element instanceof LayoutElement)) { + + if (!(element instanceof LayoutElement) && + !(element instanceof ColorDomElement) && + (!(element instanceof DrawableDomElement) || element instanceof UnknownDrawableElement)) { Processor existingSubtagsFilter = element instanceof XmlResourceElement ? new Processor() { public boolean process(String s) { @@ -516,6 +534,31 @@ public class AndroidDomExtender extends DomExtender { } } + private static void registerExtensionsForDrawable(AndroidFacet facet, + String tagName, + AndroidDomElement element, + DomExtensionsRegistrar registrar) { + final String specialStyleableName = DrawableDomFileDescription.SPECIAL_STYLEABLE_NAMES.get(tagName); + if (specialStyleableName != null) { + registerAttributes(facet, element, specialStyleableName, SYSTEM_RESOURCE_PACKAGE, registrar); + } + + if (element instanceof DrawableStateListItem || element instanceof ColorStateListItem) { + registerAttributes(facet, element, "DrawableStates", SYSTEM_RESOURCE_PACKAGE, registrar); + + final AttributeDefinitions attrDefs = getAttrDefs(facet); + if (attrDefs != null) { + registerAttributes(facet, element, attrDefs.getStateStyleables(), SYSTEM_RESOURCE_PACKAGE, registrar, null); + } + } + } + + @Nullable + private static AttributeDefinitions getAttrDefs(AndroidFacet facet) { + final SystemResourceManager manager = facet.getSystemResourceManager(); + return manager != null ? manager.getAttributeDefinitions() : null; + } + private static void registerSubtags(@NotNull String name, Type type, DomExtensionsRegistrar registrar, Set registeredTags) { registrar.registerCollectionChildrenExtension(new XmlName(name), type); registeredTags.add(name); diff --git a/plugins/android/src/org/jetbrains/android/dom/attrs/AttributeDefinitions.java b/plugins/android/src/org/jetbrains/android/dom/attrs/AttributeDefinitions.java index b843fde94081..ca2c46d7302d 100644 --- a/plugins/android/src/org/jetbrains/android/dom/attrs/AttributeDefinitions.java +++ b/plugins/android/src/org/jetbrains/android/dom/attrs/AttributeDefinitions.java @@ -34,6 +34,8 @@ public class AttributeDefinitions { private Map myAttrs = new HashMap(); private Map myStyleables = new HashMap(); + private final List myStateStyleables = new ArrayList(); + public AttributeDefinitions() { } @@ -150,6 +152,11 @@ public class AttributeDefinitions { parentMap.put(def, parentNames); } myStyleables.put(name, def); + + if (name.endsWith("State")) { + myStateStyleables.add(def); + } + for (XmlTag subTag : tag.findSubTags("attr")) { parseStyleableAttr(def, subTag); } @@ -196,4 +203,8 @@ public class AttributeDefinitions { public Set getStyleableNames() { return myStyleables.keySet(); } + + public StyleableDefinition[] getStateStyleables() { + return myStateStyleables.toArray(new StyleableDefinition[myStateStyleables.size()]); + } } diff --git a/plugins/android/src/org/jetbrains/android/dom/color/ColorDomElement.java b/plugins/android/src/org/jetbrains/android/dom/color/ColorDomElement.java new file mode 100644 index 000000000000..e32cdeaca560 --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/dom/color/ColorDomElement.java @@ -0,0 +1,24 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.android.dom.color; + +import org.jetbrains.android.dom.AndroidDomElement; + +/** + * @author Eugene.Kudelevsky + */ +public interface ColorDomElement extends AndroidDomElement { +} diff --git a/plugins/android/src/org/jetbrains/android/dom/color/ColorDomFileDescription.java b/plugins/android/src/org/jetbrains/android/dom/color/ColorDomFileDescription.java new file mode 100644 index 000000000000..723f55cf13c4 --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/dom/color/ColorDomFileDescription.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.android.dom.color; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.util.Computable; +import com.intellij.psi.xml.XmlFile; +import org.jetbrains.android.dom.AndroidResourceDomFileDescription; + +/** + * @author Eugene.Kudelevsky + */ +public class ColorDomFileDescription extends AndroidResourceDomFileDescription { + public ColorDomFileDescription() { + super(ColorSelector.class, "selector", "color"); + } + + @Override + public boolean acceptsOtherRootTagNames() { + return false; + } + + public static boolean isColorResourceFile(final XmlFile file) { + return ApplicationManager.getApplication().runReadAction(new Computable() { + public Boolean compute() { + return new ColorDomFileDescription().isMyFile(file, null); + } + }); + } +} diff --git a/plugins/android/src/org/jetbrains/android/dom/color/ColorSelector.java b/plugins/android/src/org/jetbrains/android/dom/color/ColorSelector.java new file mode 100644 index 000000000000..3060448b1fda --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/dom/color/ColorSelector.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.android.dom.color; + +import com.intellij.util.xml.DefinesXml; + +import java.util.List; + +/** + * @author Eugene.Kudelevsky + */ +@DefinesXml +public interface ColorSelector extends ColorDomElement { + List getItems(); +} diff --git a/plugins/android/src/org/jetbrains/android/dom/color/ColorStateListItem.java b/plugins/android/src/org/jetbrains/android/dom/color/ColorStateListItem.java new file mode 100644 index 000000000000..2b42fbdc2d9c --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/dom/color/ColorStateListItem.java @@ -0,0 +1,33 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.android.dom.color; + +import com.intellij.util.xml.Convert; +import com.intellij.util.xml.Required; +import org.jetbrains.android.dom.AndroidAttributeValue; +import org.jetbrains.android.dom.ResourceType; +import org.jetbrains.android.dom.converters.ResourceReferenceConverter; +import org.jetbrains.android.dom.resources.ResourceValue; + +/** + * @author Eugene.Kudelevsky + */ +public interface ColorStateListItem extends ColorDomElement { + @Convert(ResourceReferenceConverter.class) + @ResourceType("color") + @Required + AndroidAttributeValue getColor(); +} diff --git a/plugins/android/src/org/jetbrains/android/dom/drawable/DrawableDomElement.java b/plugins/android/src/org/jetbrains/android/dom/drawable/DrawableDomElement.java index 57bdbde91e54..87cad802d262 100644 --- a/plugins/android/src/org/jetbrains/android/dom/drawable/DrawableDomElement.java +++ b/plugins/android/src/org/jetbrains/android/dom/drawable/DrawableDomElement.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2011 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 org.jetbrains.android.dom.drawable; import org.jetbrains.android.dom.AndroidDomElement; -import com.intellij.util.xml.DefinesXml; /** * Created by IntelliJ IDEA. @@ -26,6 +25,5 @@ import com.intellij.util.xml.DefinesXml; * Time: 1:36:56 PM * To change this template use File | Settings | File Templates. */ -@DefinesXml public interface DrawableDomElement extends AndroidDomElement{ } diff --git a/plugins/android/src/org/jetbrains/android/dom/drawable/DrawableDomFileDescription.java b/plugins/android/src/org/jetbrains/android/dom/drawable/DrawableDomFileDescription.java index 02d94fdb8598..233a6933a0ec 100644 --- a/plugins/android/src/org/jetbrains/android/dom/drawable/DrawableDomFileDescription.java +++ b/plugins/android/src/org/jetbrains/android/dom/drawable/DrawableDomFileDescription.java @@ -16,7 +16,17 @@ package org.jetbrains.android.dom.drawable; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.util.Computable; +import com.intellij.psi.xml.XmlFile; +import com.intellij.psi.xml.XmlTag; +import com.intellij.util.containers.HashMap; import org.jetbrains.android.dom.AndroidResourceDomFileDescription; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; /** * Created by IntelliJ IDEA. @@ -25,13 +35,38 @@ import org.jetbrains.android.dom.AndroidResourceDomFileDescription; * Time: 9:42:38 PM * To change this template use File | Settings | File Templates. */ -public class DrawableDomFileDescription extends AndroidResourceDomFileDescription { +public class DrawableDomFileDescription extends AndroidResourceDomFileDescription { + public static final Map SPECIAL_STYLEABLE_NAMES = new HashMap(); + public DrawableDomFileDescription() { - super(DrawableDomElement.class, "selector", "drawable", "color"); + super(UnknownDrawableElement.class, "shape", "drawable"); } @Override public boolean acceptsOtherRootTagNames() { return true; } + + public static boolean isDrawableResourceFile(final XmlFile file) { + return ApplicationManager.getApplication().runReadAction(new Computable() { + public Boolean compute() { + return new DrawableDomFileDescription().isMyFile(file, null); + } + }); + } + + @Override + public boolean isMyFile(@NotNull XmlFile file, @Nullable Module module) { + if (!super.isMyFile(file, module)) { + return false; + } + + final XmlTag rootTag = file.getRootTag(); + if (rootTag == null) { + return false; + } + + final String rootTagName = rootTag.getName(); + return !"selector".equals(rootTagName); + } } diff --git a/plugins/android/src/org/jetbrains/android/dom/drawable/DrawableSelector.java b/plugins/android/src/org/jetbrains/android/dom/drawable/DrawableSelector.java new file mode 100644 index 000000000000..350d2207410f --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/dom/drawable/DrawableSelector.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.android.dom.drawable; + +import com.intellij.util.xml.DefinesXml; + +import java.util.List; + +/** + * @author Eugene.Kudelevsky + */ +@DefinesXml +public interface DrawableSelector extends DrawableDomElement { + List getItems(); +} diff --git a/plugins/android/src/org/jetbrains/android/dom/drawable/DrawableStateListDomFileDescription.java b/plugins/android/src/org/jetbrains/android/dom/drawable/DrawableStateListDomFileDescription.java new file mode 100644 index 000000000000..73bb4da1f4d2 --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/dom/drawable/DrawableStateListDomFileDescription.java @@ -0,0 +1,55 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.android.dom.drawable; + +import com.intellij.openapi.module.Module; +import com.intellij.psi.xml.XmlFile; +import com.intellij.psi.xml.XmlTag; +import org.jetbrains.android.dom.AndroidResourceDomFileDescription; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Eugene.Kudelevsky + */ +public class DrawableStateListDomFileDescription extends AndroidResourceDomFileDescription { + + @NonNls private static final String SELECTOR_TAG_NAME = "selector"; + + public DrawableStateListDomFileDescription() { + super(DrawableSelector.class, SELECTOR_TAG_NAME, "drawable"); + } + + @Override + public boolean acceptsOtherRootTagNames() { + return true; + } + + @Override + public boolean isMyFile(@NotNull XmlFile file, @Nullable Module module) { + if (!super.isMyFile(file, module)) { + return false; + } + + final XmlTag rootTag = file.getRootTag(); + if (rootTag == null) { + return false; + } + + return SELECTOR_TAG_NAME.equals(rootTag.getName()); + } +} diff --git a/plugins/android/src/org/jetbrains/android/dom/drawable/DrawableStateListItem.java b/plugins/android/src/org/jetbrains/android/dom/drawable/DrawableStateListItem.java new file mode 100644 index 000000000000..feeab917d186 --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/dom/drawable/DrawableStateListItem.java @@ -0,0 +1,33 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.android.dom.drawable; + +import com.intellij.util.xml.Convert; +import com.intellij.util.xml.Required; +import org.jetbrains.android.dom.AndroidAttributeValue; +import org.jetbrains.android.dom.ResourceType; +import org.jetbrains.android.dom.converters.ResourceReferenceConverter; +import org.jetbrains.android.dom.resources.ResourceValue; + +/** + * @author Eugene.Kudelevsky + */ +public interface DrawableStateListItem extends DrawableDomElement { + @Convert(ResourceReferenceConverter.class) + @ResourceType("drawable") + @Required + AndroidAttributeValue getDrawable(); +} diff --git a/plugins/android/src/org/jetbrains/android/dom/drawable/UnknownDrawableElement.java b/plugins/android/src/org/jetbrains/android/dom/drawable/UnknownDrawableElement.java new file mode 100644 index 000000000000..b9de972d9196 --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/dom/drawable/UnknownDrawableElement.java @@ -0,0 +1,26 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.android.dom.drawable; + +import com.intellij.util.xml.DefinesXml; +import org.jetbrains.android.dom.AndroidDomElement; + +/** + * @author Eugene.Kudelevksy + */ +@DefinesXml +public interface UnknownDrawableElement extends AndroidDomElement { +} diff --git a/plugins/android/testData/dom/color/colors.xml b/plugins/android/testData/dom/color/colors.xml new file mode 100644 index 000000000000..76e68e0b3dce --- /dev/null +++ b/plugins/android/testData/dom/color/colors.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/plugins/android/testData/dom/other/2.xml b/plugins/android/testData/dom/color/stateListCompletion1.xml similarity index 69% rename from plugins/android/testData/dom/other/2.xml rename to plugins/android/testData/dom/color/stateListCompletion1.xml index 3258d9c8c421..18e265b3f0c5 100644 --- a/plugins/android/testData/dom/other/2.xml +++ b/plugins/android/testData/dom/color/stateListCompletion1.xml @@ -1,6 +1,5 @@ - + - diff --git a/plugins/android/testData/dom/color/stateListCompletion1_after.xml b/plugins/android/testData/dom/color/stateListCompletion1_after.xml new file mode 100644 index 000000000000..f6add76dcbe7 --- /dev/null +++ b/plugins/android/testData/dom/color/stateListCompletion1_after.xml @@ -0,0 +1,5 @@ + + + + diff --git a/plugins/android/testData/dom/color/stateListCompletion2.xml b/plugins/android/testData/dom/color/stateListCompletion2.xml new file mode 100644 index 000000000000..1d1894b27108 --- /dev/null +++ b/plugins/android/testData/dom/color/stateListCompletion2.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/plugins/android/testData/dom/color/stateListCompletion2_after.xml b/plugins/android/testData/dom/color/stateListCompletion2_after.xml new file mode 100644 index 000000000000..b393683a7c4e --- /dev/null +++ b/plugins/android/testData/dom/color/stateListCompletion2_after.xml @@ -0,0 +1,5 @@ + + + + diff --git a/plugins/android/testData/dom/color/stateListCompletion3.xml b/plugins/android/testData/dom/color/stateListCompletion3.xml new file mode 100644 index 000000000000..06a6987bcea6 --- /dev/null +++ b/plugins/android/testData/dom/color/stateListCompletion3.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/plugins/android/testData/dom/color/stateListCompletion3_after.xml b/plugins/android/testData/dom/color/stateListCompletion3_after.xml new file mode 100644 index 000000000000..675b773d4bd6 --- /dev/null +++ b/plugins/android/testData/dom/color/stateListCompletion3_after.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/plugins/android/testData/dom/color/stateListCompletion4.xml b/plugins/android/testData/dom/color/stateListCompletion4.xml new file mode 100644 index 000000000000..448420cb8e71 --- /dev/null +++ b/plugins/android/testData/dom/color/stateListCompletion4.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/plugins/android/testData/dom/color/stateListCompletion4_after.xml b/plugins/android/testData/dom/color/stateListCompletion4_after.xml new file mode 100644 index 000000000000..93ced7a9489f --- /dev/null +++ b/plugins/android/testData/dom/color/stateListCompletion4_after.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/plugins/android/testData/dom/color/stateListCompletion5.xml b/plugins/android/testData/dom/color/stateListCompletion5.xml new file mode 100644 index 000000000000..c15b636cc014 --- /dev/null +++ b/plugins/android/testData/dom/color/stateListCompletion5.xml @@ -0,0 +1,3 @@ + + + diff --git a/plugins/android/testData/dom/color/stateListCompletion5_after.xml b/plugins/android/testData/dom/color/stateListCompletion5_after.xml new file mode 100644 index 000000000000..44dfa0ab1527 --- /dev/null +++ b/plugins/android/testData/dom/color/stateListCompletion5_after.xml @@ -0,0 +1,3 @@ + + + + + + + + + <item android:state_middle="true"/> + + diff --git a/plugins/android/testData/dom/drawable/myDrawable.png b/plugins/android/testData/dom/drawable/myDrawable.png new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/plugins/android/testData/dom/drawable/stateListCompletion1.xml b/plugins/android/testData/dom/drawable/stateListCompletion1.xml new file mode 100644 index 000000000000..18e265b3f0c5 --- /dev/null +++ b/plugins/android/testData/dom/drawable/stateListCompletion1.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/plugins/android/testData/dom/drawable/stateListCompletion1_after.xml b/plugins/android/testData/dom/drawable/stateListCompletion1_after.xml new file mode 100644 index 000000000000..f6add76dcbe7 --- /dev/null +++ b/plugins/android/testData/dom/drawable/stateListCompletion1_after.xml @@ -0,0 +1,5 @@ + + + + diff --git a/plugins/android/testData/dom/drawable/stateListCompletion2.xml b/plugins/android/testData/dom/drawable/stateListCompletion2.xml new file mode 100644 index 000000000000..1d1894b27108 --- /dev/null +++ b/plugins/android/testData/dom/drawable/stateListCompletion2.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/plugins/android/testData/dom/drawable/stateListCompletion2_after.xml b/plugins/android/testData/dom/drawable/stateListCompletion2_after.xml new file mode 100644 index 000000000000..b393683a7c4e --- /dev/null +++ b/plugins/android/testData/dom/drawable/stateListCompletion2_after.xml @@ -0,0 +1,5 @@ + + + + diff --git a/plugins/android/testData/dom/drawable/stateListCompletion3.xml b/plugins/android/testData/dom/drawable/stateListCompletion3.xml new file mode 100644 index 000000000000..06a6987bcea6 --- /dev/null +++ b/plugins/android/testData/dom/drawable/stateListCompletion3.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/plugins/android/testData/dom/drawable/stateListCompletion3_after.xml b/plugins/android/testData/dom/drawable/stateListCompletion3_after.xml new file mode 100644 index 000000000000..675b773d4bd6 --- /dev/null +++ b/plugins/android/testData/dom/drawable/stateListCompletion3_after.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/plugins/android/testData/dom/drawable/stateListCompletion4.xml b/plugins/android/testData/dom/drawable/stateListCompletion4.xml new file mode 100644 index 000000000000..1596d6f85575 --- /dev/null +++ b/plugins/android/testData/dom/drawable/stateListCompletion4.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/plugins/android/testData/dom/drawable/stateListCompletion4_after.xml b/plugins/android/testData/dom/drawable/stateListCompletion4_after.xml new file mode 100644 index 000000000000..8d32f8aa92f2 --- /dev/null +++ b/plugins/android/testData/dom/drawable/stateListCompletion4_after.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/plugins/android/testData/dom/drawable/stateListCompletion5.xml b/plugins/android/testData/dom/drawable/stateListCompletion5.xml new file mode 100644 index 000000000000..c15b636cc014 --- /dev/null +++ b/plugins/android/testData/dom/drawable/stateListCompletion5.xml @@ -0,0 +1,3 @@ + + + diff --git a/plugins/android/testData/dom/drawable/stateListCompletion5_after.xml b/plugins/android/testData/dom/drawable/stateListCompletion5_after.xml new file mode 100644 index 000000000000..44dfa0ab1527 --- /dev/null +++ b/plugins/android/testData/dom/drawable/stateListCompletion5_after.xml @@ -0,0 +1,3 @@ + + + + + + + + + <item android:state_middle="true"/> + + diff --git a/plugins/android/testData/dom/other/1.xml b/plugins/android/testData/dom/other/1.xml index 723b4e379596..167eb410ee2b 100644 --- a/plugins/android/testData/dom/other/1.xml +++ b/plugins/android/testData/dom/other/1.xml @@ -1,5 +1,7 @@ - - - \ No newline at end of file + + + + \ No newline at end of file diff --git a/plugins/android/testSrc/org/jetbrains/android/dom/AndroidColorStateListDomTest.java b/plugins/android/testSrc/org/jetbrains/android/dom/AndroidColorStateListDomTest.java new file mode 100644 index 000000000000..116ddab31a9f --- /dev/null +++ b/plugins/android/testSrc/org/jetbrains/android/dom/AndroidColorStateListDomTest.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.android.dom; + +/** + * @author Eugene.Kudelevsky + */ +public class AndroidColorStateListDomTest extends AndroidDomTest { + public AndroidColorStateListDomTest() { + super(true, "dom/color"); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + copyFileToProject("colors.xml", "res/values/colors.xml"); + } + + @Override + protected String getPathToCopy(String testFileName) { + return "res/color/" + testFileName; + } + + public void testStateListHighlighting() throws Throwable { + doTestHighlighting(); + } + + public void testStateListCompletion1() throws Throwable { + doTestCompletion(); + } + + public void testStateListCompletion2() throws Throwable { + doTestCompletion(); + } + + public void testStateListCompletion3() throws Throwable { + doTestCompletion(); + } + + public void testStateListCompletion4() throws Throwable { + doTestCompletion(); + } +} + diff --git a/plugins/android/testSrc/org/jetbrains/android/dom/AndroidDomTest.java b/plugins/android/testSrc/org/jetbrains/android/dom/AndroidDomTest.java index 6a74467ecb4d..6012b6dc21c2 100644 --- a/plugins/android/testSrc/org/jetbrains/android/dom/AndroidDomTest.java +++ b/plugins/android/testSrc/org/jetbrains/android/dom/AndroidDomTest.java @@ -61,12 +61,20 @@ abstract class AndroidDomTest extends AndroidTestCase { return list; } + protected void doTestHighlighting() throws Throwable { + doTestHighlighting(getTestName(true) + ".xml"); + } + protected void doTestHighlighting(String file) throws Throwable { VirtualFile virtualFile = copyFileToProject(file); myFixture.configureFromExistingVirtualFile(virtualFile); myFixture.checkHighlighting(false, false, false); } + protected void doTestCompletion() throws Throwable { + toTestCompletion(getTestName(true) + ".xml", getTestName(true) + "_after.xml"); + } + protected void toTestCompletion(String fileBefore, String fileAfter) throws Throwable { VirtualFile file = copyFileToProject(fileBefore); myFixture.configureFromExistingVirtualFile(file); diff --git a/plugins/android/testSrc/org/jetbrains/android/dom/AndroidDrawableResourcesDomTest.java b/plugins/android/testSrc/org/jetbrains/android/dom/AndroidDrawableResourcesDomTest.java new file mode 100644 index 000000000000..8d7b11bfe56b --- /dev/null +++ b/plugins/android/testSrc/org/jetbrains/android/dom/AndroidDrawableResourcesDomTest.java @@ -0,0 +1,56 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.android.dom; + +/** + * @author Eugene.Kudelevsky + */ +public class AndroidDrawableResourcesDomTest extends AndroidDomTest { + public AndroidDrawableResourcesDomTest() { + super(true, "dom/drawable"); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + copyFileToProject("myDrawable.png", "res/drawable/myDrawable.png"); + } + + @Override + protected String getPathToCopy(String testFileName) { + return "res/drawable/" + testFileName; + } + + public void testStateListHighlighting() throws Throwable { + doTestHighlighting(); + } + + public void testStateListCompletion1() throws Throwable { + doTestCompletion(); + } + + public void testStateListCompletion2() throws Throwable { + doTestCompletion(); + } + + public void testStateListCompletion3() throws Throwable { + doTestCompletion(); + } + + public void testStateListCompletion4() throws Throwable { + doTestCompletion(); + } +} diff --git a/plugins/android/testSrc/org/jetbrains/android/dom/AndroidDrawableResourcesTest.java b/plugins/android/testSrc/org/jetbrains/android/dom/AndroidDrawableResourcesTest.java index 722d9d3f7a30..8c6269b5abcd 100644 --- a/plugins/android/testSrc/org/jetbrains/android/dom/AndroidDrawableResourcesTest.java +++ b/plugins/android/testSrc/org/jetbrains/android/dom/AndroidDrawableResourcesTest.java @@ -19,11 +19,7 @@ package org.jetbrains.android.dom; import com.android.sdklib.SdkConstants; /** - * Created by IntelliJ IDEA. - * User: Eugene.Kudelevsky - * Date: Aug 21, 2009 - * Time: 9:45:59 PM - * To change this template use File | Settings | File Templates. + * @author Eugene.Kudelevsky */ public class AndroidDrawableResourcesTest extends AndroidDomTest { public AndroidDrawableResourcesTest() { @@ -44,8 +40,4 @@ public class AndroidDrawableResourcesTest extends AndroidDomTest { public void testHighlighting() throws Throwable { doTestHighlighting("1.xml"); } - - public void testAttributeValueCompletion() throws Throwable { - doTestCompletionVariants("2.xml", "@drawable/picture1", "@drawable/picture2", "@drawable/picture3"); - } } diff --git a/plugins/android/testSrc/org/jetbrains/android/dom/AndroidManifestDomTest.java b/plugins/android/testSrc/org/jetbrains/android/dom/AndroidManifestDomTest.java index ddd54fe706e5..b9d477b7c176 100644 --- a/plugins/android/testSrc/org/jetbrains/android/dom/AndroidManifestDomTest.java +++ b/plugins/android/testSrc/org/jetbrains/android/dom/AndroidManifestDomTest.java @@ -154,8 +154,4 @@ public class AndroidManifestDomTest extends AndroidDomTest { copyFileToProject("MyActivity.java", "src/p1/p2/MyActivity.java"); doTestCompletion(); } - - private void doTestCompletion() throws Throwable { - toTestCompletion(getTestName(false) + ".xml", getTestName(false) + "_after.xml"); - } } From 8f4a7ee0d0117d2291fcf4c0e28774798969af22 Mon Sep 17 00:00:00 2001 From: anna Date: Wed, 13 Apr 2011 16:19:42 +0200 Subject: [PATCH 070/102] interface 'overrides' object: methods with same erasure should be accepted (IDEA-67752) --- .../daemon/impl/analysis/GenericsHighlightUtil.java | 1 + .../genericsHighlighting/OverridingMethods.java | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java index 56e043cded6d..7237257c613a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java @@ -493,6 +493,7 @@ public class GenericsHighlightUtil { if (!checkEqualsSuper && MethodSignatureUtil.isSubsignature(superSignature, signatureToCheck)) { return null; } + if (superContainingClass != null && !superContainingClass.isInterface() && checkContainingClass.isInterface() && !aClass.equals(superContainingClass)) return null; if (aClass.equals(checkContainingClass)) { boolean sameClass = aClass.equals(superContainingClass); return getSameErasureMessage(sameClass, checkMethod, superMethod, HighlightNamesUtil.getMethodDeclarationTextRange(checkMethod)); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/OverridingMethods.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/OverridingMethods.java index 45318c41832c..04d2fe24e249 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/OverridingMethods.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/OverridingMethods.java @@ -510,4 +510,8 @@ class sOk implements C { } } +} + +interface OverrideObject { + void notify(); } \ No newline at end of file From 2e0cd2d032dc6803a59e128f1a67d527f6362c83 Mon Sep 17 00:00:00 2001 From: anna Date: Wed, 13 Apr 2011 16:45:02 +0200 Subject: [PATCH 071/102] interface 'overrides' object: methods can declare different exceptions (IDEA-67753) --- .../codeInsight/daemon/impl/analysis/HighlightMethodUtil.java | 4 ++++ .../daemonCodeAnalyzer/advHighlighting/OverrideConflicts.java | 4 ++++ 2 files changed, 8 insertions(+) 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 3cc4288d9e20..f6f52429f1a3 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 @@ -247,6 +247,10 @@ public class HighlightMethodUtil { PsiMethod superMethod = superMethodSignature.getMethod(); int index = getExtraExceptionNum(methodSignature, superMethodSignature, checkedExceptions, superSubstitutor); if (index != -1) { + if (aClass.isInterface()) { + final PsiClass superContainingClass = superMethod.getContainingClass(); + if (superContainingClass != null && !superContainingClass.isInterface()) continue; + } PsiClassType exception = checkedExceptions.get(index); String message = JavaErrorMessages.message("overridden.method.does.not.throw", createClashMethodMessage(method, superMethod, true), diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/OverrideConflicts.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/OverrideConflicts.java index 3aaa540d2a0c..a6dfc3685e3a 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/OverrideConflicts.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/OverrideConflicts.java @@ -86,3 +86,7 @@ interface Coll { } class AbstrColl implements Coll {} +interface InterfaceOverridesObject { + Object clone() throws java.io.IOException; +} + From 0fe604b59e1ed0fa3a95014f068da38a13c210a7 Mon Sep 17 00:00:00 2001 From: Anton Makeev Date: Wed, 13 Apr 2011 20:54:30 +0200 Subject: [PATCH 072/102] XDebugger: auto-focusing Console/Frames tabs when necessary (like in Java-debugger) --- .../debugger/ui/DebuggerSessionTab.java | 11 ++- .../actions/FocusOnBreakpointAction.java | 4 +- .../ui/layout/LayoutViewOptions.java | 2 + .../src/messages/XDebuggerBundle.properties | 3 + .../com/intellij/xdebugger/XDebugSession.java | 3 + .../xdebugger/impl/XDebugSessionImpl.java | 14 ++++ .../xdebugger/impl/ui/XDebugSessionTab.java | 72 ++----------------- .../src/messages/DebuggerBundle.properties | 1 - 8 files changed, 35 insertions(+), 75 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java index a95baf60fdf6..16775fddc8f3 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java @@ -94,7 +94,6 @@ public class DebuggerSessionTab extends DebuggerSessionTabBase implements Dispos private ExecutionEnvironment myEnvironment; private RunProfile myConfiguration; - public static final String BREAKPOINT_CONDITION = "breakpoint"; private final ThreadsPanel myThreadsPanel; private static final String THREAD_DUMP_CONTENT_PREFIX = "Dump"; private final Icon myIcon; @@ -104,10 +103,10 @@ public class DebuggerSessionTab extends DebuggerSessionTabBase implements Dispos myIcon = icon; - myUi = RunnerLayoutUi.Factory.getInstance(project).create("JavaDebugger", DebuggerBundle.message("title.generic.debug.dialog"), sessionName, this); + myUi = RunnerLayoutUi.Factory.getInstance(project).create("JavaDebugger", XDebuggerBundle.message("xdebugger.default.content.title"), sessionName, this); - myUi.getDefaults().initTabDefaults(0, "Debugger", null). - initFocusContent(DebuggerContentInfo.FRAME_CONTENT, BREAKPOINT_CONDITION). + myUi.getDefaults().initTabDefaults(0, XDebuggerBundle.message("xdebugger.debugger.tab.title"), null). + initFocusContent(DebuggerContentInfo.FRAME_CONTENT, LayoutViewOptions.BREAKPOINT_CONDITION). initFocusContent(DebuggerContentInfo.CONSOLE_CONTENT, LayoutViewOptions.STARTUP, new LayoutAttractionPolicy.FocusOnce(false)); final DefaultActionGroup focus = new DefaultActionGroup(); @@ -479,9 +478,9 @@ public class DebuggerSessionTab extends DebuggerSessionTabBase implements Dispos private void attractFramesOnPause(final int event) { if (DebuggerSession.EVENT_PAUSE == event) { - myUi.attractBy(BREAKPOINT_CONDITION); + myUi.attractBy(LayoutViewOptions.BREAKPOINT_CONDITION); } else if (DebuggerSession.EVENT_RESUME == event) { - myUi.clearAttractionBy(BREAKPOINT_CONDITION); + myUi.clearAttractionBy(LayoutViewOptions.BREAKPOINT_CONDITION); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/FocusOnBreakpointAction.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/FocusOnBreakpointAction.java index 74c2b60220ed..d248c4a0db9e 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/FocusOnBreakpointAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/FocusOnBreakpointAction.java @@ -16,10 +16,10 @@ package com.intellij.debugger.ui.breakpoints.actions; import com.intellij.execution.ui.actions.AbstractFocusOnAction; -import com.intellij.debugger.ui.DebuggerSessionTab; +import com.intellij.execution.ui.layout.LayoutViewOptions; public class FocusOnBreakpointAction extends AbstractFocusOnAction { public FocusOnBreakpointAction() { - super(DebuggerSessionTab.BREAKPOINT_CONDITION); + super(LayoutViewOptions.BREAKPOINT_CONDITION); } } \ No newline at end of file diff --git a/platform/lang-api/src/com/intellij/execution/ui/layout/LayoutViewOptions.java b/platform/lang-api/src/com/intellij/execution/ui/layout/LayoutViewOptions.java index d312a3186ab4..a71581ba1170 100644 --- a/platform/lang-api/src/com/intellij/execution/ui/layout/LayoutViewOptions.java +++ b/platform/lang-api/src/com/intellij/execution/ui/layout/LayoutViewOptions.java @@ -16,6 +16,7 @@ package com.intellij.execution.ui.layout; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import com.intellij.openapi.actionSystem.ActionGroup; @@ -25,6 +26,7 @@ import com.intellij.ui.content.Content; public interface LayoutViewOptions { String STARTUP = "startup"; + String BREAKPOINT_CONDITION = "breakpoint"; @NotNull LayoutViewOptions setTopToolbar(@NotNull ActionGroup actions, @NotNull String place); diff --git a/platform/platform-resources-en/src/messages/XDebuggerBundle.properties b/platform/platform-resources-en/src/messages/XDebuggerBundle.properties index 1a348fb16065..3d8a4ddef3a1 100644 --- a/platform/platform-resources-en/src/messages/XDebuggerBundle.properties +++ b/platform/platform-resources-en/src/messages/XDebuggerBundle.properties @@ -2,6 +2,9 @@ xdebugger.colors.page.name=Debugger debugger.configurable.display.name=Debugger +xdebugger.default.content.title=Debug +xdebugger.debugger.tab.title=Debugger + xdebugger.remove.line.breakpoint.action.text=Remove xdebugger.disable.breakpoint.action.text=Disable xdebugger.enable.breakpoint.action.text=Enable diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugSession.java b/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugSession.java index 86453dbf60be..00b5143ce45a 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugSession.java +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugSession.java @@ -19,6 +19,7 @@ package com.intellij.xdebugger; import com.intellij.execution.configurations.RunProfile; import com.intellij.execution.ui.ConsoleView; import com.intellij.execution.ui.RunContentDescriptor; +import com.intellij.execution.ui.RunnerLayoutUi; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageType; import com.intellij.xdebugger.breakpoints.XBreakpoint; @@ -135,4 +136,6 @@ public interface XDebugSession extends AbstractDebuggerSession { void updateExecutionPosition(); ConsoleView getConsoleView(); + + RunnerLayoutUi getUI(); } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java index 14da42c4b621..c4f81befec53 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java @@ -28,6 +28,8 @@ import com.intellij.execution.runners.ProgramRunner; import com.intellij.execution.ui.ConsoleView; import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.execution.ui.RunContentDescriptor; +import com.intellij.execution.ui.RunnerLayoutUi; +import com.intellij.execution.ui.layout.LayoutViewOptions; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.application.Result; import com.intellij.openapi.diagnostic.Logger; @@ -217,6 +219,11 @@ public class XDebugSessionImpl implements XDebugSession { return mySessionTab; } + @Override + public RunnerLayoutUi getUI() { + return mySessionTab.getUi(); + } + private void initSessionTab() { mySessionTab = new XDebugSessionTab(myProject, mySessionName); if (myEnvironment != null) { @@ -408,6 +415,12 @@ public class XDebugSessionImpl implements XDebugSession { myCurrentStackFrame = null; myCurrentPosition = null; myPaused = false; + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + mySessionTab.getUi().clearAttractionBy(LayoutViewOptions.BREAKPOINT_CONDITION); + } + }); myDispatcher.getMulticaster().sessionResumed(); } @@ -574,6 +587,7 @@ public class XDebugSessionImpl implements XDebugSession { showSessionTab(); } mySessionTab.toFront(); + mySessionTab.getUi().attractBy(LayoutViewOptions.BREAKPOINT_CONDITION); } }); myDispatcher.getMulticaster().sessionPaused(); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java index 3f2b06d4a977..d29928bca354 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java @@ -29,6 +29,8 @@ import com.intellij.execution.ui.ExecutionConsole; import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.execution.ui.RunnerLayoutUi; import com.intellij.execution.ui.actions.CloseAction; +import com.intellij.execution.ui.layout.LayoutAttractionPolicy; +import com.intellij.execution.ui.layout.LayoutViewOptions; import com.intellij.execution.ui.layout.PlaceInGrid; import com.intellij.ide.CommonActionsManager; import com.intellij.ide.actions.ContextHelpAction; @@ -68,7 +70,10 @@ public class XDebugSessionTab extends DebuggerSessionTabBase { mySessionName = sessionName; myUi = RunnerLayoutUi.Factory.getInstance(project).create("Debug", "unknown!", sessionName, this); - myUi.getDefaults().initTabDefaults(0, "Debug", null); + myUi.getDefaults() + .initTabDefaults(0, XDebuggerBundle.message("xdebugger.debugger.tab.title"), null) + .initFocusContent(DebuggerContentInfo.FRAME_CONTENT, LayoutViewOptions.BREAKPOINT_CONDITION) + .initFocusContent(DebuggerContentInfo.CONSOLE_CONTENT, LayoutViewOptions.STARTUP, new LayoutAttractionPolicy.FocusOnce(false)); } private static ActionGroup getActionGroup(final String id) { @@ -201,71 +206,6 @@ public class XDebugSessionTab extends DebuggerSessionTabBase { return myRunContentDescriptor; } - private RunContentDescriptor initUI(final @NotNull XDebugSession session, final @NotNull XDebugSessionData sessionData, - final @Nullable ExecutionEnvironment environment, - final @Nullable ProgramRunner runner, - ConsoleView consoleView) { - final XDebugProcess debugProcess = session.getDebugProcess(); - ProcessHandler processHandler = debugProcess.getProcessHandler(); - myConsole = consoleView; - myRunContentDescriptor = new RunContentDescriptor(myConsole, processHandler, myUi.getComponent(), mySessionName); - - myUi.addContent(createFramesContent(session), 0, PlaceInGrid.left, false); - myUi.addContent(createVariablesContent(session), 0, PlaceInGrid.center, false); - myUi.addContent(createWatchesContent(session, sessionData), 0, PlaceInGrid.right, false); - final Content consoleContent = createConsoleContent(); - myUi.addContent(consoleContent, 1, PlaceInGrid.bottom, false); - attachNotificationTo(consoleContent); - - session.getDebugProcess().registerAdditionalContent(myUi); - RunContentBuilder.addAdditionalConsoleEditorActions(myConsole, consoleContent); - myUi.addContent(consoleContent, 0, PlaceInGrid.bottom, false); - - if (ApplicationManager.getApplication().isUnitTestMode()) { - return myRunContentDescriptor; - } - - DefaultActionGroup leftToolbar = new DefaultActionGroup(); - final Executor executor = DefaultDebugExecutor.getDebugExecutorInstance(); - if (runner != null && environment != null) { - RestartAction restartAction = new RestartAction(executor, runner, myRunContentDescriptor.getProcessHandler(), XDebuggerUIConstants.DEBUG_AGAIN_ICON, - myRunContentDescriptor, environment); - leftToolbar.add(restartAction); - restartAction.registerShortcut(myUi.getComponent()); - } - - leftToolbar.addAll(getActionGroup(XDebuggerActions.TOOL_WINDOW_LEFT_TOOLBAR_GROUP)); - - //group.addSeparator(); - //addAction(group, DebuggerActions.EXPORT_THREADS); - leftToolbar.addSeparator(); - - leftToolbar.add(myUi.getOptions().getLayoutActions()); - - leftToolbar.addSeparator(); - - leftToolbar.add(PinToolwindowTabAction.getPinAction()); - leftToolbar.add(new CloseAction(executor, myRunContentDescriptor, getProject())); - leftToolbar.add(new ContextHelpAction(executor.getHelpId())); - - DefaultActionGroup topToolbar = new DefaultActionGroup(); - topToolbar.addAll(getActionGroup(XDebuggerActions.TOOL_WINDOW_TOP_TOOLBAR_GROUP)); - - session.getDebugProcess().registerAdditionalActions(leftToolbar, topToolbar); - myUi.getOptions().setLeftToolbar(leftToolbar, ActionPlaces.DEBUGGER_TOOLBAR); - myUi.getOptions().setTopToolbar(topToolbar, ActionPlaces.DEBUGGER_TOOLBAR); - - if (environment != null) { - final RunProfile runConfiguration = environment.getRunProfile(); - registerFileMatcher(runConfiguration); - initLogConsoles(runConfiguration, myRunContentDescriptor.getProcessHandler()); - } - - rebuildViews(); - - return myRunContentDescriptor; - } - public RunnerLayoutUi getUi() { return myUi; } diff --git a/resources-en/src/messages/DebuggerBundle.properties b/resources-en/src/messages/DebuggerBundle.properties index 9239dd87a967..d0acc93f0c4c 100644 --- a/resources-en/src/messages/DebuggerBundle.properties +++ b/resources-en/src/messages/DebuggerBundle.properties @@ -69,7 +69,6 @@ error.vm.disconnected=VM disconnected. Target virtual machine closed connection error.unknown.host=Cannot connect to remote process, host is unknown error.cannot.open.debugger.port=Unable to open debugger port error.exception.while.connecting=Error connecting to remote process.\nException occurred: {0}\nException message: {1} -title.generic.debug.dialog=Debug status.waiting.attach=Debugger is waiting for application to start; debug address: ''{0}''; transport: ''{1}'' status.listening=Listening to the connection, address: ''{0}'', transport: ''{1}'' status.connecting=Connecting to the target VM, address: ''{0}'', transport: ''{1}'' From 5e1e51ed21470ee0e87b35f87bca4dbd41536fba Mon Sep 17 00:00:00 2001 From: Gregory Shrago Date: Wed, 13 Apr 2011 23:05:04 +0400 Subject: [PATCH 073/102] IDEA-68051 Database support: encoding of .ids files is system default --- .../intellij/execution/console/ConsoleHistoryController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/execution/console/ConsoleHistoryController.java b/platform/lang-impl/src/com/intellij/execution/console/ConsoleHistoryController.java index 94c2086dd306..ca98abdf0048 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/ConsoleHistoryController.java +++ b/platform/lang-impl/src/com/intellij/execution/console/ConsoleHistoryController.java @@ -285,7 +285,7 @@ public class ConsoleHistoryController { } private void saveHistory(final XmlSerializer out) throws IOException { - out.startDocument(System.getProperty(CharsetToolkit.FILE_ENCODING_PROPERTY), null); + out.startDocument("UTF8", null); out.startTag(null, "console-history"); out.attribute(null, "id", myId); for (String s : myModel.getHistory()) { From 4cfe2bf18a3a02c0f8e8b35d6d86920f56b61ba9 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Tue, 12 Apr 2011 20:02:25 +0200 Subject: [PATCH 074/102] use QueryExecutorBase --- .../psi/search/SingleTargetRequestResultProcessor.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/platform/lang-api/src/com/intellij/psi/search/SingleTargetRequestResultProcessor.java b/platform/lang-api/src/com/intellij/psi/search/SingleTargetRequestResultProcessor.java index 9c9628ec91da..edd55f417dfe 100644 --- a/platform/lang-api/src/com/intellij/psi/search/SingleTargetRequestResultProcessor.java +++ b/platform/lang-api/src/com/intellij/psi/search/SingleTargetRequestResultProcessor.java @@ -7,6 +7,8 @@ import com.intellij.psi.ReferenceRange; import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; +import java.util.List; + /** * @author peter */ @@ -20,7 +22,9 @@ public final class SingleTargetRequestResultProcessor extends RequestResultProce } public boolean processTextOccurrence(PsiElement element, int offsetInElement, final Processor consumer) { - for (PsiReference ref : ourReferenceService.getReferences(element, new PsiReferenceService.Hints(myTarget, offsetInElement))) { + final List references = ourReferenceService.getReferences(element, + new PsiReferenceService.Hints(myTarget, offsetInElement)); + for (PsiReference ref : references) { if (ReferenceRange.containsOffsetInElement(ref, offsetInElement)) { if (ref.isReferenceTo(myTarget)) { if (!consumer.process(ref)) { From b7c703783692b260130d9223d7fb0e18d71d43ed Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 13 Apr 2011 13:29:02 +0200 Subject: [PATCH 075/102] exception tolerance (PY-3334 & friends) --- .../intellij/openapi/application/impl/ApplicationImpl.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java index a878e19483cc..d679cecbe8db 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java @@ -486,7 +486,12 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application ExtensionPoint point = Extensions.getRootArea().getExtensionPoint("com.intellij.ApplicationLoadListener"); final ApplicationLoadListener[] objects = point.getExtensions(); for (ApplicationLoadListener object : objects) { - object.beforeApplicationLoaded(this); + try { + object.beforeApplicationLoaded(this); + } + catch(Exception e) { + LOG.error(e); + } } } From 5eb3e4d48852dd27f08583d922e0803ee6e5f259 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 13 Apr 2011 17:14:02 +0200 Subject: [PATCH 076/102] IDEA-41363 --- .../src/com/intellij/uiDesigner/editor/UIFormEditor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/editor/UIFormEditor.java b/plugins/ui-designer/src/com/intellij/uiDesigner/editor/UIFormEditor.java index 39dd6b9c1e23..23993b22377f 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/editor/UIFormEditor.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/editor/UIFormEditor.java @@ -80,7 +80,7 @@ public final class UIFormEditor extends UserDataHolderBase implements /*Navigata } public boolean isModified(){ - return FileDocumentManager.getInstance().isFileModified(myFile); + return false; } public boolean isValid(){ From 9a915100d3732b5e05cac5d77d8d37517c4b4d2d Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 13 Apr 2011 17:12:13 +0200 Subject: [PATCH 077/102] @Nullable --- .../psi/impl/PsiJavaParserFacadeImpl.java | 46 ++++++++++--------- .../com/intellij/psi/PsiJavaParserFacade.java | 46 +++++++++---------- 2 files changed, 47 insertions(+), 45 deletions(-) diff --git a/java/java-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java b/java/java-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java index 42dd27340cf9..5dc7bdf197ce 100644 --- a/java/java-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java @@ -170,7 +170,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiAnnotation createAnnotationFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiAnnotation createAnnotationFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, ANNOTATION, level(context)), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); if (!(element instanceof PsiAnnotation)) { @@ -187,7 +187,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiDocTag createDocTagFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiDocTag createDocTagFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { return createDocTagFromText(text); } @@ -202,13 +202,13 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiDocComment createDocCommentFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiDocComment createDocCommentFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { return createDocCommentFromText(text); } @NotNull @Override - public PsiClass createClassFromText(@NotNull final String body, final PsiElement context) throws IncorrectOperationException { + public PsiClass createClassFromText(@NotNull final String body, @Nullable final PsiElement context) throws IncorrectOperationException { final PsiJavaFile aFile = createDummyJavaFile(StringUtil.join("class _Dummy_ { ", body, " }")); final PsiClass[] classes = aFile.getClasses(); if (classes.length != 1) { @@ -219,7 +219,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiField createFieldFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiField createFieldFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, DECLARATION, level(context)), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); if (!(element instanceof PsiField)) { @@ -230,7 +230,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiMethod createMethodFromText(@NotNull final String text, final PsiElement context, final LanguageLevel level) throws IncorrectOperationException { + public PsiMethod createMethodFromText(@NotNull final String text, @Nullable final PsiElement context, final LanguageLevel level) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, DECLARATION, level), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); if (!(element instanceof PsiMethod)) { @@ -241,14 +241,14 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public final PsiMethod createMethodFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public final PsiMethod createMethodFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { final LanguageLevel level = LanguageLevelProjectExtension.getInstance(myManager.getProject()).getLanguageLevel(); return createMethodFromText(text, context, level); } @NotNull @Override - public PsiParameter createParameterFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiParameter createParameterFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, PARAMETER, level(context)), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); if (!(element instanceof PsiParameter)) { @@ -259,7 +259,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiResourceVariable createResourceFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiResourceVariable createResourceFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, RESOURCE, level(context)), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); if (!(element instanceof PsiResourceVariable)) { @@ -270,13 +270,13 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiType createTypeFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiType createTypeFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { return createTypeInner(text, context, false); } @NotNull @Override - public PsiTypeElement createTypeElementFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiTypeElement createTypeElementFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, TYPE, level(context)), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); if (!(element instanceof PsiTypeElement)) { @@ -285,7 +285,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ return (PsiTypeElement)element; } - protected PsiType createTypeInner(final String text, final PsiElement context, final boolean markAsCopy) throws IncorrectOperationException { + protected PsiType createTypeInner(final String text, @Nullable final PsiElement context, final boolean markAsCopy) throws IncorrectOperationException { final PsiPrimitiveType primitiveType = PRIMITIVE_TYPES.get(text); if (primitiveType != null) return primitiveType; @@ -298,7 +298,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiJavaCodeReferenceElement createReferenceFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiJavaCodeReferenceElement createReferenceFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { final boolean isStaticImport = context instanceof PsiImportStaticStatement && !((PsiImportStaticStatement)context).isOnDemand(); final boolean mayHaveDiamonds = context instanceof PsiNewExpression && @@ -314,7 +314,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiCodeBlock createCodeBlockFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiCodeBlock createCodeBlockFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, CODE_BLOCK, level(context), true), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); if (!(element instanceof PsiCodeBlock)) { @@ -325,7 +325,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiStatement createStatementFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiStatement createStatementFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, STATEMENT, level(context)), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); if (!(element instanceof PsiStatement)) { @@ -336,7 +336,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiExpression createExpressionFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiExpression createExpressionFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, EXPRESSION, level(context)), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); if (!(element instanceof PsiExpression)) { @@ -353,7 +353,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiTypeParameter createTypeParameterFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiTypeParameter createTypeParameterFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, TYPE_PARAMETER, level(context)), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); if (!(element instanceof PsiTypeParameter)) { @@ -364,7 +364,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiComment createCommentFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiComment createCommentFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { final PsiJavaFile aFile = createDummyJavaFile(text); for (PsiElement aChildren : aFile.getChildren()) { if (aChildren instanceof PsiComment) { @@ -382,7 +382,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiEnumConstant createEnumConstantFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiEnumConstant createEnumConstantFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, ENUM_CONSTANT, level(context)), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); if (!(element instanceof PsiEnumConstant)) { @@ -393,8 +393,9 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiCatchSection createCatchSection(@NotNull final PsiClassType exceptionType, @NotNull final String exceptionName, - final PsiElement context) throws IncorrectOperationException { + public PsiCatchSection createCatchSection(@NotNull final PsiClassType exceptionType, + @NotNull final String exceptionName, + @Nullable final PsiElement context) throws IncorrectOperationException { final String text = StringUtil .join("catch (", exceptionType.getCanonicalText(), " ", exceptionName, ") {}"); final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, CATCH_SECTION, level(context)), context); @@ -406,7 +407,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ return (PsiCatchSection)myManager.getCodeStyleManager().reformat(element); } - private void setupCatchBlock(final String exceptionName, final PsiElement context, final PsiCatchSection psiCatchSection) + private void setupCatchBlock(final String exceptionName, @Nullable final PsiElement context, final PsiCatchSection psiCatchSection) throws IncorrectOperationException { final FileTemplate catchBodyTemplate = FileTemplateManager.getInstance().getCodeTemplate(JavaTemplateUtil.TEMPLATE_CATCH_BODY); LOG.assertTrue(catchBodyTemplate != null); @@ -433,6 +434,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ psiCatchSection.getCatchBlock().replace(codeBlockFromText); } + @NotNull @Override public PsiType createPrimitiveType(@NotNull final String text, @NotNull final PsiAnnotation[] annotations) throws IncorrectOperationException { final PsiPrimitiveType primitiveType = getPrimitiveType(text); diff --git a/java/openapi/src/com/intellij/psi/PsiJavaParserFacade.java b/java/openapi/src/com/intellij/psi/PsiJavaParserFacade.java index 332f2f2928f2..7029a6ff4a60 100644 --- a/java/openapi/src/com/intellij/psi/PsiJavaParserFacade.java +++ b/java/openapi/src/com/intellij/psi/PsiJavaParserFacade.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.psi; import com.intellij.pom.java.LanguageLevel; @@ -22,8 +21,9 @@ import com.intellij.psi.javadoc.PsiDocTag; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -/* +/** * @author max */ public interface PsiJavaParserFacade extends PsiParserFacade { @@ -41,7 +41,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @deprecated use {@link #createDocTagFromText(String)} (to remove in IDEA 11) */ @NotNull - PsiDocTag createDocTagFromText(@NotNull String docTagText, PsiElement context) throws IncorrectOperationException; + PsiDocTag createDocTagFromText(@NotNull String docTagText, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a JavaDoc comment from the specified text. @@ -57,7 +57,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @deprecated use {@link #createDocCommentFromText(String)} (to remove in IDEA 11) */ @NotNull - PsiDocComment createDocCommentFromText(@NotNull String docCommentText, PsiElement context) throws IncorrectOperationException; + PsiDocComment createDocCommentFromText(@NotNull String docCommentText, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a Java class from the specified text. @@ -69,7 +69,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text is not a valid class body. */ @NotNull - PsiClass createClassFromText(@NotNull @NonNls String text, PsiElement context) throws IncorrectOperationException; + PsiClass createClassFromText(@NotNull @NonNls String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a Java field from the specified text. @@ -80,7 +80,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text is not a valid field body. */ @NotNull - PsiField createFieldFromText(@NotNull @NonNls String text, PsiElement context) throws IncorrectOperationException; + PsiField createFieldFromText(@NotNull @NonNls String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a Java method from the specified text with the specified language level. @@ -92,7 +92,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text is not a valid method body. */ @NotNull - PsiMethod createMethodFromText(@NotNull @NonNls String text, PsiElement context, LanguageLevel languageLevel) throws IncorrectOperationException; + PsiMethod createMethodFromText(@NotNull @NonNls String text, @Nullable PsiElement context, LanguageLevel languageLevel) throws IncorrectOperationException; /** * Creates a Java method from the specified text. @@ -103,7 +103,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text is not a valid method body. */ @NotNull - PsiMethod createMethodFromText(@NotNull @NonNls String text, PsiElement context) throws IncorrectOperationException; + PsiMethod createMethodFromText(@NotNull @NonNls String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a Java parameter from the specified text. @@ -114,7 +114,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text is not a valid parameter body. */ @NotNull - PsiParameter createParameterFromText(@NotNull @NonNls String text, PsiElement context) throws IncorrectOperationException; + PsiParameter createParameterFromText(@NotNull @NonNls String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a Java try-resource from the specified text. @@ -125,7 +125,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text is not a valid resource definition. */ @NotNull - PsiResourceVariable createResourceFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException; + PsiResourceVariable createResourceFromText(@NotNull String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a Java type from the specified text. @@ -137,7 +137,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text does not specify a valid type. */ @NotNull - PsiType createTypeFromText(@NotNull @NonNls String text, PsiElement context) throws IncorrectOperationException; + PsiType createTypeFromText(@NotNull @NonNls String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a Java type element from the specified text. @@ -149,7 +149,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text does not specify a valid type. */ @NotNull - PsiTypeElement createTypeElementFromText(@NotNull @NonNls String text, PsiElement context) throws IncorrectOperationException; + PsiTypeElement createTypeElementFromText(@NotNull @NonNls String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a Java code reference from the specified text. @@ -161,7 +161,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text does not specify a valid type. */ @NotNull - PsiJavaCodeReferenceElement createReferenceFromText(@NotNull @NonNls String text, PsiElement context) throws IncorrectOperationException; + PsiJavaCodeReferenceElement createReferenceFromText(@NotNull @NonNls String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a Java code block from the specified text. @@ -172,7 +172,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text does not specify a valid code block. */ @NotNull - PsiCodeBlock createCodeBlockFromText(@NotNull @NonNls String text, PsiElement context) throws IncorrectOperationException; + PsiCodeBlock createCodeBlockFromText(@NotNull @NonNls String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a Java statement from the specified text. @@ -183,7 +183,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text does not specify a valid statement. */ @NotNull - PsiStatement createStatementFromText(@NotNull @NonNls String text, PsiElement context) throws IncorrectOperationException; + PsiStatement createStatementFromText(@NotNull @NonNls String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a Java expression from the specified text. @@ -194,7 +194,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text does not specify a valid expression. */ @NotNull - PsiExpression createExpressionFromText(@NotNull @NonNls String text, PsiElement context) throws IncorrectOperationException; + PsiExpression createExpressionFromText(@NotNull @NonNls String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a Java comment from the specified text. @@ -205,7 +205,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text does not specify a valid comment. */ @NotNull - PsiComment createCommentFromText(@NotNull String text, PsiElement context) throws IncorrectOperationException; + PsiComment createCommentFromText(@NotNull String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a type parameter from the specified text. @@ -216,7 +216,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text does not specify a valid type parameter. */ @NotNull - PsiTypeParameter createTypeParameterFromText(@NotNull @NonNls String text, PsiElement context) throws IncorrectOperationException; + PsiTypeParameter createTypeParameterFromText(@NotNull @NonNls String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates an annotation from the specified text. @@ -227,11 +227,10 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text does not specify a valid annotation. */ @NotNull - PsiAnnotation createAnnotationFromText(@NotNull @NonNls String annotationText, PsiElement context) throws IncorrectOperationException; + PsiAnnotation createAnnotationFromText(@NotNull @NonNls String annotationText, @Nullable PsiElement context) throws IncorrectOperationException; @NotNull - PsiEnumConstant createEnumConstantFromText(@NotNull String text, PsiElement context) throws IncorrectOperationException; - + PsiEnumConstant createEnumConstantFromText(@NotNull String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a catch section for catching an exception of the specified @@ -243,8 +242,8 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @return the created catch section instance. * @throws IncorrectOperationException if some of the parameters are not valid. */ - @NotNull PsiCatchSection createCatchSection(@NotNull PsiClassType exceptionType, @NotNull String exceptionName, PsiElement context) - throws IncorrectOperationException; + @NotNull + PsiCatchSection createCatchSection(@NotNull PsiClassType exceptionType, @NotNull String exceptionName, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a Java type from the specified text. @@ -254,5 +253,6 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @return the created type instance. * @throws IncorrectOperationException if some of the parameters are not valid. */ + @NotNull PsiType createPrimitiveType(@NotNull String text, @NotNull PsiAnnotation[] annotations) throws IncorrectOperationException; } From 17c21afadfc4c686a2953f6c938902dcb0370d69 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 13 Apr 2011 18:13:44 +0200 Subject: [PATCH 078/102] Little fix in Java parser facade (correctly create class members with comments) --- .../src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java b/java/java-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java index 5dc7bdf197ce..827ae506379a 100644 --- a/java/java-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java @@ -209,7 +209,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override public PsiClass createClassFromText(@NotNull final String body, @Nullable final PsiElement context) throws IncorrectOperationException { - final PsiJavaFile aFile = createDummyJavaFile(StringUtil.join("class _Dummy_ { ", body, " }")); + final PsiJavaFile aFile = createDummyJavaFile(StringUtil.join("class _Dummy_ {\n", body, "\n}")); final PsiClass[] classes = aFile.getClasses(); if (classes.length != 1) { throw new IncorrectOperationException("Incorrect class \"" + body + "\"."); From cc68adee4ecfe59a5c90d9770ffa87891b9cf28b Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 13 Apr 2011 19:32:43 +0200 Subject: [PATCH 079/102] Cleanup --- .../move/moveMembers/MockMoveMembersOptions.java | 4 ++-- .../intellij/refactoring/BaseRefactoringProcessor.java | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/java/testFramework/src/com/intellij/refactoring/move/moveMembers/MockMoveMembersOptions.java b/java/testFramework/src/com/intellij/refactoring/move/moveMembers/MockMoveMembersOptions.java index b10bc2e57495..bc6b7473ad2b 100644 --- a/java/testFramework/src/com/intellij/refactoring/move/moveMembers/MockMoveMembersOptions.java +++ b/java/testFramework/src/com/intellij/refactoring/move/moveMembers/MockMoveMembersOptions.java @@ -17,6 +17,7 @@ package com.intellij.refactoring.move.moveMembers; import com.intellij.psi.PsiMember; import com.intellij.psi.PsiModifier; +import org.jetbrains.annotations.Nullable; import java.util.Collection; @@ -47,7 +48,7 @@ public class MockMoveMembersOptions implements MoveMembersOptions { return true; } - public void setMemberVisibility(String visibility) { + public void setMemberVisibility(@Nullable String visibility) { myMemberVisibility = visibility; } @@ -60,5 +61,4 @@ public class MockMoveMembersOptions implements MoveMembersOptions { public String getTargetClassName() { return myTargetClassName; } - } diff --git a/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java b/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java index a5670b2e26b8..d8c4d996c419 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java +++ b/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java @@ -149,7 +149,7 @@ public abstract class BaseRefactoringProcessor { final Ref refUsages = new Ref(); final Ref refErrorLanguage = new Ref(); final Ref refProcessCanceled = new Ref(); - final Ref dumbModeOccured = new Ref(); + final Ref dumbModeOccurred = new Ref(); final Runnable findUsagesRunnable = new Runnable() { public void run() { @@ -163,7 +163,7 @@ public abstract class BaseRefactoringProcessor { refProcessCanceled.set(Boolean.TRUE); } catch (IndexNotReadyException e) { - dumbModeOccured.set(Boolean.TRUE); + dumbModeOccurred.set(Boolean.TRUE); } } }; @@ -176,13 +176,12 @@ public abstract class BaseRefactoringProcessor { Messages.showErrorDialog(myProject, RefactoringBundle.message("unsupported.refs.found", refErrorLanguage.get().getDisplayName()), RefactoringBundle.message("error.title")); return; } - if (!dumbModeOccured.isNull()) { + if (!dumbModeOccurred.isNull()) { DumbService.getInstance(myProject).showDumbModeNotification("Usage search is not available until indices are ready"); return; } if (!refProcessCanceled.isNull()) { - Messages.showErrorDialog(myProject, "Index corruption detected. Please retry the refactoring - indexes will be rebuilt automatically", - RefactoringBundle.message("error.title")); + Messages.showErrorDialog(myProject, "Index corruption detected. Please retry the refactoring - indexes will be rebuilt automatically", RefactoringBundle.message("error.title")); return; } From c5adb0d74ec4bfecd6a1ece0f7dfee521945358d Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 14 Apr 2011 00:30:19 +0200 Subject: [PATCH 080/102] some logging for mysteriously failing tests --- .../util/xml/impl/FileDescriptionCachedValueProvider.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/FileDescriptionCachedValueProvider.java b/xml/dom-impl/src/com/intellij/util/xml/impl/FileDescriptionCachedValueProvider.java index 8a1f6cf54cf2..bc6b082c39be 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/FileDescriptionCachedValueProvider.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/FileDescriptionCachedValueProvider.java @@ -15,6 +15,7 @@ */ package com.intellij.util.xml.impl; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Key; @@ -68,7 +69,11 @@ class FileDescriptionCachedValueProvider implements SemEle public final DomFileElementImpl getFileElement() { if (myComputed) return myLastResult; - DomFileElementImpl result = _computeFileElement(false, getRootTag(), null); + final StringBuilder log = ApplicationManager.getApplication().isUnitTestMode() ? new StringBuilder() : null; + DomFileElementImpl result = _computeFileElement(false, getRootTag(), log); + if (log != null && result == null) { + System.out.println(log); + } synchronized (myCondition) { if (myComputed) return myLastResult; From da3c058a190f183066840ca55c0a74645c128310 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Thu, 14 Apr 2011 10:28:25 +0400 Subject: [PATCH 081/102] show warning when unable to modify --- .../lang-impl/src/com/intellij/ide/util/DeleteHandler.java | 7 ++++--- .../intellij/refactoring/inline/GenericInlineHandler.java | 2 +- .../intellij/refactoring/safeDelete/SafeDeleteHandler.java | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/util/DeleteHandler.java b/platform/lang-impl/src/com/intellij/ide/util/DeleteHandler.java index a458b57396e3..99c6273904e2 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/DeleteHandler.java +++ b/platform/lang-impl/src/com/intellij/ide/util/DeleteHandler.java @@ -31,6 +31,7 @@ import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.ex.MessagesEx; import com.intellij.openapi.vfs.VirtualFile; @@ -112,10 +113,10 @@ public class DeleteHandler { if (safeDeleteApplicable && !dumb) { DeleteDialog dialog = new DeleteDialog(project, elements, new DeleteDialog.Callback() { public void run(final DeleteDialog dialog) { - if (!CommonRefactoringUtil.checkReadOnlyStatusRecursively(project, Arrays.asList(elements))) return; + if (!CommonRefactoringUtil.checkReadOnlyStatusRecursively(project, Arrays.asList(elements), true)) return; SafeDeleteProcessor.createInstance(project, new Runnable() { public void run() { - dialog.close(DeleteDialog.CANCEL_EXIT_CODE); + dialog.close(DialogWrapper.CANCEL_EXIT_CODE); } }, elements, dialog.isSearchInComments(), dialog.isSearchInNonJava(), true).run(); } @@ -174,7 +175,7 @@ public class DeleteHandler { ArrayList readOnlyFiles = new ArrayList(); getReadOnlyVirtualFiles(virtualFile, readOnlyFiles, ftManager); - if (readOnlyFiles.size() > 0) { + if (!readOnlyFiles.isEmpty()) { int _result = Messages.showYesNoDialog(project, IdeBundle.message("prompt.directory.contains.read.only.files", virtualFile.getPresentableUrl()), IdeBundle.message("title.delete"), Messages.getQuestionIcon()); diff --git a/platform/lang-impl/src/com/intellij/refactoring/inline/GenericInlineHandler.java b/platform/lang-impl/src/com/intellij/refactoring/inline/GenericInlineHandler.java index 875bee27ff72..207d28df1ae1 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/inline/GenericInlineHandler.java +++ b/platform/lang-impl/src/com/intellij/refactoring/inline/GenericInlineHandler.java @@ -119,7 +119,7 @@ public class GenericInlineHandler { elements.add(element); } - if (!CommonRefactoringUtil.checkReadOnlyStatusRecursively(project, elements)) { + if (!CommonRefactoringUtil.checkReadOnlyStatusRecursively(project, elements, true)) { return true; } ApplicationManager.getApplication().runWriteAction(new Runnable() { diff --git a/platform/lang-impl/src/com/intellij/refactoring/safeDelete/SafeDeleteHandler.java b/platform/lang-impl/src/com/intellij/refactoring/safeDelete/SafeDeleteHandler.java index 190ba8e8c501..2f3f3db0ff6c 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/safeDelete/SafeDeleteHandler.java +++ b/platform/lang-impl/src/com/intellij/refactoring/safeDelete/SafeDeleteHandler.java @@ -96,7 +96,7 @@ public class SafeDeleteHandler implements RefactoringActionHandler { ContainerUtil.addAll(fullElementsSet, temptoDelete); } - if (!CommonRefactoringUtil.checkReadOnlyStatusRecursively(project, fullElementsSet)) return; + if (!CommonRefactoringUtil.checkReadOnlyStatusRecursively(project, fullElementsSet, true)) return; final PsiElement[] elementsToDelete = PsiUtilBase.toPsiElementArray(fullElementsSet); From 636f5cf38c859fb079da854f27cfe4ca553b2de7 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Wed, 13 Apr 2011 19:31:27 +0400 Subject: [PATCH 082/102] IDEA-67921 IDEA-65888 Mercurial installed via easy_install/pip on Windows. Root cause: the pipe symbol (|) used in changesets templates (--template) is interpreted by system in the case of such configuration and running via hg.bat). If Windows, surround the template by double-quotes. It breaks UNIX version, however, so don't do it for UNIX. Refactored all usages of --template to go through HgChangesetUtil.makeTemplate() using common separators and quoting if needed. --- .../hg4idea/command/HgChangesetsCommand.java | 9 ++-- .../hg4idea/command/HgRevisionsCommand.java | 17 ++++--- ...TrackFileNamesAccrossRevisionsCommand.java | 13 +++-- .../HgWorkingCopyRevisionsCommand.java | 7 +-- .../zmlx/hg4idea/util/HgChangesetUtil.java | 48 +++++++++++++++++++ 5 files changed, 70 insertions(+), 24 deletions(-) create mode 100644 plugins/hg4idea/src/org/zmlx/hg4idea/util/HgChangesetUtil.java diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgChangesetsCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgChangesetsCommand.java index 261fdda52a77..c8f1ad54d7e8 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgChangesetsCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgChangesetsCommand.java @@ -20,6 +20,7 @@ import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.HgRevisionNumber; import org.zmlx.hg4idea.execution.HgCommandExecutor; import org.zmlx.hg4idea.execution.HgCommandResult; +import org.zmlx.hg4idea.util.HgChangesetUtil; import java.util.ArrayList; import java.util.Arrays; @@ -33,8 +34,6 @@ public abstract class HgChangesetsCommand { private static final Logger LOG = Logger.getInstance(HgChangesetsCommand.class.getName()); - private static final String SEPARATOR_STRING = "\u0017"; //ascii: end of transmission block - protected final Project project; protected final String command; @@ -50,7 +49,7 @@ public abstract class HgChangesetsCommand { protected List getRevisions(VirtualFile repo) { List args = new ArrayList(Arrays.asList( "--template", - "{rev}|{node|short}|{author}|{desc|firstline}" + SEPARATOR_STRING, + HgChangesetUtil.makeTemplate("{rev}", "{node|short}", "{author}", "{desc|firstline}"), "--quiet" )); @@ -67,11 +66,11 @@ public abstract class HgChangesetsCommand { return Collections.emptyList(); } - String[] changesets = output.split(SEPARATOR_STRING); + String[] changesets = output.split(HgChangesetUtil.CHANGESET_SEPARATOR); List revisions = new ArrayList(changesets.length); for(String changeset: changesets) { - String[] parts = StringUtils.split(changeset, "|", 4); + String[] parts = StringUtils.split(changeset, HgChangesetUtil.ITEM_SEPARATOR, 4); if (parts.length == 4) { revisions.add(HgRevisionNumber.getInstance(parts[0], parts[1], parts[2], parts[3])); } else { diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRevisionsCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRevisionsCommand.java index 3e5ee5319ce6..ce13c6e053fa 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRevisionsCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRevisionsCommand.java @@ -23,6 +23,7 @@ import org.zmlx.hg4idea.HgFile; import org.zmlx.hg4idea.HgFileRevision; import org.zmlx.hg4idea.HgRevisionNumber; import org.zmlx.hg4idea.HgUtil; +import org.zmlx.hg4idea.util.HgChangesetUtil; import org.zmlx.hg4idea.execution.HgCommandResult; import org.zmlx.hg4idea.execution.HgCommandExecutor; @@ -33,12 +34,10 @@ import java.util.*; abstract class HgRevisionsCommand { private static final Logger LOG = Logger.getInstance(HgRevisionsCommand.class.getName()); - private static final String SEPARATOR_STRING = "\u0017"; //ascii: end of transmission block - private static final String SHORT_TEMPLATE = "{rev}|{node|short}|{parents}|{date|isodatesec}|{author}|{branches}|{desc}" + SEPARATOR_STRING; - private static final int SHORT_ITEM_COUNT = 7; - private static final String LONG_TEMPLATE = "{rev}|{node|short}|{parents}|{date|isodatesec}|{author}|{branches}|{desc}|{file_adds}|{file_mods}|{file_dels}|{file_copies}" + SEPARATOR_STRING; - private static final int LONG_ITEM_COUNT = 11; + private static final String[] SHORT_TEMPLATE_ITEMS = { "{rev}","{node|short}", "{parents}", "{date|isodatesec}", "{author}", "{branches}", "{desc}" }; + private static final String[] LONG_TEMPLATE_ITEMS = + { "{rev}", "{node|short}", "{parents}", "{date|isodatesec}", "{author}", "{branches}", "{desc}", "{file_adds}", "{file_mods}", "{file_dels}", "{file_copies}" }; private static final int REVISION_INDEX = 0; private static final int CHANGESET_INDEX = 1; @@ -73,8 +72,8 @@ abstract class HgRevisionsCommand { HgCommandExecutor hgCommandExecutor = new HgCommandExecutor(project); - String template = includeFiles ? LONG_TEMPLATE : SHORT_TEMPLATE; - int itemCount = includeFiles ? LONG_ITEM_COUNT : SHORT_ITEM_COUNT; + String template = HgChangesetUtil.makeTemplate(includeFiles ? LONG_TEMPLATE_ITEMS : SHORT_TEMPLATE_ITEMS); + int itemCount = includeFiles ? LONG_TEMPLATE_ITEMS.length : SHORT_TEMPLATE_ITEMS.length; FilePath originalFileName = HgUtil.getOriginalFileName(hgFile.toFilePath(), ChangeListManager.getInstance(project)); HgFile originalHgFile = new HgFile(hgFile.getRepo(), originalFileName); @@ -84,10 +83,10 @@ abstract class HgRevisionsCommand { List revisions = new LinkedList(); String output = result.getRawOutput(); - String[] changeSets = output.split(SEPARATOR_STRING); + String[] changeSets = output.split(HgChangesetUtil.CHANGESET_SEPARATOR); for (String line : changeSets) { try { - String[] attributes = StringUtils.splitPreserveAllTokens(line, '|'); + String[] attributes = line.split(HgChangesetUtil.ITEM_SEPARATOR); if (attributes.length != itemCount) { LOG.debug("Wrong format. Skipping line " + line); continue; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgTrackFileNamesAccrossRevisionsCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgTrackFileNamesAccrossRevisionsCommand.java index ee141ca08e9a..49e171540ebf 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgTrackFileNamesAccrossRevisionsCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgTrackFileNamesAccrossRevisionsCommand.java @@ -19,16 +19,15 @@ import org.apache.commons.lang.StringUtils; import org.zmlx.hg4idea.HgFile; import org.zmlx.hg4idea.execution.HgCommandExecutor; import org.zmlx.hg4idea.execution.HgCommandResult; +import org.zmlx.hg4idea.util.HgChangesetUtil; import java.util.*; class HgTrackFileNamesAccrossRevisionsCommand { private static final Logger LOG = Logger.getInstance(HgTrackFileNamesAccrossRevisionsCommand.class.getName()); - private static final String SEPARATOR_STRING = "\u0027"; //ascii: end of transmission block - private static final String TEMPLATE = "{rev}|{file_dels}|{file_copies}" + SEPARATOR_STRING; - private static final int ITEM_COUNT = 3; + private static final String[] TEMPLATE_ITEMS = { "{rev}", "{file_dels}", "{file_copies}" }; private static final int REVISION_INDEX = 0; private static final int FILES_DELETED_INDEX = 1; @@ -48,7 +47,7 @@ class HgTrackFileNamesAccrossRevisionsCommand { arguments.add("--follow"); arguments.add("--template"); - arguments.add(TEMPLATE); + arguments.add(HgChangesetUtil.makeTemplate(TEMPLATE_ITEMS)); if (limit != -1) { arguments.add("--limit"); @@ -69,15 +68,15 @@ class HgTrackFileNamesAccrossRevisionsCommand { HgCommandResult result = execute(hgCommandExecutor, hgFile.getRepo(), limit, hgFile, currentRevision, givenRevision); String output = result.getRawOutput(); - String[] changeSets = output.split(SEPARATOR_STRING); + String[] changeSets = output.split(HgChangesetUtil.CHANGESET_SEPARATOR); String currentFileName = hgFile.getRelativePath(); // needed on windows machines currentFileName = currentFileName.replaceAll("\\\\", "/"); for (String line : changeSets) { try { - String[] attributes = StringUtils.splitPreserveAllTokens(line, '|'); - if (attributes.length != ITEM_COUNT) { + String[] attributes = line.split(HgChangesetUtil.ITEM_SEPARATOR); + if (attributes.length != TEMPLATE_ITEMS.length) { LOG.debug("Wrong format. Skipping line " + line); continue; } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgWorkingCopyRevisionsCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgWorkingCopyRevisionsCommand.java index db4e5de1ab98..689ceb481b7d 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgWorkingCopyRevisionsCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgWorkingCopyRevisionsCommand.java @@ -25,6 +25,7 @@ import org.zmlx.hg4idea.HgRevisionNumber; import org.zmlx.hg4idea.HgUtil; import org.zmlx.hg4idea.execution.HgCommandResult; import org.zmlx.hg4idea.execution.HgCommandExecutor; +import org.zmlx.hg4idea.util.HgChangesetUtil; import java.util.ArrayList; import java.util.Arrays; @@ -165,7 +166,7 @@ public class HgWorkingCopyRevisionsCommand { boolean silent) { final List args = new LinkedList(); args.add("--template"); - args.add("{rev}|{node|short}\\n"); + args.add(HgChangesetUtil.makeTemplate("{rev}", "{node|short}")); if (revision != null) { args.add("-r"); args.add(revision.getChangeset()); @@ -180,10 +181,10 @@ public class HgWorkingCopyRevisionsCommand { if (result == null) { return new ArrayList(0); } - final List lines = result.getOutputLines(); + final List lines = Arrays.asList(result.getRawOutput().split(HgChangesetUtil.CHANGESET_SEPARATOR)); final List revisions = new ArrayList(lines.size()); for(String line: lines) { - final String[] parts = StringUtils.split(line, '|'); + final String[] parts = StringUtils.split(line, HgChangesetUtil.ITEM_SEPARATOR); revisions.add(HgRevisionNumber.getInstance(parts[0], parts[1])); } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgChangesetUtil.java b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgChangesetUtil.java new file mode 100644 index 000000000000..9118dc217fb9 --- /dev/null +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgChangesetUtil.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2011 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.zmlx.hg4idea.util; + +import com.intellij.openapi.util.SystemInfo; + +/** + * Utilities for operations involving working with a number of changesets: log, incoming, outgoing, parents, etc. + * @author Kirill Likhodedov + */ +public class HgChangesetUtil { + + public static final String CHANGESET_SEPARATOR = "\u0003"; + public static final String ITEM_SEPARATOR = "\u0017"; + + /** + * Common method for hg commands which receive templates via --template option. + * @param templateItems template items like
    {rev}
    ,
    {node}
    . + * @return items joined by ITEM_SEPARATOR, ended by CHANGESET_SEPARATOR, and, if needed (for Windows), surrounded with double-quotes. + */ + public static String makeTemplate(String... templateItems) { + StringBuilder template = new StringBuilder(); + + for (String item : templateItems) { + template.append(item).append(ITEM_SEPARATOR); + } + + template.append(CHANGESET_SEPARATOR); + if (SystemInfo.isWindows) { + return "\"" + template + "\""; + } + return template.toString(); + } + +} From 5058298f241a5c526750e03383162285ed52613f Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Wed, 13 Apr 2011 19:32:37 +0400 Subject: [PATCH 083/102] [hg] move HgUtil and HgErrorUtil to the util subpackage. --- plugins/hg4idea/src/org/zmlx/hg4idea/HgContentRevision.java | 1 + plugins/hg4idea/src/org/zmlx/hg4idea/HgFileRevision.java | 1 + plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java | 2 ++ plugins/hg4idea/src/org/zmlx/hg4idea/HgRootsHandler.java | 1 + plugins/hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java | 1 + plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java | 1 + .../src/org/zmlx/hg4idea/action/HgAbstractFilesAction.java | 2 +- .../src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java | 4 ++-- .../src/org/zmlx/hg4idea/action/HgCommandResultNotifier.java | 2 +- plugins/hg4idea/src/org/zmlx/hg4idea/action/HgInit.java | 2 +- .../hg4idea/src/org/zmlx/hg4idea/command/HgAddCommand.java | 2 +- .../hg4idea/src/org/zmlx/hg4idea/command/HgInitCommand.java | 2 +- .../hg4idea/src/org/zmlx/hg4idea/command/HgRemoveCommand.java | 2 +- .../src/org/zmlx/hg4idea/command/HgRevisionsCommand.java | 2 +- .../zmlx/hg4idea/command/HgWorkingCopyRevisionsCommand.java | 2 +- .../src/org/zmlx/hg4idea/execution/HgCommandExecutor.java | 1 + .../src/org/zmlx/hg4idea/provider/HgHistoryProvider.java | 2 +- .../src/org/zmlx/hg4idea/provider/HgMergeProvider.java | 2 +- .../src/org/zmlx/hg4idea/provider/update/HgHeadMerger.java | 2 +- plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgInitDialog.java | 2 +- .../hg4idea/src/org/zmlx/hg4idea/{ => util}/HgErrorUtil.java | 2 +- plugins/hg4idea/src/org/zmlx/hg4idea/{ => util}/HgUtil.java | 3 ++- 22 files changed, 25 insertions(+), 16 deletions(-) rename plugins/hg4idea/src/org/zmlx/hg4idea/{ => util}/HgErrorUtil.java (98%) rename plugins/hg4idea/src/org/zmlx/hg4idea/{ => util}/HgUtil.java (99%) diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgContentRevision.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgContentRevision.java index 41d1d3dfe930..d213e5703b51 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgContentRevision.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgContentRevision.java @@ -24,6 +24,7 @@ import org.apache.commons.lang.builder.HashCodeBuilder; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.command.HgCatCommand; +import org.zmlx.hg4idea.util.HgUtil; import java.io.UnsupportedEncodingException; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgFileRevision.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgFileRevision.java index 070190b7ae33..240febc364e3 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgFileRevision.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgFileRevision.java @@ -18,6 +18,7 @@ import com.intellij.openapi.vcs.history.VcsFileRevision; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.zmlx.hg4idea.command.HgCatCommand; +import org.zmlx.hg4idea.util.HgUtil; import java.io.IOException; import java.io.UnsupportedEncodingException; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java index 6d9932321be5..399290077632 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java @@ -25,6 +25,8 @@ import org.zmlx.hg4idea.command.HgPushCommand; import org.zmlx.hg4idea.execution.HgCommandResult; import org.zmlx.hg4idea.execution.HgCommandResultHandler; import org.zmlx.hg4idea.ui.HgPushDialog; +import org.zmlx.hg4idea.util.HgErrorUtil; +import org.zmlx.hg4idea.util.HgUtil; import java.util.List; import java.util.regex.Matcher; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgRootsHandler.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgRootsHandler.java index 5da62435f18a..4aef2c466071 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgRootsHandler.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgRootsHandler.java @@ -23,6 +23,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.vcsUtil.VcsUtil; import gnu.trove.THashSet; import org.jetbrains.annotations.Nullable; +import org.zmlx.hg4idea.util.HgUtil; import java.util.ArrayList; import java.util.List; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java index 0f98a89c5eca..10c8dbac9970 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java @@ -27,6 +27,7 @@ import com.intellij.util.ui.VcsBackgroundTask; import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.NotNull; import org.zmlx.hg4idea.command.*; +import org.zmlx.hg4idea.util.HgUtil; import java.util.*; import java.util.concurrent.atomic.AtomicReference; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java index a58acb43336b..0afbaf0ec6b4 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java @@ -59,6 +59,7 @@ import org.zmlx.hg4idea.provider.update.HgIntegrateEnvironment; import org.zmlx.hg4idea.provider.update.HgUpdateEnvironment; import org.zmlx.hg4idea.ui.HgChangesetStatus; import org.zmlx.hg4idea.ui.HgCurrentBranchStatus; +import org.zmlx.hg4idea.util.HgUtil; import javax.swing.*; import java.io.File; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractFilesAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractFilesAction.java index 2efb5e73116a..82e8489074a9 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractFilesAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractFilesAction.java @@ -21,7 +21,7 @@ import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vcs.TransactionRunnable; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VirtualFile; -import org.zmlx.hg4idea.HgUtil; +import org.zmlx.hg4idea.util.HgUtil; import org.zmlx.hg4idea.HgVcs; import java.lang.reflect.InvocationTargetException; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java index e752629af847..1c4e1ea0c350 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java @@ -18,7 +18,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.Nullable; -import org.zmlx.hg4idea.HgUtil; +import org.zmlx.hg4idea.util.HgUtil; import org.zmlx.hg4idea.execution.HgCommandException; import java.lang.reflect.InvocationTargetException; @@ -42,7 +42,7 @@ abstract class HgAbstractGlobalAction extends AnAction { } try { command.execute(); - HgUtil.markDirectoryDirty(project,command.getRepo()); + HgUtil.markDirectoryDirty(project, command.getRepo()); } catch (HgCommandException e) { handleException(project, e); } catch (InvocationTargetException e) { diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommandResultNotifier.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommandResultNotifier.java index 7b2aba879952..5eaa0f5bed54 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommandResultNotifier.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommandResultNotifier.java @@ -19,7 +19,7 @@ import com.intellij.openapi.project.Project; import com.intellij.vcsUtil.VcsUtil; import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.Nullable; -import org.zmlx.hg4idea.HgErrorUtil; +import org.zmlx.hg4idea.util.HgErrorUtil; import org.zmlx.hg4idea.HgVcs; import org.zmlx.hg4idea.execution.HgCommandResult; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgInit.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgInit.java index e745a7b0085e..8ab3aaa6c7e1 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgInit.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgInit.java @@ -13,7 +13,7 @@ import com.intellij.openapi.vcs.VcsDirectoryMapping; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; -import org.zmlx.hg4idea.HgUtil; +import org.zmlx.hg4idea.util.HgUtil; import org.zmlx.hg4idea.HgVcs; import org.zmlx.hg4idea.HgVcsMessages; import org.zmlx.hg4idea.command.HgInitCommand; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgAddCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgAddCommand.java index 7025c7f68227..fb2445f56450 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgAddCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgAddCommand.java @@ -16,7 +16,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.zmlx.hg4idea.HgFile; -import org.zmlx.hg4idea.HgUtil; +import org.zmlx.hg4idea.util.HgUtil; import org.zmlx.hg4idea.execution.HgCommandExecutor; import java.util.Arrays; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgInitCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgInitCommand.java index 9043571410b0..805becdf15b2 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgInitCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgInitCommand.java @@ -5,7 +5,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.zmlx.hg4idea.HgErrorUtil; +import org.zmlx.hg4idea.util.HgErrorUtil; import org.zmlx.hg4idea.execution.HgCommandExecutor; import org.zmlx.hg4idea.execution.HgCommandResult; import org.zmlx.hg4idea.execution.HgCommandResultHandler; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoveCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoveCommand.java index 6f21cff6bcbb..802e8b88fc69 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoveCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoveCommand.java @@ -16,7 +16,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.zmlx.hg4idea.HgFile; -import org.zmlx.hg4idea.HgUtil; +import org.zmlx.hg4idea.util.HgUtil; import org.zmlx.hg4idea.execution.HgCommandExecutor; import java.util.Arrays; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRevisionsCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRevisionsCommand.java index ce13c6e053fa..eaa89a78c6c0 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRevisionsCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRevisionsCommand.java @@ -22,7 +22,7 @@ import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.HgFile; import org.zmlx.hg4idea.HgFileRevision; import org.zmlx.hg4idea.HgRevisionNumber; -import org.zmlx.hg4idea.HgUtil; +import org.zmlx.hg4idea.util.HgUtil; import org.zmlx.hg4idea.util.HgChangesetUtil; import org.zmlx.hg4idea.execution.HgCommandResult; import org.zmlx.hg4idea.execution.HgCommandExecutor; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgWorkingCopyRevisionsCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgWorkingCopyRevisionsCommand.java index 689ceb481b7d..263abab6aa40 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgWorkingCopyRevisionsCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgWorkingCopyRevisionsCommand.java @@ -22,7 +22,7 @@ import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.HgRevisionNumber; -import org.zmlx.hg4idea.HgUtil; +import org.zmlx.hg4idea.util.HgUtil; import org.zmlx.hg4idea.execution.HgCommandResult; import org.zmlx.hg4idea.execution.HgCommandExecutor; import org.zmlx.hg4idea.util.HgChangesetUtil; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandExecutor.java b/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandExecutor.java index 385e390e8b77..0b974bfa4c74 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandExecutor.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandExecutor.java @@ -21,6 +21,7 @@ import com.intellij.vcsUtil.VcsUtil; import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.*; +import org.zmlx.hg4idea.util.HgErrorUtil; import javax.swing.*; import java.awt.*; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgHistoryProvider.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgHistoryProvider.java index a6690f64f6de..f19a2429102a 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgHistoryProvider.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgHistoryProvider.java @@ -23,7 +23,7 @@ import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.HgFile; import org.zmlx.hg4idea.HgFileRevision; -import org.zmlx.hg4idea.HgUtil; +import org.zmlx.hg4idea.util.HgUtil; import org.zmlx.hg4idea.command.HgLogCommand; import org.zmlx.hg4idea.command.HgWorkingCopyRevisionsCommand; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgMergeProvider.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgMergeProvider.java index 1d31179d512a..a21515c79577 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgMergeProvider.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgMergeProvider.java @@ -29,7 +29,7 @@ import org.jetbrains.annotations.NotNull; import org.zmlx.hg4idea.HgContentRevision; import org.zmlx.hg4idea.HgFile; import org.zmlx.hg4idea.HgRevisionNumber; -import org.zmlx.hg4idea.HgUtil; +import org.zmlx.hg4idea.util.HgUtil; import org.zmlx.hg4idea.command.HgResolveCommand; import org.zmlx.hg4idea.command.HgWorkingCopyRevisionsCommand; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgHeadMerger.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgHeadMerger.java index 7120af385c8d..8e710804ac44 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgHeadMerger.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgHeadMerger.java @@ -22,7 +22,7 @@ import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.zmlx.hg4idea.HgChange; import org.zmlx.hg4idea.HgFile; -import org.zmlx.hg4idea.HgUtil; +import org.zmlx.hg4idea.util.HgUtil; import org.zmlx.hg4idea.HgVcs; import org.zmlx.hg4idea.execution.HgCommandResult; import org.zmlx.hg4idea.command.HgMergeCommand; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgInitDialog.java b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgInitDialog.java index 936d99151478..281c9b860a21 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgInitDialog.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgInitDialog.java @@ -24,7 +24,7 @@ import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.Nullable; -import org.zmlx.hg4idea.HgUtil; +import org.zmlx.hg4idea.util.HgUtil; import org.zmlx.hg4idea.HgVcsMessages; import javax.swing.*; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgErrorUtil.java b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgErrorUtil.java similarity index 98% rename from plugins/hg4idea/src/org/zmlx/hg4idea/HgErrorUtil.java rename to plugins/hg4idea/src/org/zmlx/hg4idea/util/HgErrorUtil.java index a9c087df5035..6f328d14f6fe 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgErrorUtil.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgErrorUtil.java @@ -10,7 +10,7 @@ // 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.zmlx.hg4idea; +package org.zmlx.hg4idea.util; import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.Nullable; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgUtil.java b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java similarity index 99% rename from plugins/hg4idea/src/org/zmlx/hg4idea/HgUtil.java rename to plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java index 9a8c4b6fc989..2545612e5831 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgUtil.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java @@ -10,7 +10,7 @@ // 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.zmlx.hg4idea; +package org.zmlx.hg4idea.util; import com.intellij.notification.Notification; import com.intellij.notification.NotificationType; @@ -31,6 +31,7 @@ import com.intellij.util.containers.HashMap; import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.zmlx.hg4idea.*; import org.zmlx.hg4idea.command.HgRemoveCommand; import org.zmlx.hg4idea.command.HgStatusCommand; import org.zmlx.hg4idea.command.HgWorkingCopyRevisionsCommand; From c1527ea9465233bace7da35187667c3d8cb116b9 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Wed, 13 Apr 2011 19:47:05 +0400 Subject: [PATCH 084/102] [hg] don't check for incoming/outgoing changes if there is no default repository. For outgoing changes check default-push instead of default (if exists). --- .../zmlx/hg4idea/command/HgOutgoingCommand.java | 5 +++++ .../hg4idea/command/HgRemoteChangesetsCommand.java | 14 +++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgOutgoingCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgOutgoingCommand.java index a14eb43e2cac..cc045d2affd7 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgOutgoingCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgOutgoingCommand.java @@ -13,6 +13,7 @@ package org.zmlx.hg4idea.command; import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; public class HgOutgoingCommand extends HgRemoteChangesetsCommand { @@ -20,4 +21,8 @@ public class HgOutgoingCommand extends HgRemoteChangesetsCommand { super(project, "outgoing"); } + protected String getRepositoryUrl(VirtualFile repo) { + return new HgShowConfigCommand(project).getDefaultPushPath(repo); + } + } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoteChangesetsCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoteChangesetsCommand.java index 2dedb57a86cb..702e419c1ca3 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoteChangesetsCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoteChangesetsCommand.java @@ -19,6 +19,7 @@ import com.intellij.notification.Notification; import com.intellij.notification.NotificationListener; import com.intellij.notification.NotificationType; import com.intellij.notification.Notifications; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; @@ -36,6 +37,9 @@ import java.util.List; * @author Kirill Likhodedov */ public abstract class HgRemoteChangesetsCommand extends HgChangesetsCommand { + + private static final Logger LOG = Logger.getInstance(HgRemoteChangesetsCommand.class); + public HgRemoteChangesetsCommand(Project project, String command) { super(project, command); } @@ -50,9 +54,17 @@ public abstract class HgRemoteChangesetsCommand extends HgChangesetsCommand { return true; } + protected String getRepositoryUrl(VirtualFile repo) { + return new HgShowConfigCommand(project).getDefaultPath(repo); + } + @Override protected HgCommandResult executeCommand(VirtualFile repo, List args) { - String repositoryURL = new HgShowConfigCommand(project).getDefaultPath(repo); + String repositoryURL = getRepositoryUrl(repo); + if (repositoryURL == null) { + LOG.info("executeCommand no default path configured"); + return null; + } HgCommandResult result = new HgCommandExecutor(project).executeInCurrentThread(repo, command, args); if (result == HgCommandResult.CANCELLED) { final HgVcs vcs = HgVcs.getInstance(project); From f9a9d3af22e89bfd5f6e2d921980f665c6fbc74f Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Wed, 13 Apr 2011 20:16:21 +0400 Subject: [PATCH 085/102] GitUIUtil change \n by
    when displaying exception message --- plugins/git4idea/src/git4idea/ui/GitUIUtil.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/git4idea/src/git4idea/ui/GitUIUtil.java b/plugins/git4idea/src/git4idea/ui/GitUIUtil.java index 52a7ad517847..6f6c19331a20 100644 --- a/plugins/git4idea/src/git4idea/ui/GitUIUtil.java +++ b/plugins/git4idea/src/git4idea/ui/GitUIUtil.java @@ -72,7 +72,9 @@ public class GitUIUtil { } else { errorMessages = new HashSet(errors.size()); for (VcsException error : errors) { - errorMessages.addAll(Arrays.asList(error.getMessages())); + for (String message : error.getMessages()) { + errorMessages.add(message.replace("\n", "
    ")); + } } } notifyMessages(project, title, description, type, important, errorMessages); From eb7d6c5e3b91e603c52df8f193daed1a4af10b25 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Thu, 14 Apr 2011 10:48:36 +0400 Subject: [PATCH 086/102] [hg] Show actual executable in the command line (not hg.exe for hg.bat, for instance). --- .../src/org/zmlx/hg4idea/execution/HgCommandExecutor.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandExecutor.java b/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandExecutor.java index 0b974bfa4c74..b7f9cbc9cf0f 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandExecutor.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandExecutor.java @@ -181,7 +181,11 @@ public final class HgCommandExecutor { // logging to the Version Control console (without extensions and configs) private void log(String operation, List arguments, HgCommandResult result) { - final String executable = mySettings.isRunViaBash() ? "bash -c " + HgVcs.HG_EXECUTABLE_FILE_NAME : HgVcs.HG_EXECUTABLE_FILE_NAME; + String exeName; + final int lastSlashIndex = mySettings.getHgExecutable().lastIndexOf("/"); + exeName = mySettings.getHgExecutable().substring(lastSlashIndex + 1); + + final String executable = mySettings.isRunViaBash() ? "bash -c " + exeName : exeName; final String cmdString = String.format("%s %s %s", executable, operation, StringUtils.join(arguments, " ")); // log command From bf271b1a9496881c43511040db4f75d126261fae Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Thu, 14 Apr 2011 12:48:00 +0400 Subject: [PATCH 087/102] Git: split clone into atomic operations. Split clone to mkdir, init, add remote, fetch and checkout. Add notifications in the case of error. Reason: extract the remote FETCH operation, which will be handled by JGit for HTTP in futher changes. --- plugins/git4idea/src/git4idea/Git.java | 44 +++++ .../src/git4idea/actions/GitInit.java | 16 +- .../checkout/GitCheckoutProvider.java | 166 ++++++++++++------ .../src/git4idea/commands/GitHandlerUtil.java | 2 +- .../github/GithubCheckoutProvider.java | 2 +- 5 files changed, 164 insertions(+), 66 deletions(-) create mode 100644 plugins/git4idea/src/git4idea/Git.java diff --git a/plugins/git4idea/src/git4idea/Git.java b/plugins/git4idea/src/git4idea/Git.java new file mode 100644 index 000000000000..9d1c50133508 --- /dev/null +++ b/plugins/git4idea/src/git4idea/Git.java @@ -0,0 +1,44 @@ +/* + * Copyright 2000-2011 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 git4idea; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vfs.VirtualFile; +import git4idea.commands.GitCommand; +import git4idea.commands.GitHandlerUtil; +import git4idea.commands.GitLineHandler; + +/** + * Low level layer of Git commands. + * + * @author Kirill Likhodedov + */ +public class Git { + + /** + * Calls 'git init' on the specified directory. + */ + public static void init(Project project, VirtualFile root) throws VcsException { + GitLineHandler h = new GitLineHandler(project, root, GitCommand.INIT); + h.setNoSSH(true); + GitHandlerUtil.runInCurrentThread(h, null); + if (!h.errors().isEmpty()) { + throw h.errors().get(0); + } + } + +} diff --git a/plugins/git4idea/src/git4idea/actions/GitInit.java b/plugins/git4idea/src/git4idea/actions/GitInit.java index b234fb22d740..ae31838a3d88 100644 --- a/plugins/git4idea/src/git4idea/actions/GitInit.java +++ b/plugins/git4idea/src/git4idea/actions/GitInit.java @@ -28,12 +28,11 @@ import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vcs.VcsDirectoryMapping; +import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VirtualFile; +import git4idea.Git; import git4idea.GitUtil; import git4idea.GitVcs; -import git4idea.commands.GitCommand; -import git4idea.commands.GitHandlerUtil; -import git4idea.commands.GitLineHandler; import git4idea.i18n.GitBundle; import git4idea.ui.GitUIUtil; import org.jetbrains.annotations.NotNull; @@ -73,13 +72,14 @@ public class GitInit extends DumbAwareAction { return; } } - GitLineHandler h = new GitLineHandler(project, root, GitCommand.INIT); - h.setNoSSH(true); - GitHandlerUtil.doSynchronously(h, GitBundle.getString("initializing.title"), h.printableCommandLine()); - if (!h.errors().isEmpty()) { - GitUIUtil.showOperationErrors(project, h.errors(), "git init"); + + try { + Git.init(project, root); + } catch (VcsException ex) { + GitUIUtil.showOperationErrors(project, Collections.singleton(ex), "git init"); return; } + if (project.isDefault()) return; int rc = Messages.showYesNoDialog(project, GitBundle.getString("init.add.root.message"), GitBundle.getString("init.add.root.title"), Messages.getQuestionIcon()); diff --git a/plugins/git4idea/src/git4idea/checkout/GitCheckoutProvider.java b/plugins/git4idea/src/git4idea/checkout/GitCheckoutProvider.java index ee5fe42d0217..269e0c843a62 100644 --- a/plugins/git4idea/src/git4idea/checkout/GitCheckoutProvider.java +++ b/plugins/git4idea/src/git4idea/checkout/GitCheckoutProvider.java @@ -15,31 +15,39 @@ */ package git4idea.checkout; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.CheckoutProvider; +import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; -import git4idea.GitVcs; +import com.intellij.vcsUtil.VcsUtil; +import git4idea.Git; import git4idea.actions.BasicAction; -import git4idea.commands.*; -import git4idea.config.GitVersion; +import git4idea.commands.GitCommand; +import git4idea.commands.GitSimpleHandler; import git4idea.i18n.GitBundle; import git4idea.ui.GitUIUtil; +import git4idea.update.GitFetcher; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; +import java.util.concurrent.atomic.AtomicBoolean; /** * Checkout provider for the Git */ public class GitCheckoutProvider implements CheckoutProvider { - /** - * The version number since which "-v" options is supported. - */ - // TODO check if they will actually support the switch in the released 1.6.0.5 - private static final GitVersion VERBOSE_CLONE_SUPPORTED = new GitVersion(1, 6, 0, 5); + + private static final Logger LOG = Logger.getInstance(GitCheckoutProvider.class); + + public String getVcsName() { + return "_Git"; + } public void doCheckout(@NotNull final Project project, @Nullable final Listener listener) { BasicAction.saveAll(); @@ -56,64 +64,110 @@ public class GitCheckoutProvider implements CheckoutProvider { final String sourceRepositoryURL = dialog.getSourceRepositoryURL(); final String directoryName = dialog.getDirectoryName(); final String parentDirectory = dialog.getParentDirectory(); - checkout(project, listener, destinationParent, sourceRepositoryURL, directoryName, parentDirectory); + clone(project, listener, destinationParent, sourceRepositoryURL, directoryName, parentDirectory); } - public static void checkout(final Project project, - final Listener listener, - final VirtualFile destinationParent, - final String sourceRepositoryURL, - final String directoryName, - final String parentDirectory) { - final GitLineHandler handler = getCloneHandler(project, sourceRepositoryURL, new File(parentDirectory), directoryName); - GitTask task = new GitTask(project, handler, GitBundle.message("cloning.repository", sourceRepositoryURL)); - task.setProgressAnalyzer(new GitStandardProgressAnalyzer()); - task.executeAsync(new GitTaskResultHandlerAdapter() { + public static void clone(final Project project, + final Listener listener, + final VirtualFile destinationParent, + final String sourceRepositoryURL, + final String directoryName, + final String parentDirectory) { + + final AtomicBoolean cloneResult = new AtomicBoolean(); + new Task.Backgroundable(project, GitBundle.message("cloning.repository", sourceRepositoryURL)) { + @Override + public void run(@NotNull ProgressIndicator indicator) { + cloneResult.set(doClone(indicator, project, directoryName, parentDirectory, sourceRepositoryURL)); + } + @Override public void onSuccess() { - destinationParent.refresh(true, true, new Runnable() { - public void run() { - if (project.isOpen() && (!project.isDisposed()) && (!project.isDefault())) { - final VcsDirtyScopeManager mgr = VcsDirtyScopeManager.getInstance(project); - mgr.fileDirty(destinationParent); - } + if (!cloneResult.get()) { + return; + } + + destinationParent.refresh(true, true, new Runnable() { + public void run() { + if (project.isOpen() && (!project.isDisposed()) && (!project.isDefault())) { + final VcsDirtyScopeManager mgr = VcsDirtyScopeManager.getInstance(project); + mgr.fileDirty(destinationParent); } - }); - listener.directoryCheckedOut(new File(parentDirectory, directoryName)); - listener.checkoutCompleted(); + } + }); + listener.directoryCheckedOut(new File(parentDirectory, directoryName)); + listener.checkoutCompleted(); } - - @Override - protected void onFailure() { - GitUIUtil.notifyGitErrors(project, "Couldn't clone", "Couldn't clone from " + sourceRepositoryURL, handler.errors()); - } - }); + }.queue(); } - /** - * {@inheritDoc} - */ - public String getVcsName() { - return "_Git"; + private static boolean doClone(ProgressIndicator indicator, Project project, String directoryName, String parentDirectory, String sourceRepositoryURL) { + final VirtualFile root = mkdir(project, directoryName, parentDirectory); + if (root == null) { return false; } + if (!init(project, root)) { return false; } + if (!addRemote(project, root, sourceRepositoryURL)) { return false; } + if (!fetch(project, root, indicator)) { return false; } + return checkout(project, root); } - /** - * Prepare clone handler - * - * @param project a project - * @param url an url - * @param directory a base directory - * @param name a name to checkout - * @param originName origin name (ignored if null or empty string) - * @return a handler for clone operation - */ - public static GitLineHandler getCloneHandler(Project project, final String url, final File directory, final String name) { - GitLineHandler handler = new GitLineHandler(project, directory, GitCommand.CLONE); - if (VERBOSE_CLONE_SUPPORTED.isOlderOrEqual(GitVcs.getInstance(project).getVersion())) { - handler.addParameters("-v"); + private static @Nullable VirtualFile mkdir(Project project, String directoryName, String parentDirectory) { + final File dir = new File(parentDirectory, directoryName); + if (dir.exists()) { + GitUIUtil.notifyError(project, "Couldn't clone", "Directory " + dir + " already exists."); + return null; } - handler.addParameters(url, name); - handler.addProgressParameter(); - return handler; + if (!dir.mkdir()) { + GitUIUtil.notifyError(project, "Couldn't clone", "Can't create directory " + dir + ""); + return null; + } + + return VcsUtil.getVirtualFileWithRefresh(dir); } + + private static boolean init(Project project, VirtualFile root) { + try { + Git.init(project, root); + } catch (VcsException e) { + LOG.info("init ", e); + GitUIUtil.notifyError(project, "Couldn't clone", "Couldn't git init in " + root.getPresentableUrl() + "", true, e); + return false; + } + return true; + } + + private static boolean addRemote(Project project, VirtualFile root, String remoteUrl) { + final GitSimpleHandler addRemoteHandler = new GitSimpleHandler(project, root, GitCommand.REMOTE); + addRemoteHandler.setNoSSH(true); + addRemoteHandler.addParameters("add", "origin", remoteUrl); + try { + addRemoteHandler.run(); + return true; + } + catch (VcsException e) { + LOG.info("addRemote ", e); + GitUIUtil.notifyError(project, "Couldn't clone", "Couldn't add remote " + remoteUrl + "", true, e); + return false; + } + } + + private static boolean fetch(Project project, VirtualFile root, ProgressIndicator indicator) { + return new GitFetcher(project, indicator).fetch(root); + } + + private static boolean checkout(Project project, VirtualFile root) { + GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.CHECKOUT); + h.setNoSSH(true); + h.addParameters("-b", "master", "origin/master"); + try { + h.run(); + return true; + } + catch (VcsException e) { + LOG.info("checkout ", e); + GitUIUtil.notifyError(project, "Clone not completed", + "Couldn't checkout master branch.
    All changes were fetched to " + root + ".", true, e); + return false; + } + } + } diff --git a/plugins/git4idea/src/git4idea/commands/GitHandlerUtil.java b/plugins/git4idea/src/git4idea/commands/GitHandlerUtil.java index 5b16c138a697..3e9acd911347 100644 --- a/plugins/git4idea/src/git4idea/commands/GitHandlerUtil.java +++ b/plugins/git4idea/src/git4idea/commands/GitHandlerUtil.java @@ -181,7 +181,7 @@ public class GitHandlerUtil { * @param handler a handler to run * @param postStartAction an action that is executed */ - static void runInCurrentThread(final GitHandler handler, @Nullable final Runnable postStartAction) { + public static void runInCurrentThread(final GitHandler handler, @Nullable final Runnable postStartAction) { handler.runInCurrentThread(postStartAction); } diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCheckoutProvider.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCheckoutProvider.java index 4efad1a01bfd..8ec8f7b1edc4 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCheckoutProvider.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCheckoutProvider.java @@ -109,7 +109,7 @@ public class GithubCheckoutProvider implements CheckoutProvider { final String repositoryName = name; final String repositoryOwner = owner; final String checkoutUrl = host + repositoryOwner + "/" + repositoryName + ".git"; - GitCheckoutProvider.checkout(project, listener, selectedPathFile, checkoutUrl, projectName, selectedPath); + GitCheckoutProvider.clone(project, listener, selectedPathFile, checkoutUrl, projectName, selectedPath); } @Override From 040fcbbc7b55e45eb205fa38134db4ea028ab0e8 Mon Sep 17 00:00:00 2001 From: nik Date: Thu, 14 Apr 2011 12:57:57 +0400 Subject: [PATCH 088/102] move --- .../src/com/intellij/debugger/ui/DebuggerSessionTab.java | 6 +++--- .../ui/breakpoints/actions/FocusOnBreakpointAction.java | 4 ++-- .../intellij/execution/ui/layout/LayoutViewOptions.java | 6 ++---- .../src/com/intellij/xdebugger/impl/XDebugSessionImpl.java | 7 +++---- .../com/intellij/xdebugger/impl/ui/XDebugSessionTab.java | 2 +- .../intellij/xdebugger/impl/ui/XDebuggerUIConstants.java | 1 + 6 files changed, 12 insertions(+), 14 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java index 16775fddc8f3..a024d125154f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java @@ -106,7 +106,7 @@ public class DebuggerSessionTab extends DebuggerSessionTabBase implements Dispos myUi = RunnerLayoutUi.Factory.getInstance(project).create("JavaDebugger", XDebuggerBundle.message("xdebugger.default.content.title"), sessionName, this); myUi.getDefaults().initTabDefaults(0, XDebuggerBundle.message("xdebugger.debugger.tab.title"), null). - initFocusContent(DebuggerContentInfo.FRAME_CONTENT, LayoutViewOptions.BREAKPOINT_CONDITION). + initFocusContent(DebuggerContentInfo.FRAME_CONTENT, XDebuggerUIConstants.LAYOUT_VIEW_BREAKPOINT_CONDITION). initFocusContent(DebuggerContentInfo.CONSOLE_CONTENT, LayoutViewOptions.STARTUP, new LayoutAttractionPolicy.FocusOnce(false)); final DefaultActionGroup focus = new DefaultActionGroup(); @@ -478,9 +478,9 @@ public class DebuggerSessionTab extends DebuggerSessionTabBase implements Dispos private void attractFramesOnPause(final int event) { if (DebuggerSession.EVENT_PAUSE == event) { - myUi.attractBy(LayoutViewOptions.BREAKPOINT_CONDITION); + myUi.attractBy(XDebuggerUIConstants.LAYOUT_VIEW_BREAKPOINT_CONDITION); } else if (DebuggerSession.EVENT_RESUME == event) { - myUi.clearAttractionBy(LayoutViewOptions.BREAKPOINT_CONDITION); + myUi.clearAttractionBy(XDebuggerUIConstants.LAYOUT_VIEW_BREAKPOINT_CONDITION); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/FocusOnBreakpointAction.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/FocusOnBreakpointAction.java index d248c4a0db9e..91b223c613c9 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/FocusOnBreakpointAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/FocusOnBreakpointAction.java @@ -16,10 +16,10 @@ package com.intellij.debugger.ui.breakpoints.actions; import com.intellij.execution.ui.actions.AbstractFocusOnAction; -import com.intellij.execution.ui.layout.LayoutViewOptions; +import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants; public class FocusOnBreakpointAction extends AbstractFocusOnAction { public FocusOnBreakpointAction() { - super(LayoutViewOptions.BREAKPOINT_CONDITION); + super(XDebuggerUIConstants.LAYOUT_VIEW_BREAKPOINT_CONDITION); } } \ No newline at end of file diff --git a/platform/lang-api/src/com/intellij/execution/ui/layout/LayoutViewOptions.java b/platform/lang-api/src/com/intellij/execution/ui/layout/LayoutViewOptions.java index a71581ba1170..900d4b929a93 100644 --- a/platform/lang-api/src/com/intellij/execution/ui/layout/LayoutViewOptions.java +++ b/platform/lang-api/src/com/intellij/execution/ui/layout/LayoutViewOptions.java @@ -16,17 +16,15 @@ package com.intellij.execution.ui.layout; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import com.intellij.openapi.actionSystem.ActionGroup; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.ui.content.Content; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public interface LayoutViewOptions { String STARTUP = "startup"; - String BREAKPOINT_CONDITION = "breakpoint"; @NotNull LayoutViewOptions setTopToolbar(@NotNull ActionGroup actions, @NotNull String place); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java index c4f81befec53..ea8d0cfa129f 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java @@ -29,14 +29,12 @@ import com.intellij.execution.ui.ConsoleView; import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.execution.ui.RunnerLayoutUi; -import com.intellij.execution.ui.layout.LayoutViewOptions; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.application.Result; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.ToolWindowId; import com.intellij.openapi.wm.ToolWindowManager; @@ -53,6 +51,7 @@ import com.intellij.xdebugger.impl.evaluate.quick.common.ValueLookupManager; import com.intellij.xdebugger.impl.ui.DebuggerUIUtil; import com.intellij.xdebugger.impl.ui.XDebugSessionData; import com.intellij.xdebugger.impl.ui.XDebugSessionTab; +import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants; import com.intellij.xdebugger.stepping.XSmartStepIntoHandler; import com.intellij.xdebugger.stepping.XSmartStepIntoVariant; import org.jetbrains.annotations.NotNull; @@ -418,7 +417,7 @@ public class XDebugSessionImpl implements XDebugSession { UIUtil.invokeLaterIfNeeded(new Runnable() { @Override public void run() { - mySessionTab.getUi().clearAttractionBy(LayoutViewOptions.BREAKPOINT_CONDITION); + mySessionTab.getUi().clearAttractionBy(XDebuggerUIConstants.LAYOUT_VIEW_BREAKPOINT_CONDITION); } }); myDispatcher.getMulticaster().sessionResumed(); @@ -587,7 +586,7 @@ public class XDebugSessionImpl implements XDebugSession { showSessionTab(); } mySessionTab.toFront(); - mySessionTab.getUi().attractBy(LayoutViewOptions.BREAKPOINT_CONDITION); + mySessionTab.getUi().attractBy(XDebuggerUIConstants.LAYOUT_VIEW_BREAKPOINT_CONDITION); } }); myDispatcher.getMulticaster().sessionPaused(); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java index d29928bca354..d96830595c0b 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java @@ -72,7 +72,7 @@ public class XDebugSessionTab extends DebuggerSessionTabBase { myUi = RunnerLayoutUi.Factory.getInstance(project).create("Debug", "unknown!", sessionName, this); myUi.getDefaults() .initTabDefaults(0, XDebuggerBundle.message("xdebugger.debugger.tab.title"), null) - .initFocusContent(DebuggerContentInfo.FRAME_CONTENT, LayoutViewOptions.BREAKPOINT_CONDITION) + .initFocusContent(DebuggerContentInfo.FRAME_CONTENT, XDebuggerUIConstants.LAYOUT_VIEW_BREAKPOINT_CONDITION) .initFocusContent(DebuggerContentInfo.CONSOLE_CONTENT, LayoutViewOptions.STARTUP, new LayoutAttractionPolicy.FocusOnce(false)); } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerUIConstants.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerUIConstants.java index cdafa528aeea..d467eac7bea4 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerUIConstants.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerUIConstants.java @@ -50,6 +50,7 @@ public class XDebuggerUIConstants { public static final Icon WATCHES_TAB_ICON = IconLoader.getIcon("/debugger/watches.png"); public static final Icon CONSOLE_TAB_ICON = IconLoader.getIcon("/debugger/console.png"); public static final SimpleTextAttributes TYPE_ATTRIBUTES = SimpleTextAttributes.GRAY_ATTRIBUTES; + public static final String LAYOUT_VIEW_BREAKPOINT_CONDITION = "breakpoint"; private XDebuggerUIConstants() { } From f6245f2e922886f25548050f9c78dac761de912c Mon Sep 17 00:00:00 2001 From: sweinreuter Date: Tue, 12 Apr 2011 10:00:12 +0200 Subject: [PATCH 089/102] IDEA-67908 XSLT: empty XPath expression is green --- .../xslt/validation/XsltXmlAnnotator.java | 51 +++++++++++++++++++ .../lang/xpath/xslt/XsltHighlightingTest.java | 4 ++ .../xslt/highlighting/emptyExpression.xsl | 7 +++ .../xpath/xpath-view/src/META-INF/plugin.xml | 1 + 4 files changed, 63 insertions(+) create mode 100644 plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/validation/XsltXmlAnnotator.java create mode 100644 plugins/xpath/xpath-lang/testData/xslt/highlighting/emptyExpression.xsl diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/validation/XsltXmlAnnotator.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/validation/XsltXmlAnnotator.java new file mode 100644 index 000000000000..b16e944f3cf1 --- /dev/null +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/validation/XsltXmlAnnotator.java @@ -0,0 +1,51 @@ +/* + * Copyright 2006 Sascha Weinreuter + * + * 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.intellij.lang.xpath.xslt.validation; + +import com.intellij.lang.annotation.AnnotationHolder; +import com.intellij.lang.annotation.Annotator; +import com.intellij.psi.PsiElement; +import com.intellij.psi.XmlElementVisitor; +import com.intellij.psi.xml.XmlAttribute; +import com.intellij.psi.xml.XmlAttributeValue; +import org.intellij.lang.xpath.xslt.XsltSupport; +import org.jetbrains.annotations.NotNull; + +public class XsltXmlAnnotator extends XmlElementVisitor implements Annotator { + + private AnnotationHolder myHolder; + + public void annotate(@NotNull PsiElement psiElement, @NotNull AnnotationHolder holder) { + try { + myHolder = holder; + psiElement.accept(this); + } finally { + myHolder = null; + } + } + + @Override + public void visitXmlAttributeValue(XmlAttributeValue value) { + final String s = value.getValue(); + if (s == null || s.trim().length() == 0) { + final PsiElement parent = value.getParent(); + if (parent instanceof XmlAttribute && XsltSupport.isXPathAttribute((XmlAttribute)parent)) { + myHolder.createErrorAnnotation(value, "Empty XPath expression"); + } + } + super.visitXmlAttributeValue(value); + } +} diff --git a/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltHighlightingTest.java b/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltHighlightingTest.java index 88d163e738e5..9b003072ccca 100644 --- a/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltHighlightingTest.java +++ b/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltHighlightingTest.java @@ -108,6 +108,10 @@ public class XsltHighlightingTest extends TestBase { doXsltHighlighting(); } + public void testEmptyExpression() throws Throwable { + doXsltHighlighting(); + } + public void xtestPerformance() throws Throwable { myFixture.configureByFile(getTestFileName() + ".xsl"); final long l = runHighlighting(); diff --git a/plugins/xpath/xpath-lang/testData/xslt/highlighting/emptyExpression.xsl b/plugins/xpath/xpath-lang/testData/xslt/highlighting/emptyExpression.xsl new file mode 100644 index 000000000000..c21e55c459df --- /dev/null +++ b/plugins/xpath/xpath-lang/testData/xslt/highlighting/emptyExpression.xsl @@ -0,0 +1,7 @@ + + + + "" /> + + + \ No newline at end of file diff --git a/plugins/xpath/xpath-view/src/META-INF/plugin.xml b/plugins/xpath/xpath-view/src/META-INF/plugin.xml index 125f30415bf6..a1de025bb314 100644 --- a/plugins/xpath/xpath-view/src/META-INF/plugin.xml +++ b/plugins/xpath/xpath-view/src/META-INF/plugin.xml @@ -119,6 +119,7 @@ + From b30d1753dda4077f7032cb40a890950b93eb5f5b Mon Sep 17 00:00:00 2001 From: sweinreuter Date: Tue, 12 Apr 2011 14:49:06 +0200 Subject: [PATCH 090/102] EA-26861 - assert: XPathFunctionCallImpl.getQName - diagnostic info added (though probably obsolete) --- .../lang/xpath/psi/impl/XPathBinaryExpressionImpl.java | 4 ++-- .../org/intellij/lang/xpath/psi/impl/XPathElementImpl.java | 6 ++++++ .../lang/xpath/psi/impl/XPathFilterExpressionImpl.java | 2 +- .../intellij/lang/xpath/psi/impl/XPathFunctionCallImpl.java | 4 ++-- .../org/intellij/lang/xpath/psi/impl/XPathNodeTestImpl.java | 2 +- .../lang/xpath/psi/impl/XPathPrefixExpressionImpl.java | 2 +- 6 files changed, 13 insertions(+), 7 deletions(-) diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathBinaryExpressionImpl.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathBinaryExpressionImpl.java index 675d34434f3c..ebe301e369e6 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathBinaryExpressionImpl.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathBinaryExpressionImpl.java @@ -48,7 +48,7 @@ public class XPathBinaryExpressionImpl extends XPathElementImpl implements XPath public XPathElementType getOperator() { final ASTNode[] nodes = getNode().getChildren(BINARY_OPERATIONS); final XPathElementType elementType = (XPathElementType)(nodes.length > 0 ? nodes[0].getElementType() : null); - assert elementType != null; + assert elementType != null : unexpectedPsiAssertion(); return elementType; } @@ -87,7 +87,7 @@ public class XPathBinaryExpressionImpl extends XPathElementImpl implements XPath return XPath2Type.DAYTIMEDURATION; } if (sameType(lop, rop)) { - assert lop != null; + assert lop != null : unexpectedPsiAssertion(); return lop.getType(); } diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathElementImpl.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathElementImpl.java index 96c718fc5f2a..8191b98dde5e 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathElementImpl.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathElementImpl.java @@ -20,6 +20,7 @@ import com.intellij.lang.ASTNode; import com.intellij.openapi.util.NotNullLazyValue; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; +import com.intellij.psi.impl.PsiTreeDebugBuilder; import com.intellij.util.IncorrectOperationException; import org.intellij.lang.xpath.XPath2ElementTypes; import org.intellij.lang.xpath.XPathElementTypes; @@ -128,6 +129,11 @@ public class XPathElementImpl extends ASTWrapperPsiElement implements XPathEleme return getContainingFile().getXPathVersion(); } + protected String unexpectedPsiAssertion() { + final PsiTreeDebugBuilder builder = new PsiTreeDebugBuilder(); + return "Unexpected PSI structure: " + builder.psiToString(this) + "--\ninside: " + builder.psiToString(getContainingFile()); + } + @Override public final void accept(@NotNull PsiElementVisitor visitor) { if (visitor instanceof XPathElementVisitor) { diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathFilterExpressionImpl.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathFilterExpressionImpl.java index edf9aa109c75..1598f0309527 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathFilterExpressionImpl.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathFilterExpressionImpl.java @@ -51,7 +51,7 @@ public class XPathFilterExpressionImpl extends XPathElementImpl implements XPath @NotNull public XPathPredicate getPredicate() { final ASTNode[] nodes = getNode().getChildren(TokenSet.create(XPathElementTypes.PREDICATE)); - assert nodes.length == 1; + assert nodes.length == 1 : unexpectedPsiAssertion(); return (XPathPredicate)nodes[0].getPsi(); } diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathFunctionCallImpl.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathFunctionCallImpl.java index e4ad35267384..466bf6ab01fe 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathFunctionCallImpl.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathFunctionCallImpl.java @@ -76,7 +76,7 @@ public class XPathFunctionCallImpl extends XPathElementImpl implements XPathFunc public String getFunctionName() { final ASTNode node = getNameNode(); final String name = node != null ? node.getText() : null; - assert name != null; + assert name != null : unexpectedPsiAssertion(); return name; } @@ -93,7 +93,7 @@ public class XPathFunctionCallImpl extends XPathElementImpl implements XPathFunc @NotNull public PrefixedName getQName() { final ASTNode node = getNameNode(); - assert node != null; + assert node != null : unexpectedPsiAssertion(); return new PrefixedNameImpl(getPrefixNode(), node); } diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathNodeTestImpl.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathNodeTestImpl.java index 47a83f94c4a9..8837dffb776b 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathNodeTestImpl.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathNodeTestImpl.java @@ -32,7 +32,7 @@ public class XPathNodeTestImpl extends XPathElementImpl implements XPathNodeTest @NotNull public XPathStep getStep() { final XPathStep step = PsiTreeUtil.getParentOfType(this, XPathStep.class); - assert step != null; + assert step != null : unexpectedPsiAssertion(); return step; } diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathPrefixExpressionImpl.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathPrefixExpressionImpl.java index 30b1047c0261..6c18090b9b5c 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathPrefixExpressionImpl.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathPrefixExpressionImpl.java @@ -49,7 +49,7 @@ public class XPathPrefixExpressionImpl extends XPathElementImpl implements XPath public XPathElementType getOperator() { final ASTNode node = getNode().findChildByType(XPathTokenTypes.ADD_OPS); final XPathElementType elementType = (XPathElementType)(node != null ? node.getElementType() : null); - assert elementType != null; + assert elementType != null : unexpectedPsiAssertion(); return elementType; } From 9e7e22e9c65002f2cca68cdea4894e13bf90e39d Mon Sep 17 00:00:00 2001 From: sweinreuter Date: Wed, 13 Apr 2011 16:50:00 +0200 Subject: [PATCH 091/102] IDEA-67806: correctly select file for configure associations quickfix --- .../intellij/lang/xpath/xslt/context/XsltQuickFixFactory.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/context/XsltQuickFixFactory.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/context/XsltQuickFixFactory.java index 424d7a5d7c1a..31fd024313ef 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/context/XsltQuickFixFactory.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/context/XsltQuickFixFactory.java @@ -19,6 +19,8 @@ import com.intellij.codeInspection.SuppressIntentionAction; import com.intellij.openapi.project.Project; 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.util.IncorrectOperationException; import org.intellij.lang.xpath.psi.XPathExpression; import org.intellij.lang.xpath.psi.XPathNodeTest; @@ -84,7 +86,7 @@ public class XsltQuickFixFactory implements XPathQuickFixFactory { } protected void invokeImpl(final Project project, final PsiFile file) throws IncorrectOperationException { - FileAssociationsConfigurable.editAssociations(project, file); + FileAssociationsConfigurable.editAssociations(project, PsiTreeUtil.getContextOfType(file, XmlFile.class, false)); } @NotNull From dde6d653a014aec62794a307a8e74b378837b219 Mon Sep 17 00:00:00 2001 From: sweinreuter Date: Wed, 13 Apr 2011 17:05:08 +0200 Subject: [PATCH 092/102] IDEA-67806: correctly select file for configure associations quickfix --- .../associations/impl/AssociationsEditor.java | 75 ++++++++++++------- 1 file changed, 46 insertions(+), 29 deletions(-) diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/AssociationsEditor.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/AssociationsEditor.java index cb23373a85f0..79e0c91811ba 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/AssociationsEditor.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/AssociationsEditor.java @@ -10,19 +10,22 @@ import com.intellij.ide.util.treeView.NodeDescriptor; import com.intellij.ide.util.treeView.NodeRenderer; import com.intellij.ide.util.treeView.TreeState; import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.Progressive; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.DimensionService; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.IconLoader; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiManager; import com.intellij.ui.LayeredIcon; +import com.intellij.ui.TreeSpeedSearch; import com.intellij.ui.components.JBList; import com.intellij.ui.treeStructure.Tree; import com.intellij.uiDesigner.core.GridConstraints; import org.intellij.lang.xpath.xslt.XsltSupport; import org.intellij.lang.xpath.xslt.associations.FileAssociationsManager; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -34,7 +37,8 @@ import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreePath; import java.awt.*; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; class AssociationsEditor { @@ -51,7 +55,7 @@ class AssociationsEditor { private final TransactionalManager myManager; private final ProjectTreeBuilder myBuilder; - public AssociationsEditor(final Project project, TreeState oldState) { + public AssociationsEditor(final Project project, final TreeState oldState) { myManager = ((FileAssociationsManagerImpl)FileAssociationsManager.getInstance(project)).getTempManager(); final DefaultActionGroup group = new DefaultActionGroup(); @@ -62,16 +66,29 @@ class AssociationsEditor { myToolbar.add(toolbar.getComponent(), new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null)); final DefaultTreeModel treeModel = new DefaultTreeModel(new DefaultMutableTreeNode()); + myTree.setModel(treeModel); + myBuilder = new ProjectTreeBuilder(project, myTree, treeModel, new MyGroupByTypeComparator(), new MyProjectStructure(project)); - myTree.setModel(treeModel); + myTree.expandRow(0); myTree.setCellRenderer(new MyNodeRenderer(myManager)); + new TreeSpeedSearch(myTree); - if (oldState == null) { - expandTree(treeModel, project, myBuilder); - } else { - oldState.applyTo(myTree); - } + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + if (oldState == null) { + expandTree(treeModel); + } else { + oldState.applyTo(myTree); + } + } + }); + } + }); myListModel = new AssociationsModel(myTree, myManager); myListModel.addListDataListener(new ListDataListener() { @@ -103,25 +120,20 @@ class AssociationsEditor { myList.getEmptyText().setText("No associated files"); } - private void expandTree(DefaultTreeModel newModel, Project project, ProjectTreeBuilder builder) { - final TreePath rootPath = new TreePath(newModel.getRoot()); - myTree.setSelectionPath(rootPath); + private void expandTree(DefaultTreeModel newModel) { + final TreePath rootPath = new TreePath(newModel.getRoot()); - final PsiManager psiManager = PsiManager.getInstance(project); - final Set files = myManager.getAssociations().keySet(); - if (files.size() > 0) { - for (VirtualFile file : files) { - builder.select(psiManager.findFile(file), file, true); - } - } else { - final Enumeration enumeration = ((DefaultMutableTreeNode)myTree.getModel().getRoot()).children(); - while (enumeration.hasMoreElements()) { - DefaultMutableTreeNode node = (DefaultMutableTreeNode)enumeration.nextElement(); - myTree.expandPath(new TreePath(node.getPath())); - } + final Object element = myBuilder.getTreeStructure().getRootElement(); + myBuilder.batch(new Progressive() { + @Override + public void run(@NotNull ProgressIndicator indicator) { + myBuilder.expand(element, null); + myBuilder.expand(myBuilder.getTreeStructure().getChildElements(element), null); } - myTree.setSelectionPath(rootPath); - myTree.scrollRectToVisible(new Rectangle(new Point(0, 0))); + }); + + myTree.setSelectionPath(rootPath); + myTree.scrollRectToVisible(new Rectangle(new Point(0, 0))); } public TreeState getState() { @@ -169,8 +181,13 @@ class AssociationsEditor { myManager.dispose(); } - public void select(PsiFile file) { - myBuilder.select(file, file.getVirtualFile(), true); + public void select(final PsiFile file) { + myBuilder.getReady(this).doWhenDone(new Runnable() { + @Override + public void run() { + myBuilder.select(file, file.getVirtualFile(), true); + } + }); } class AddAssociationActionWrapper extends AddAssociationAction { From a19b29d535e954b2ca3f9728cdaf3ec5afceaf47 Mon Sep 17 00:00:00 2001 From: Denis Zhdanov Date: Thu, 14 Apr 2011 13:47:20 +0400 Subject: [PATCH 093/102] IDEA-67384 Emacs Tab does not work properly Added Emacs Tab functionality at python-mode (change indent level of the current line if possible) --- .../editorActions/EmacsStyleIndentAction.java | 10 +++ .../emacs/DefaultEmacsProcessingHandler.java | 34 ++++++++++ .../emacs/EmacsProcessingHandler.java | 62 +++++++++++++++++++ .../emacs/LanguageEmacsExtension.java | 32 ++++++++++ .../src/META-INF/LangExtensionPoints.xml | 2 + 5 files changed, 140 insertions(+) create mode 100644 platform/lang-impl/src/com/intellij/codeInsight/editorActions/emacs/DefaultEmacsProcessingHandler.java create mode 100644 platform/lang-impl/src/com/intellij/codeInsight/editorActions/emacs/EmacsProcessingHandler.java create mode 100644 platform/lang-impl/src/com/intellij/codeInsight/editorActions/emacs/LanguageEmacsExtension.java diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/EmacsStyleIndentAction.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/EmacsStyleIndentAction.java index bbfc43917200..7121fcbcf80e 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/EmacsStyleIndentAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/EmacsStyleIndentAction.java @@ -18,6 +18,8 @@ package com.intellij.codeInsight.editorActions; import com.intellij.codeInsight.CodeInsightActionHandler; import com.intellij.codeInsight.actions.BaseCodeInsightAction; +import com.intellij.codeInsight.editorActions.emacs.EmacsProcessingHandler; +import com.intellij.codeInsight.editorActions.emacs.LanguageEmacsExtension; import com.intellij.lang.LanguageFormatting; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; @@ -57,6 +59,14 @@ public class EmacsStyleIndentAction extends BaseCodeInsightAction implements Dum return; } + EmacsProcessingHandler emacsProcessingHandler = LanguageEmacsExtension.INSTANCE.forLanguage(file.getLanguage()); + if (emacsProcessingHandler != null) { + EmacsProcessingHandler.Result result = emacsProcessingHandler.changeIndent(project, editor, file); + if (result == EmacsProcessingHandler.Result.STOP) { + return; + } + } + final Document document = editor.getDocument(); final int startOffset = editor.getCaretModel().getOffset(); final int line = editor.offsetToLogicalPosition(startOffset).line; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/emacs/DefaultEmacsProcessingHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/emacs/DefaultEmacsProcessingHandler.java new file mode 100644 index 000000000000..63f842a369e7 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/emacs/DefaultEmacsProcessingHandler.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2011 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.editorActions.emacs; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; + +/** + * @author Denis Zhdanov + * @since 4/11/11 2:36 PM + */ +public class DefaultEmacsProcessingHandler implements EmacsProcessingHandler { + + @NotNull + @Override + public Result changeIndent(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) { + return Result.CONTINUE; + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/emacs/EmacsProcessingHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/emacs/EmacsProcessingHandler.java new file mode 100644 index 000000000000..c527150b8325 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/emacs/EmacsProcessingHandler.java @@ -0,0 +1,62 @@ +/* + * Copyright 2000-2011 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.editorActions.emacs; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; + +/** + * This interface is assumed to define general contract for Emacs-like functionality. + * + * @author Denis Zhdanov + * @since 4/11/11 1:56 PM + */ +public interface EmacsProcessingHandler { + + /** + * Enumerates possible processing results. + */ + enum Result { + /** + * Proceed to the next handler in a chain. + */ + CONTINUE, + + /** + * Stop current processing as everything is done by the current handler + */ + STOP + } + + /** + * Emacs handles Tab pressing as + * 'auto indent line' + * most of the time. However, there are extensions to this like python-mode + * that changes indentation level of the current line (makes it belong to the other code block). + *

    + * So, current method may be implemented by changing code block for the active line by changing its indentation. + * {@link Result#STOP} should be returned then. + * + * @param project current project + * @param editor current editor + * @param file current file + * @return processing result + */ + @NotNull + Result changeIndent(@NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile file); +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/emacs/LanguageEmacsExtension.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/emacs/LanguageEmacsExtension.java new file mode 100644 index 000000000000..1a7d6268b2ff --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/emacs/LanguageEmacsExtension.java @@ -0,0 +1,32 @@ +/* + * Copyright 2000-2011 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.editorActions.emacs; + +import com.intellij.lang.LanguageExtension; + +/** + * @author Denis Zhdanov + * @since 4/11/11 2:21 PM + */ +public class LanguageEmacsExtension extends LanguageExtension { + + public static final String EP_NAME = "com.intellij.lang.emacs"; + public static final LanguageEmacsExtension INSTANCE = new LanguageEmacsExtension(); + + public LanguageEmacsExtension() { + super(EP_NAME, new DefaultEmacsProcessingHandler()); + } +} diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index 05a5f7cca9d1..2f4573781ecf 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -200,6 +200,8 @@ + + From 2c2d0815b95cb3256035abeeb686ab868c9dbec9 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Thu, 14 Apr 2011 13:57:45 +0400 Subject: [PATCH 094/102] do not process jsps here --- .../com/intellij/psi/impl/file/JavaDirectoryServiceImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/psi/impl/file/JavaDirectoryServiceImpl.java b/java/java-impl/src/com/intellij/psi/impl/file/JavaDirectoryServiceImpl.java index e3d2e9b9975f..8b90ac321c85 100644 --- a/java/java-impl/src/com/intellij/psi/impl/file/JavaDirectoryServiceImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/file/JavaDirectoryServiceImpl.java @@ -62,7 +62,8 @@ public class JavaDirectoryServiceImpl extends JavaDirectoryService { List classes = null; for (PsiFile file : dir.getFiles()) { - if (file instanceof PsiClassOwner) { + FileViewProvider viewProvider = file.getViewProvider(); + if (file instanceof PsiClassOwner && file == viewProvider.getPsi(viewProvider.getBaseLanguage())) { PsiClass[] psiClasses = ((PsiClassOwner)file).getClasses(); if (psiClasses.length == 0) continue; if (classes == null) classes = new ArrayList(); From 95fcd3e30ddb74855f9ca0ad66e2eb700c435b7f Mon Sep 17 00:00:00 2001 From: Kirill Kalishev Date: Thu, 14 Apr 2011 14:11:26 +0400 Subject: [PATCH 095/102] eval deialog in statement mode - editor height fix --- .../src/com/intellij/debugger/ui/DebuggerStatementEditor.java | 1 + 1 file changed, 1 insertion(+) diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerStatementEditor.java b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerStatementEditor.java index b3a24995596d..5d16074e0706 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerStatementEditor.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerStatementEditor.java @@ -61,6 +61,7 @@ public class DebuggerStatementEditor extends DebuggerEditorImpl { return false; } }; + myEditor.setCenterByHeight(false); setLayout(new BorderLayout()); add(myEditor, BorderLayout.CENTER); From 11b6b01b94b455fc61453fc5cd33fc16109d887e Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 14 Apr 2011 12:22:24 +0200 Subject: [PATCH 096/102] don't write logs --- .../util/xml/impl/FileDescriptionCachedValueProvider.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/FileDescriptionCachedValueProvider.java b/xml/dom-impl/src/com/intellij/util/xml/impl/FileDescriptionCachedValueProvider.java index bc6b082c39be..8a1f6cf54cf2 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/FileDescriptionCachedValueProvider.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/FileDescriptionCachedValueProvider.java @@ -15,7 +15,6 @@ */ package com.intellij.util.xml.impl; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Key; @@ -69,11 +68,7 @@ class FileDescriptionCachedValueProvider implements SemEle public final DomFileElementImpl getFileElement() { if (myComputed) return myLastResult; - final StringBuilder log = ApplicationManager.getApplication().isUnitTestMode() ? new StringBuilder() : null; - DomFileElementImpl result = _computeFileElement(false, getRootTag(), log); - if (log != null && result == null) { - System.out.println(log); - } + DomFileElementImpl result = _computeFileElement(false, getRootTag(), null); synchronized (myCondition) { if (myComputed) return myLastResult; From aa9c2efb9f309baebee31862cf2dbec22bef97e5 Mon Sep 17 00:00:00 2001 From: Alexey Pegov Date: Thu, 14 Apr 2011 14:47:51 +0400 Subject: [PATCH 097/102] =?UTF-8?q?OC-607=20"Open=20xcode=20project"=20fai?= =?UTF-8?q?ls=20to=20go=20through=20directories=20with=20"=C3=A9"=20char?= =?UTF-8?q?=20in=20their=20name?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/com/intellij/ui/mac/MacFileChooserDialogImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ui/mac/MacFileChooserDialogImpl.java b/platform/platform-impl/src/com/intellij/ui/mac/MacFileChooserDialogImpl.java index effadf8b1a61..7cd2a4feeb34 100644 --- a/platform/platform-impl/src/com/intellij/ui/mac/MacFileChooserDialogImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/mac/MacFileChooserDialogImpl.java @@ -54,7 +54,7 @@ public class MacFileChooserDialogImpl implements MacFileChooserDialog { public boolean callback(ID self, String selector, ID panel, ID filename) { if (filename == null || filename.intValue() == 0) return false; final String fileName = Foundation.toStringViaUTF8(filename); - final VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByPath(fileName); + final VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByPath(fileName); return virtualFile != null && (virtualFile.isDirectory() || getDescriptor().isFileSelectable(virtualFile)); } }; @@ -63,7 +63,7 @@ public class MacFileChooserDialogImpl implements MacFileChooserDialog { public boolean callback(ID self, String selector, ID panel, ID filename) { if (filename == null || filename.intValue() == 0) return false; final String fileName = Foundation.toStringViaUTF8(filename); - final VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByPath(fileName); + final VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByPath(fileName); return virtualFile != null && (!virtualFile.isDirectory() || getDescriptor().isFileSelectable(virtualFile)); } }; From 008f210d759083b51d3a6741e3ac5de5ca42d563 Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 14 Apr 2011 13:09:43 +0200 Subject: [PATCH 098/102] fix spring test: prefer java.util.Date to java.sql.Date --- .../com/intellij/psi/util/proximity/KnownElementWeigher.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/java/java-impl/src/com/intellij/psi/util/proximity/KnownElementWeigher.java b/java/java-impl/src/com/intellij/psi/util/proximity/KnownElementWeigher.java index 7d510277860e..473735f376c9 100644 --- a/java/java-impl/src/com/intellij/psi/util/proximity/KnownElementWeigher.java +++ b/java/java-impl/src/com/intellij/psi/util/proximity/KnownElementWeigher.java @@ -32,6 +32,8 @@ public class KnownElementWeigher extends ProximityWeigher { if (element instanceof PsiClass) { @NonNls final String qname = ((PsiClass)element).getQualifiedName(); if (qname != null) { + if (qname.startsWith("java.lang")) return 4; + if (qname.startsWith("java.util")) return 3; if (qname.startsWith("java.")) return 2; if (qname.startsWith("javax.")) return 1; if (qname.startsWith("com.")) return -1; From 3975825eb4a5c9007b1761f6fd940031578923eb Mon Sep 17 00:00:00 2001 From: Sergey Evdokimov Date: Thu, 14 Apr 2011 15:29:36 +0400 Subject: [PATCH 099/102] Fix: IDEA-67827 (Smarter completion of tags) --- .../src/META-INF/XmlPlugin.xml | 2 + .../completion/XmlTagInsertHandler.java | 45 +++++-- .../intellij/xml/util/TagSetRuleProvider.java | 68 ++++++++++ .../xml/util/XmlTagRuleProviderBase.java | 125 ++++++++++++++++++ .../com/intellij/xml/XmlTagRuleProvider.java | 42 ++++++ 5 files changed, 268 insertions(+), 14 deletions(-) create mode 100644 xml/impl/src/com/intellij/xml/util/TagSetRuleProvider.java create mode 100644 xml/impl/src/com/intellij/xml/util/XmlTagRuleProviderBase.java create mode 100644 xml/openapi/src/com/intellij/xml/XmlTagRuleProvider.java diff --git a/platform/platform-resources/src/META-INF/XmlPlugin.xml b/platform/platform-resources/src/META-INF/XmlPlugin.xml index f7c41a14e2b6..dab28f21f1c0 100644 --- a/platform/platform-resources/src/META-INF/XmlPlugin.xml +++ b/platform/platform-resources/src/META-INF/XmlPlugin.xml @@ -45,6 +45,8 @@ + + diff --git a/xml/impl/src/com/intellij/codeInsight/completion/XmlTagInsertHandler.java b/xml/impl/src/com/intellij/codeInsight/completion/XmlTagInsertHandler.java index 8df86060d087..3592b78e1811 100644 --- a/xml/impl/src/com/intellij/codeInsight/completion/XmlTagInsertHandler.java +++ b/xml/impl/src/com/intellij/codeInsight/completion/XmlTagInsertHandler.java @@ -45,10 +45,7 @@ import com.intellij.psi.html.HtmlTag; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.xml.XmlTag; import com.intellij.psi.xml.XmlTokenType; -import com.intellij.xml.XmlAttributeDescriptor; -import com.intellij.xml.XmlElementDescriptor; -import com.intellij.xml.XmlElementDescriptorWithCDataContent; -import com.intellij.xml.XmlExtension; +import com.intellij.xml.*; import com.intellij.xml.actions.GenerateXmlTagAction; import com.intellij.xml.impl.schema.XmlElementDescriptorImpl; import com.intellij.xml.util.HtmlUtil; @@ -209,7 +206,7 @@ public class XmlTagInsertHandler implements InsertHandler { if (inspection != null) { StringTokenizer tokenizer = new StringTokenizer(inspection.getAdditionalEntries(0)); - notRequiredAttributes = new HashSet(1); + notRequiredAttributes = new HashSet(); while(tokenizer.hasMoreElements()) notRequiredAttributes.add(tokenizer.nextToken()); } @@ -284,22 +281,42 @@ public class XmlTagInsertHandler implements InsertHandler { else if (completionChar == ' ' && template.getSegmentsCount() == 0) { if (WebEditorOptions.getInstance().isAutomaticallyStartAttribute() && (descriptor.getAttributesDescriptors(tag).length > 0 || isTagFromHtml(tag) && !HtmlUtil.isTagWithoutAttributes(tag.getName()))) { - template.addTextSegment(" "); - template.addVariable(new MacroCallNode(new CompleteMacro()), true); - template.addTextSegment("=\""); - template.addEndVariable(); - template.addTextSegment("\""); + completeAttribute(template); return true; } } else if (completionChar == Lookup.AUTO_INSERT_SELECT_CHAR || completionChar == Lookup.NORMAL_SELECT_CHAR) { - if (WebEditorOptions.getInstance().isAutomaticallyInsertClosingTag() && - HtmlUtil.isSingleHtmlTag(tag.getName())) { - + if (WebEditorOptions.getInstance().isAutomaticallyInsertClosingTag() && HtmlUtil.isSingleHtmlTag(tag.getName())) { template.addTextSegment(tag instanceof HtmlTag ? ">" : "/>"); } else { - completeTagTail(template, descriptor, tag.getContainingFile(), tag, true); + if (needAlLeastOneAttribute(tag) && WebEditorOptions.getInstance().isAutomaticallyStartAttribute()) { + completeAttribute(template); + return true; + } + else { + completeTagTail(template, descriptor, tag.getContainingFile(), tag, true); + } + } + } + + return false; + } + + private static void completeAttribute(Template template) { + template.addTextSegment(" "); + template.addVariable(new MacroCallNode(new CompleteMacro()), true); + template.addTextSegment("=\""); + template.addEndVariable(); + template.addTextSegment("\""); + } + + private static boolean needAlLeastOneAttribute(XmlTag tag) { + for (XmlTagRuleProvider ruleProvider : XmlTagRuleProvider.EP_NAME.getExtensions()) { + for (XmlTagRuleProvider.Rule rule : ruleProvider.getTagRule(tag)) { + if (rule.needAtLeastOneAttribute(tag)) { + return true; + } } } diff --git a/xml/impl/src/com/intellij/xml/util/TagSetRuleProvider.java b/xml/impl/src/com/intellij/xml/util/TagSetRuleProvider.java new file mode 100644 index 000000000000..e4e20b9ac570 --- /dev/null +++ b/xml/impl/src/com/intellij/xml/util/TagSetRuleProvider.java @@ -0,0 +1,68 @@ +/* + * Copyright 2000-2011 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.xml.util; + +import com.intellij.psi.xml.XmlTag; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Sergey Evdokimov + */ +public abstract class TagSetRuleProvider extends XmlTagRuleProviderBase { + + private final Map map = Collections.synchronizedMap(new HashMap()); + + @Nullable + protected abstract String getNamespace(@NotNull XmlTag tag); + + protected abstract void initMap(TagsRuleMap map, @NotNull String version); + + @Override + public Rule[] getTagRule(@NotNull XmlTag tag) { + String namespace = getNamespace(tag); + if (namespace == null) return Rule.EMPTY_ARRAY; + + return getTagRule(tag, namespace); + } + + public Rule[] getTagRule(@NotNull XmlTag tag, String namespace) { + TagsRuleMap ruleMap = map.get(namespace); + if (ruleMap == null) { + ruleMap = new TagsRuleMap(); + initMap(ruleMap, namespace); + map.put(namespace, ruleMap); + } + + String tagName = tag.getLocalName(); + Rule[] rules = ruleMap.get(tagName); + if (rules == null) return Rule.EMPTY_ARRAY; + + return rules; + } + + protected static class TagsRuleMap extends HashMap { + public void add(String tagName, Rule ... rules) { + assert rules.length > 0; + Rule[] oldValue = put(tagName, rules); + assert oldValue == null; + } + } +} diff --git a/xml/impl/src/com/intellij/xml/util/XmlTagRuleProviderBase.java b/xml/impl/src/com/intellij/xml/util/XmlTagRuleProviderBase.java new file mode 100644 index 000000000000..12ec13ce9a93 --- /dev/null +++ b/xml/impl/src/com/intellij/xml/util/XmlTagRuleProviderBase.java @@ -0,0 +1,125 @@ +/* + * Copyright 2000-2011 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.xml.util; + +import com.intellij.codeInsight.daemon.impl.analysis.InsertRequiredAttributeFix; +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemHighlightType; +import com.intellij.codeInspection.ProblemsHolder; +import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; +import com.intellij.psi.tree.RoleFinder; +import com.intellij.psi.xml.XmlChildRole; +import com.intellij.psi.xml.XmlTag; +import com.intellij.xml.XmlTagRuleProvider; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public abstract class XmlTagRuleProviderBase extends XmlTagRuleProvider { + + public static RequireAttributeOneOf requireAttr(String ... oneOf) { + return new RequireAttributeOneOf(oneOf); + } + + public static IncompatiblesAttributeRule incompatible(String attribute, String ... excluded) { + return new IncompatiblesAttributeRule(attribute, excluded); + } + + public static ShouldHaveParams shouldHaveParams() { + return new ShouldHaveParams(); + } + + public static class IncompatiblesAttributeRule extends Rule { + private final String[] myExcludedAttributes; + private final String myAttribute; + + public IncompatiblesAttributeRule(String attribute, String ... excluded) { + myAttribute = attribute; + myExcludedAttributes = excluded; + } + } + + public static class ShouldHaveParams extends Rule { + @Override + public boolean needAtLeastOneAttribute(@NotNull XmlTag tag) { + return true; + } + } + + @Nullable + public static PsiElement getTagElement(RoleFinder roleFinder, XmlTag tag) { + ASTNode tagNode = tag.getNode(); + if (tagNode == null) return null; + + ASTNode nameElement = roleFinder.findChild(tagNode); + if (nameElement == null) return null; + + return nameElement.getPsi(); + } + + @Nullable + public static PsiElement getTagNameElement(XmlTag tag) { + return getTagElement(XmlChildRole.START_TAG_NAME_FINDER, tag); + } + + public static boolean isClosedTag(XmlTag tag) { + return getTagElement(XmlChildRole.EMPTY_TAG_END_FINDER, tag) != null || getTagElement(XmlChildRole.CLOSING_TAG_START_FINDER, tag) != null; + } + + public static class RequireAttributeOneOf extends ShouldHaveParams { + private final String[] myAttributeNames; + private final ProblemHighlightType myProblemHighlightType; + + public RequireAttributeOneOf(String ... attributeNames) { + myAttributeNames = attributeNames; + myProblemHighlightType = ProblemHighlightType.GENERIC_ERROR_OR_WARNING; + } + + public RequireAttributeOneOf(@NotNull ProblemHighlightType problemHighlightType, String... attributeNames) { + assert attributeNames.length > 0; + myAttributeNames = attributeNames; + myProblemHighlightType = problemHighlightType; + } + + public String[] getAttributeNames() { + return myAttributeNames; + } + + @Override + public void annotate(@NotNull XmlTag tag, ProblemsHolder holder) { + for (String attributeName : myAttributeNames) { + if (tag.getAttribute(attributeName) != null) { + return; + } + } + + if (!isClosedTag(tag)) return; + + PsiElement tagNameElement = getTagNameElement(tag); + if (tagNameElement == null) return; + + LocalQuickFix[] fixes = new LocalQuickFix[myAttributeNames.length]; + for (int i = 0; i < myAttributeNames.length; i++) { + fixes[i] = new InsertRequiredAttributeFix(tag, myAttributeNames[i], null); + } + + holder.registerProblem(tagNameElement, "Tag should have one of following attributes: " + StringUtil.join(myAttributeNames, ", "), + myProblemHighlightType, + fixes); + } + } +} diff --git a/xml/openapi/src/com/intellij/xml/XmlTagRuleProvider.java b/xml/openapi/src/com/intellij/xml/XmlTagRuleProvider.java new file mode 100644 index 000000000000..69d3bbef1951 --- /dev/null +++ b/xml/openapi/src/com/intellij/xml/XmlTagRuleProvider.java @@ -0,0 +1,42 @@ +/* + * Copyright 2000-2011 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.xml; + +import com.intellij.codeInspection.ProblemsHolder; +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.psi.xml.XmlTag; +import org.jetbrains.annotations.NotNull; + +public abstract class XmlTagRuleProvider { + + public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.xml.xmlTagRuleProvider"); + + public abstract Rule[] getTagRule(@NotNull XmlTag tag); + + public static class Rule { + + public static final Rule[] EMPTY_ARRAY = new Rule[0]; + + public void annotate(@NotNull XmlTag tag, ProblemsHolder holder) { + + } + + public boolean needAtLeastOneAttribute(@NotNull XmlTag tag) { + return false; + } + } + +} From 1bd5fb51dc7eaea5d1560f1e7ba81b1d0d8145d3 Mon Sep 17 00:00:00 2001 From: Denis Zhdanov Date: Thu, 14 Apr 2011 15:44:27 +0400 Subject: [PATCH 100/102] IDEA-68003 Java Formatter: Correct formatting of anonymous classes at method call arguments 1. Returned old indent processing for 'child block that doesn't start new line from parent block' use-case; 2. Corrected java blocks indent construction; --- .../psi/formatter/java/AbstractJavaBlock.java | 2 +- .../formatting/AbstractBlockWrapper.java | 83 ++++++++++++------- .../formatting/CompositeBlockWrapper.java | 9 ++ .../intellij/formatting/LeafBlockWrapper.java | 5 ++ 4 files changed, 66 insertions(+), 33 deletions(-) diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java index f654587578f8..aed4ec8201c2 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java @@ -1372,7 +1372,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo ); } final boolean rBrace = isRBrace(child); - Indent childIndent = rBrace ? Indent.getNoneIndent() : getCodeBlockInternalIndent(childrenIndent, true); + Indent childIndent = rBrace ? Indent.getNoneIndent() : getCodeBlockInternalIndent(childrenIndent, false); if (!rBrace && child.getElementType() == JavaElementType.CODE_BLOCK && (getBraceStyle() == CommonCodeStyleSettings.NEXT_LINE_SHIFTED || getBraceStyle() == CommonCodeStyleSettings.NEXT_LINE_SHIFTED2)) diff --git a/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java b/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java index cf0773617e46..debe73fdb099 100644 --- a/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java +++ b/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java @@ -21,13 +21,21 @@ import com.intellij.psi.codeStyle.CodeStyleSettings; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; + +import static java.util.Arrays.asList; /** * @author lesya */ public abstract class AbstractBlockWrapper { + private static final Set RELATIVE_INDENT_TYPES = new HashSet(asList( + Indent.Type.NORMAL, Indent.Type.CONTINUATION, Indent.Type.CONTINUATION_WITHOUT_FIRST + )); + protected WhiteSpace myWhiteSpace; protected CompositeBlockWrapper myParent; protected int myStart; @@ -158,41 +166,40 @@ public abstract class AbstractBlockWrapper { public IndentData getChildOffset(AbstractBlockWrapper child, CodeStyleSettings.IndentOptions options, int targetBlockStartOffset) { final boolean childStartsNewLine = child.getWhiteSpace().containsLineFeeds(); + IndentImpl.Type childIndentType = child.getIndent().getType(); IndentData childIndent; // Calculate child indent. - if (childStartsNewLine) { + if (childStartsNewLine + || (!getWhiteSpace().containsLineFeeds() && RELATIVE_INDENT_TYPES.contains(childIndentType) && indentAlreadyUsedBefore(child))) + { childIndent = getIndent(options, child, targetBlockStartOffset); } - else { - childIndent = new IndentData(0); - } - - // Enforce indent if child doesn't start new line, e.g. prefer the code below: - // void test() { - // foo("test", new Runnable() { - // public void run() { - // } - // }, - // new Runnable() { - // public void run() { - // } - // } - // ); - // } - // to this one: - // void test() { - // foo("test", new Runnable() { - // public void run() { - // } - // }, - // new Runnable() { - // public void run() { - // } - // } - // ); - // } - if (child.getIndent().isEnforceIndentToChildren() && !child.getWhiteSpace().containsLineFeeds()) { + else if (child.getIndent().isEnforceIndentToChildren() && !child.getWhiteSpace().containsLineFeeds()) { + // Enforce indent if child doesn't start new line, e.g. prefer the code below: + // void test() { + // foo("test", new Runnable() { + // public void run() { + // } + // }, + // new Runnable() { + // public void run() { + // } + // } + // ); + // } + // to this one: + // void test() { + // foo("test", new Runnable() { + // public void run() { + // } + // }, + // new Runnable() { + // public void run() { + // } + // } + // ); + // } AlignmentImpl alignment = child.getAlignment(); if (alignment != null) { // Generally, we want to handle situation like the one below: @@ -209,7 +216,7 @@ public abstract class AbstractBlockWrapper { // ); // I.e. we want 'run()' method from the first anonymous class to be aligned with the 'run()' method of the second anonymous class. - AbstractBlockWrapper anchorBlock = alignment.getOffsetRespBlockBefore(child); + AbstractBlockWrapper anchorBlock = alignment.getOffsetRespBlockBefore(child); if (anchorBlock == null) { anchorBlock = this; if (anchorBlock instanceof CompositeBlockWrapper) { @@ -224,7 +231,10 @@ public abstract class AbstractBlockWrapper { } return anchorBlock.getNumberOfSymbolsBeforeBlock(); } - childIndent = childIndent.add(getIndent(options, child, getStartOffset())); + childIndent = getIndent(options, child, getStartOffset()); + } + else { + childIndent = new IndentData(0); } // Use child indent if it's absolute and the child is contained on new line. @@ -287,6 +297,15 @@ public abstract class AbstractBlockWrapper { } } + /** + * Allows to answer if current wrapped block has a child block that is located before given block and has line feed. + * + * @param child target child block to process + * @return true if current block has a child that is located before the given block and contains line feed; + * false otherwise + */ + protected abstract boolean indentAlreadyUsedBefore(final AbstractBlockWrapper child); + /** * Allows to retrieve object that encapsulates information about number of symbols before the current block starting * from the line start. I.e. all symbols (either white space or not) between start of the line where current block begins diff --git a/platform/lang-impl/src/com/intellij/formatting/CompositeBlockWrapper.java b/platform/lang-impl/src/com/intellij/formatting/CompositeBlockWrapper.java index aaec1d4902b1..dca827b624f4 100644 --- a/platform/lang-impl/src/com/intellij/formatting/CompositeBlockWrapper.java +++ b/platform/lang-impl/src/com/intellij/formatting/CompositeBlockWrapper.java @@ -57,6 +57,15 @@ public class CompositeBlockWrapper extends AbstractBlockWrapper{ } } + @Override + protected boolean indentAlreadyUsedBefore(final AbstractBlockWrapper child) { + for (AbstractBlockWrapper childBefore : myChildren) { + if (childBefore == child) return false; + if (childBefore.getWhiteSpace().containsLineFeeds()) return true; + } + return false; + } + @Override protected IndentData getNumberOfSymbolsBeforeBlock() { if (myChildren == null || myChildren.isEmpty()) { diff --git a/platform/lang-impl/src/com/intellij/formatting/LeafBlockWrapper.java b/platform/lang-impl/src/com/intellij/formatting/LeafBlockWrapper.java index 4ee2f339dc46..99b38484192a 100644 --- a/platform/lang-impl/src/com/intellij/formatting/LeafBlockWrapper.java +++ b/platform/lang-impl/src/com/intellij/formatting/LeafBlockWrapper.java @@ -126,6 +126,11 @@ class LeafBlockWrapper extends AbstractBlockWrapper { myNextBlock = nextBlock; } + @Override + protected boolean indentAlreadyUsedBefore(final AbstractBlockWrapper child) { + return false; + } + @Override protected IndentData getNumberOfSymbolsBeforeBlock() { int spaces = getWhiteSpace().getSpaces(); From 0b6f18b18be98777d10a17b3197d2b83062eebed Mon Sep 17 00:00:00 2001 From: Alexey Pegov Date: Thu, 14 Apr 2011 15:52:56 +0400 Subject: [PATCH 101/102] remove "View as:" useless prefix in project view under Mac OS --- .../ide/projectView/impl/ProjectViewImpl.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java index 849cf1acc0ca..e00dd14a854a 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java @@ -269,17 +269,22 @@ public final class ProjectViewImpl extends ProjectView implements PersistentStat private void constructUi() { myActionGroupPanel = new JPanel(new BorderLayout()); - myLabel = new JLabel("View as:"); - if (!SystemInfo.isMac) { // See IDEADEV-41315 + myLabel = SystemInfo.isMac ? null : new JLabel("View as:"); + if (myLabel != null && !SystemInfo.isMac) { // See IDEADEV-41315 myLabel.setDisplayedMnemonic('a'); } + myCombo = new ComboBox(); myCombo.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 0)); - myLabel.setLabelFor(myCombo); final JPanel combo = new JPanel(new BorderLayout()); combo.setBorder(new EmptyBorder(4, 4, 4, 4)); - combo.add(myLabel, BorderLayout.WEST); + + if(myLabel != null) { + myLabel.setLabelFor(myCombo); + combo.add(myLabel, BorderLayout.WEST); + } + combo.add(myCombo, BorderLayout.CENTER); @@ -655,11 +660,11 @@ public final class ProjectViewImpl extends ProjectView implements PersistentStat }; private void installLabelFocusListener() { - myLabel.addFocusListener(myLabelFocusListener); + if (myLabel != null) myLabel.addFocusListener(myLabelFocusListener); } private void removeLabelFocusListener() { - myLabel.removeFocusListener(myLabelFocusListener); + if (myLabel != null) myLabel.removeFocusListener(myLabelFocusListener); } private boolean viewSelectionChanged() { From e71480a25c6a83dce12b77bd2624440a2f9dbb9e Mon Sep 17 00:00:00 2001 From: Gregory Shrago Date: Thu, 14 Apr 2011 16:46:48 +0400 Subject: [PATCH 102/102] IDEA-63340 Add "find usage" to fields in database [initial] --- .../find/findUsages/CustomUsageSearcher.java | 31 +++++++++++++++++++ .../find/findUsages/FindUsagesManager.java | 8 +++++ .../src/META-INF/LangExtensionPoints.xml | 1 + 3 files changed, 40 insertions(+) create mode 100644 platform/lang-impl/src/com/intellij/find/findUsages/CustomUsageSearcher.java diff --git a/platform/lang-impl/src/com/intellij/find/findUsages/CustomUsageSearcher.java b/platform/lang-impl/src/com/intellij/find/findUsages/CustomUsageSearcher.java new file mode 100644 index 000000000000..61b2b5f6f291 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/find/findUsages/CustomUsageSearcher.java @@ -0,0 +1,31 @@ +/* + * Copyright 2000-2011 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.find.findUsages; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.psi.PsiElement; +import com.intellij.usages.Usage; +import com.intellij.util.Processor; + +/** + * @author gregsh + */ +public abstract class CustomUsageSearcher { + public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.customUsageSearcher"); + + public abstract void processElementUsages(final PsiElement element, final Processor processor, final FindUsagesOptions options); +} diff --git a/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesManager.java b/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesManager.java index 5bff937c484d..8748875b854d 100644 --- a/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesManager.java +++ b/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesManager.java @@ -380,6 +380,14 @@ public class FindUsagesManager implements JDOMExternalizable { } }); handler.processElementUsages(element, usageInfoProcessor, options); + for (CustomUsageSearcher searcher : Extensions.getExtensions(CustomUsageSearcher.EP_NAME)) { + try { + searcher.processElementUsages(element, processor, options); + } + catch (Exception e) { + LOG.error(e); + } + } } Project project = ApplicationManager.getApplication().runReadAction(new Computable() { diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index 2f4573781ecf..6e15798e5d84 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -313,6 +313,7 @@ +