From 29487068f7500ae76cc9a385658d931fff11bdfe Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Tue, 1 Jul 2014 12:03:29 +0400 Subject: [PATCH 01/59] ResourceBundleEditor improvements: * "add property" action in editor toolbar and context menu * rename actions: rename property key, property group prefix, resource bundle base name in editor, rename resource bundle base name in project view * find usages in RB editor * delete property in RB editor * copy provider (copy key name) in RB editor --- .../rename/PsiElementRenameHandler.java | 2 +- .../InconsistentResourceBundleInspection.java | 2 +- .../messages/PropertiesBundle.properties | 12 +- .../lang/properties/EmptyResourceBundle.java | 25 ++- .../lang/properties/PropertiesUtil.java | 32 ++-- .../lang/properties/ResourceBundle.java | 18 +++ .../lang/properties/BundleNameEvaluator.java | 8 +- .../lang/properties/PropertiesImplUtil.java | 67 ++++++-- .../lang/properties/ResourceBundleImpl.java | 103 ++++++------ .../editor/ResourceBundleAsVirtualFile.java | 40 +++-- .../ResourceBundleEditorViewElement.java | 30 ++++ ...esourceBundleFileStructureViewElement.java | 31 ++-- ...rceBundlePropertyStructureViewElement.java | 29 ++-- .../ResourceBundleStructureViewModel.java | 20 +-- .../properties/editor/ResourceBundleUtil.java | 6 +- .../psi/impl/PropertiesFileImpl.java | 2 +- .../references/PropertyReferenceBase.java | 2 +- .../PropertiesFileStructureViewElement.java | 10 +- .../PropertiesFileStructureViewModel.java | 14 +- .../structureView/PropertiesPrefixGroup.java | 48 +++++- .../PropertiesSeparatorManager.java | 84 ++++------ .../PropertiesStructureViewElement.java | 10 +- .../properties/xml/XmlPropertiesFileImpl.java | 2 +- .../properties/PropertiesCoreEnvironment.java | 2 +- plugins/properties/src/META-INF/plugin.xml | 10 +- .../ResourcesFavoriteNodeProvider.java | 8 +- .../properties/editor/NewPropertyAction.java | 138 ++++++++++++++++ ...pertiesGroupingStructureViewComponent.java | 1 + .../editor/ResourceBundleEditor.java | 86 +++++----- .../editor/ResourceBundleEditorProvider.java | 6 +- .../ResourceBundleStructureViewComponent.java | 140 +++++++++++++++- .../ResourceBundleDeleteProvider.java | 2 +- .../ResourceBundleMoveProvider.java | 2 +- .../projectView/ResourceBundleNode.java | 12 +- .../refactoring/PropertyRenameHandler.java | 69 -------- .../ResourceBundleKeyRenameHandler.java | 130 --------------- .../ResourceBundleRenameHandler.java | 134 --------------- .../{ => rename}/RenamePropertyProcessor.java | 40 +++-- ...ResourceBundleFromEditorRenameHandler.java | 120 ++++++++++++++ ...rceBundleFromProjectViewRenameHandler.java | 65 ++++++++ .../rename/ResourceBundleRenameUtil.java | 152 ++++++++++++++++++ .../rename/ResourceBundleRenamer.java | 74 +++++++++ .../rename/ResourceBundleRenamerFactory.java | 64 ++++++++ .../references/I18nizeQuickFixDialog.java | 4 +- .../lang/properties/PropertiesUtilTest.java | 15 +- .../properties/ResourceBundleRenameTest.java | 51 ++++++ 46 files changed, 1286 insertions(+), 636 deletions(-) create mode 100644 plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundleEditorViewElement.java create mode 100644 plugins/properties/src/com/intellij/lang/properties/editor/NewPropertyAction.java delete mode 100644 plugins/properties/src/com/intellij/lang/properties/refactoring/PropertyRenameHandler.java delete mode 100644 plugins/properties/src/com/intellij/lang/properties/refactoring/ResourceBundleKeyRenameHandler.java delete mode 100644 plugins/properties/src/com/intellij/lang/properties/refactoring/ResourceBundleRenameHandler.java rename plugins/properties/src/com/intellij/lang/properties/refactoring/{ => rename}/RenamePropertyProcessor.java (59%) create mode 100644 plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleFromEditorRenameHandler.java create mode 100644 plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleFromProjectViewRenameHandler.java create mode 100644 plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenameUtil.java create mode 100644 plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenamer.java create mode 100644 plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenamerFactory.java create mode 100644 plugins/properties/testSrc/com/intellij/lang/properties/ResourceBundleRenameTest.java diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/PsiElementRenameHandler.java b/platform/lang-impl/src/com/intellij/refactoring/rename/PsiElementRenameHandler.java index fe34cc6c6aa6..7b200641b945 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/PsiElementRenameHandler.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/PsiElementRenameHandler.java @@ -82,7 +82,7 @@ public class PsiElementRenameHandler implements RenameHandler { } } - public static void invoke(PsiElement element, Project project, PsiElement nameSuggestionContext, Editor editor) { + public static void invoke(PsiElement element, Project project, PsiElement nameSuggestionContext, @Nullable Editor editor) { if (element != null && !canRename(project, editor, element)) { return; } diff --git a/plugins/java-i18n/src/com/intellij/codeInspection/i18n/inconsistentResourceBundle/InconsistentResourceBundleInspection.java b/plugins/java-i18n/src/com/intellij/codeInspection/i18n/inconsistentResourceBundle/InconsistentResourceBundleInspection.java index 48f4b05adfb2..1e71e5d1ce50 100644 --- a/plugins/java-i18n/src/com/intellij/codeInspection/i18n/inconsistentResourceBundle/InconsistentResourceBundleInspection.java +++ b/plugins/java-i18n/src/com/intellij/codeInspection/i18n/inconsistentResourceBundle/InconsistentResourceBundleInspection.java @@ -144,7 +144,7 @@ public class InconsistentResourceBundleInspection extends GlobalSimpleInspection ResourceBundle resourceBundle = propertiesFile.getResourceBundle(); assert visitedBundles != null; if (!visitedBundles.add(resourceBundle)) return; - List files = resourceBundle.getPropertiesFiles(manager.getProject()); + List files = resourceBundle.getPropertiesFiles(); if (files.size() < 2) return; BidirectionalMap parents = new BidirectionalMap(); for (PropertiesFile f : files) { diff --git a/plugins/properties/properties-psi-api/resources/messages/PropertiesBundle.properties b/plugins/properties/properties-psi-api/resources/messages/PropertiesBundle.properties index 0864d1e31206..06e0c2e3ae03 100644 --- a/plugins/properties/properties-psi-api/resources/messages/PropertiesBundle.properties +++ b/plugins/properties/properties-psi-api/resources/messages/PropertiesBundle.properties @@ -4,7 +4,9 @@ properties.files.file.type.description=Properties files remove.property.intention.text=Remove property rename.bundle.enter.new.resource.bundle.base.name.prompt.text=Enter new resource bundle base name rename.bundle.enter.new.resource.bundle.key.name.prompt.text=Enter new resource bundle key name +rename.bundle.enter.new.resource.bundle.section.name.prompt.text=Enter new resource bundle section name rename.resource.bundle.dialog.title=Rename Resource Bundle +rename.resource.bundle.section.dialog.title=Rename Resource Bundle Section rename.resource.bundle.key.dialog.title=Rename Resource Bundle Key properties.files.inspection.group.display.name=Properties Files unused.property.inspection.display.name=Unused Property @@ -40,4 +42,12 @@ options.properties.attribute.descriptor.property.value=Property value options.properties.attribute.descriptor.key.value.separator=Key/value separator options.properties.attribute.descriptor.comment=Comment options.properties.attribute.descriptor.valid.string.escape=Valid string escape -options.properties.attribute.descriptor.invalid.string.escape=Invalid string escape \ No newline at end of file +options.properties.attribute.descriptor.invalid.string.escape=Invalid string escape + +new.property.dialog.title=New Property Key +new.property.dialog.name.prompt.text=Enter new property key name + +resource.bundle.renamer=Rename resource bundle properties files +resource.bundle.renamer.dialog.description=Rename resource bundle properties files with the following names to: +resource.bundle.renamer.entity.name=Resource bundle +resource.bundle.renamer.option=Rename bound &resource bundle \ No newline at end of file diff --git a/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/EmptyResourceBundle.java b/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/EmptyResourceBundle.java index 17858a2ca77d..a343ad34b477 100644 --- a/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/EmptyResourceBundle.java +++ b/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/EmptyResourceBundle.java @@ -18,6 +18,7 @@ package com.intellij.lang.properties; import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiDirectory; import org.jetbrains.annotations.NotNull; import java.util.Collections; @@ -31,15 +32,29 @@ public class EmptyResourceBundle { private static class Holder { private static final ResourceBundle NULL = new ResourceBundle() { @NotNull - public List getPropertiesFiles(final Project project) { + @Override + public List getPropertiesFiles() { return Collections.emptyList(); } @NotNull - public PropertiesFile getDefaultPropertiesFile(final Project project) { + @Override + public List getPropertiesFiles(final Project project) { + return getPropertiesFiles(); + } + + @NotNull + @Override + public PropertiesFile getDefaultPropertiesFile() { throw new IllegalStateException(); } + @NotNull + @Override + public PropertiesFile getDefaultPropertiesFile(final Project project) { + return getDefaultPropertiesFile(); + } + @NotNull public String getBaseName() { return ""; @@ -49,6 +64,12 @@ public class EmptyResourceBundle { public VirtualFile getBaseDirectory() { throw new IllegalStateException(); } + + @NotNull + @Override + public Project getProject() { + throw new IllegalStateException(); + } }; } public static ResourceBundle getInstance() { diff --git a/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/PropertiesUtil.java b/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/PropertiesUtil.java index abc281f7ea82..9ccd7569aba3 100644 --- a/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/PropertiesUtil.java +++ b/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/PropertiesUtil.java @@ -24,6 +24,7 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiFile; import com.intellij.util.SmartList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -41,8 +42,16 @@ public class PropertiesUtil { private final static Locale DEFAULT_LOCALE = new Locale("", "", ""); - public static boolean isPropertyComplete(final Project project, ResourceBundle resourceBundle, String propertyName) { - List propertiesFiles = resourceBundle.getPropertiesFiles(project); + /** + * @deprecated use PropertiesUtil.isPropertyComplete(ResourceBundle resourceBundle, String propertyName) + */ + @Deprecated + public static boolean isPropertyComplete(final Project project, final ResourceBundle resourceBundle, final String propertyName) { + return isPropertyComplete(resourceBundle, propertyName); + } + + public static boolean isPropertyComplete(final ResourceBundle resourceBundle, final String propertyName) { + List propertiesFiles = resourceBundle.getPropertiesFiles(); for (PropertiesFile propertiesFile : propertiesFiles) { if (propertiesFile.findPropertyByKey(propertyName) == null) return false; } @@ -50,8 +59,13 @@ public class PropertiesUtil { } @NotNull - public static String getBaseName(@NotNull VirtualFile virtualFile) { - String name = virtualFile.getName(); + public static String getBaseName(@NotNull PsiFile file) { + return getBaseName(file.getContainingFile().getVirtualFile()); + } + + @NotNull + public static String getBaseName(@NotNull VirtualFile file) { + final String name = file.getName(); final Matcher matcher = LOCALE_PATTERN.matcher(name); final String baseNameWithExtension; if (matcher.find()) { @@ -92,10 +106,10 @@ public class PropertiesUtil { } @Nullable - public static String getFullName(final PropertiesFile psiFile) { + public static String getFullName(final PropertiesFile propertiesFile) { return ApplicationManager.getApplication().runReadAction(new NullableComputable() { public String compute() { - PsiDirectory directory = psiFile.getParent(); + PsiDirectory directory = propertiesFile.getParent(); String packageQualifiedName = getPackageQualifiedName(directory); if (packageQualifiedName == null) { return null; @@ -104,9 +118,7 @@ public class PropertiesUtil { if (qName.length() > 0) { qName.append("."); } - final VirtualFile virtualFile = psiFile.getVirtualFile(); - assert virtualFile != null; - qName.append(getBaseName(virtualFile)); + qName.append(getBaseName(propertiesFile.getContainingFile())); return qName.toString(); } }); @@ -132,7 +144,7 @@ public class PropertiesUtil { @NotNull public static List findAllProperties(Project project, @NotNull ResourceBundle resourceBundle, String key) { List result = new SmartList(); - List propertiesFiles = resourceBundle.getPropertiesFiles(project); + List propertiesFiles = resourceBundle.getPropertiesFiles(); for (PropertiesFile propertiesFile : propertiesFiles) { result.addAll(propertiesFile.findPropertiesByKey(key)); } diff --git a/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/ResourceBundle.java b/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/ResourceBundle.java index d4a43a522b04..7ea56269949d 100644 --- a/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/ResourceBundle.java +++ b/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/ResourceBundle.java @@ -26,6 +26,7 @@ import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.openapi.actionSystem.DataKey; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiDirectory; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -33,9 +34,23 @@ import java.util.List; public abstract class ResourceBundle { public static final DataKey ARRAY_DATA_KEY = DataKey.create("resource.bundle.array"); + @NotNull + public abstract List getPropertiesFiles(); + + /** + * @deprecated, use getPropertiesFiles() instead this method + */ + @Deprecated @NotNull public abstract List getPropertiesFiles(final Project project); + @NotNull + public abstract PropertiesFile getDefaultPropertiesFile(); + + /** + * @deprecated, use getDefaultPropertiesFile() instead this method + */ + @Deprecated @NotNull public abstract PropertiesFile getDefaultPropertiesFile(final Project project); @@ -44,4 +59,7 @@ public abstract class ResourceBundle { @NotNull public abstract VirtualFile getBaseDirectory(); + + @NotNull + public abstract Project getProject(); } diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/BundleNameEvaluator.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/BundleNameEvaluator.java index 43ffb513a4b2..ebe28b38b37e 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/BundleNameEvaluator.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/BundleNameEvaluator.java @@ -15,7 +15,6 @@ */ package com.intellij.lang.properties; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.Nullable; @@ -26,11 +25,6 @@ public interface BundleNameEvaluator { @Nullable public String evaluateBundleName(final PsiFile psiFile) { - final VirtualFile virtualFile = psiFile == null ? null : psiFile.getOriginalFile().getVirtualFile(); - if (virtualFile == null) { - return null; - } - final PsiDirectory directory = psiFile.getParent(); if (directory == null) { return null; @@ -43,7 +37,7 @@ public interface BundleNameEvaluator { if (qName.length() > 0) { qName.append("."); } - qName.append(PropertiesUtil.getBaseName(virtualFile)); + qName.append(PropertiesUtil.getBaseName(psiFile)); return qName.toString(); } return null; diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/PropertiesImplUtil.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/PropertiesImplUtil.java index 118437e942aa..5908219098b7 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/PropertiesImplUtil.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/PropertiesImplUtil.java @@ -23,44 +23,64 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.indexing.FileBasedIndex; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; /** * @author Konstantin Bulenkov */ public class PropertiesImplUtil extends PropertiesUtil { - public static ResourceBundle getResourceBundle(final PsiFile containingFile) { - VirtualFile virtualFile = containingFile.getVirtualFile(); - if (!containingFile.isValid() || virtualFile == null) { + + @Nullable + public static ResourceBundle getResourceBundle(@NotNull final PropertiesFile representative) { + final PsiFile containingFile = representative.getContainingFile(); + if (!containingFile.isValid()) { return EmptyResourceBundle.getInstance(); } - String baseName = getBaseName(virtualFile); - PsiDirectory directory = ApplicationManager.getApplication().runReadAction(new Computable() { + final String baseName = getBaseName(containingFile); + final PsiDirectory directory = ApplicationManager.getApplication().runReadAction(new Computable() { @Nullable public PsiDirectory compute() { return containingFile.getContainingDirectory(); }}); if (directory == null) return EmptyResourceBundle.getInstance(); - - return new ResourceBundleImpl(directory.getVirtualFile(), baseName); + return getResourceBundle(baseName, directory); } - public static boolean isPropertiesFile(VirtualFile file, Project project) { + @Nullable + private static ResourceBundle getResourceBundle(@NotNull final String baseName, @NotNull final PsiDirectory baseDirectory) { + PropertiesFile defaultPropertiesFile = null; + for (final PsiFile psiFile : baseDirectory.getFiles()) { + if (baseName.equals(getBaseName(psiFile))) { + final PropertiesFile propertiesFile = getPropertiesFile(psiFile); + if (propertiesFile != null) { + if (defaultPropertiesFile == null || defaultPropertiesFile.getName().compareTo(propertiesFile.getName()) < 0) { + defaultPropertiesFile = propertiesFile; + } + } + } + } + if (defaultPropertiesFile == null) { + return null; + } + return new ResourceBundleImpl(defaultPropertiesFile); + } + + public static boolean isPropertiesFile(@NotNull VirtualFile file, @NotNull Project project) { return getPropertiesFile(PsiManager.getInstance(project).findFile(file)) != null; } - public static boolean isPropertiesFile(PsiFile file) { + public static boolean isPropertiesFile(@Nullable PsiFile file) { return getPropertiesFile(file) != null; } @@ -70,8 +90,6 @@ public class PropertiesImplUtil extends PropertiesUtil { return file instanceof PropertiesFile ? (PropertiesFile)file : XmlPropertiesFileImpl.getPropertiesFile(file); } - - @NotNull public static List findPropertiesByKey(final Project project, final String key) { final GlobalSearchScope scope = GlobalSearchScope.allScope(project); @@ -94,4 +112,23 @@ public class PropertiesImplUtil extends PropertiesUtil { return properties; } + @Nullable + public static ResourceBundle createByUrl(final @NotNull String url, final @NotNull Project project) { + if (!url.startsWith(ResourceBundleImpl.RESOURCE_BUNDLE_PREFIX)) return null; + + final String defaultPropertiesUrl = url.substring(ResourceBundleImpl.RESOURCE_BUNDLE_PREFIX.length()); + final int idx = defaultPropertiesUrl.lastIndexOf('/'); + if (idx == -1) return null; + final String baseDirectoryName = defaultPropertiesUrl.substring(0, idx); + final String baseName = defaultPropertiesUrl.substring(idx + 1); + final VirtualFile baseDirectoryVirtualFile = VirtualFileManager.getInstance().findFileByUrl(baseDirectoryName); + if (baseDirectoryVirtualFile == null) { + return null; + } + final PsiFile baseDirectory = PsiManager.getInstance(project).findFile(baseDirectoryVirtualFile); + if (baseDirectory == null || !(baseDirectory instanceof PsiDirectory)) { + return null; + } + return getResourceBundle(baseName, (PsiDirectory)baseDirectory); + } } diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleImpl.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleImpl.java index 1ac96a96f6af..d257824166e9 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleImpl.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleImpl.java @@ -23,36 +23,32 @@ import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileManager; -import com.intellij.psi.PsiManager; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiFile; import com.intellij.util.SmartList; -import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import java.util.Comparator; import java.util.List; public class ResourceBundleImpl extends ResourceBundle { - @NonNls private static final String RESOURCE_BUNDLE_PREFIX = "resourceBundle:"; - @NotNull protected final VirtualFile myBaseDirectory; - @NotNull protected final String myBaseName; + @NonNls public static final String RESOURCE_BUNDLE_PREFIX = "resourceBundle:"; + @NotNull private final PropertiesFile myDefaultPropertiesFile; - public ResourceBundleImpl(@NotNull VirtualFile baseDirectory, @NotNull String baseName) { - myBaseDirectory = baseDirectory; - myBaseName = baseName; + public ResourceBundleImpl(@NotNull final PropertiesFile defaultPropertiesFile) { + myDefaultPropertiesFile = defaultPropertiesFile; } @NotNull - public List getPropertiesFiles(final Project project) { - VirtualFile[] children = myBaseDirectory.getChildren(); + @Override + public List getPropertiesFiles() { + PsiFile[] children = myDefaultPropertiesFile.getParent().getFiles(); + final String baseName = getBaseName(); List result = new SmartList(); - PsiManager psiManager = PsiManager.getInstance(project); - for (VirtualFile file : children) { - if (!file.isValid() || file.getExtension() == null) continue; - if (Comparing.strEqual(PropertiesUtil.getBaseName(file), myBaseName)) { - PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile(psiManager.findFile(file)); + for (PsiFile file : children) { + if (!file.isValid() || file.getVirtualFile().getExtension() == null) continue; + if (Comparing.strEqual(PropertiesUtil.getBaseName(file), baseName)) { + PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile(file); if (propertiesFile != null) { result.add(propertiesFile); } @@ -62,20 +58,38 @@ public class ResourceBundleImpl extends ResourceBundle { } @NotNull - public PropertiesFile getDefaultPropertiesFile(final Project project) { - List files = getPropertiesFiles(project); - // put default properties file first - ContainerUtil.quickSort(files, new Comparator() { - public int compare(final PropertiesFile o1, final PropertiesFile o2) { - return Comparing.compare(o1.getName(), o2.getName()); - } - }); - return files.get(0); + @Override + public List getPropertiesFiles(final Project project) { + return getPropertiesFiles(); } @NotNull + @Override + public PropertiesFile getDefaultPropertiesFile() { + return myDefaultPropertiesFile; + } + + @NotNull + @Override + public PropertiesFile getDefaultPropertiesFile(final Project project) { + return getDefaultPropertiesFile(); + } + + @NotNull + @Override public String getBaseName() { - return myBaseName; + return PropertiesUtil.getBaseName(myDefaultPropertiesFile.getContainingFile()); + } + + @NotNull + public VirtualFile getBaseDirectory() { + return myDefaultPropertiesFile.getParent().getVirtualFile(); + } + + @NotNull + @Override + public Project getProject() { + return myDefaultPropertiesFile.getProject(); } public boolean equals(final Object o) { @@ -83,42 +97,15 @@ public class ResourceBundleImpl extends ResourceBundle { if (o == null || getClass() != o.getClass()) return false; final ResourceBundleImpl resourceBundle = (ResourceBundleImpl)o; - - if (!myBaseDirectory.equals(resourceBundle.myBaseDirectory)) return false; - if (!myBaseName.equals(resourceBundle.myBaseName)) return false; - + if (!myDefaultPropertiesFile.equals(resourceBundle.myDefaultPropertiesFile)) return false; return true; } public int hashCode() { - int result = myBaseDirectory.hashCode(); - result = 29 * result + myBaseName.hashCode(); - return result; - } - - @Nullable - public static ResourceBundle createByUrl(String url) { - if (!url.startsWith(RESOURCE_BUNDLE_PREFIX)) return null; - - String defaultPropertiesUrl = url.substring(RESOURCE_BUNDLE_PREFIX.length()); - final int idx = defaultPropertiesUrl.lastIndexOf('/'); - if (idx == -1) return null; - String baseDir = defaultPropertiesUrl.substring(0, idx); - String baseName = defaultPropertiesUrl.substring(idx + 1); - VirtualFile baseDirectory = VirtualFileManager.getInstance().findFileByUrl(baseDir); - if (baseDirectory != null) { - return new ResourceBundleImpl(baseDirectory, baseName); - } - return null; + return myDefaultPropertiesFile.hashCode(); } public String getUrl() { - return RESOURCE_BUNDLE_PREFIX +getBaseDirectory() + "/" + getBaseName(); + return RESOURCE_BUNDLE_PREFIX + getBaseDirectory() + "/" + getBaseName(); } - - @NotNull - public VirtualFile getBaseDirectory() { - return myBaseDirectory; - } - } \ No newline at end of file diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundleAsVirtualFile.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundleAsVirtualFile.java index f46d207dc935..36915e7e6962 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundleAsVirtualFile.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundleAsVirtualFile.java @@ -19,31 +19,50 @@ */ package com.intellij.lang.properties.editor; +import com.intellij.ide.presentation.Presentation; +import com.intellij.lang.properties.PropertiesImplUtil; +import com.intellij.lang.properties.PropertiesUtil; import com.intellij.lang.properties.ResourceBundle; +import com.intellij.lang.properties.psi.PropertiesFile; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileSystem; +import com.intellij.psi.PsiManager; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +@Presentation(icon = "AllIcons.Nodes.ResourceBundle") public class ResourceBundleAsVirtualFile extends VirtualFile { - private final ResourceBundle myResourceBundle; + private final VirtualFile myBasePropertiesFile; - public ResourceBundleAsVirtualFile(@NotNull ResourceBundle resourceBundle) { - myResourceBundle = resourceBundle; + private ResourceBundleAsVirtualFile(@NotNull final VirtualFile basePropertiesFile) { + myBasePropertiesFile = basePropertiesFile; } @NotNull - public ResourceBundle getResourceBundle() { - return myResourceBundle; + public static ResourceBundleAsVirtualFile fromResourceBundle(final @NotNull ResourceBundle resourceBundle) { + return new ResourceBundleAsVirtualFile(resourceBundle.getDefaultPropertiesFile().getVirtualFile()); + } + + @Nullable + public ResourceBundle getResourceBundle(final Project project) { + final PsiManager psiManager = PsiManager.getInstance(project); + final PropertiesFile file = PropertiesImplUtil.getPropertiesFile(psiManager.findFile(myBasePropertiesFile)); + if (file == null) { + return null; + } + return PropertiesImplUtil.getResourceBundle(file); } @Override @NotNull public VirtualFileSystem getFileSystem() { - return myResourceBundle.getBaseDirectory().getFileSystem(); + return LocalFileSystem.getInstance(); } @Override @@ -55,7 +74,7 @@ public class ResourceBundleAsVirtualFile extends VirtualFile { @Override @NotNull public String getName() { - return myResourceBundle.getBaseName(); + return PropertiesUtil.getBaseName(myBasePropertiesFile); } public boolean equals(final Object o) { @@ -64,17 +83,18 @@ public class ResourceBundleAsVirtualFile extends VirtualFile { final ResourceBundleAsVirtualFile resourceBundleAsVirtualFile = (ResourceBundleAsVirtualFile)o; - if (!myResourceBundle.equals(resourceBundleAsVirtualFile.myResourceBundle)) return false; + if (!myBasePropertiesFile.equals(resourceBundleAsVirtualFile.myBasePropertiesFile)) return false; return true; } public int hashCode() { - return myResourceBundle.hashCode(); + return myBasePropertiesFile.hashCode(); } @Override public void rename(Object requestor, @NotNull String newName) throws IOException { + throw new UnsupportedOperationException(); } @Override @@ -94,7 +114,7 @@ public class ResourceBundleAsVirtualFile extends VirtualFile { @Override public VirtualFile getParent() { - return myResourceBundle.getBaseDirectory(); + return myBasePropertiesFile.getParent(); } @Override diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundleEditorViewElement.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundleEditorViewElement.java new file mode 100644 index 000000000000..00c21d8d3811 --- /dev/null +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundleEditorViewElement.java @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.lang.properties.editor; + + +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; + +/** + * @author Dmitry Batkovich + */ +public interface ResourceBundleEditorViewElement { + + PsiElement[] getPsiElements(@NotNull Project project); + +} diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundleFileStructureViewElement.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundleFileStructureViewElement.java index 2a1f94af4c95..25220d35311a 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundleFileStructureViewElement.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundleFileStructureViewElement.java @@ -26,6 +26,9 @@ import com.intellij.lang.properties.ResourceBundle; import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.navigation.ItemPresentation; import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -34,36 +37,35 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -public class ResourceBundleFileStructureViewElement implements StructureViewTreeElement { - private final Project myProject; +public class ResourceBundleFileStructureViewElement implements StructureViewTreeElement, ResourceBundleEditorViewElement { private final ResourceBundle myResourceBundle; - public ResourceBundleFileStructureViewElement(final Project project, final ResourceBundle resourceBundle) { - myProject = project; + public ResourceBundleFileStructureViewElement(final ResourceBundle resourceBundle) { myResourceBundle = resourceBundle; } + @Override public ResourceBundle getValue() { return myResourceBundle; } @NotNull public StructureViewTreeElement[] getChildren() { - List propertiesFiles = myResourceBundle.getPropertiesFiles(myProject); + List propertiesFiles = myResourceBundle.getPropertiesFiles(); Map propertyNames = new LinkedHashMap(); for (PropertiesFile propertiesFile : propertiesFiles) { List properties = propertiesFile.getProperties(); for (IProperty property : properties) { - String name = property.getUnescapedKey(); + String name = property.getKey(); if (!propertyNames.containsKey(name)) { propertyNames.put(name, property); } } } List result = new ArrayList(propertyNames.size()); - for (String property : propertyNames.keySet()) { - //result.add(new PropertiesStructureViewElement(property)); - result.add(new ResourceBundlePropertyStructureViewElement(myProject, myResourceBundle, property)); + for (Map.Entry propertyEntry : propertyNames.entrySet()) { + //result.add(new PropertiesStructureViewElement(propertyEntry)); + result.add(new ResourceBundlePropertyStructureViewElement(myResourceBundle, propertyEntry.getValue())); } return result.toArray(new StructureViewTreeElement[result.size()]); } @@ -85,6 +87,17 @@ public class ResourceBundleFileStructureViewElement implements StructureViewTree }; } + @Override + public PsiElement[] getPsiElements(@NotNull Project project) { + final List propertiesFiles = getValue().getPropertiesFiles(); + return ContainerUtil.map2Array(propertiesFiles, new PsiElement[propertiesFiles.size()], new Function() { + @Override + public PsiElement fun(PropertiesFile propertiesFile) { + return propertiesFile.getContainingFile(); + } + }); + } + public void navigate(boolean requestFocus) { } diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundlePropertyStructureViewElement.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundlePropertyStructureViewElement.java index e521047cb9ba..8b387e802597 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundlePropertyStructureViewElement.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundlePropertyStructureViewElement.java @@ -20,6 +20,7 @@ package com.intellij.lang.properties.editor; import com.intellij.ide.structureView.StructureViewTreeElement; +import com.intellij.lang.properties.IProperty; import com.intellij.lang.properties.PropertiesHighlighter; import com.intellij.lang.properties.PropertiesUtil; import com.intellij.lang.properties.ResourceBundle; @@ -29,16 +30,16 @@ import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.TextAttributesKey; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; import com.intellij.util.PlatformIcons; import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; -public class ResourceBundlePropertyStructureViewElement implements StructureViewTreeElement { - private final String myPropertyName; - private final Project myProject; +public class ResourceBundlePropertyStructureViewElement implements StructureViewTreeElement, ResourceBundleEditorViewElement { private final ResourceBundle myResourceBundle; + private final IProperty myProperty; private String myPresentableName; private static final TextAttributesKey INCOMPLETE_PROPERTY_KEY; @@ -49,10 +50,19 @@ public class ResourceBundlePropertyStructureViewElement implements StructureView INCOMPLETE_PROPERTY_KEY = TextAttributesKey.createTextAttributesKey("INCOMPLETE_PROPERTY_KEY", textAttributes); } - public ResourceBundlePropertyStructureViewElement(final Project project, final ResourceBundle resourceBundle, String propertyName) { - myProject = project; + + public ResourceBundlePropertyStructureViewElement(final ResourceBundle resourceBundle, final IProperty property) { myResourceBundle = resourceBundle; - myPropertyName = propertyName; + myProperty = property; + } + + public IProperty getProperty() { + return myProperty; + } + + @Override + public PsiElement[] getPsiElements(final @NotNull Project project) { + return new PsiElement[] {getProperty().getPsiElement()}; } public void setPresentableName(final String presentableName) { @@ -61,7 +71,7 @@ public class ResourceBundlePropertyStructureViewElement implements StructureView @Override public String getValue() { - return myPropertyName; + return myProperty.getName(); } @Override @@ -76,7 +86,7 @@ public class ResourceBundlePropertyStructureViewElement implements StructureView return new ColoredItemPresentation() { @Override public String getPresentableText() { - return myPresentableName == null ? myPropertyName : myPresentableName; + return myPresentableName == null ? myProperty.getName() : myPresentableName; } @Override @@ -91,7 +101,7 @@ public class ResourceBundlePropertyStructureViewElement implements StructureView @Override public TextAttributesKey getTextAttributesKey() { - boolean isComplete = PropertiesUtil.isPropertyComplete(myProject, myResourceBundle, myPropertyName); + boolean isComplete = PropertiesUtil.isPropertyComplete(myResourceBundle, myProperty.getName()); if (isComplete) { return PropertiesHighlighter.PROPERTY_KEY; @@ -115,5 +125,4 @@ public class ResourceBundlePropertyStructureViewElement implements StructureView public boolean canNavigateToSource() { return false; } - } diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundleStructureViewModel.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundleStructureViewModel.java index 24ba3c513c38..fc1aa60d4ac9 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundleStructureViewModel.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundleStructureViewModel.java @@ -25,7 +25,6 @@ import com.intellij.ide.util.treeView.smartTree.Sorter; import com.intellij.lang.properties.ResourceBundle; import com.intellij.lang.properties.structureView.GroupByWordPrefixes; import com.intellij.lang.properties.structureView.PropertiesSeparatorManager; -import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; /** @@ -33,23 +32,24 @@ import org.jetbrains.annotations.NotNull; */ public class ResourceBundleStructureViewModel implements PropertiesGroupingStructureViewModel, StructureViewModel.ExpandInfoProvider { private final ResourceBundle myResourceBundle; - private final GroupByWordPrefixes myGroupByWordPrefixes; + private final GroupByWordPrefixes myByWordPrefixesGrouper; private final StructureViewTreeElement myRoot; - public ResourceBundleStructureViewModel(final Project project, ResourceBundle root) { + public ResourceBundleStructureViewModel(ResourceBundle root) { myResourceBundle = root; - String separator = PropertiesSeparatorManager.getInstance().getSeparator(project, new ResourceBundleAsVirtualFile(myResourceBundle)); - myGroupByWordPrefixes = new GroupByWordPrefixes(separator); - myRoot = new ResourceBundleFileStructureViewElement(project, myResourceBundle); + String separator = PropertiesSeparatorManager.getInstance(root.getProject()). + getSeparator(myResourceBundle); + myByWordPrefixesGrouper = new GroupByWordPrefixes(separator); + myRoot = new ResourceBundleFileStructureViewElement(myResourceBundle); } public void setSeparator(String separator) { - myGroupByWordPrefixes.setSeparator(separator); - PropertiesSeparatorManager.getInstance().setSeparator(new ResourceBundleAsVirtualFile(myResourceBundle), separator); + myByWordPrefixesGrouper.setSeparator(separator); + PropertiesSeparatorManager.getInstance(myResourceBundle.getProject()).setSeparator(myResourceBundle, separator); } public String getSeparator() { - return myGroupByWordPrefixes.getSeparator(); + return myByWordPrefixesGrouper.getSeparator(); } @NotNull @@ -59,7 +59,7 @@ public class ResourceBundleStructureViewModel implements PropertiesGroupingStruc @NotNull public Grouper[] getGroupers() { - return new Grouper[]{myGroupByWordPrefixes}; + return new Grouper[]{myByWordPrefixesGrouper}; } @NotNull diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundleUtil.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundleUtil.java index 53a9bd4dc31a..e4a35e7e677c 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundleUtil.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundleUtil.java @@ -54,10 +54,10 @@ public class ResourceBundleUtil { if (virtualFile == null) { return null; } - if (virtualFile instanceof ResourceBundleAsVirtualFile) { - return ((ResourceBundleAsVirtualFile)virtualFile).getResourceBundle(); + final Project project = CommonDataKeys.PROJECT.getData(dataContext); + if (virtualFile instanceof ResourceBundleAsVirtualFile && project != null) { + return ((ResourceBundleAsVirtualFile)virtualFile).getResourceBundle(project); } - Project project = CommonDataKeys.PROJECT.getData(dataContext); if (project != null) { final PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile); if (psiFile instanceof PropertiesFile) { diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/psi/impl/PropertiesFileImpl.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/psi/impl/PropertiesFileImpl.java index 77be36abc7a7..759ce6cb46fb 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/psi/impl/PropertiesFileImpl.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/psi/impl/PropertiesFileImpl.java @@ -114,7 +114,7 @@ public class PropertiesFileImpl extends PsiFileBase implements PropertiesFile { @Override @NotNull public ResourceBundle getResourceBundle() { - return PropertiesImplUtil.getResourceBundle(getContainingFile()); + return PropertiesImplUtil.getResourceBundle(this); } @Override diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/references/PropertyReferenceBase.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/references/PropertyReferenceBase.java index a740d8ece66f..2cc4851b012f 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/references/PropertyReferenceBase.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/references/PropertyReferenceBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2009 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/structureView/PropertiesFileStructureViewElement.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/structureView/PropertiesFileStructureViewElement.java index d0a203a7644f..432739c9df96 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/structureView/PropertiesFileStructureViewElement.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/structureView/PropertiesFileStructureViewElement.java @@ -18,9 +18,12 @@ package com.intellij.lang.properties.structureView; import com.intellij.ide.structureView.StructureViewTreeElement; import com.intellij.ide.structureView.impl.common.PsiTreeElementBase; import com.intellij.lang.properties.IProperty; +import com.intellij.lang.properties.editor.ResourceBundleEditorViewElement; import com.intellij.lang.properties.psi.Property; import com.intellij.lang.properties.psi.impl.PropertiesFileImpl; import com.intellij.navigation.ItemPresentation; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -31,7 +34,7 @@ import java.util.List; /** * @author max */ -public class PropertiesFileStructureViewElement extends PsiTreeElementBase { +public class PropertiesFileStructureViewElement extends PsiTreeElementBase implements ResourceBundleEditorViewElement { protected PropertiesFileStructureViewElement(PropertiesFileImpl propertiesFile) { super(propertiesFile); @@ -48,6 +51,11 @@ public class PropertiesFileStructureViewElement extends PsiTreeElementBase myProperties; private final @NotNull String myPrefix; private final String myPresentableName; private final @NotNull String mySeparator; - public PropertiesPrefixGroup(final Collection properties, String prefix, String presentableName, final String separator) { + public PropertiesPrefixGroup(final Collection properties, + final @NotNull String prefix, + final String presentableName, + final @NotNull String separator) { myProperties = properties; myPrefix = prefix; myPresentableName = presentableName; mySeparator = separator; } + public String getPresentableName() { + return myPresentableName; + } + + @NotNull + public String getSeparator() { + return mySeparator; + } + + @NotNull + public String getPrefix() { + return myPrefix; + } + @NotNull public ItemPresentation getPresentation() { return new ItemPresentation() { @@ -112,8 +136,24 @@ public class PropertiesPrefixGroup implements Group { return result; } - public String getPrefix() { - return myPrefix; + @Override + public PsiElement[] getPsiElements(final @NotNull Project project) { + final List elements = ContainerUtil.mapNotNull(getChildren(), new NullableFunction() { + @Nullable + @Override + public PsiElement fun(final TreeElement treeElement) { + if (treeElement instanceof PropertiesStructureViewElement) { + PropertiesStructureViewElement propertiesElement = (PropertiesStructureViewElement)treeElement; + IProperty property = propertiesElement.getValue(); + return property.getPsiElement(); + } + else if (treeElement instanceof ResourceBundlePropertyStructureViewElement) { + return ((ResourceBundlePropertyStructureViewElement)treeElement).getPsiElements(project)[0]; + } + return null; + } + }); + return elements.toArray(new PsiElement[elements.size()]); } public boolean equals(final Object o) { diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/structureView/PropertiesSeparatorManager.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/structureView/PropertiesSeparatorManager.java index f5e636811b92..cb60de04bc4f 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/structureView/PropertiesSeparatorManager.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/structureView/PropertiesSeparatorManager.java @@ -19,28 +19,18 @@ */ package com.intellij.lang.properties.structureView; -import com.intellij.lang.properties.IProperty; -import com.intellij.lang.properties.PropertiesLanguage; -import com.intellij.lang.properties.ResourceBundle; -import com.intellij.lang.properties.ResourceBundleImpl; -import com.intellij.lang.properties.editor.ResourceBundleAsVirtualFile; +import com.intellij.lang.properties.*; import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.openapi.components.*; import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileManager; -import com.intellij.psi.FileViewProvider; -import com.intellij.psi.PsiManager; -import com.intellij.util.SmartList; -import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashMap; import gnu.trove.TIntLongHashMap; import gnu.trove.TIntProcedure; import org.jdom.Element; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Collection; import java.util.List; import java.util.Map; @@ -48,45 +38,42 @@ import java.util.Map; name="PropertiesSeparatorManager", storages= { @Storage( - file = StoragePathMacros.APP_CONFIG + "/other.xml" + file = StoragePathMacros.PROJECT_FILE )} ) public class PropertiesSeparatorManager implements PersistentStateComponent { @NonNls private static final String FILE_ELEMENT = "file"; @NonNls private static final String URL_ELEMENT = "url"; @NonNls private static final String SEPARATOR_ATTR = "separator"; + private final Project myProject; - public static PropertiesSeparatorManager getInstance() { - return ServiceManager.getService(PropertiesSeparatorManager.class); + public static PropertiesSeparatorManager getInstance(final Project project) { + return ServiceManager.getService(project, PropertiesSeparatorManager.class); } - private final Map mySeparators = new THashMap(); + private final Map mySeparators = new THashMap(); - public String getSeparator(Project project, VirtualFile file) { - String separator = mySeparators.get(file); + public PropertiesSeparatorManager(final Project project) { + myProject = project; + } + + @NotNull + public String getSeparator(final ResourceBundle resourceBundle) { + if (!(resourceBundle instanceof ResourceBundleImpl)) { + return "."; + } + String separator = mySeparators.get(((ResourceBundleImpl)resourceBundle).getUrl()); if (separator == null) { - separator = guessSeparator(project, file); - setSeparator(file, separator); + separator = guessSeparator((ResourceBundleImpl)resourceBundle); + setSeparator(resourceBundle, separator); } return separator; } //returns most probable separator in properties files - private static String guessSeparator(final Project project, final VirtualFile file) { - Collection files; - if (file instanceof ResourceBundleAsVirtualFile) { - files = ((ResourceBundleAsVirtualFile)file).getResourceBundle().getPropertiesFiles(project); - } - else { - PsiManager psiManager = PsiManager.getInstance(project); - final FileViewProvider provider = psiManager.findViewProvider(file); - files = new SmartList(); - if (provider != null) { - ContainerUtil.addIfNotNull((PropertiesFile)provider.getPsi(PropertiesLanguage.INSTANCE), files); - } - } + private static String guessSeparator(final ResourceBundleImpl resourceBundle) { final TIntLongHashMap charCounts = new TIntLongHashMap(); - for (PropertiesFile propertiesFile : files) { + for (PropertiesFile propertiesFile : resourceBundle.getPropertiesFiles()) { if (propertiesFile == null) continue; List properties = propertiesFile.getProperties(); for (IProperty property : properties) { @@ -119,8 +106,10 @@ public class PropertiesSeparatorManager implements PersistentStateComponent - @@ -44,11 +44,11 @@ - - - + + + + - diff --git a/plugins/properties/src/com/intellij/ide/favoritesTreeView/ResourcesFavoriteNodeProvider.java b/plugins/properties/src/com/intellij/ide/favoritesTreeView/ResourcesFavoriteNodeProvider.java index 4b6a574c2024..67ddbf2d10f2 100644 --- a/plugins/properties/src/com/intellij/ide/favoritesTreeView/ResourcesFavoriteNodeProvider.java +++ b/plugins/properties/src/com/intellij/ide/favoritesTreeView/ResourcesFavoriteNodeProvider.java @@ -22,13 +22,13 @@ package com.intellij.ide.favoritesTreeView; import com.intellij.ide.projectView.ViewSettings; import com.intellij.ide.util.treeView.AbstractTreeNode; +import com.intellij.lang.properties.PropertiesImplUtil; import com.intellij.lang.properties.ResourceBundle; import com.intellij.lang.properties.ResourceBundleImpl; import com.intellij.lang.properties.projectView.ResourceBundleNode; import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; @@ -64,7 +64,7 @@ public class ResourcesFavoriteNodeProvider extends FavoriteNodeProvider { public boolean elementContainsFile(final Object element, final VirtualFile vFile) { if (element instanceof ResourceBundle) { ResourceBundle bundle = (ResourceBundle)element; - final List propertiesFiles = bundle.getPropertiesFiles(myProject); + final List propertiesFiles = bundle.getPropertiesFiles(); for (PropertiesFile file : propertiesFiles) { final VirtualFile virtualFile = file.getVirtualFile(); if (virtualFile == null) continue; @@ -87,7 +87,7 @@ public class ResourcesFavoriteNodeProvider extends FavoriteNodeProvider { public boolean isInvalidElement(final Object element) { if (element instanceof ResourceBundle) { ResourceBundle resourceBundle = (ResourceBundle)element; - List propertiesFiles = resourceBundle.getPropertiesFiles(myProject); + List propertiesFiles = resourceBundle.getPropertiesFiles(); if (propertiesFiles.size() == 1) { //todo result.add(new PsiFileNode(myProject, propertiesFiles.iterator().next(), this)); return true; @@ -113,6 +113,6 @@ public class ResourcesFavoriteNodeProvider extends FavoriteNodeProvider { } public Object[] createPathFromUrl(final Project project, final String url, final String moduleName) { - return new Object[]{ResourceBundleImpl.createByUrl(url)}; + return new Object[]{PropertiesImplUtil.createByUrl(url, project)}; } } diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/NewPropertyAction.java b/plugins/properties/src/com/intellij/lang/properties/editor/NewPropertyAction.java new file mode 100644 index 000000000000..d25b780bd769 --- /dev/null +++ b/plugins/properties/src/com/intellij/lang/properties/editor/NewPropertyAction.java @@ -0,0 +1,138 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.lang.properties.editor; + +import com.intellij.icons.AllIcons; +import com.intellij.lang.properties.PropertiesBundle; +import com.intellij.lang.properties.ResourceBundle; +import com.intellij.lang.properties.psi.PropertiesFile; +import com.intellij.lang.properties.structureView.PropertiesPrefixGroup; +import com.intellij.openapi.actionSystem.ActionPlaces; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.command.CommandProcessor; +import com.intellij.openapi.fileEditor.FileEditor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.InputValidator; +import com.intellij.openapi.ui.Messages; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** +* @author Dmitry Batkovich +*/ +class NewPropertyAction extends AnAction { + public NewPropertyAction() { + super("New Property", null, AllIcons.General.Add); + } + + @Override + public void actionPerformed(final AnActionEvent e) { + final Project project = getEventProject(e); + if (project == null) { + return; + } + final FileEditor editor = PlatformDataKeys.FILE_EDITOR.getData(e.getDataContext()); + if (editor == null || !(editor instanceof ResourceBundleEditor)) { + return; + } + final ResourceBundleEditor resourceBundleEditor = (ResourceBundleEditor)editor; + + final String prefix; + final String separator; + final String place = e.getPlace(); + if (ActionPlaces.STRUCTURE_VIEW_TOOLBAR.equals(place)) { + prefix = null; + separator = null; + } else { + final ResourceBundleEditorViewElement selectedElement = resourceBundleEditor.getSelectedElement(); + if (selectedElement == null) { + return; + } + if (selectedElement instanceof PropertiesPrefixGroup) { + final PropertiesPrefixGroup group = (PropertiesPrefixGroup)selectedElement; + prefix = group.getPrefix(); + separator = group.getSeparator(); + } + else if (selectedElement instanceof ResourceBundlePropertyStructureViewElement || + selectedElement instanceof ResourceBundleFileStructureViewElement) { + prefix = null; + separator = null; + } + else { + throw new IllegalStateException("unsupported type: " + selectedElement.getClass()); + } + } + final ResourceBundle resourceBundle = resourceBundleEditor.getResourceBundle(); + + Messages.showInputDialog(project, + PropertiesBundle.message("new.property.dialog.name.prompt.text"), + PropertiesBundle.message("new.property.dialog.title"), + Messages.getQuestionIcon(), + null, + new NewPropertyNameValidator(resourceBundle, prefix, separator)); + } + + private static class NewPropertyNameValidator implements InputValidator { + private final @NotNull ResourceBundle myResourceBundle; + private final @Nullable String myPrefix; + private final @Nullable String mySeparator; + + + public NewPropertyNameValidator(final @NotNull ResourceBundle resourceBundle, + final @Nullable String prefix, + final @Nullable String separator) { + myResourceBundle = resourceBundle; + myPrefix = prefix; + mySeparator = separator; + } + + @Override + public boolean checkInput(final String inputString) { + return true; + } + + @Override + public boolean canClose(final String inputString) { + final String newPropertyName = myPrefix == null ? inputString : (myPrefix + mySeparator + inputString); + + for (final PropertiesFile propertiesFile : myResourceBundle.getPropertiesFiles()) { + for (final String propertyName : propertiesFile.getNamesMap().keySet()) { + if (newPropertyName.equals(propertyName)) { + Messages.showErrorDialog("Can't add new property. Property with key \'" + newPropertyName + "\' already exists.", "New Property"); + return false; + } + } + } + + final PropertiesFile defaultPropertiesFile = myResourceBundle.getDefaultPropertiesFile(); + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + CommandProcessor.getInstance().runUndoTransparentAction(new Runnable() { + @Override + public void run() { + defaultPropertiesFile.addProperty(newPropertyName, ""); + } + }); + } + }); + return true; + } + } +} diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/PropertiesGroupingStructureViewComponent.java b/plugins/properties/src/com/intellij/lang/properties/editor/PropertiesGroupingStructureViewComponent.java index 8765943c7c4a..733f229bc687 100644 --- a/plugins/properties/src/com/intellij/lang/properties/editor/PropertiesGroupingStructureViewComponent.java +++ b/plugins/properties/src/com/intellij/lang/properties/editor/PropertiesGroupingStructureViewComponent.java @@ -32,6 +32,7 @@ import java.util.Set; * @author cdr */ public class PropertiesGroupingStructureViewComponent extends StructureViewComponent { + protected PropertiesGroupingStructureViewComponent(Project project, FileEditor editor, PropertiesGroupingStructureViewModel structureViewModel) { diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java index b3799a338b8c..1c79c0fd6074 100644 --- a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java +++ b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java @@ -69,10 +69,13 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.border.TitledBorder; -import javax.swing.event.*; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreePath; import java.awt.*; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; import java.beans.PropertyChangeListener; import java.util.*; import java.util.List; @@ -85,7 +88,6 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit private final StructureViewComponent myStructureViewComponent; private final Map myEditors; - private String myOldPropertyName; private final ResourceBundle myResourceBundle; private final Map myTitledPanels; private final JComponent myNoPropertySelectedPanel = new NoPropertySelectedPanel().getComponent(); @@ -102,8 +104,8 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit private VirtualFileListener myVfsListener; private Editor mySelectedEditor; - public ResourceBundleEditor(Project project, ResourceBundle resourceBundle) { - myProject = project; + public ResourceBundleEditor(@NotNull ResourceBundle resourceBundle) { + myProject = resourceBundle.getProject(); final JPanel splitPanel = new JPanel(); myValuesPanel = new JPanel(); @@ -118,7 +120,7 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit splitPanel.add(splitter, BorderLayout.CENTER); myResourceBundle = resourceBundle; - myStructureViewComponent = new ResourceBundleStructureViewComponent(project, myResourceBundle, this); + myStructureViewComponent = new ResourceBundleStructureViewComponent(myResourceBundle, this); myStructureViewPanel.setLayout(new BorderLayout()); myStructureViewPanel.add(myStructureViewComponent, BorderLayout.CENTER); @@ -130,9 +132,8 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit public void valueChanged(TreeSelectionEvent e) { // filter out temp unselect/select events if (getSelectedPropertyName() == null) return; - if (!Comparing.strEqual(selectedPropertyName, getSelectedPropertyName()) - || !Comparing.equal(selectedPropertiesFile, getSelectedPropertiesFile())) - { + if (!Comparing.strEqual(selectedPropertyName, getSelectedPropertyName()) || + !Comparing.equal(selectedPropertiesFile, getSelectedPropertiesFile())) { selectedPropertyName = getSelectedPropertyName(); selectedPropertiesFile = getSelectedPropertiesFile(); selectionChanged(); @@ -153,7 +154,7 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit } myDataProviderPanel = new DataProviderPanel(splitPanel); - project.getMessageBus().connect(project).subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, new FileEditorManagerAdapter() { + myProject.getMessageBus().connect(myProject).subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, new FileEditorManagerAdapter() { @Override public void selectionChanged(@NotNull FileEditorManagerEvent event) { onSelectionChanged(event); @@ -161,6 +162,10 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit }); } + public ResourceBundle getResourceBundle() { + return myResourceBundle; + } + private void onSelectionChanged(@NotNull FileEditorManagerEvent event) { // Ignore events which don't target current editor. FileEditor oldEditor = event.getOldEditor(); @@ -194,6 +199,9 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit } private void setStructureViewSelection(@NotNull final String propertyName) { + if (myStructureViewComponent.isDisposed()) { + return; + } JTree tree = myStructureViewComponent.getTree(); if (tree == null) { return; @@ -264,19 +272,24 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit @Nullable private static String getNodeValue(@NotNull DefaultMutableTreeNode node) { + final ResourceBundleEditorViewElement element = getSelectedElement(node); + return element instanceof ResourceBundlePropertyStructureViewElement ? ((ResourceBundlePropertyStructureViewElement)element).getValue() + : null; + } + + @Nullable + private static ResourceBundleEditorViewElement getSelectedElement(@NotNull DefaultMutableTreeNode node) { Object userObject = node.getUserObject(); if (!(userObject instanceof AbstractTreeNode)) return null; Object value = ((AbstractTreeNode)userObject).getValue(); - return value instanceof ResourceBundlePropertyStructureViewElement ? ((ResourceBundlePropertyStructureViewElement)value).getValue() - : null; + return value instanceof ResourceBundleEditorViewElement ? (ResourceBundleEditorViewElement) value : null; } private void writeEditorPropertyValue(final Editor editor, final PropertiesFile propertiesFile) { final String currentValue = editor.getDocument().getText(); final String currentSelectedProperty = getSelectedPropertyName(); - final String selectedProperty = myOldPropertyName == null ? currentSelectedProperty : myOldPropertyName; - assert selectedProperty != null; + assert currentSelectedProperty != null; ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override @@ -284,10 +297,10 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit WriteCommandAction.runWriteCommandAction(myProject, new Runnable() { @Override public void run() { - final IProperty property = propertiesFile.findPropertyByKey(selectedProperty); + final IProperty property = propertiesFile.findPropertyByKey(currentSelectedProperty); try { if (property == null) { - propertiesFile.addProperty(selectedProperty, currentValue); + propertiesFile.addProperty(currentSelectedProperty, currentValue); } else { property.setValue(currentValue); @@ -318,7 +331,7 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit }, VALUES); myValuesPanel.add(myNoPropertySelectedPanel, NO_PROPERTY_SELECTED); - List propertiesFiles = myResourceBundle.getPropertiesFiles(myProject); + List propertiesFiles = myResourceBundle.getPropertiesFiles(); GridBagConstraints gc = new GridBagConstraints(0, 0, 0, 0, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0); @@ -342,6 +355,12 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit writeEditorPropertyValue(editor, propertiesFile); } }); + editor.getComponent().addFocusListener(new FocusAdapter() { + @Override + public void focusLost(FocusEvent e) { + writeEditorPropertyValue(editor, propertiesFile); + } + }); editor.getDocument().putUserData(UndoConstants.DONT_RECORD_UNDO, Boolean.TRUE); gc.gridx = 0; gc.gridy = y++; @@ -510,18 +529,11 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit } private void selectionChanged() { myBackSlashPressed.clear(); - final String currentSelectedPropertyName = getSelectedPropertyName(); UIUtil.invokeLaterIfNeeded(new Runnable() { @Override public void run() { - if (myOldPropertyName != null && !myOldPropertyName.equals(currentSelectedPropertyName)) { - for (final Map.Entry entry : myEditors.entrySet()) { - writeEditorPropertyValue(entry.getValue(), entry.getKey()); - } - } updateEditorsFromProperties(); - myOldPropertyName = currentSelectedPropertyName; } }); } @@ -537,7 +549,7 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit } @Nullable - private String getSelectedPropertyName() { + public String getSelectedPropertyName() { JTree tree = myStructureViewComponent.getTree(); if (tree == null) return null; TreePath selected = tree.getSelectionModel().getSelectionPath(); @@ -545,6 +557,15 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit return getNodeValue((DefaultMutableTreeNode)selected.getLastPathComponent()); } + @Nullable + public ResourceBundleEditorViewElement getSelectedElement() { + JTree tree = myStructureViewComponent.getTree(); + if (tree == null) return null; + TreePath selected = tree.getSelectionModel().getSelectionPath(); + if (selected == null) return null; + return getSelectedElement((DefaultMutableTreeNode)selected.getLastPathComponent()); + } + @Override @NotNull public JComponent getComponent() { @@ -706,23 +727,6 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit myEditors.clear(); } - /** - * Renames target property if the one is available. - *

- * Note: is assumed to be called under {@link WriteAction write action}. - * - * @param oldName old property name - * @param newName new property name - */ - public void renameProperty(@NotNull String oldName, @NotNull String newName) { - for (PropertiesFile properties : myResourceBundle.getPropertiesFiles(myProject)) { - IProperty property = properties.findPropertyByKey(oldName); - if (property != null) { - property.setName(newName); - } - } - } - public static class ResourceBundleEditorState implements FileEditorState { private final String myPropertyName; diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditorProvider.java b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditorProvider.java index f29a9cbb7b7a..fdbc2c0c5e59 100644 --- a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditorProvider.java +++ b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditorProvider.java @@ -42,7 +42,7 @@ public class ResourceBundleEditorProvider extends FileTypeFactory implements Fil if (!file.isValid()) return false; PsiFile psiFile = PsiManager.getInstance(project).findFile(file); PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile(psiFile); - return propertiesFile != null && propertiesFile.getResourceBundle().getPropertiesFiles(project).size() > 1; + return propertiesFile != null && propertiesFile.getResourceBundle().getPropertiesFiles().size() > 1; } @Override @@ -50,7 +50,7 @@ public class ResourceBundleEditorProvider extends FileTypeFactory implements Fil public FileEditor createEditor(@NotNull Project project, @NotNull final VirtualFile file){ ResourceBundle resourceBundle; if (file instanceof ResourceBundleAsVirtualFile) { - resourceBundle = ((ResourceBundleAsVirtualFile)file).getResourceBundle(); + resourceBundle = ((ResourceBundleAsVirtualFile)file).getResourceBundle(project); } else { PsiFile psiFile = PsiManager.getInstance(project).findFile(file); @@ -60,7 +60,7 @@ public class ResourceBundleEditorProvider extends FileTypeFactory implements Fil resourceBundle = PropertiesImplUtil.getPropertiesFile(psiFile).getResourceBundle(); } - return new ResourceBundleEditor(project, resourceBundle); + return new ResourceBundleEditor(resourceBundle); } @Override diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleStructureViewComponent.java b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleStructureViewComponent.java index 9289eb24a4cb..ee8e47a446e4 100644 --- a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleStructureViewComponent.java +++ b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleStructureViewComponent.java @@ -15,25 +15,118 @@ */ package com.intellij.lang.properties.editor; +import com.intellij.find.findUsages.PsiElement2UsageTargetAdapter; +import com.intellij.ide.CopyProvider; +import com.intellij.ide.DeleteProvider; +import com.intellij.lang.properties.IProperty; import com.intellij.lang.properties.ResourceBundle; -import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.lang.properties.psi.PropertiesFile; +import com.intellij.lang.properties.psi.Property; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.ide.CopyPasteManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiNamedElement; +import com.intellij.psi.util.PsiUtilBase; +import com.intellij.psi.util.PsiUtilCore; +import com.intellij.refactoring.safeDelete.SafeDeleteHandler; +import com.intellij.ui.PopupHandler; +import com.intellij.usages.UsageTarget; +import com.intellij.usages.UsageView; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; + +import java.awt.datatransfer.StringSelection; +import java.util.ArrayList; +import java.util.List; /** * @author cdr */ class ResourceBundleStructureViewComponent extends PropertiesGroupingStructureViewComponent { + private final static Logger LOG = Logger.getInstance(ResourceBundleStructureViewComponent.class); + private final ResourceBundle myResourceBundle; - public ResourceBundleStructureViewComponent(Project project, ResourceBundle resourceBundle, ResourceBundleEditor editor) { - super(project, editor, new ResourceBundleStructureViewModel(project, resourceBundle)); + public ResourceBundleStructureViewComponent(final ResourceBundle resourceBundle, final ResourceBundleEditor editor) { + super(resourceBundle.getProject(), editor, new ResourceBundleStructureViewModel(resourceBundle)); myResourceBundle = resourceBundle; + tunePopupActionGroup(); } - public Object getData(String dataId) { + @Override + protected void addGroupByActions(final DefaultActionGroup result) { + super.addGroupByActions(result); + result.add(new NewPropertyAction(), Constraints.FIRST); + } + + private void tunePopupActionGroup() { + final DefaultActionGroup propertiesPopupGroup = new DefaultActionGroup(); + propertiesPopupGroup.copyFromGroup((DefaultActionGroup)ActionManager.getInstance().getAction(IdeActions.GROUP_STRUCTURE_VIEW_POPUP)); + propertiesPopupGroup.add(Separator.getInstance(), Constraints.FIRST); + propertiesPopupGroup.add(new NewPropertyAction(), Constraints.FIRST); + PopupHandler.installPopupHandler(getTree(), propertiesPopupGroup, IdeActions.GROUP_STRUCTURE_VIEW_POPUP, ActionManager.getInstance()); + } + + public Object getData(final String dataId) { if (CommonDataKeys.VIRTUAL_FILE.is(dataId)) { - return new ResourceBundleAsVirtualFile(myResourceBundle); + return ResourceBundleAsVirtualFile.fromResourceBundle(myResourceBundle); + } else if (PlatformDataKeys.FILE_EDITOR.is(dataId)) { + return getFileEditor(); + } else if (LangDataKeys.PSI_ELEMENT_ARRAY.is(dataId)) { + final ResourceBundleEditorViewElement selectedElement = ((ResourceBundleEditor)getFileEditor()).getSelectedElement(); + if (selectedElement != null) { + final Project project = CommonDataKeys.PROJECT.getData(this); + if (project != null) { + final PsiElement[] psiElements = selectedElement.getPsiElements(project); + if (psiElements != null) { + return psiElements; + } + } + } + } else if (PlatformDataKeys.DELETE_ELEMENT_PROVIDER.is(dataId)) { + final PsiElement[] psiElements = LangDataKeys.PSI_ELEMENT_ARRAY.getData(this); + if (psiElements != null && psiElements.length > 0) { + return new PsiElementsDeleteProvider(psiElements); + } + } else if (UsageView.USAGE_TARGETS_KEY.is(dataId)) { + final PsiElement[] chosenElements = (PsiElement[]) getData(LangDataKeys.PSI_ELEMENT_ARRAY.getName()); + if (chosenElements != null) { + final UsageTarget[] usageTargets = new UsageTarget[chosenElements.length]; + for (int i = 0; i < chosenElements.length; i++) { + usageTargets[i] = new PsiElement2UsageTargetAdapter(chosenElements[i]); + } + return usageTargets; + } + } else if (PlatformDataKeys.COPY_PROVIDER.is(dataId)) { + return new CopyProvider() { + @Override + public void performCopy(@NotNull final DataContext dataContext) { + final PsiElement[] selectedPsiElements = (PsiElement[])getData(LangDataKeys.PSI_ELEMENT_ARRAY.getName()); + if (selectedPsiElements != null) { + final List names = new ArrayList(selectedPsiElements.length); + for (final PsiElement element : selectedPsiElements) { + if (element instanceof PsiNamedElement) { + names.add(((PsiNamedElement)element).getName()); + } + } + CopyPasteManager.getInstance().setContents(new StringSelection(StringUtil.join(names, "\n"))); + } + } + + @Override + public boolean isCopyEnabled(@NotNull final DataContext dataContext) { + return true; + } + + @Override + public boolean isCopyVisible(@NotNull final DataContext dataContext) { + return true; + } + }; } return super.getData(dataId); } @@ -41,5 +134,40 @@ class ResourceBundleStructureViewComponent extends PropertiesGroupingStructureVi protected boolean showScrollToFromSourceActions() { return false; } + + private class PsiElementsDeleteProvider implements DeleteProvider { + private final PsiElement[] myElements; + + private PsiElementsDeleteProvider(final PsiElement[] elements) { + myElements = elements; + } + + @Override + public void deleteElement(@NotNull final DataContext dataContext) { + final List bundlePropertiesFiles = myResourceBundle.getPropertiesFiles(); + + final List toDelete = new ArrayList(); + for (PsiElement element : myElements) { + final Property property = (Property) element; + final String key = property.getKey(); + if (key == null) { + LOG.error("key must be not null " + element); + } else { + for (PropertiesFile propertiesFile : bundlePropertiesFiles) { + for (final IProperty iProperty : propertiesFile.findPropertiesByKey(key)) { + toDelete.add(iProperty.getPsiElement()); + } + } + } + } + + new SafeDeleteHandler().invoke(myElements[0].getProject(), PsiUtilCore.toPsiElementArray(toDelete), dataContext); + } + + @Override + public boolean canDeleteElement(@NotNull final DataContext dataContext) { + return true; + } + } } diff --git a/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleDeleteProvider.java b/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleDeleteProvider.java index 7ba44a86c2bd..a681e10f3af1 100644 --- a/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleDeleteProvider.java +++ b/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleDeleteProvider.java @@ -48,7 +48,7 @@ class ResourceBundleDeleteProvider implements DeleteProvider { public void deleteElement(@NotNull DataContext dataContext) { final Project project = CommonDataKeys.PROJECT.getData(dataContext); - List propertiesFiles = myResourceBundle.getPropertiesFiles(project); + List propertiesFiles = myResourceBundle.getPropertiesFiles(); assert project != null; new SafeDeleteHandler().invoke(project, ContainerUtil.map2Array(propertiesFiles, PsiElement.class, MAPPER), dataContext); } diff --git a/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleMoveProvider.java b/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleMoveProvider.java index a2b1b621f068..d61282aefba2 100644 --- a/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleMoveProvider.java +++ b/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleMoveProvider.java @@ -57,7 +57,7 @@ public class ResourceBundleMoveProvider extends MoveHandlerDelegate { final ResourceBundle[] bundles = ResourceBundle.ARRAY_DATA_KEY.getData(dataContext); LOG.assertTrue(bundles != null); for (ResourceBundle bundle : bundles) { - List propertiesFiles = bundle.getPropertiesFiles(CommonDataKeys.PROJECT.getData(dataContext)); + List propertiesFiles = bundle.getPropertiesFiles(); for (PropertiesFile propertiesFile : propertiesFiles) { filesOrDirs.add(propertiesFile.getContainingFile()); } diff --git a/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleNode.java b/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleNode.java index 7de856226e01..a415e4544aa0 100644 --- a/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleNode.java +++ b/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleNode.java @@ -25,9 +25,7 @@ import com.intellij.ide.projectView.ProjectViewNode; import com.intellij.ide.projectView.ViewSettings; import com.intellij.ide.projectView.impl.nodes.PsiFileNode; import com.intellij.ide.util.treeView.AbstractTreeNode; -import com.intellij.lang.properties.PropertiesBundle; -import com.intellij.lang.properties.PropertiesImplUtil; -import com.intellij.lang.properties.ResourceBundle; +import com.intellij.lang.properties.*; import com.intellij.lang.properties.editor.ResourceBundleAsVirtualFile; import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.openapi.fileEditor.FileEditorManager; @@ -50,7 +48,7 @@ public class ResourceBundleNode extends ProjectViewNode{ @NotNull public Collection getChildren() { - List propertiesFiles = getValue().getPropertiesFiles(myProject); + List propertiesFiles = getValue().getPropertiesFiles(); Collection children = new ArrayList(); for (PropertiesFile propertiesFile : propertiesFiles) { AbstractTreeNode node = new PsiFileNode(myProject, propertiesFile.getContainingFile(), getSettings()); @@ -63,11 +61,11 @@ public class ResourceBundleNode extends ProjectViewNode{ if (!file.isValid()) return false; PsiFile psiFile = PsiManager.getInstance(getProject()).findFile(file); PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile(psiFile); - return propertiesFile != null && getValue().getPropertiesFiles(myProject).contains(propertiesFile); + return propertiesFile != null && getValue().getPropertiesFiles().contains(propertiesFile); } public VirtualFile getVirtualFile() { - final List list = getValue().getPropertiesFiles(myProject); + final List list = getValue().getPropertiesFiles(); if (!list.isEmpty()) { return list.get(0).getVirtualFile(); } @@ -88,7 +86,7 @@ public class ResourceBundleNode extends ProjectViewNode{ } public void navigate(final boolean requestFocus) { - OpenFileDescriptor descriptor = new OpenFileDescriptor(getProject(), new ResourceBundleAsVirtualFile(getValue())); + OpenFileDescriptor descriptor = new OpenFileDescriptor(getProject(), ResourceBundleAsVirtualFile.fromResourceBundle(getValue())); FileEditorManager.getInstance(getProject()).openTextEditor(descriptor, requestFocus); } diff --git a/plugins/properties/src/com/intellij/lang/properties/refactoring/PropertyRenameHandler.java b/plugins/properties/src/com/intellij/lang/properties/refactoring/PropertyRenameHandler.java deleted file mode 100644 index 99355d34bc6e..000000000000 --- a/plugins/properties/src/com/intellij/lang/properties/refactoring/PropertyRenameHandler.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.lang.properties.refactoring; - -import com.intellij.codeInsight.TargetElementUtilBase; -import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.actionSystem.LangDataKeys; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.ScrollType; -import com.intellij.openapi.project.Project; -import com.intellij.psi.*; -import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference; -import com.intellij.refactoring.rename.PsiElementRenameHandler; -import com.intellij.lang.properties.references.PropertyReferenceBase; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * @author Dmitry Avdeev - */ -public class PropertyRenameHandler extends PsiElementRenameHandler { - - public boolean isAvailableOnDataContext(final DataContext dataContext) { - final Editor editor = LangDataKeys.EDITOR.getData(dataContext); - if (editor != null) { - if (getPsiElement(editor) != null) return true; - } - return false; - } - - @Nullable - private static PsiElement getPsiElement(final Editor editor) { - final PsiReference reference = TargetElementUtilBase.findReference(editor); - if (reference instanceof PropertyReferenceBase) { - final ResolveResult[] resolveResults = ((PropertyReferenceBase)reference).multiResolve(false); - return resolveResults.length > 0 ? resolveResults[0].getElement() : null; - } else if (reference instanceof PsiMultiReference) { - final PsiReference[] references = ((PsiMultiReference)reference).getReferences(); - for (PsiReference psiReference : references) { - if (psiReference instanceof PropertyReferenceBase) { - final ResolveResult[] resolveResults = ((PropertyReferenceBase)psiReference).multiResolve(false); - if (resolveResults.length > 0) return resolveResults[0].getElement(); - } - } - } - return null; - } - - @Override - public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file, final DataContext dataContext) { - PsiElement element = getPsiElement(editor); - editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); - final PsiElement nameSuggestionContext = file.findElementAt(editor.getCaretModel().getOffset()); - invoke(element, project, nameSuggestionContext, editor); - } -} diff --git a/plugins/properties/src/com/intellij/lang/properties/refactoring/ResourceBundleKeyRenameHandler.java b/plugins/properties/src/com/intellij/lang/properties/refactoring/ResourceBundleKeyRenameHandler.java deleted file mode 100644 index 7d7dbc14aead..000000000000 --- a/plugins/properties/src/com/intellij/lang/properties/refactoring/ResourceBundleKeyRenameHandler.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2000-2014 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.lang.properties.refactoring; - -import com.intellij.lang.properties.IProperty; -import com.intellij.lang.properties.PropertiesBundle; -import com.intellij.lang.properties.ResourceBundle; -import com.intellij.lang.properties.editor.ResourceBundleEditor; -import com.intellij.lang.properties.editor.ResourceBundleEditorUtil; -import com.intellij.lang.properties.editor.ResourceBundleUtil; -import com.intellij.lang.properties.psi.PropertiesFile; -import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.fileEditor.FileEditorStateLevel; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.InputValidator; -import com.intellij.openapi.ui.Messages; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.refactoring.rename.RenameHandler; -import com.intellij.util.containers.HashSet; -import org.jetbrains.annotations.NotNull; - -import java.util.Set; - -/** - * Encapsulates logic of renaming resource bundle property key. - * - * @author Denis Zhdanov - * @since 11/9/10 4:13 PM - */ -public class ResourceBundleKeyRenameHandler implements RenameHandler { - - @Override - public boolean isAvailableOnDataContext(DataContext dataContext) { - ResourceBundleEditor editor = ResourceBundleEditorUtil.getEditor(dataContext); - if (editor == null) { - return false; - } - return editor.getState(FileEditorStateLevel.NAVIGATION).getPropertyName() != null; - } - - @Override - public boolean isRenaming(DataContext dataContext) { - return isAvailableOnDataContext(dataContext); - } - - @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) { - ResourceBundleEditor bundleEditor = ResourceBundleEditorUtil.getEditor(dataContext); - if (bundleEditor == null) { - return; - } - - String propertyName = bundleEditor.getState(FileEditorStateLevel.NAVIGATION).getPropertyName(); - if (propertyName == null) { - return; - } - - ResourceBundle bundle = ResourceBundleUtil.getResourceBundleFromDataContext(dataContext); - if (bundle == null) { - return; - } - Messages.showInputDialog(project, PropertiesBundle.message("rename.bundle.enter.new.resource.bundle.key.name.prompt.text"), - PropertiesBundle.message("rename.resource.bundle.key.dialog.title"), Messages.getQuestionIcon(), propertyName, - new ResourceBundleKeyRenameValidator(project, bundleEditor, bundle, propertyName)); - } - - @Override - public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, DataContext dataContext) { - invoke(project, null, null, dataContext); - } - - private static class ResourceBundleKeyRenameValidator implements InputValidator { - - private final Set myExistingProperties = new HashSet(); - - private final ResourceBundleEditor myEditor; - private final String myOldPropertyName; - - ResourceBundleKeyRenameValidator(Project project, ResourceBundleEditor editor, ResourceBundle bundle, String oldPropertyName) { - myEditor = editor; - myOldPropertyName = oldPropertyName; - for (PropertiesFile file : bundle.getPropertiesFiles(project)) { - for (IProperty property : file.getProperties()) { - myExistingProperties.add(property.getKey()); - } - } - myExistingProperties.remove(oldPropertyName); - } - - @Override - public boolean checkInput(String inputString) { - return inputString != null && !inputString.isEmpty() && !myExistingProperties.contains(inputString); - } - - @Override - public boolean canClose(final String inputString) { - if (!checkInput(inputString)) { - return false; - } - - if (myOldPropertyName.equals(inputString)) { - return true; - } - - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - myEditor.renameProperty(myOldPropertyName, inputString); - } - }); - return true; - } - } -} diff --git a/plugins/properties/src/com/intellij/lang/properties/refactoring/ResourceBundleRenameHandler.java b/plugins/properties/src/com/intellij/lang/properties/refactoring/ResourceBundleRenameHandler.java deleted file mode 100644 index fe555a7a2ca7..000000000000 --- a/plugins/properties/src/com/intellij/lang/properties/refactoring/ResourceBundleRenameHandler.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright 2000-2014 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Alexey - */ -package com.intellij.lang.properties.refactoring; - -import com.intellij.codeInsight.FileModificationService; -import com.intellij.lang.properties.PropertiesBundle; -import com.intellij.lang.properties.ResourceBundle; -import com.intellij.lang.properties.editor.ResourceBundleAsVirtualFile; -import com.intellij.lang.properties.editor.ResourceBundleEditor; -import com.intellij.lang.properties.editor.ResourceBundleEditorUtil; -import com.intellij.lang.properties.editor.ResourceBundleUtil; -import com.intellij.lang.properties.psi.PropertiesFile; -import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.fileEditor.FileEditorStateLevel; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.InputValidator; -import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.refactoring.rename.RenameHandler; -import com.intellij.refactoring.rename.RenameProcessor; -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.util.List; - -public class ResourceBundleRenameHandler implements RenameHandler { - private static final Logger LOG = Logger.getInstance("#" + ResourceBundleRenameHandler.class.getName()); - - public boolean isAvailableOnDataContext(DataContext dataContext) { - final Project project = CommonDataKeys.PROJECT.getData(dataContext); - if (project == null) { - return false; - } - final ResourceBundle bundle = ResourceBundleUtil.getResourceBundleFromDataContext(dataContext); - if (bundle == null) { - return false; - } - - final VirtualFile virtualFile = CommonDataKeys.VIRTUAL_FILE.getData(dataContext); - - ResourceBundleEditor editor = ResourceBundleEditorUtil.getEditor(dataContext); - return (editor == null || editor.getState(FileEditorStateLevel.NAVIGATION).getPropertyName() == null /* user selected non-bundle key element */) - && bundle.getPropertiesFiles(project).size() > 1 && (virtualFile instanceof ResourceBundleAsVirtualFile || virtualFile == null); - } - - public boolean isRenaming(DataContext dataContext) { - return isAvailableOnDataContext(dataContext); - } - - public void invoke(@NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) { - ResourceBundle resourceBundle = ResourceBundleUtil.getResourceBundleFromDataContext(dataContext); - - assert resourceBundle != null; - Messages.showInputDialog(project, - PropertiesBundle.message("rename.bundle.enter.new.resource.bundle.base.name.prompt.text"), - PropertiesBundle.message("rename.resource.bundle.dialog.title"), - Messages.getQuestionIcon(), - resourceBundle.getBaseName(), - new MyInputValidator(project, resourceBundle)); - } - - public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, DataContext dataContext) { - invoke(project, null, null, dataContext); - } - - private static class MyInputValidator implements InputValidator { - private final Project myProject; - private final ResourceBundle myResourceBundle; - - public MyInputValidator(final Project project, final ResourceBundle resourceBundle) { - myProject = project; - myResourceBundle = resourceBundle; - } - - public boolean checkInput(String inputString) { - return inputString.indexOf(File.separatorChar) < 0 && inputString.indexOf('/') < 0; - } - - public boolean canClose(final String inputString) { - return doRename(inputString); - } - private boolean doRename(final String inputString) { - final List propertiesFiles = myResourceBundle.getPropertiesFiles(myProject); - for (PropertiesFile propertiesFile : propertiesFiles) { - if (!FileModificationService.getInstance().prepareFileForWrite(propertiesFile.getContainingFile())) return false; - } - - RenameProcessor renameProcessor = null; - String baseName = myResourceBundle.getBaseName(); - for (PropertiesFile propertiesFile : propertiesFiles) { - final VirtualFile virtualFile = propertiesFile.getVirtualFile(); - if (virtualFile == null) { - continue; - } - final String newName = inputString + virtualFile.getNameWithoutExtension().substring(baseName.length()) + "." - + virtualFile.getExtension(); - if (renameProcessor == null) { - renameProcessor = new RenameProcessor(myProject, propertiesFile.getContainingFile(), newName, false, false); - continue; - } - renameProcessor.addElement(propertiesFile.getContainingFile(), newName); - } - if (renameProcessor == null) { - LOG.assertTrue(false); - return true; - } - renameProcessor.setCommandName(PropertiesBundle.message("rename.resource.bundle.dialog.title")); - renameProcessor.doRun(); - return true; - } - } -} \ No newline at end of file diff --git a/plugins/properties/src/com/intellij/lang/properties/refactoring/RenamePropertyProcessor.java b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/RenamePropertyProcessor.java similarity index 59% rename from plugins/properties/src/com/intellij/lang/properties/refactoring/RenamePropertyProcessor.java rename to plugins/properties/src/com/intellij/lang/properties/refactoring/rename/RenamePropertyProcessor.java index 6bdaa0957133..f3c81736673f 100644 --- a/plugins/properties/src/com/intellij/lang/properties/refactoring/RenamePropertyProcessor.java +++ b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/RenamePropertyProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,12 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.lang.properties.refactoring; +package com.intellij.lang.properties.refactoring.rename; import com.intellij.lang.properties.IProperty; import com.intellij.lang.properties.PropertiesUtil; import com.intellij.lang.properties.ResourceBundle; import com.intellij.lang.properties.psi.PropertiesFile; +import com.intellij.lang.properties.refactoring.PropertiesRefactoringSettings; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.psi.PsiElement; import com.intellij.refactoring.rename.RenamePsiElementProcessor; @@ -26,6 +28,7 @@ import com.intellij.refactoring.rename.UnresolvableCollisionUsageInfo; import com.intellij.usageView.UsageInfo; import org.jetbrains.annotations.NotNull; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -36,12 +39,17 @@ public class RenamePropertyProcessor extends RenamePsiElementProcessor { public void prepareRenaming(final PsiElement element, final String newName, final Map allRenames) { - IProperty property = (IProperty) element; - ResourceBundle resourceBundle = property.getPropertiesFile().getResourceBundle(); - List properties = PropertiesUtil.findAllProperties(element.getProject(), resourceBundle, property.getUnescapedKey()); + final Project project = element.getProject(); + ResourceBundle resourceBundle = ((IProperty) element).getPropertiesFile().getResourceBundle(); + + final Map allRenamesCopy = new LinkedHashMap(allRenames); allRenames.clear(); - for (IProperty otherProperty : properties) { - allRenames.put(otherProperty.getPsiElement(), newName); + for (final Map.Entry e : allRenamesCopy.entrySet()) { + final IProperty property = (IProperty) e.getKey(); + final List properties = PropertiesUtil.findAllProperties(project, resourceBundle, property.getUnescapedKey()); + for (final IProperty toRename : properties) { + allRenames.put(toRename.getPsiElement(), e.getValue()); + } } } @@ -50,14 +58,16 @@ public class RenamePropertyProcessor extends RenamePsiElementProcessor { final String newName, Map allRenames, List result) { - for (IProperty property : ((PropertiesFile)element.getContainingFile()).getProperties()) { - if (Comparing.strEqual(newName, property.getKey())) { - result.add(new UnresolvableCollisionUsageInfo(property.getPsiElement(), element) { - @Override - public String getDescription() { - return "New property name \'" + newName + "\' hides existing property"; - } - }); + for (final Map.Entry e: allRenames.entrySet()) { + for (IProperty property : ((PropertiesFile)e.getKey().getContainingFile()).getProperties()) { + if (Comparing.strEqual(e.getValue(), property.getKey())) { + result.add(new UnresolvableCollisionUsageInfo(property.getPsiElement(), e.getKey()) { + @Override + public String getDescription() { + return "New property name \'" + e.getValue() + "\' hides existing property"; + } + }); + } } } } diff --git a/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleFromEditorRenameHandler.java b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleFromEditorRenameHandler.java new file mode 100644 index 000000000000..0c04bec80620 --- /dev/null +++ b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleFromEditorRenameHandler.java @@ -0,0 +1,120 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Alexey + */ +package com.intellij.lang.properties.refactoring.rename; + +import com.intellij.ide.util.treeView.smartTree.TreeElement; +import com.intellij.lang.properties.ResourceBundle; +import com.intellij.lang.properties.editor.*; +import com.intellij.lang.properties.structureView.PropertiesPrefixGroup; +import com.intellij.lang.properties.structureView.PropertiesStructureViewElement; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.command.CommandProcessor; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.fileEditor.FileEditor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.refactoring.rename.RenameHandler; +import com.intellij.util.NullableFunction; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * @author Dmitry Batkovich + */ +public class ResourceBundleFromEditorRenameHandler implements RenameHandler { + + @Override + public boolean isAvailableOnDataContext(DataContext dataContext) { + final Project project = CommonDataKeys.PROJECT.getData(dataContext); + if (project == null) { + return false; + } + final ResourceBundle bundle = ResourceBundleUtil.getResourceBundleFromDataContext(dataContext); + if (bundle == null) { + return false; + } + final FileEditor fileEditor = PlatformDataKeys.FILE_EDITOR.getData(dataContext); + if (fileEditor == null || !(fileEditor instanceof ResourceBundleEditor)) { + return false; + } + final VirtualFile virtualFile = CommonDataKeys.VIRTUAL_FILE.getData(dataContext); + return !(virtualFile == null || !(virtualFile instanceof ResourceBundleAsVirtualFile)); + } + + @Override + public boolean isRenaming(DataContext dataContext) { + return isAvailableOnDataContext(dataContext); + } + + @Override + public void invoke(final @NotNull Project project, Editor editor, final PsiFile file, DataContext dataContext) { + final ResourceBundleEditor resourceBundleEditor = (ResourceBundleEditor)PlatformDataKeys.FILE_EDITOR.getData(dataContext); + assert resourceBundleEditor != null; + final ResourceBundleEditorViewElement selectedElement = resourceBundleEditor.getSelectedElement(); + if (selectedElement != null) { + CommandProcessor.getInstance().runUndoTransparentAction(new Runnable() { + @Override + public void run() { + if (selectedElement instanceof PropertiesPrefixGroup) { + final PropertiesPrefixGroup group = (PropertiesPrefixGroup)selectedElement; + ResourceBundleRenameUtil.renameResourceBundleKeySection(getPsiElementsFromGroup(group), + group.getPresentableName(), + group.getPrefix().length() - group.getPresentableName().length()); + } else if (selectedElement instanceof ResourceBundlePropertyStructureViewElement) { + final PsiElement psiElement = ((ResourceBundlePropertyStructureViewElement)selectedElement).getProperty().getPsiElement(); + ResourceBundleRenameUtil.renameResourceBundleKey(psiElement, project); + } else if (selectedElement instanceof ResourceBundleFileStructureViewElement) { + ResourceBundleRenameUtil.renameResourceBundleBaseName(((ResourceBundleFileStructureViewElement)selectedElement).getValue(), project); + } else { + throw new IllegalStateException("unsupported type: " + selectedElement.getClass()); + } + } + }); + } + } + + @Override + public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, DataContext dataContext) { + invoke(project, null, null, dataContext); + } + + private static List getPsiElementsFromGroup(final PropertiesPrefixGroup propertiesPrefixGroup) { + return ContainerUtil.mapNotNull(propertiesPrefixGroup.getChildren(), new NullableFunction() { + @Nullable + @Override + public PsiElement fun(TreeElement treeElement) { + if (treeElement instanceof PropertiesStructureViewElement) { + return ((PropertiesStructureViewElement)treeElement).getValue().getPsiElement(); + } + if (treeElement instanceof ResourceBundlePropertyStructureViewElement) { + return ((ResourceBundlePropertyStructureViewElement)treeElement).getProperty().getPsiElement(); + } + return null; + } + }); + } +} diff --git a/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleFromProjectViewRenameHandler.java b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleFromProjectViewRenameHandler.java new file mode 100644 index 000000000000..f2cbca033b6b --- /dev/null +++ b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleFromProjectViewRenameHandler.java @@ -0,0 +1,65 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.lang.properties.refactoring.rename; + +import com.intellij.lang.properties.ResourceBundle; +import com.intellij.lang.properties.editor.*; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.refactoring.RefactoringActionHandlerFactory; +import com.intellij.refactoring.rename.RenameHandler; +import org.jetbrains.annotations.NotNull; + +/** + * @author Dmitry Batkovich + */ +public class ResourceBundleFromProjectViewRenameHandler implements RenameHandler { + + @Override + public boolean isAvailableOnDataContext(DataContext dataContext) { + final Project project = CommonDataKeys.PROJECT.getData(dataContext); + if (project == null) { + return false; + } + final ResourceBundle bundle = ResourceBundleUtil.getResourceBundleFromDataContext(dataContext); + if (bundle == null || bundle.getPropertiesFiles().size() < 2) { + return false; + } + return PlatformDataKeys.FILE_EDITOR.getData(dataContext) == null && CommonDataKeys.VIRTUAL_FILE.getData(dataContext) == null; + } + + @Override + public boolean isRenaming(DataContext dataContext) { + return isAvailableOnDataContext(dataContext); + } + + @Override + public void invoke(final @NotNull Project project, Editor editor, final PsiFile file, DataContext dataContext) { + final ResourceBundle resourceBundle = ResourceBundleUtil.getResourceBundleFromDataContext(dataContext); + assert resourceBundle != null; + RefactoringActionHandlerFactory.getInstance().createRenameHandler().invoke(project, new PsiElement[] {resourceBundle.getDefaultPropertiesFile().getContainingFile()}, dataContext); + } + + @Override + public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, DataContext dataContext) { + invoke(project, null, null, dataContext); + } +} diff --git a/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenameUtil.java b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenameUtil.java new file mode 100644 index 000000000000..79694f7ae35a --- /dev/null +++ b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenameUtil.java @@ -0,0 +1,152 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.lang.properties.refactoring.rename; + +import com.intellij.codeInsight.FileModificationService; +import com.intellij.lang.properties.PropertiesBundle; +import com.intellij.lang.properties.ResourceBundle; +import com.intellij.lang.properties.psi.PropertiesFile; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.InputValidator; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiNamedElement; +import com.intellij.refactoring.rename.PsiElementRenameHandler; +import com.intellij.refactoring.rename.RenameProcessor; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.List; + +/** + * @author Dmitry Batkovich + */ +public class ResourceBundleRenameUtil { + private final static Logger LOG = Logger.getInstance(ResourceBundleRenameUtil.class); + + public static void renameResourceBundleKey(final @NotNull PsiElement psiElement, final @NotNull Project project) { + PsiElementRenameHandler.invoke(psiElement, project, psiElement.getContainingFile(), null); + } + + public static void renameResourceBundleBaseName(final @NotNull ResourceBundle resourceBundle, final @NotNull Project project) { + Messages.showInputDialog(project, PropertiesBundle.message("rename.bundle.enter.new.resource.bundle.base.name.prompt.text"), + PropertiesBundle.message("rename.resource.bundle.dialog.title"), Messages.getQuestionIcon(), + resourceBundle.getBaseName(), new ResourceBundleBaseNameInputValidator(project, resourceBundle)); + } + + public static void renameResourceBundleKeySection(final List psiElements, final String section, final int sectionPosition) { + if (psiElements.isEmpty()) { + return; + } + final Project project = psiElements.get(0).getProject(); + Messages.showInputDialog(project, PropertiesBundle.message("rename.bundle.enter.new.resource.bundle.section.name.prompt.text"), + PropertiesBundle.message("rename.resource.bundle.section.dialog.title"), Messages.getQuestionIcon(), section, + new ResourceBundleKeySectionInputValidator(psiElements, section, sectionPosition, project)); + } + + private static class ResourceBundleKeySectionInputValidator implements InputValidator { + + private final List myPsiElements; + private final String mySection; + private final int mySectionPosition; + private final Project myProject; + + private ResourceBundleKeySectionInputValidator(final List psiElements, + final String section, + final int sectionPosition, + final Project project) { + myPsiElements = psiElements; + mySection = section; + mySectionPosition = sectionPosition; + myProject = project; + } + + @Override + public boolean checkInput(final String inputString) { + return inputString.indexOf('.') < 0; + } + + @Override + public boolean canClose(final String inputString) { + RenameProcessor renameProcessor = null; + for (final PsiElement psiElement : myPsiElements) { + assert psiElement instanceof PsiNamedElement; + final String oldName = ((PsiNamedElement)psiElement).getName(); + assert oldName != null; + final String newName = + oldName.substring(0, mySectionPosition) + inputString + oldName.substring(mySectionPosition + mySection.length()); + if (renameProcessor == null) { + renameProcessor = new RenameProcessor(myProject, psiElement, newName, false, false); + } + else { + renameProcessor.addElement(psiElement, newName); + } + } + assert renameProcessor != null; + renameProcessor.setCommandName(PropertiesBundle.message("rename.resource.bundle.section.dialog.title")); + renameProcessor.doRun(); + return true; + } + } + + private static class ResourceBundleBaseNameInputValidator implements InputValidator { + private final Project myProject; + private final ResourceBundle myResourceBundle; + + public ResourceBundleBaseNameInputValidator(final Project project, final ResourceBundle resourceBundle) { + myProject = project; + myResourceBundle = resourceBundle; + } + + public boolean checkInput(String inputString) { + return inputString.indexOf(File.separatorChar) < 0 && inputString.indexOf('/') < 0; + } + + public boolean canClose(final String inputString) { + final List propertiesFiles = myResourceBundle.getPropertiesFiles(); + for (PropertiesFile propertiesFile : propertiesFiles) { + if (!FileModificationService.getInstance().prepareFileForWrite(propertiesFile.getContainingFile())) return false; + } + + RenameProcessor renameProcessor = null; + final String baseName = myResourceBundle.getBaseName(); + for (PropertiesFile propertiesFile : propertiesFiles) { + final VirtualFile virtualFile = propertiesFile.getVirtualFile(); + if (virtualFile == null) { + continue; + } + final String newName = + inputString + virtualFile.getNameWithoutExtension().substring(baseName.length()) + "." + virtualFile.getExtension(); + if (renameProcessor == null) { + renameProcessor = new RenameProcessor(myProject, propertiesFile.getContainingFile(), newName, false, false); + continue; + } + renameProcessor.addElement(propertiesFile.getContainingFile(), newName); + } + if (renameProcessor == null) { + LOG.assertTrue(false); + return true; + } + + renameProcessor.setCommandName(PropertiesBundle.message("rename.resource.bundle.dialog.title")); + renameProcessor.doRun(); + + return true; + } + } +} diff --git a/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenamer.java b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenamer.java new file mode 100644 index 000000000000..ab1b4391b0f6 --- /dev/null +++ b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenamer.java @@ -0,0 +1,74 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.lang.properties.refactoring.rename; + +import com.intellij.lang.properties.PropertiesBundle; +import com.intellij.lang.properties.PropertiesUtil; +import com.intellij.lang.properties.psi.PropertiesFile; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiNamedElement; +import com.intellij.refactoring.rename.naming.AutomaticRenamer; +import org.jetbrains.annotations.NonNls; + +/** + * @author Dmitry Batkovich + */ +public class ResourceBundleRenamer extends AutomaticRenamer { + + public ResourceBundleRenamer(final PropertiesFile propertiesFile, final String newName) { + for (final PropertiesFile file : propertiesFile.getResourceBundle().getPropertiesFiles()) { + if (file.equals(propertiesFile)) { + continue; + } + final PsiFile containingFile = file.getContainingFile(); + myElements.add(containingFile); + } + suggestAllNames(propertiesFile.getName(), newName); + } + + @Override + protected String nameToCanonicalName(@NonNls final String name, final PsiNamedElement element) { + return PropertiesUtil.getBaseName((PsiFile)element); + } + + @Override + protected String canonicalNameToName(@NonNls final String canonicalName, final PsiNamedElement element) { + final String oldCanonicalName = PropertiesUtil.getBaseName((PsiFile)element); + final String oldName = element.getName(); + assert oldName != null; + return canonicalName + oldName.substring(oldCanonicalName.length()); + } + + @Override + public boolean isSelectedByDefault() { + return true; + } + + @Override + public String getDialogTitle() { + return PropertiesBundle.message("resource.bundle.renamer"); + } + + @Override + public String getDialogDescription() { + return PropertiesBundle.message("resource.bundle.renamer.dialog.description"); + } + + @Override + public String entityName() { + return PropertiesBundle.message("resource.bundle.renamer.entity.name"); + } +} diff --git a/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenamerFactory.java b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenamerFactory.java new file mode 100644 index 000000000000..ec4bd31acbf3 --- /dev/null +++ b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenamerFactory.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.lang.properties.refactoring.rename; + +import com.intellij.lang.properties.PropertiesBundle; +import com.intellij.lang.properties.PropertiesImplUtil; +import com.intellij.lang.properties.psi.PropertiesFile; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.refactoring.rename.naming.AutomaticRenamer; +import com.intellij.refactoring.rename.naming.AutomaticRenamerFactory; +import com.intellij.usageView.UsageInfo; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +/** + * @author Dmitry Batkovich + */ +public class ResourceBundleRenamerFactory implements AutomaticRenamerFactory { + @Override + public boolean isApplicable(final PsiElement element) { + if (!(element instanceof PsiFile)) { + return false; + } + return PropertiesImplUtil.isPropertiesFile((PsiFile)element); + } + + + @Nullable + @Override + public String getOptionName() { + return PropertiesBundle.message("resource.bundle.renamer.option"); + } + + @Override + public boolean isEnabled() { + return true; + } + + @Override + public void setEnabled(final boolean enabled) { + } + + @Override + public AutomaticRenamer createRenamer(final PsiElement element, final String newName, final Collection usages) { + final PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile((PsiFile)element); + assert propertiesFile != null; + return new ResourceBundleRenamer(propertiesFile, newName); + } +} diff --git a/plugins/properties/src/com/intellij/lang/properties/references/I18nizeQuickFixDialog.java b/plugins/properties/src/com/intellij/lang/properties/references/I18nizeQuickFixDialog.java index b19510be034b..f044a6db681c 100644 --- a/plugins/properties/src/com/intellij/lang/properties/references/I18nizeQuickFixDialog.java +++ b/plugins/properties/src/com/intellij/lang/properties/references/I18nizeQuickFixDialog.java @@ -275,7 +275,7 @@ public class I18nizeQuickFixDialog extends DialogWrapper implements I18nizeQuick private void propertiesFileChanged() { PropertiesFile propertiesFile = getPropertiesFile(); boolean hasResourceBundle = - propertiesFile != null && propertiesFile.getResourceBundle().getPropertiesFiles(propertiesFile.getProject()).size() > 1; + propertiesFile != null && propertiesFile.getResourceBundle().getPropertiesFiles().size() > 1; myUseResourceBundle.setEnabled(hasResourceBundle); } @@ -497,7 +497,7 @@ public class I18nizeQuickFixDialog extends DialogWrapper implements I18nizeQuick if (propertiesFile == null) return Collections.emptySet(); Collection propertiesFiles; if (isUseResourceBundle()) { - propertiesFiles = propertiesFile.getResourceBundle().getPropertiesFiles(myProject); + propertiesFiles = propertiesFile.getResourceBundle().getPropertiesFiles(); } else { propertiesFiles = Collections.singleton(propertiesFile); diff --git a/plugins/properties/testSrc/com/intellij/lang/properties/PropertiesUtilTest.java b/plugins/properties/testSrc/com/intellij/lang/properties/PropertiesUtilTest.java index 5ebf25d4258f..ec1ae720e129 100644 --- a/plugins/properties/testSrc/com/intellij/lang/properties/PropertiesUtilTest.java +++ b/plugins/properties/testSrc/com/intellij/lang/properties/PropertiesUtilTest.java @@ -16,13 +16,16 @@ package com.intellij.lang.properties; import com.intellij.openapi.vfs.newvfs.impl.StubVirtualFile; +import com.intellij.psi.PsiFile; +import com.intellij.psi.impl.FakePsiElement; +import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; import junit.framework.TestCase; import org.jetbrains.annotations.NotNull; /** * @author Dmitry Batkovich */ -public class PropertiesUtilTest extends TestCase { +public class PropertiesUtilTest extends LightPlatformCodeInsightFixtureTestCase { public void testBaseNameWithoutLocale() { assertBaseNameEquals("property-file.properties", "property-file"); @@ -62,14 +65,8 @@ public class PropertiesUtilTest extends TestCase { assertBaseNameEquals("Base_Page.utf8.properties", "Base_Page.utf8"); } - private static void assertBaseNameEquals(final String propertyFileName, final String expectedBaseName) { - final String actualBaseName = PropertiesUtil.getBaseName(new StubVirtualFile() { - @NotNull - @Override - public String getName() { - return propertyFileName; - } - }); + private void assertBaseNameEquals(final String propertyFileName, final String expectedBaseName) { + final String actualBaseName = PropertiesUtil.getBaseName(myFixture.configureByText(propertyFileName, "")); assertEquals(expectedBaseName, actualBaseName); } } diff --git a/plugins/properties/testSrc/com/intellij/lang/properties/ResourceBundleRenameTest.java b/plugins/properties/testSrc/com/intellij/lang/properties/ResourceBundleRenameTest.java new file mode 100644 index 000000000000..f8c435817ea4 --- /dev/null +++ b/plugins/properties/testSrc/com/intellij/lang/properties/ResourceBundleRenameTest.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.lang.properties; + +import com.intellij.lang.properties.refactoring.rename.ResourceBundleRenamerFactory; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.psi.PsiFile; +import com.intellij.refactoring.rename.RenameProcessor; +import com.intellij.refactoring.rename.naming.AutomaticRenamerFactory; +import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; + +/** + * @author Dmitry Batkovich + */ +public class ResourceBundleRenameTest extends LightPlatformCodeInsightFixtureTestCase { + + public void testRenameResourceBundleEntryFile() { + final PsiFile toRenameFile = myFixture.addFileToProject("old_p.properties", ""); + final PsiFile toCheck = myFixture.addFileToProject("old_p_en.properties", ""); + + final RenameProcessor processor = new RenameProcessor(getProject(), toRenameFile, "new_p.properties", true, true); + for (AutomaticRenamerFactory factory : Extensions.getExtensions(AutomaticRenamerFactory.EP_NAME)) { + if (factory instanceof ResourceBundleRenamerFactory) { + processor.addRenamerFactory(factory); + } + } + processor.run(); + + assertEquals("new_p_en.properties", toCheck.getName()); + } + + public void testRenamePropertyKey() { + final PsiFile toCheckFile = myFixture.addFileToProject("p.properties", "key=value"); + myFixture.configureByText("p_en.properties", "key=en_value"); + myFixture.renameElementAtCaret("new_key"); + assertEquals(toCheckFile.getText(), "new_key=value"); + } +} From a314cf4634325cbe8da8b47f5597deddb33f088d Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Tue, 1 Jul 2014 12:04:19 +0400 Subject: [PATCH 02/59] cleanup --- .../lang/properties/editor/ResourceBundleEditor.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java index 1c79c0fd6074..7c48d9d834ef 100644 --- a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java +++ b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java @@ -355,12 +355,6 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit writeEditorPropertyValue(editor, propertiesFile); } }); - editor.getComponent().addFocusListener(new FocusAdapter() { - @Override - public void focusLost(FocusEvent e) { - writeEditorPropertyValue(editor, propertiesFile); - } - }); editor.getDocument().putUserData(UndoConstants.DONT_RECORD_UNDO, Boolean.TRUE); gc.gridx = 0; gc.gridy = y++; From 3b910ff2ee51579644bf21cfdbfb3a8b62324a96 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Tue, 1 Jul 2014 12:10:14 +0400 Subject: [PATCH 03/59] cleanup --- .../intellij/lang/properties/editor/ResourceBundleEditor.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java index 7c48d9d834ef..a68eeb4d25ca 100644 --- a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java +++ b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java @@ -74,8 +74,6 @@ import javax.swing.event.TreeSelectionListener; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreePath; import java.awt.*; -import java.awt.event.FocusAdapter; -import java.awt.event.FocusEvent; import java.beans.PropertyChangeListener; import java.util.*; import java.util.List; From 4122e62d7d34c6ba8240a646aa97fed1749294be Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Tue, 1 Jul 2014 12:37:47 +0400 Subject: [PATCH 04/59] resource bundle editor -- after change another property previous will save now --- .../editor/ResourceBundleEditor.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java index a68eeb4d25ca..32ba85943826 100644 --- a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java +++ b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java @@ -132,6 +132,16 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit if (getSelectedPropertyName() == null) return; if (!Comparing.strEqual(selectedPropertyName, getSelectedPropertyName()) || !Comparing.equal(selectedPropertiesFile, getSelectedPropertiesFile())) { + + if (e.getOldLeadSelectionPath() != null) { + for (Map.Entry entry : myEditors.entrySet()) { + if (entry.getValue() == mySelectedEditor) { + writeEditorPropertyValue(mySelectedEditor, entry.getKey(), selectedPropertyName); + break; + } + } + } + selectedPropertyName = getSelectedPropertyName(); selectedPropertiesFile = getSelectedPropertiesFile(); selectionChanged(); @@ -283,9 +293,9 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit return value instanceof ResourceBundleEditorViewElement ? (ResourceBundleEditorViewElement) value : null; } - private void writeEditorPropertyValue(final Editor editor, final PropertiesFile propertiesFile) { + private void writeEditorPropertyValue(final Editor editor, final PropertiesFile propertiesFile, final @Nullable String propertyName) { final String currentValue = editor.getDocument().getText(); - final String currentSelectedProperty = getSelectedPropertyName(); + final String currentSelectedProperty = propertyName == null ? getSelectedPropertyName() : propertyName; assert currentSelectedProperty != null; @@ -350,7 +360,7 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit @Override public void focusLost(final Editor eventEditor) { - writeEditorPropertyValue(editor, propertiesFile); + writeEditorPropertyValue(editor, propertiesFile, null); } }); editor.getDocument().putUserData(UndoConstants.DONT_RECORD_UNDO, Boolean.TRUE); @@ -521,7 +531,6 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit } private void selectionChanged() { myBackSlashPressed.clear(); - UIUtil.invokeLaterIfNeeded(new Runnable() { @Override public void run() { @@ -699,7 +708,7 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit if (mySelectedEditor != null) { for (final Map.Entry entry : myEditors.entrySet()) { if (mySelectedEditor.equals(entry.getValue())) { - writeEditorPropertyValue(mySelectedEditor, entry.getKey()); + writeEditorPropertyValue(mySelectedEditor, entry.getKey(), null); } } } From 8ad4d136d67629aa1b83f4509089ac8b05d50422 Mon Sep 17 00:00:00 2001 From: "andrey.vokin" Date: Mon, 30 Jun 2014 14:53:08 +0400 Subject: [PATCH 05/59] RUBY-6250 Rename refactoring for Cucumber step definitions --- .../intellij/refactoring/rename/RenameDialog.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/RenameDialog.java b/platform/lang-impl/src/com/intellij/refactoring/rename/RenameDialog.java index 48460c912403..4020c8fc5cae 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/RenameDialog.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/RenameDialog.java @@ -26,7 +26,6 @@ import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.help.HelpManager; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.Comparing; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; @@ -137,12 +136,12 @@ public class RenameDialog extends RefactoringDialog { return RenamePsiElementProcessor.forElement(myPsiElement).isToSearchInComments(myPsiElement); } - private String getFullName() { + protected String getFullName() { final String name = DescriptiveNameUtil.getDescriptiveName(myPsiElement); return (UsageViewUtil.getType(myPsiElement) + " " + name).trim(); } - private void createNewNameComponent() { + protected void createNewNameComponent() { String[] suggestedNames = getSuggestedNames(); myOldName = suggestedNames.length > 0 ? suggestedNames[0] : null; myNameSuggestionsField = new NameSuggestionsField(suggestedNames, myProject, FileTypes.PLAIN_TEXT, myEditor) { @@ -341,4 +340,12 @@ public class RenameDialog extends RefactoringDialog { final String newName = getNewName(); return RenameUtil.isValidName(myProject, myPsiElement, newName); } + + protected NameSuggestionsField getNameSuggestionsField() { + return myNameSuggestionsField; + } + + public JCheckBox getCbSearchInComments() { + return myCbSearchInComments; + } } From 71ea3c627dde5a5569eb8527985803888e06bed9 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Fri, 27 Jun 2014 14:39:42 +0400 Subject: [PATCH 06/59] notnull --- .../vfs/newvfs/events/VFileContentChangeEvent.java | 1 + .../openapi/vfs/newvfs/events/VFileCopyEvent.java | 14 ++++++++++---- .../vfs/newvfs/events/VFileCreateEvent.java | 9 ++++++--- .../vfs/newvfs/events/VFileDeleteEvent.java | 6 +++++- .../openapi/vfs/newvfs/events/VFileEvent.java | 5 ++++- .../openapi/vfs/newvfs/events/VFileMoveEvent.java | 12 ++++++++---- .../newvfs/events/VFilePropertyChangeEvent.java | 2 ++ 7 files changed, 36 insertions(+), 13 deletions(-) diff --git a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileContentChangeEvent.java b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileContentChangeEvent.java index cc1614c16ecd..3c9dbb6c6bdd 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileContentChangeEvent.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileContentChangeEvent.java @@ -60,6 +60,7 @@ public class VFileContentChangeEvent extends VFileEvent { return "VfsEvent[update: " + myFile.getUrl() + "]"; } + @NotNull @Override public String getPath() { return myFile.getPath(); diff --git a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileCopyEvent.java b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileCopyEvent.java index 50ac2c99cc51..5ea519067db8 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileCopyEvent.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileCopyEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +29,7 @@ public class VFileCopyEvent extends VFileEvent { private final VirtualFile myNewParent; private final String myNewChildName; - public VFileCopyEvent(final Object requestor, final VirtualFile file, final VirtualFile newParent, final String newChildName) { + public VFileCopyEvent(final Object requestor, @NotNull VirtualFile file, @NotNull VirtualFile newParent, @NotNull String newChildName) { super(requestor, false); myFile = file; myNewParent = newParent; @@ -37,23 +37,28 @@ public class VFileCopyEvent extends VFileEvent { } @Override + @NotNull public VirtualFile getFile() { return myFile; } + @NotNull public VirtualFile getNewParent() { return myNewParent; } + @NotNull public String getNewChildName() { return myNewChildName; } + @Override @NonNls public String toString() { return "VfsEvent[copy " + myFile +" to " + myNewParent + " as " + myNewChildName +"]"; } + @NotNull @Override public String getPath() { return myNewParent.getPath() + "/" + myNewChildName; @@ -70,6 +75,7 @@ public class VFileCopyEvent extends VFileEvent { return myFile.isValid() && myNewParent.findChild(myNewChildName) == null; } + @Override public boolean equals(final Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; @@ -83,9 +89,9 @@ public class VFileCopyEvent extends VFileEvent { return true; } + @Override public int hashCode() { - int result; - result = myFile.hashCode(); + int result = myFile.hashCode(); result = 31 * result + myNewParent.hashCode(); result = 31 * result + myNewChildName.hashCode(); return result; diff --git a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileCreateEvent.java b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileCreateEvent.java index e3a9b9040e32..c730b9b9fe6b 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileCreateEvent.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileCreateEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,9 +24,9 @@ import org.jetbrains.annotations.NotNull; * @author max */ public class VFileCreateEvent extends VFileEvent { - private final VirtualFile myParent; + @NotNull private final VirtualFile myParent; private final boolean myDirectory; - private final String myChildName; + @NotNull private final String myChildName; private final boolean myReCreation; private VirtualFile myCreatedFile; @@ -51,6 +51,7 @@ public class VFileCreateEvent extends VFileEvent { myReCreation = isReCreation; } + @NotNull public String getChildName() { return myChildName; } @@ -59,6 +60,7 @@ public class VFileCreateEvent extends VFileEvent { return myDirectory; } + @NotNull public VirtualFile getParent() { return myParent; } @@ -74,6 +76,7 @@ public class VFileCreateEvent extends VFileEvent { myChildName + " in " + myParent.getUrl() + "]"; } + @NotNull @Override public String getPath() { return myParent.getPath() + "/" + myChildName; diff --git a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileDeleteEvent.java b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileDeleteEvent.java index 10b03e082575..f1ed38a12e9b 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileDeleteEvent.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileDeleteEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,11 +40,13 @@ public class VFileDeleteEvent extends VFileEvent { return myFile; } + @Override @NonNls public String toString() { return "VfsEvent[deleted: " + myFile.getUrl() + "]"; } + @NotNull @Override public String getPath() { return myFile.getPath(); @@ -61,6 +63,7 @@ public class VFileDeleteEvent extends VFileEvent { return myFile.isValid(); } + @Override public boolean equals(final Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; @@ -70,6 +73,7 @@ public class VFileDeleteEvent extends VFileEvent { return myFile.equals(event.myFile); } + @Override public int hashCode() { return myFile.hashCode(); } diff --git a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileEvent.java b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileEvent.java index 3e931a588d7d..22eb1f3a3fb8 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileEvent.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,6 +41,7 @@ public abstract class VFileEvent { return myRequestor; } + @NotNull public abstract String getPath(); /** @@ -58,6 +59,8 @@ public abstract class VFileEvent { public abstract boolean isValid(); + @Override public abstract int hashCode(); + @Override public abstract boolean equals(Object o); } diff --git a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileMoveEvent.java b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileMoveEvent.java index 42ff9d42d8a0..dd145f88bc69 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileMoveEvent.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileMoveEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,7 +30,7 @@ public class VFileMoveEvent extends VFileEvent { private final VirtualFile myOldParent; private final VirtualFile myNewParent; - public VFileMoveEvent(final Object requestor, @NotNull final VirtualFile file, final VirtualFile newParent) { + public VFileMoveEvent(final Object requestor, @NotNull VirtualFile file, @NotNull VirtualFile newParent) { super(requestor, false); myFile = file; myNewParent = newParent; @@ -43,6 +43,7 @@ public class VFileMoveEvent extends VFileEvent { return myFile; } + @NotNull public VirtualFile getNewParent() { return myNewParent; } @@ -51,11 +52,13 @@ public class VFileMoveEvent extends VFileEvent { return myOldParent; } + @Override @NonNls public String toString() { return "VfsEvent[move " + myFile.getName() +" from " + myOldParent + " to " + myNewParent + "]"; } + @NotNull @Override public String getPath() { return myFile.getPath(); @@ -72,6 +75,7 @@ public class VFileMoveEvent extends VFileEvent { return myFile.isValid() && Comparing.equal(myFile.getParent(), myOldParent) && myOldParent.isValid(); } + @Override public boolean equals(final Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; @@ -85,9 +89,9 @@ public class VFileMoveEvent extends VFileEvent { return true; } + @Override public int hashCode() { - int result; - result = myFile.hashCode(); + int result = myFile.hashCode(); result = 31 * result + myOldParent.hashCode(); result = 31 * result + myNewParent.hashCode(); return result; diff --git a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFilePropertyChangeEvent.java b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFilePropertyChangeEvent.java index 360ce833a28b..90d10a76d3a8 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFilePropertyChangeEvent.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFilePropertyChangeEvent.java @@ -91,6 +91,7 @@ public class VFilePropertyChangeEvent extends VFileEvent { return myPropertyName; } + @NotNull @Override public String getPath() { return myFile.getPath(); @@ -131,6 +132,7 @@ public class VFilePropertyChangeEvent extends VFileEvent { return result; } + @Override @NotNull @NonNls public String toString() { From 1f49e3283bee7777bf9284a52c36e012c12b65f0 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Fri, 27 Jun 2014 17:29:24 +0400 Subject: [PATCH 07/59] cleanup --- .../FacetModificationTrackingServiceImpl.java | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/facet/impl/FacetModificationTrackingServiceImpl.java b/platform/lang-impl/src/com/intellij/facet/impl/FacetModificationTrackingServiceImpl.java index b5ae84e3d931..deb5cc516e6c 100644 --- a/platform/lang-impl/src/com/intellij/facet/impl/FacetModificationTrackingServiceImpl.java +++ b/platform/lang-impl/src/com/intellij/facet/impl/FacetModificationTrackingServiceImpl.java @@ -22,6 +22,7 @@ import com.intellij.facet.FacetManagerAdapter; import com.intellij.facet.FacetModificationTrackingService; import com.intellij.openapi.Disposable; import com.intellij.openapi.module.Module; +import com.intellij.openapi.util.ModificationTracker; import com.intellij.openapi.util.ModificationTrackerListener; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.SimpleModificationTracker; @@ -35,8 +36,8 @@ import java.util.Map; * @author nik */ public class FacetModificationTrackingServiceImpl extends FacetModificationTrackingService { - private final Map>> myModificationsTrackers = - new THashMap>>(); + private final Map>> myModificationsTrackers = + new THashMap>>(); public FacetModificationTrackingServiceImpl(final Module module) { module.getMessageBus().connect().subscribe(FacetManager.FACETS_TOPIC, new FacetModificationTrackingListener()); @@ -44,14 +45,14 @@ public class FacetModificationTrackingServiceImpl extends FacetModificationTrack @Override @NotNull - public FacetModificationTracker getFacetModificationTracker(@NotNull final Facet facet) { + public ModificationTracker getFacetModificationTracker(@NotNull final Facet facet) { return getFacetInfo(facet).first; } - private Pair> getFacetInfo(final Facet facet) { - Pair> pair = myModificationsTrackers.get(facet); + private Pair> getFacetInfo(final Facet facet) { + Pair> pair = myModificationsTrackers.get(facet); if (pair == null) { - pair = Pair.create(new FacetModificationTracker(), EventDispatcher.create(ModificationTrackerListener.class)); + pair = Pair.create(new SimpleModificationTracker(), EventDispatcher.create(ModificationTrackerListener.class)); myModificationsTrackers.put(facet, pair); } return pair; @@ -59,7 +60,7 @@ public class FacetModificationTrackingServiceImpl extends FacetModificationTrack @Override public void incFacetModificationTracker(@NotNull final Facet facet) { - final Pair> pair = getFacetInfo(facet); + final Pair> pair = getFacetInfo(facet); pair.first.incModificationCount(); pair.second.getMulticaster().modificationCountChanged(facet); } @@ -74,13 +75,10 @@ public class FacetModificationTrackingServiceImpl extends FacetModificationTrack getFacetInfo(facet).second.removeListener(listener); } - private static class FacetModificationTracker extends SimpleModificationTracker { - } - private class FacetModificationTrackingListener extends FacetManagerAdapter { @Override public void facetConfigurationChanged(@NotNull final Facet facet) { - final Pair> pair = myModificationsTrackers.get(facet); + final Pair> pair = myModificationsTrackers.get(facet); if (pair != null) { pair.first.incModificationCount(); pair.second.getMulticaster().modificationCountChanged(facet); From 3a0b46414681ac782a49bf8329dd056faa0027a8 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Fri, 27 Jun 2014 17:35:49 +0400 Subject: [PATCH 08/59] replaced with the concrete bug number --- .../intellij/openapi/util/SimpleModificationTracker.java | 3 ++- platform/util/src/com/intellij/Patches.java | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/platform/core-api/src/com/intellij/openapi/util/SimpleModificationTracker.java b/platform/core-api/src/com/intellij/openapi/util/SimpleModificationTracker.java index d26cef614566..5232dc439b90 100644 --- a/platform/core-api/src/com/intellij/openapi/util/SimpleModificationTracker.java +++ b/platform/core-api/src/com/intellij/openapi/util/SimpleModificationTracker.java @@ -25,7 +25,8 @@ import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; public class SimpleModificationTracker implements ModificationTracker { static { // field made public to workaround bug in JDK7 when AtomicIntegerFieldUpdater can't be created for private field, even from within its own class - assert Patches.HACK_USED_WHICH_IS_FIXED_IN_JDK8; + // fixed in JDK8 + assert Patches.JDK_BUG_ID_7103570; } public volatile int myCounter; diff --git a/platform/util/src/com/intellij/Patches.java b/platform/util/src/com/intellij/Patches.java index ec9a3bee1650..edbf8e2b8496 100644 --- a/platform/util/src/com/intellij/Patches.java +++ b/platform/util/src/com/intellij/Patches.java @@ -147,8 +147,8 @@ public class Patches { public static final boolean USE_REFLECTION_TO_ACCESS_JDK7 = true; /** - * Marker field to find all usages of workarounds - * which will not be needed when migrated to JDK 8+ + * AtomicIntegerFieldUpdater does not work when SecurityManager is installed + * fixed in JDK8 */ - public static final boolean HACK_USED_WHICH_IS_FIXED_IN_JDK8 = true; + public static final boolean JDK_BUG_ID_7103570 = true; } From f29a59397b2940f464241bf4946b6f1fa615128e Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 30 Jun 2014 15:21:52 +0400 Subject: [PATCH 09/59] run tests with "-server" to speedup performance tests --- build/scripts/utils.gant | 1 + 1 file changed, 1 insertion(+) diff --git a/build/scripts/utils.gant b/build/scripts/utils.gant index ed09424fa0c4..44fbe4f56935 100644 --- a/build/scripts/utils.gant +++ b/build/scripts/utils.gant @@ -226,6 +226,7 @@ binding.setVariable("wireBuildDate", { String buildNumber, String appInfoFile -> binding.setVariable("commonJvmArgs", { return [ "-ea", + "-server", "-Didea.home.path=$home", "-Xbootclasspath/p:${projectBuilder.moduleOutput(findModule("boot"))}", "-XX:+HeapDumpOnOutOfMemoryError", From 37711bc42076500894f4c449ab8020623da5210f Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 30 Jun 2014 18:55:53 +0400 Subject: [PATCH 10/59] IDEA-120751 --- .../src/com/intellij/find/FindManager.java | 4 +- .../find/actions/ShowUsagesAction.java | 196 ++++--- .../actions/ShowUsagesTableCellRenderer.java | 105 +++- .../find/findUsages/FindUsagesManager.java | 23 +- .../PsiElement2UsageTargetAdapter.java | 9 +- .../PsiElement2UsageTargetComposite.java | 2 +- .../intellij/find/impl/FindManagerImpl.java | 12 +- .../usages/impl/SearchForUsagesRunnable.java | 478 ++++++++++++++++++ .../usages/impl/UsageViewManagerImpl.java | 436 ++-------------- 9 files changed, 761 insertions(+), 504 deletions(-) create mode 100644 platform/usageView/src/com/intellij/usages/impl/SearchForUsagesRunnable.java diff --git a/platform/lang-api/src/com/intellij/find/FindManager.java b/platform/lang-api/src/com/intellij/find/FindManager.java index 102872655dca..56339d116e14 100644 --- a/platform/lang-api/src/com/intellij/find/FindManager.java +++ b/platform/lang-api/src/com/intellij/find/FindManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; +import com.intellij.psi.search.SearchScope; import com.intellij.util.messages.Topic; import org.intellij.lang.annotations.MagicConstant; import org.jetbrains.annotations.NotNull; @@ -217,6 +218,7 @@ public abstract class FindManager { * @param element the element to find the usages for. */ public abstract void findUsages(@NotNull PsiElement element); + public abstract void findUsagesInScope(@NotNull PsiElement element, @NotNull SearchScope searchScope); /** * Shows the Find Usages dialog (if {@code showDialog} is true} and performs the Find Usages operation for the diff --git a/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java b/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java index f84fed5a05d9..84776f4bf7ff 100644 --- a/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java +++ b/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java @@ -37,6 +37,7 @@ import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.ui.popup.PopupChooserBuilder; @@ -50,7 +51,6 @@ import com.intellij.pom.Navigatable; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.search.ProjectScope; import com.intellij.psi.search.PsiElementProcessor; import com.intellij.psi.search.SearchScope; import com.intellij.ui.*; @@ -84,14 +84,17 @@ import java.awt.event.ActionListener; import java.util.*; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; public class ShowUsagesAction extends AnAction implements PopupAction { private final boolean showSettingsDialogBefore; private static final int USAGES_PAGE_SIZE = 100; - static final NullUsage MORE_USAGES_SEPARATOR = NullUsage.INSTANCE; + static final Usage MORE_USAGES_SEPARATOR = NullUsage.INSTANCE; private static final UsageNode MORE_USAGES_SEPARATOR_NODE = UsageViewImpl.NULL_NODE; + static final Usage USAGES_OUTSIDE_SCOPE_SEPARATOR = new UsageAdapter(); + private static final UsageNode USAGES_OUTSIDE_SCOPE_NODE = new UsageNode(USAGES_OUTSIDE_SCOPE_SEPARATOR, new UsageViewTreeModelBuilder(new UsageViewPresentation(), UsageTarget.EMPTY_ARRAY)); private static final Comparator USAGE_NODE_COMPARATOR = new Comparator() { @Override @@ -100,8 +103,9 @@ public class ShowUsagesAction extends AnAction implements PopupAction { if (c2 instanceof StringNode) return -1; Usage o1 = c1.getUsage(); Usage o2 = c2.getUsage(); - if (o1 == MORE_USAGES_SEPARATOR) return 1; - if (o2 == MORE_USAGES_SEPARATOR) return -1; + int weight1 = o1 == USAGES_OUTSIDE_SCOPE_SEPARATOR ? 2 : o1 == MORE_USAGES_SEPARATOR ? 1 : 0; + int weight2 = o2 == USAGES_OUTSIDE_SCOPE_SEPARATOR ? 2 : o2 == MORE_USAGES_SEPARATOR ? 1 : 0; + if (weight1 != weight2) return weight1 - weight2; VirtualFile v1 = UsageListCellRenderer.getVirtualFile(o1); VirtualFile v2 = UsageListCellRenderer.getVirtualFile(o2); @@ -193,26 +197,18 @@ public class ShowUsagesAction extends AnAction implements PopupAction { private void startFindUsages(@NotNull PsiElement element, @NotNull RelativePoint popupPosition, Editor editor, int maxUsages) { Project project = element.getProject(); FindUsagesManager findUsagesManager = ((FindManagerImpl)FindManager.getInstance(project)).getFindUsagesManager(); - FindUsagesHandler handler = findUsagesManager.getNewFindUsagesHandler(element, false); + FindUsagesHandler handler = findUsagesManager.getFindUsagesHandler(element, false); if (handler == null) return; if (showSettingsDialogBefore) { showDialogAndFindUsages(handler, popupPosition, editor, maxUsages); return; } - showElementUsages(handler, editor, popupPosition, maxUsages, getDefaultOptions(handler)); + showElementUsages(editor, popupPosition, handler, maxUsages, handler.getFindUsagesOptions(DataManager.getInstance().getDataContext())); } - @NotNull - private static FindUsagesOptions getDefaultOptions(@NotNull FindUsagesHandler handler) { - FindUsagesOptions options = handler.getFindUsagesOptions(DataManager.getInstance().getDataContext()); - // by default, scope in FindUsagesOptions is copied from the FindSettings, but we need a default one - options.searchScope = GlobalSearchScope.projectScope(handler.getProject()); - return options; - } - - private void showElementUsages(@NotNull final FindUsagesHandler handler, - final Editor editor, + private void showElementUsages(final Editor editor, @NotNull final RelativePoint popupPosition, + @NotNull final FindUsagesHandler handler, final int maxUsages, @NotNull final FindUsagesOptions options) { ApplicationManager.getApplication().assertIsDispatchThread(); @@ -236,30 +232,26 @@ public class ShowUsagesAction extends AnAction implements PopupAction { usageViewSettings.loadState(savedGlobalSettings); } }); + final AtomicInteger outOfScopeUsages = new AtomicInteger(); final List usages = new ArrayList(); final Set visibleNodes = new LinkedHashSet(); final MyTable table = new MyTable(); final AsyncProcessIcon processIcon = new AsyncProcessIcon("xxx"); - boolean hadMoreSeparator = visibleNodes.remove(MORE_USAGES_SEPARATOR_NODE); - if (hadMoreSeparator) { - usages.add(MORE_USAGES_SEPARATOR); - visibleNodes.add(MORE_USAGES_SEPARATOR_NODE); - } addUsageNodes(usageView.getRoot(), usageView, new ArrayList()); TableScrollingUtil.installActions(table); final List data = collectData(usages, visibleNodes, usageView, presentation); - setTableModel(table, usageView, data); + setTableModel(table, usageView, data, outOfScopeUsages, options.searchScope); SpeedSearchBase speedSearch = new MySpeedSearch(table); speedSearch.setComparator(new SpeedSearchComparator(false)); final JBPopup popup = createUsagePopup(usages, visibleNodes, handler, editor, popupPosition, - maxUsages, usageView, options, table, presentation, processIcon, hadMoreSeparator); + maxUsages, usageView, options, table, presentation, processIcon); Disposer.register(popup, usageView); @@ -293,7 +285,8 @@ public class ShowUsagesAction extends AnAction implements PopupAction { copy = new ArrayList(usages); } - rebuildPopup(usageView, copy, nodes, table, popup, presentation, popupPosition, !processIcon.isDisposed()); + rebuildPopup(usageView, copy, nodes, table, popup, presentation, popupPosition, !processIcon.isDisposed(), outOfScopeUsages, + options.searchScope); } }); @@ -305,11 +298,17 @@ public class ShowUsagesAction extends AnAction implements PopupAction { } }); - + final UsageTarget[] myUsageTarget = {new PsiElement2UsageTargetAdapter(handler.getPsiElement())}; Processor collect = new Processor() { - private final UsageTarget[] myUsageTarget = {new PsiElement2UsageTargetAdapter(handler.getPsiElement())}; @Override public boolean process(@NotNull final Usage usage) { + if (!UsageViewManagerImpl.isInScope(usage, options.searchScope)) { + if (outOfScopeUsages.getAndIncrement() == 0) { + visibleNodes.add(USAGES_OUTSIDE_SCOPE_NODE); + usages.add(USAGES_OUTSIDE_SCOPE_SEPARATOR); + } + return true; + } synchronized (usages) { if (visibleNodes.size() >= maxUsages) return false; if(UsageViewManager.isSelfUsage(usage, myUsageTarget)) return true; @@ -352,8 +351,8 @@ public class ShowUsagesAction extends AnAction implements PopupAction { synchronized (usages) { if (visibleNodes.isEmpty()) { if (usages.isEmpty()) { - String text = UsageViewBundle.message("no.usages.found.in", searchScopePresentableName(options, project)); - showHint(text, editor, popupPosition, handler, maxUsages, options); + String text = UsageViewBundle.message("no.usages.found.in", searchScopePresentableName(options)); + hint(editor, text, handler, popupPosition, maxUsages, options, false); popup.cancel(); } else { @@ -364,8 +363,13 @@ public class ShowUsagesAction extends AnAction implements PopupAction { if (usages.size() == 1) { //the only usage Usage usage = visibleNodes.iterator().next().getUsage(); - String message = UsageViewBundle.message("show.usages.only.usage", searchScopePresentableName(options, project)); - navigateAndHint(usage, message, handler, popupPosition, maxUsages, options); + if (usage == USAGES_OUTSIDE_SCOPE_SEPARATOR) { + hint(editor, UsageViewManagerImpl.outOfScopeMessage(outOfScopeUsages.get(), options.searchScope), handler, popupPosition, maxUsages, options, true); + } + else { + String message = UsageViewBundle.message("show.usages.only.usage", searchScopePresentableName(options)); + navigateAndHint(usage, message, handler, popupPosition, maxUsages, options); + } popup.cancel(); } else { @@ -373,7 +377,7 @@ public class ShowUsagesAction extends AnAction implements PopupAction { // usage view can filter usages down to one Usage visibleUsage = visibleNodes.iterator().next().getUsage(); if (areAllUsagesInOneLine(visibleUsage, usages)) { - String hint = UsageViewBundle.message("all.usages.are.in.this.line", usages.size(), searchScopePresentableName(options, project)); + String hint = UsageViewBundle.message("all.usages.are.in.this.line", usages.size(), searchScopePresentableName(options)); navigateAndHint(visibleUsage, hint, handler, popupPosition, maxUsages, options); popup.cancel(); } @@ -451,21 +455,6 @@ public class ShowUsagesAction extends AnAction implements PopupAction { } } - private void showHint(@NotNull String text, - @Nullable final Editor editor, - @NotNull final RelativePoint popupPosition, - @NotNull FindUsagesHandler handler, - int maxUsages, - @NotNull FindUsagesOptions options) { - JComponent label = createHintComponent(text, handler, popupPosition, editor, HIDE_HINTS_ACTION, maxUsages, options); - if (editor == null || editor.isDisposed() || !editor.getComponent().isShowing()) { - HintManager.getInstance().showHint(label, popupPosition, HintManager.HIDE_BY_ANY_KEY | - HintManager.HIDE_BY_TEXT_CHANGE | HintManager.HIDE_BY_SCROLLING, 0); - } - else { - HintManager.getInstance().showInformationHint(editor, label); - } - } @NotNull private JComponent createHintComponent(@NotNull String text, @@ -474,8 +463,12 @@ public class ShowUsagesAction extends AnAction implements PopupAction { final Editor editor, @NotNull final Runnable cancelAction, final int maxUsages, - @NotNull final FindUsagesOptions options) { + @NotNull final FindUsagesOptions options, + boolean isWarning) { JComponent label = HintUtil.createInformationLabel(suggestSecondInvocation(options, handler, text + " ")); + if (isWarning) { + label.setBackground(MessageType.WARNING.getPopupBackground()); + } InplaceButton button = createSettingsButton(handler, popupPosition, editor, maxUsages, cancelAction); JPanel panel = new JPanel(new BorderLayout()) { @@ -540,19 +533,13 @@ public class ShowUsagesAction extends AnAction implements PopupAction { if (dialog.isOK()) { dialog.calcFindUsagesOptions(); FindUsagesOptions options = handler.getFindUsagesOptions(DataManager.getInstance().getDataContext()); - showElementUsages(handler, editor, popupPosition, maxUsages, options); + showElementUsages(editor, popupPosition, handler, maxUsages, options); } } - private static String searchScopePresentableName(@NotNull FindUsagesOptions options, @NotNull Project project) { - return notNullizeScope(options, project).getDisplayName(); - } - @NotNull - private static SearchScope notNullizeScope(@NotNull FindUsagesOptions options, @NotNull Project project) { - SearchScope scope = options.searchScope; - if (scope == null) return ProjectScope.getAllScope(project); - return scope; + private static String searchScopePresentableName(@NotNull FindUsagesOptions options) { + return options.searchScope.getDisplayName(); } @NotNull @@ -566,8 +553,7 @@ public class ShowUsagesAction extends AnAction implements PopupAction { @NotNull final FindUsagesOptions options, @NotNull final JTable table, @NotNull final UsageViewPresentation presentation, - @NotNull final AsyncProcessIcon processIcon, - boolean hadMoreSeparator) { + @NotNull final AsyncProcessIcon processIcon) { table.setRowHeight(PlatformIcons.CLASS_ICON.getIconHeight()+2); table.setShowGrid(false); table.setShowVerticalLines(false); @@ -579,14 +565,15 @@ public class ShowUsagesAction extends AnAction implements PopupAction { PopupChooserBuilder builder = new PopupChooserBuilder(table); final String title = presentation.getTabText(); if (title != null) { - String result = getFullTitle(usages, title, hadMoreSeparator, visibleNodes.size() - 1, true); + String result = getFullTitle(usages, title, false, visibleNodes.size() - 1, true); builder.setTitle(result); builder.setAdText(getSecondInvocationTitle(options, handler)); } builder.setMovable(true).setResizable(true); final AtomicReference selectedUsage = new AtomicReference(); - final AtomicBoolean moreUsages = new AtomicBoolean(); + final AtomicBoolean moreUsagesSelected = new AtomicBoolean(); + final AtomicBoolean outsideScopeUsagesSelected = new AtomicBoolean(); table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { @@ -596,12 +583,17 @@ public class ShowUsagesAction extends AnAction implements PopupAction { Object value = table.getValueAt(i, 0); if (value instanceof UsageNode) { Usage usage = ((UsageNode)value).getUsage(); - if (usage == MORE_USAGES_SEPARATOR) { - moreUsages.set(true); + outsideScopeUsagesSelected.set(false); + moreUsagesSelected.set(false); + if (usage == USAGES_OUTSIDE_SCOPE_SEPARATOR) { + outsideScopeUsagesSelected.set(true); + selectedUsage.set(null); + } + else if (usage == MORE_USAGES_SEPARATOR) { + moreUsagesSelected.set(true); selectedUsage.set(null); } else { - moreUsages.set(false); selectedUsage.set(usage instanceof UsageInfo2UsageAdapter ? ((UsageInfo2UsageAdapter)usage).getUsageInfo().copy() : usage); } break; @@ -613,10 +605,15 @@ public class ShowUsagesAction extends AnAction implements PopupAction { builder.setItemChoosenCallback(new Runnable() { @Override public void run() { - if (moreUsages.get()) { + if (moreUsagesSelected.get()) { appendMoreUsages(editor, popupPosition, handler, maxUsages, options); return; } + if (outsideScopeUsagesSelected.get()) { + options.searchScope = GlobalSearchScope.projectScope(handler.getProject()); + showElementUsages(editor, popupPosition, handler, maxUsages, options); + return; + } Object usage = selectedUsage.get(); if (usage instanceof UsageInfo) { UsageViewUtil.navigateTo((UsageInfo)usage, true); @@ -684,7 +681,7 @@ public class ShowUsagesAction extends AnAction implements PopupAction { JComponent content = popup[0].getContent(); myWidth = (int)(toolBar.getPreferredSize().getWidth() - + new JLabel(getFullTitle(usages, title, hadMoreSeparator, visibleNodes.size() - 1, true)).getPreferredSize().getWidth() + + new JLabel(getFullTitle(usages, title, false, visibleNodes.size() - 1, true)).getPreferredSize().getWidth() + settingsButton.getPreferredSize().getWidth()); myWidth = -1; for (AnAction action : toolbar.getChildren(null)) { @@ -770,7 +767,7 @@ public class ShowUsagesAction extends AnAction implements PopupAction { private static String getSecondInvocationTitle(@NotNull FindUsagesOptions options, @NotNull FindUsagesHandler handler) { if (getShowUsagesShortcut() != null) { GlobalSearchScope maximalScope = FindUsagesManager.getMaximalScope(handler); - if (!notNullizeScope(options, handler.getProject()).equals(maximalScope)) { + if (!options.searchScope.equals(maximalScope)) { return "Press " + KeymapUtil.getShortcutText(getShowUsagesShortcut()) + " again to search in " + maximalScope.getDisplayName(); } } @@ -784,7 +781,7 @@ public class ShowUsagesAction extends AnAction implements PopupAction { int maxUsages) { FindUsagesOptions cloned = options.clone(); cloned.searchScope = FindUsagesManager.getMaximalScope(handler); - showElementUsages(handler, editor, popupPosition, maxUsages, cloned); + showElementUsages(editor, popupPosition, handler, maxUsages, cloned); } @Nullable @@ -827,7 +824,9 @@ public class ShowUsagesAction extends AnAction implements PopupAction { @NotNull private static MyModel setTableModel(@NotNull JTable table, @NotNull UsageViewImpl usageView, - @NotNull final List data) { + @NotNull final List data, + @NotNull AtomicInteger outOfScopeUsages, + @NotNull SearchScope searchScope) { ApplicationManager.getApplication().assertIsDispatchThread(); final int columnCount = calcColumnCount(data); MyModel model = table.getModel() instanceof MyModel ? (MyModel)table.getModel() : null; @@ -835,7 +834,7 @@ public class ShowUsagesAction extends AnAction implements PopupAction { model = new MyModel(data, columnCount); table.setModel(model); - ShowUsagesTableCellRenderer renderer = new ShowUsagesTableCellRenderer(usageView); + ShowUsagesTableCellRenderer renderer = new ShowUsagesTableCellRenderer(usageView, outOfScopeUsages, searchScope); for (int i=0;i data = collectData(usages, nodes, usageView, presentation); - MyModel tableModel = setTableModel(table, usageView, data); + MyModel tableModel = setTableModel(table, usageView, data, outOfScopeUsages, searchScope); List existingData = tableModel.getItems(); int row = table.getSelectedRow(); @@ -1021,8 +1026,9 @@ public class ShowUsagesAction extends AnAction implements PopupAction { private void appendMoreUsages(Editor editor, @NotNull RelativePoint popupPosition, @NotNull FindUsagesHandler handler, - int maxUsages, final FindUsagesOptions options) { - showElementUsages(handler, editor, popupPosition, maxUsages+USAGES_PAGE_SIZE, options); + int maxUsages, + @NotNull FindUsagesOptions options) { + showElementUsages(editor, popupPosition, handler, maxUsages+USAGES_PAGE_SIZE, options); } private static void addUsageNodes(@NotNull GroupNode root, @NotNull final UsageViewImpl usageView, @NotNull List outNodes) { @@ -1054,25 +1060,51 @@ public class ShowUsagesAction extends AnAction implements PopupAction { if (hint == null) return; final Editor newEditor = getEditorFor(usage); if (newEditor == null) return; + hint(newEditor, hint, handler, popupPosition, maxUsages, options, false); + } + + private void showHint(@Nullable final Editor editor, + @NotNull String hint, + @NotNull FindUsagesHandler handler, + @NotNull final RelativePoint popupPosition, + int maxUsages, + @NotNull FindUsagesOptions options, + boolean isWarning) { + JComponent label = createHintComponent(hint, handler, popupPosition, editor, HIDE_HINTS_ACTION, maxUsages, options, isWarning); + if (editor == null || editor.isDisposed() || !editor.getComponent().isShowing()) { + HintManager.getInstance().showHint(label, popupPosition, HintManager.HIDE_BY_ANY_KEY | + HintManager.HIDE_BY_TEXT_CHANGE | HintManager.HIDE_BY_SCROLLING, 0); + } + else { + HintManager.getInstance().showInformationHint(editor, label); + } + } + + private void hint(@Nullable final Editor editor, + @NotNull final String hint, + @NotNull final FindUsagesHandler handler, + @NotNull final RelativePoint popupPosition, + final int maxUsages, + @NotNull final FindUsagesOptions options, + final boolean isWarning) { final Project project = handler.getProject(); //opening editor is performing in invokeLater IdeFocusManager.getInstance(project).doWhenFocusSettlesDown(new Runnable() { @Override public void run() { - newEditor.getScrollingModel().runActionOnScrollingFinished(new Runnable() { + Runnable runnable = new Runnable() { @Override public void run() { // after new editor created, some editor resizing events are still bubbling. To prevent hiding hint, invokeLater this IdeFocusManager.getInstance(project).doWhenFocusSettlesDown(new Runnable() { @Override public void run() { - if (newEditor.getComponent().isShowing()) { - showHint(hint, newEditor, popupPosition, handler, maxUsages, options); - } + showHint(editor, hint, handler, popupPosition, maxUsages, options, isWarning); } }); } - }); + }; + if (editor == null) runnable.run(); else editor.getScrollingModel().runActionOnScrollingFinished(runnable); } }); } @@ -1119,9 +1151,9 @@ public class ShowUsagesAction extends AnAction implements PopupAction { } static class StringNode extends UsageNode { - private final Object myString; + @NotNull private final Object myString; - public StringNode(Object string) { + public StringNode(@NotNull Object string) { super(NullUsage.INSTANCE, new UsageViewTreeModelBuilder(new UsageViewPresentation(), UsageTarget.EMPTY_ARRAY)); myString = string; } @@ -1159,7 +1191,7 @@ public class ShowUsagesAction extends AnAction implements PopupAction { UsageNode node = (UsageNode)element; if (node instanceof StringNode) return ""; Usage usage = node.getUsage(); - if (usage == MORE_USAGES_SEPARATOR) return ""; + if (usage == MORE_USAGES_SEPARATOR || usage == USAGES_OUTSIDE_SCOPE_SEPARATOR) return ""; GroupNode group = (GroupNode)node.getParent(); return usage.getPresentation().getPlainText() + group; } diff --git a/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesTableCellRenderer.java b/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesTableCellRenderer.java index 7603bab35b7b..d9848fdec4b0 100644 --- a/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesTableCellRenderer.java +++ b/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesTableCellRenderer.java @@ -20,6 +20,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; +import com.intellij.psi.search.SearchScope; import com.intellij.ui.FileColorManager; import com.intellij.ui.SimpleColoredComponent; import com.intellij.ui.SimpleTextAttributes; @@ -30,24 +31,30 @@ import com.intellij.usages.UsagePresentation; import com.intellij.usages.impl.GroupNode; import com.intellij.usages.impl.UsageNode; import com.intellij.usages.impl.UsageViewImpl; +import com.intellij.usages.impl.UsageViewManagerImpl; import com.intellij.usages.rules.UsageInFile; import com.intellij.util.ui.EmptyIcon; import com.intellij.util.ui.UIUtil; -import com.intellij.xml.util.XmlStringUtil; import org.jetbrains.annotations.NotNull; import javax.swing.*; import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumnModel; import java.awt.*; +import java.util.concurrent.atomic.AtomicInteger; /** * @author cdr */ class ShowUsagesTableCellRenderer implements TableCellRenderer { private final UsageViewImpl myUsageView; + @NotNull private final AtomicInteger myOutOfScopeUsages; + @NotNull private final SearchScope mySearchScope; - ShowUsagesTableCellRenderer(@NotNull UsageViewImpl usageView) { + ShowUsagesTableCellRenderer(@NotNull UsageViewImpl usageView, @NotNull AtomicInteger outOfScopeUsages, @NotNull SearchScope searchScope) { myUsageView = usageView; + myOutOfScopeUsages = outOfScopeUsages; + mySearchScope = searchScope; } @Override @@ -60,32 +67,37 @@ class ShowUsagesTableCellRenderer implements TableCellRenderer { Color fileBgColor = getBackgroundColor(isSelected, usage); final Color bg = UIUtil.getListSelectionBackground(); final Color fg = UIUtil.getListSelectionForeground(); - panel.setBackground(isSelected ? bg : fileBgColor == null ? list.getBackground() : fileBgColor); - panel.setForeground(isSelected ? fg : list.getForeground()); - - if (usage == null || usageNode instanceof ShowUsagesAction.StringNode) { - panel.setLayout(new BorderLayout()); - if (column == 0) { - panel.add(new JLabel(XmlStringUtil.wrapInHtml("" + value + ""), SwingConstants.CENTER)); - } - return panel; - } - + Color panelBackground = isSelected ? bg : fileBgColor == null ? list.getBackground() : fileBgColor; + Color panelForeground = isSelected ? fg : list.getForeground(); + panel.setBackground(panelBackground); + panel.setForeground(panelForeground); SimpleColoredComponent textChunks = new SimpleColoredComponent(); - textChunks.setIpad(new Insets(0,0,0,0)); + textChunks.setIpad(new Insets(0, 0, 0, 0)); textChunks.setBorder(null); + if (usage == null || usageNode instanceof ShowUsagesAction.StringNode) { + textChunks.append(value.toString(), SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES); + return textComponentSpanningWholeRow(textChunks, panelBackground, panelForeground, column, list, row); + } + if (usage == ShowUsagesAction.MORE_USAGES_SEPARATOR) { + textChunks.append("...<"); + textChunks.append("more usages", SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES); + textChunks.append(">..."); + return textComponentSpanningWholeRow(textChunks, panelBackground, panelForeground, column, list, row); + } + else if (usage == ShowUsagesAction.USAGES_OUTSIDE_SCOPE_SEPARATOR) { + textChunks.append("...<"); + textChunks.append(UsageViewManagerImpl.outOfScopeMessage(myOutOfScopeUsages.get(), mySearchScope), SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES); + textChunks.append(">..."); + return textComponentSpanningWholeRow(textChunks, panelBackground, panelForeground, column, list, row); + } + if (column == 0) { GroupNode parent = (GroupNode)usageNode.getParent(); appendGroupText(parent, panel, fileBgColor); - if (usage == ShowUsagesAction.MORE_USAGES_SEPARATOR) { - textChunks.append("...<"); - textChunks.append("more usages", SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES); - textChunks.append(">..."); - } } - else if (usage != ShowUsagesAction.MORE_USAGES_SEPARATOR) { + else if (usage != ShowUsagesAction.MORE_USAGES_SEPARATOR && usage != ShowUsagesAction.USAGES_OUTSIDE_SCOPE_SEPARATOR) { UsagePresentation presentation = usage.getPresentation(); TextChunk[] text = presentation.getText(); @@ -116,6 +128,59 @@ class ShowUsagesTableCellRenderer implements TableCellRenderer { return panel; } + @NotNull + private static Component textComponentSpanningWholeRow(@NotNull SimpleColoredComponent chunks, + Color panelBackground, + Color panelForeground, + final int column, + @NotNull final JTable table, int row) { + final SimpleColoredComponent component = new SimpleColoredComponent() { + @Override + protected void doPaint(Graphics2D g) { + int offset = 0; + int i = 0; + final TableColumnModel columnModel = table.getColumnModel(); + while (i < column) { + offset += columnModel.getColumn(i).getWidth(); + i++; + } + g.translate(-offset, 0); + + //if (column == columnModel.getColumnCount()-1) { + //} + setSize(getWidth()+offset, getHeight()); // should increase the column width so that selection background will be visible even after offset translation + + super.doPaint(g); + + g.translate(+offset, 0); + } + + @NotNull + @Override + public Dimension getPreferredSize() { + //return super.getPreferredSize(); + return column == table.getColumnModel().getColumnCount()-1 ? super.getPreferredSize() : new Dimension(0,0); + // it should span the whole row, so we can't return any specific value here, + // because otherwise it would be used in the "max width" calculation in com.intellij.find.actions.ShowUsagesAction.calcMaxWidth + } + }; + + component.setIpad(new Insets(0,0,0,0)); + component.setBorder(null); + component.setBackground(panelBackground); + component.setForeground(panelForeground); + + for (SimpleColoredComponent.ColoredIterator iterator = chunks.iterator(); iterator.hasNext(); ) { + iterator.next(); + String fragment = iterator.getFragment(); + SimpleTextAttributes attributes = iterator.getTextAttributes(); + attributes = attributes.derive(attributes.getStyle(), panelForeground, panelBackground, attributes.getWaveColor()); + component.append(fragment, attributes); + } + + return component; + } + private static SimpleTextAttributes deriveAttributesWithColor(SimpleTextAttributes attributes, Color fileBgColor) { if (fileBgColor != null) { attributes = attributes.derive(-1,null, fileBgColor,null); diff --git a/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesManager.java b/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesManager.java index 6e6765594e22..d3978780e535 100644 --- a/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesManager.java +++ b/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesManager.java @@ -205,8 +205,8 @@ public class FindUsagesManager implements JDOMExternalizable { return null; } - public void findUsages(@NotNull PsiElement psiElement, final PsiFile scopeFile, final FileEditor editor, boolean showDialog) { - FindUsagesHandler handler = getNewFindUsagesHandler(psiElement, false); + public void findUsages(@NotNull PsiElement psiElement, final PsiFile scopeFile, final FileEditor editor, boolean showDialog, @Nullable("null means default (stored in options)") SearchScope searchScope) { + FindUsagesHandler handler = getFindUsagesHandler(psiElement, false); if (handler == null) return; boolean singleFile = scopeFile != null; @@ -222,8 +222,8 @@ public class FindUsagesManager implements JDOMExternalizable { setOpenInNewTab(dialog.isShowInSeparateWindow()); FindUsagesOptions findUsagesOptions = dialog.calcFindUsagesOptions(); - if (!showDialog) { - findUsagesOptions.searchScope = GlobalSearchScope.projectScope(myProject); + if (searchScope != null) { + findUsagesOptions.searchScope = searchScope; } clearFindingNextUsageInFile(); @@ -235,7 +235,7 @@ public class FindUsagesManager implements JDOMExternalizable { @NotNull FindUsagesOptions findUsagesOptions, PsiFile scopeFile, FileEditor editor) { - FindUsagesHandler handler = getNewFindUsagesHandler(psiElement, false); + FindUsagesHandler handler = getFindUsagesHandler(psiElement, false); if (handler == null) return; startFindUsages(findUsagesOptions, handler, scopeFile, editor); } @@ -262,7 +262,7 @@ public class FindUsagesManager implements JDOMExternalizable { } } - public void showSettingsAndFindUsages(@NotNull NavigationItem[] targets) { + public static void showSettingsAndFindUsages(@NotNull NavigationItem[] targets) { if (targets.length == 0) return; NavigationItem target = targets[0]; if (!(target instanceof ConfigurableUsageTarget)) return; @@ -368,9 +368,10 @@ public class FindUsagesManager implements JDOMExternalizable { final Iterable elements = ContainerUtil.concat(primaryElements, secondaryElements); optionsClone.fastTrack = new SearchRequestCollector(new SearchSession()); - //if (optionsClone.searchScope instanceof GlobalSearchScope) { - // optionsClone.searchScope = optionsClone.searchScope.union(GlobalSearchScope.projectScope(project)); - //} + if (optionsClone.searchScope instanceof GlobalSearchScope) { + // we will search in project scope always but warn if some usage is out of scope + optionsClone.searchScope = optionsClone.searchScope.union(GlobalSearchScope.projectScope(project)); + } try { for (final PsiElement element : elements) { ApplicationManager.getApplication().runReadAction(new Runnable() { @@ -437,14 +438,14 @@ public class FindUsagesManager implements JDOMExternalizable { throw new AssertionError(handler + " " + findUsagesOptions); } Iterable allElements = ContainerUtil.concat(primaryElements, secondaryElements); - final UsageTarget[] targets = convertToUsageTargets(allElements, findUsagesOptions); + final PsiElement2UsageTargetAdapter[] targets = convertToUsageTargets(allElements, findUsagesOptions); myAnotherManager.searchAndShowUsages(targets, new Factory() { @Override public UsageSearcher create() { return createUsageSearcher(primaryElements, secondaryElements, handler, findUsagesOptions, null); } }, !toSkipUsagePanelWhenOneUsage, true, createPresentation(primaryElements[0], findUsagesOptions, shouldOpenInNewTab()), null); - myHistory.add((ConfigurableUsageTarget)targets[0]); + myHistory.add(targets[0]); } private static void dropResolveCacheRegularly(ProgressIndicator indicator, @NotNull final Project project) { diff --git a/platform/lang-impl/src/com/intellij/find/findUsages/PsiElement2UsageTargetAdapter.java b/platform/lang-impl/src/com/intellij/find/findUsages/PsiElement2UsageTargetAdapter.java index a05332d283c4..5e4c59dfd572 100644 --- a/platform/lang-impl/src/com/intellij/find/findUsages/PsiElement2UsageTargetAdapter.java +++ b/platform/lang-impl/src/com/intellij/find/findUsages/PsiElement2UsageTargetAdapter.java @@ -40,7 +40,6 @@ import com.intellij.psi.meta.PsiMetaData; import com.intellij.psi.meta.PsiMetaOwner; import com.intellij.psi.meta.PsiPresentableMetaData; import com.intellij.psi.search.LocalSearchScope; -import com.intellij.psi.search.ProjectScope; import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.ui.ComputableIcon; @@ -219,18 +218,16 @@ public class PsiElement2UsageTargetAdapter return psiElement == null ? UsageViewBundle.message("node.invalid") : FindBundle.message("recent.find.usages.action.popup", StringUtil.capitalize(UsageViewUtil.getType(psiElement)), DescriptiveNameUtil.getDescriptiveName(psiElement), - scopeString == null - ? ProjectScope.getAllScope(psiElement.getProject()).getDisplayName() - : scopeString + scopeString ); } @Override public void showSettings() { - FindUsagesManager findUsagesManager = ((FindManagerImpl)FindManager.getInstance(myPointer.getProject())).getFindUsagesManager(); PsiElement element = getElement(); if (element != null) { - findUsagesManager.findUsages(element, null, null, true); + FindUsagesManager findUsagesManager = ((FindManagerImpl)FindManager.getInstance(myPointer.getProject())).getFindUsagesManager(); + findUsagesManager.findUsages(element, null, null, true, null); } } diff --git a/platform/lang-impl/src/com/intellij/find/findUsages/PsiElement2UsageTargetComposite.java b/platform/lang-impl/src/com/intellij/find/findUsages/PsiElement2UsageTargetComposite.java index a16050a08b07..a44208095e02 100644 --- a/platform/lang-impl/src/com/intellij/find/findUsages/PsiElement2UsageTargetComposite.java +++ b/platform/lang-impl/src/com/intellij/find/findUsages/PsiElement2UsageTargetComposite.java @@ -43,7 +43,7 @@ public class PsiElement2UsageTargetComposite extends PsiElement2UsageTargetAdapt PsiElement element = getElement(); if (element == null) return; FindUsagesManager findUsagesManager = ((FindManagerImpl)FindManager.getInstance(element.getProject())).getFindUsagesManager(); - FindUsagesHandler handler = findUsagesManager.getNewFindUsagesHandler(element, false); + FindUsagesHandler handler = findUsagesManager.getFindUsagesHandler(element, false); boolean skipResultsWithOneUsage = FindSettings.getInstance().isSkipResultsWithOneUsage(); findUsagesManager.findUsages(myDescriptor.getPrimaryElements(), myDescriptor.getAdditionalElements(), handler, myOptions, skipResultsWithOneUsage); } diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java b/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java index 6400db8c43db..e327ec79c227 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java @@ -59,6 +59,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.impl.search.LexerEditorHighlighterLexer; +import com.intellij.psi.search.SearchScope; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; import com.intellij.ui.LightweightHint; @@ -859,14 +860,19 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo findUsages(element, false); } + @Override + public void findUsagesInScope(@NotNull PsiElement element, @NotNull SearchScope searchScope) { + myFindUsagesManager.findUsages(element, null, null, false, searchScope); + } + @Override public void findUsages(@NotNull PsiElement element, boolean showDialog) { - myFindUsagesManager.findUsages(element, null, null, showDialog); + myFindUsagesManager.findUsages(element, null, null, showDialog, null); } @Override public void showSettingsAndFindUsages(@NotNull NavigationItem[] targets) { - myFindUsagesManager.showSettingsAndFindUsages(targets); + FindUsagesManager.showSettingsAndFindUsages(targets); } @Override @@ -882,7 +888,7 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo Document document = editor.getDocument(); PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(document); - myFindUsagesManager.findUsages(element, psiFile, fileEditor, false); + myFindUsagesManager.findUsages(element, psiFile, fileEditor, false, null); } } diff --git a/platform/usageView/src/com/intellij/usages/impl/SearchForUsagesRunnable.java b/platform/usageView/src/com/intellij/usages/impl/SearchForUsagesRunnable.java new file mode 100644 index 000000000000..8b065b30d167 --- /dev/null +++ b/platform/usageView/src/com/intellij/usages/impl/SearchForUsagesRunnable.java @@ -0,0 +1,478 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.usages.impl; + +import com.intellij.find.FindManager; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.KeyboardShortcut; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.colors.CodeInsightColors; +import com.intellij.openapi.editor.colors.EditorColorsManager; +import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.keymap.KeymapUtil; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.util.ProgressWrapper; +import com.intellij.openapi.progress.util.TooManyUsagesStatus; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.MessageType; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.ui.popup.Balloon; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.Factory; +import com.intellij.openapi.util.Segment; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.wm.ToolWindowId; +import com.intellij.openapi.wm.ToolWindowManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.SearchScope; +import com.intellij.ui.HyperlinkAdapter; +import com.intellij.usageView.UsageViewBundle; +import com.intellij.usages.*; +import com.intellij.util.Alarm; +import com.intellij.util.ArrayUtil; +import com.intellij.util.CommonProcessors; +import com.intellij.util.Processor; +import com.intellij.util.ui.RangeBlinker; +import com.intellij.xml.util.XmlStringUtil; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.event.HyperlinkEvent; +import javax.swing.event.HyperlinkListener; +import java.awt.event.ActionEvent; +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +class SearchForUsagesRunnable implements Runnable { + @NonNls private static final String FIND_OPTIONS_HREF_TARGET = "FindOptions"; + @NonNls private static final String SEARCH_IN_PROJECT_HREF_TARGET = "SearchInProject"; + @NonNls private static final String LARGE_FILES_HREF_TARGET = "LargeFiles"; + private final AtomicInteger myUsageCountWithoutDefinition = new AtomicInteger(0); + private final AtomicReference myFirstUsage = new AtomicReference(); + @NotNull + private final Project myProject; + private final AtomicReference myUsageViewRef; + private final UsageViewPresentation myPresentation; + private final UsageTarget[] mySearchFor; + private final Factory mySearcherFactory; + private final FindUsagesProcessPresentation myProcessPresentation; + @NotNull private final SearchScope mySearchScope; + private final UsageViewManager.UsageViewStateListener myListener; + private final UsageViewManagerImpl myUsageViewManager; + private final AtomicInteger myOutOfScopeUsages = new AtomicInteger(); + + SearchForUsagesRunnable(@NotNull UsageViewManagerImpl usageViewManager, + @NotNull Project project, + @NotNull AtomicReference usageViewRef, + @NotNull UsageViewPresentation presentation, + @NotNull UsageTarget[] searchFor, + @NotNull Factory searcherFactory, + @NotNull FindUsagesProcessPresentation processPresentation, + @NotNull SearchScope scope, + @Nullable UsageViewManager.UsageViewStateListener listener) { + myProject = project; + myUsageViewRef = usageViewRef; + myPresentation = presentation; + mySearchFor = searchFor; + mySearcherFactory = searcherFactory; + myProcessPresentation = processPresentation; + mySearchScope = scope; + myListener = listener; + myUsageViewManager = usageViewManager; + } + + @NotNull + private static String createOptionsHtml(@NonNls UsageTarget[] searchFor) { + KeyboardShortcut shortcut = UsageViewImpl.getShowUsagesWithSettingsShortcut(searchFor); + String shortcutText = ""; + if (shortcut != null) { + shortcutText = " (" + KeymapUtil.getShortcutText(shortcut) + ")"; + } + return "Find Options..." + shortcutText; + } + + @NotNull + private static String createSearchInProjectHtml() { + return "Search in Project"; + } + + private static void notifyByFindBalloon(final HyperlinkListener listener, + @NotNull final MessageType info, + @NotNull FindUsagesProcessPresentation processPresentation, + @NotNull final Project project, + @NotNull final List lines) { + com.intellij.usageView.UsageViewManager.getInstance(project); // in case tool window not registered + + final Collection largeFiles = processPresentation.getLargeFiles(); + List resultLines = new ArrayList(lines); + HyperlinkListener resultListener = listener; + if (!largeFiles.isEmpty()) { + String shortMessage = "(" + + UsageViewBundle.message("large.files.were.ignored", largeFiles.size()) + ")"; + + resultLines.add(shortMessage); + resultListener = new HyperlinkAdapter(){ + @Override + protected void hyperlinkActivated(HyperlinkEvent e) { + if (e.getDescription().equals(LARGE_FILES_HREF_TARGET)) { + String detailedMessage = detailedLargeFilesMessage(largeFiles); + List strings = new ArrayList(lines); + strings.add(detailedMessage); + ToolWindowManager.getInstance(project).notifyByBalloon(ToolWindowId.FIND, info, wrapInHtml(strings), AllIcons.Actions.Find, listener); + } + else if (listener != null) { + listener.hyperlinkUpdate(e); + } + } + }; + } + + ToolWindowManager.getInstance(project).notifyByBalloon(ToolWindowId.FIND, info, wrapInHtml(resultLines), AllIcons.Actions.Find, resultListener); + } + + @NotNull + private static String wrapInHtml(@NotNull List strings) { + return XmlStringUtil.wrapInHtml(StringUtil.join(strings, "
")); + } + + @NotNull + private static String detailedLargeFilesMessage(@NotNull Collection largeFiles) { + String message = ""; + if (largeFiles.size() == 1) { + final VirtualFile vFile = largeFiles.iterator().next().getVirtualFile(); + message += "File " + presentableFileInfo(vFile) + " is "; + } + else { + message += "Files
"; + + int counter = 0; + for (PsiFile file : largeFiles) { + final VirtualFile vFile = file.getVirtualFile(); + message += presentableFileInfo(vFile) + "
"; + if (counter++ > 10) break; + } + + message += "are "; + } + + message += "too large and cannot be scanned"; + return message; + } + + @NotNull + private static String presentableFileInfo(@NotNull VirtualFile vFile) { + return getPresentablePath(vFile) + + " (" + + UsageViewManagerImpl.presentableSize(UsageViewManagerImpl.getFileLength(vFile)) + + ")"; + } + + @NotNull + private static String getPresentablePath(@NotNull final VirtualFile virtualFile) { + return "'" + ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public String compute() { + return virtualFile.getPresentableUrl(); + } + }) + "'"; + } + + @NotNull + private HyperlinkListener createGotToOptionsListener(@NotNull final UsageTarget[] targets) { + return new HyperlinkAdapter() { + @Override + protected void hyperlinkActivated(HyperlinkEvent e) { + if (e.getDescription().equals(FIND_OPTIONS_HREF_TARGET)) { + FindManager.getInstance(myProject).showSettingsAndFindUsages(targets); + } + } + }; + } + @NotNull + private HyperlinkListener createSearchInProjectListener() { + return new HyperlinkAdapter() { + @Override + protected void hyperlinkActivated(HyperlinkEvent e) { + if (e.getDescription().equals(SEARCH_IN_PROJECT_HREF_TARGET)) { + PsiElement psiElement = getPsiElement(mySearchFor); + if (psiElement != null) { + FindManager.getInstance(myProject).findUsagesInScope(psiElement, GlobalSearchScope.projectScope(myProject)); + } + } + } + }; + } + + private static PsiElement getPsiElement(UsageTarget[] searchFor) { + if (!(searchFor[0] instanceof PsiElementUsageTarget)) return null; + return ((PsiElementUsageTarget)searchFor[0]).getElement(); + } + + private static void flashUsageScriptaculously(@NotNull final Usage usage) { + if (!(usage instanceof UsageInfo2UsageAdapter)) { + return; + } + UsageInfo2UsageAdapter usageInfo = (UsageInfo2UsageAdapter)usage; + + Editor editor = usageInfo.openTextEditor(true); + if (editor == null) return; + TextAttributes attributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(CodeInsightColors.BLINKING_HIGHLIGHTS_ATTRIBUTES); + + RangeBlinker rangeBlinker = new RangeBlinker(editor, attributes, 6); + List segments = new ArrayList(); + CommonProcessors.CollectProcessor processor = new CommonProcessors.CollectProcessor(segments); + usageInfo.processRangeMarkers(processor); + rangeBlinker.resetMarkers(segments); + rangeBlinker.startBlinking(); + } + + private UsageViewImpl getUsageView(ProgressIndicator indicator) { + UsageViewImpl usageView = myUsageViewRef.get(); + if (usageView != null) return usageView; + int usageCount = myUsageCountWithoutDefinition.get(); + if (usageCount >= 2 || usageCount == 1 && myProcessPresentation.isShowPanelIfOnlyOneUsage()) { + usageView = new UsageViewImpl(myProject, myPresentation, mySearchFor, mySearcherFactory); + usageView.associateProgress(indicator); + if (myUsageViewRef.compareAndSet(null, usageView)) { + openView(usageView); + final Usage firstUsage = myFirstUsage.get(); + if (firstUsage != null) { + final UsageViewImpl finalUsageView = usageView; + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + finalUsageView.appendUsage(firstUsage); + } + }); + } + } + else { + Disposer.dispose(usageView); + } + return myUsageViewRef.get(); + } + return null; + } + + private void openView(@NotNull final UsageViewImpl usageView) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + if (myProject.isDisposed()) return; + myUsageViewManager.addContent(usageView, myPresentation); + if (myListener != null) { + myListener.usageViewCreated(usageView); + } + myUsageViewManager.showToolWindow(false); + } + }); + } + + @Override + public void run() { + AtomicBoolean findUsagesStartedShown = new AtomicBoolean(); + searchUsages(findUsagesStartedShown); + endSearchForUsages(findUsagesStartedShown); + } + + private void searchUsages(@NotNull final AtomicBoolean findStartedBalloonShown) { + ProgressIndicator indicator = ProgressWrapper.unwrap(ProgressManager.getInstance().getProgressIndicator()); + TooManyUsagesStatus.createFor(indicator); + Alarm findUsagesStartedBalloon = new Alarm(); + findUsagesStartedBalloon.addRequest(new Runnable() { + @Override + public void run() { + notifyByFindBalloon(null, MessageType.WARNING, myProcessPresentation, myProject, + Collections.singletonList(UsageViewManagerImpl.getProgressTitle(myPresentation))); + findStartedBalloonShown.set(true); + } + }, 300, ModalityState.NON_MODAL); + UsageSearcher usageSearcher = mySearcherFactory.create(); + + usageSearcher.generate(new Processor() { + @Override + public boolean process(final Usage usage) { + ProgressIndicator indicator = ProgressWrapper.unwrap(ProgressManager.getInstance().getProgressIndicator()); + if (indicator != null && indicator.isCanceled()) return false; + + if (!UsageViewManagerImpl.isInScope(usage, mySearchScope)) { + myOutOfScopeUsages.incrementAndGet(); + return true; + } + + boolean incrementCounter = !UsageViewManager.isSelfUsage(usage, mySearchFor); + + if (incrementCounter) { + final int usageCount = myUsageCountWithoutDefinition.incrementAndGet(); + if (usageCount == 1 && !myProcessPresentation.isShowPanelIfOnlyOneUsage()) { + myFirstUsage.compareAndSet(null, usage); + } + + final UsageViewImpl usageView = getUsageView(indicator); + + TooManyUsagesStatus tooManyUsagesStatus; + if (usageCount > UsageLimitUtil.USAGES_LIMIT && (tooManyUsagesStatus = TooManyUsagesStatus.getFrom(indicator)).switchTooManyUsagesStatus()) { + UsageViewManagerImpl.showTooManyUsagesWarning(myProject, tooManyUsagesStatus, indicator, myPresentation, usageCount, usageView); + } + + if (usageView != null) { + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + usageView.appendUsage(usage); + } + }); + } + } + return indicator == null || !indicator.isCanceled(); + } + }); + if (getUsageView(indicator) != null) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + myUsageViewManager.showToolWindow(true); + } + }, myProject.getDisposed()); + } + Disposer.dispose(findUsagesStartedBalloon); + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + if (findStartedBalloonShown.get()) { + Balloon balloon = ToolWindowManager.getInstance(myProject).getToolWindowBalloon(ToolWindowId.FIND); + if (balloon != null) { + balloon.hide(); + } + } + } + }, myProject.getDisposed()); + } + + private void endSearchForUsages(@NotNull final AtomicBoolean findStartedBalloonShown) { + assert !ApplicationManager.getApplication().isDispatchThread() : Thread.currentThread(); + int usageCount = myUsageCountWithoutDefinition.get(); + if (usageCount == 0 && myProcessPresentation.isShowNotFoundMessage()) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + final List notFoundActions = myProcessPresentation.getNotFoundActions(); + final String message = UsageViewBundle.message("dialog.no.usages.found.in", + StringUtil.decapitalize(myPresentation.getUsagesString()), + myPresentation.getScopeText()); + + if (notFoundActions.isEmpty()) { + List lines = new ArrayList(); + lines.add(StringUtil.escapeXml(message)); + if (myOutOfScopeUsages.get() != 0) { + lines.add(UsageViewManagerImpl.outOfScopeMessage(myOutOfScopeUsages.get(), mySearchScope)); + } + if (myProcessPresentation.isShowFindOptionsPrompt()) { + lines.add(createOptionsHtml(mySearchFor)); + } + MessageType type = myOutOfScopeUsages.get() == 0 ? MessageType.INFO : MessageType.WARNING; + notifyByFindBalloon(createGotToOptionsListener(mySearchFor), + type, myProcessPresentation, myProject, lines); + findStartedBalloonShown.set(false); + } + else { + List titles = new ArrayList(notFoundActions.size() + 1); + titles.add(UsageViewBundle.message("dialog.button.ok")); + for (Action action : notFoundActions) { + Object value = action.getValue(FindUsagesProcessPresentation.NAME_WITH_MNEMONIC_KEY); + if (value == null) value = action.getValue(Action.NAME); + + titles.add((String)value); + } + + int option = Messages.showDialog(myProject, message, UsageViewBundle.message("dialog.title.information"), + ArrayUtil.toStringArray(titles), 0, Messages.getInformationIcon()); + + if (option > 0) { + notFoundActions.get(option - 1).actionPerformed(new ActionEvent(this, 0, titles.get(option))); + } + } + } + }, ModalityState.NON_MODAL, myProject.getDisposed()); + } + else if (usageCount == 1 && !myProcessPresentation.isShowPanelIfOnlyOneUsage()) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + Usage usage = myFirstUsage.get(); + if (usage.canNavigate()) { + usage.navigate(true); + flashUsageScriptaculously(usage); + } + List lines = new ArrayList(); + + lines.add("Only one usage found."); + if (myOutOfScopeUsages.get() != 0) { + lines.add(UsageViewManagerImpl.outOfScopeMessage(myOutOfScopeUsages.get(), mySearchScope)); + } + lines.add(createOptionsHtml(mySearchFor)); + MessageType type = myOutOfScopeUsages.get() == 0 ? MessageType.INFO : MessageType.WARNING; + notifyByFindBalloon(createGotToOptionsListener(mySearchFor), + type, myProcessPresentation, myProject, + lines); + } + }, ModalityState.NON_MODAL, myProject.getDisposed()); + } + else { + final UsageViewImpl usageView = myUsageViewRef.get(); + if (usageView != null) { + usageView.drainQueuedUsageNodes(); + usageView.setSearchInProgress(false); + } + + final List lines; + final HyperlinkListener hyperlinkListener; + if (myOutOfScopeUsages.get() == 0 || getPsiElement(mySearchFor)==null) { + lines = Collections.emptyList(); + hyperlinkListener = null; + } + else { + lines = Arrays.asList(UsageViewManagerImpl.outOfScopeMessage(myOutOfScopeUsages.get(), mySearchScope), createSearchInProjectHtml()); + hyperlinkListener = createSearchInProjectListener(); + } + + if (!myProcessPresentation.getLargeFiles().isEmpty() || myOutOfScopeUsages.get() != 0) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + MessageType type = myOutOfScopeUsages.get() == 0 ? MessageType.INFO : MessageType.WARNING; + notifyByFindBalloon(hyperlinkListener, type, myProcessPresentation, myProject, lines); + } + }, ModalityState.NON_MODAL, myProject.getDisposed()); + } + } + + if (myListener != null) { + myListener.findingUsagesFinished(myUsageViewRef.get()); + } + } +} diff --git a/platform/usageView/src/com/intellij/usages/impl/UsageViewManagerImpl.java b/platform/usageView/src/com/intellij/usages/impl/UsageViewManagerImpl.java index 1667cc4a9858..6d7ce9c07a14 100644 --- a/platform/usageView/src/com/intellij/usages/impl/UsageViewManagerImpl.java +++ b/platform/usageView/src/com/intellij/usages/impl/UsageViewManagerImpl.java @@ -15,59 +15,37 @@ */ package com.intellij.usages.impl; -import com.intellij.find.FindManager; import com.intellij.find.SearchInBackgroundOption; -import com.intellij.icons.AllIcons; -import com.intellij.openapi.actionSystem.KeyboardShortcut; +import com.intellij.openapi.actionSystem.DataKey; +import com.intellij.openapi.actionSystem.DataSink; +import com.intellij.openapi.actionSystem.TypeSafeDataProvider; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ModalityState; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.colors.CodeInsightColors; -import com.intellij.openapi.editor.colors.EditorColorsManager; -import com.intellij.openapi.editor.markup.TextAttributes; -import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; -import com.intellij.openapi.progress.util.ProgressWrapper; import com.intellij.openapi.progress.util.TooManyUsagesStatus; import com.intellij.openapi.project.DumbModeAction; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.MessageType; -import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.ui.popup.Balloon; -import com.intellij.openapi.util.*; +import com.intellij.openapi.util.Factory; +import com.intellij.openapi.util.Key; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowId; import com.intellij.openapi.wm.ToolWindowManager; -import com.intellij.psi.PsiFile; -import com.intellij.ui.HyperlinkAdapter; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.LocalSearchScope; +import com.intellij.psi.search.SearchScope; +import com.intellij.psi.util.PsiUtilCore; import com.intellij.ui.content.Content; import com.intellij.usageView.UsageViewBundle; import com.intellij.usages.*; -import com.intellij.util.Alarm; -import com.intellij.util.ArrayUtil; -import com.intellij.util.CommonProcessors; -import com.intellij.util.Processor; -import com.intellij.util.ui.RangeBlinker; +import com.intellij.usages.rules.PsiElementUsage; +import com.intellij.usages.rules.UsageInFile; import com.intellij.util.ui.UIUtil; -import com.intellij.xml.util.XmlStringUtil; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import javax.swing.*; -import javax.swing.event.HyperlinkEvent; -import javax.swing.event.HyperlinkListener; -import java.awt.event.ActionEvent; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; /** @@ -76,8 +54,6 @@ import java.util.concurrent.atomic.AtomicReference; public class UsageViewManagerImpl extends UsageViewManager { private final Project myProject; private static final Key USAGE_VIEW_KEY = Key.create("USAGE_VIEW"); - @NonNls private static final String LARGE_FILES_HREF_TARGET = "LargeFiles"; - @NonNls private static final String FIND_OPTIONS_HREF_TARGET = "FindOptions"; public UsageViewManagerImpl(@NotNull Project project) { myProject = project; @@ -113,7 +89,7 @@ public class UsageViewManagerImpl extends UsageViewManager { return showUsages(searchedFor, foundUsages, presentation, null); } - private void addContent(@NotNull UsageViewImpl usageView, @NotNull UsageViewPresentation presentation) { + void addContent(@NotNull UsageViewImpl usageView, @NotNull UsageViewPresentation presentation) { Content content = com.intellij.usageView.UsageViewManager.getInstance(myProject).addContent( presentation.getTabText(), presentation.getTabName(), @@ -146,14 +122,26 @@ public class UsageViewManagerImpl extends UsageViewManager { @NotNull final UsageViewPresentation presentation, @NotNull final FindUsagesProcessPresentation processPresentation, @Nullable final UsageViewStateListener listener) { + final SearchScope searchScope = getSearchScope(searchFor); + return doSearchAndShow(searchFor, searcherFactory, presentation, processPresentation, listener, searchScope); + } + + UsageView doSearchAndShow(@NotNull final UsageTarget[] searchFor, + @NotNull final Factory searcherFactory, + @NotNull final UsageViewPresentation presentation, + @NotNull final FindUsagesProcessPresentation processPresentation, + @Nullable final UsageViewStateListener listener, + @NotNull final SearchScope searchScope) { final AtomicReference usageViewRef = new AtomicReference(); + Task.Backgroundable task = new Task.Backgroundable(myProject, getProgressTitle(presentation), true, new SearchInBackgroundOption()) { @Override public void run(@NotNull final ProgressIndicator indicator) { - new SearchForUsagesRunnable(UsageViewManagerImpl.this.myProject, usageViewRef, presentation, searchFor, searcherFactory, - processPresentation, listener).run(); + new SearchForUsagesRunnable(UsageViewManagerImpl.this, UsageViewManagerImpl.this.myProject, usageViewRef, presentation, searchFor, searcherFactory, + processPresentation, searchScope, listener).run(); } + @NotNull @Override public DumbModeAction getDumbModeAction() { return DumbModeAction.CANCEL; @@ -170,6 +158,22 @@ public class UsageViewManagerImpl extends UsageViewManager { return usageViewRef.get(); } + @NotNull + private SearchScope getSearchScope(@NotNull UsageTarget[] searchFor) { + UsageTarget target = searchFor[0]; + if (target instanceof TypeSafeDataProvider) { + final SearchScope[] scope = new SearchScope[1]; + ((TypeSafeDataProvider)target).calcData(UsageView.USAGE_SCOPE, new DataSink() { + @Override + public void put(DataKey key, T data) { + scope[0] = (SearchScope)data; + } + }); + return scope[0]; + } + return GlobalSearchScope.projectScope(myProject); + } + @Override public void searchAndShowUsages(@NotNull UsageTarget[] searchFor, @NotNull Factory searcherFactory, @@ -197,7 +201,7 @@ public class UsageViewManagerImpl extends UsageViewManager { return StringUtil.escapeXml(result); } - private void showToolWindow(boolean activateWindow) { + void showToolWindow(boolean activateWindow) { ToolWindow toolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.FIND); toolWindow.show(null); if (activateWindow && !toolWindow.isActive()) { @@ -238,304 +242,6 @@ public class UsageViewManagerImpl extends UsageViewManager { }); } - private class SearchForUsagesRunnable implements Runnable { - private final AtomicInteger myUsageCountWithoutDefinition = new AtomicInteger(0); - private final AtomicReference myFirstUsage = new AtomicReference(); - @NotNull - private final Project myProject; - private final AtomicReference myUsageViewRef; - private final UsageViewPresentation myPresentation; - private final UsageTarget[] mySearchFor; - private final Factory mySearcherFactory; - private final FindUsagesProcessPresentation myProcessPresentation; - private final UsageViewStateListener myListener; - - private SearchForUsagesRunnable(@NotNull Project project, - @NotNull AtomicReference usageViewRef, - @NotNull UsageViewPresentation presentation, - @NotNull UsageTarget[] searchFor, - @NotNull Factory searcherFactory, - @NotNull FindUsagesProcessPresentation processPresentation, - @Nullable UsageViewStateListener listener) { - myProject = project; - myUsageViewRef = usageViewRef; - myPresentation = presentation; - mySearchFor = searchFor; - mySearcherFactory = searcherFactory; - myProcessPresentation = processPresentation; - myListener = listener; - } - - private UsageViewImpl getUsageView(ProgressIndicator indicator) { - UsageViewImpl usageView = myUsageViewRef.get(); - if (usageView != null) return usageView; - int usageCount = myUsageCountWithoutDefinition.get(); - if (usageCount >= 2 || usageCount == 1 && myProcessPresentation.isShowPanelIfOnlyOneUsage()) { - usageView = new UsageViewImpl(myProject, myPresentation, mySearchFor, mySearcherFactory); - usageView.associateProgress(indicator); - if (myUsageViewRef.compareAndSet(null, usageView)) { - openView(usageView); - final Usage firstUsage = myFirstUsage.get(); - if (firstUsage != null) { - final UsageViewImpl finalUsageView = usageView; - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - finalUsageView.appendUsage(firstUsage); - } - }); - } - } - else { - Disposer.dispose(usageView); - } - return myUsageViewRef.get(); - } - return null; - } - - private void openView(@NotNull final UsageViewImpl usageView) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - if (myProject.isDisposed()) return; - addContent(usageView, myPresentation); - if (myListener != null) { - myListener.usageViewCreated(usageView); - } - showToolWindow(false); - } - }); - } - - @Override - public void run() { - AtomicBoolean findUsagesStartedShown = new AtomicBoolean(); - searchUsages(findUsagesStartedShown); - endSearchForUsages(findUsagesStartedShown); - } - - private void searchUsages(@NotNull final AtomicBoolean findStartedBalloonShown) { - ProgressIndicator indicator = ProgressWrapper.unwrap(ProgressManager.getInstance().getProgressIndicator()); - TooManyUsagesStatus.createFor(indicator); - Alarm findUsagesStartedBalloon = new Alarm(); - findUsagesStartedBalloon.addRequest(new Runnable() { - @Override - public void run() { - notifyByFindBalloon(null, MessageType.WARNING, myProcessPresentation, UsageViewManagerImpl.this.myProject, - getProgressTitle(myPresentation)); - findStartedBalloonShown.set(true); - } - }, 300, ModalityState.NON_MODAL); - UsageSearcher usageSearcher = mySearcherFactory.create(); - - usageSearcher.generate(new Processor() { - @Override - public boolean process(final Usage usage) { - ProgressIndicator indicator = ProgressWrapper.unwrap(ProgressManager.getInstance().getProgressIndicator()); - if (indicator != null && indicator.isCanceled()) return false; - TooManyUsagesStatus tooManyUsagesStatus = TooManyUsagesStatus.getFrom(indicator); - boolean incrementCounter = !isSelfUsage(usage, mySearchFor); - - if (incrementCounter) { - final int usageCount = myUsageCountWithoutDefinition.incrementAndGet(); - if (usageCount == 1 && !myProcessPresentation.isShowPanelIfOnlyOneUsage()) { - myFirstUsage.compareAndSet(null, usage); - } - - final UsageViewImpl usageView = getUsageView(indicator); - - if (usageCount > UsageLimitUtil.USAGES_LIMIT && tooManyUsagesStatus.switchTooManyUsagesStatus()) { - showTooManyUsagesWarning(myProject, tooManyUsagesStatus, indicator, myPresentation, usageCount, usageView); - } - - if (usageView != null) { - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - usageView.appendUsage(usage); - } - }); - } - } - return indicator == null || !indicator.isCanceled(); - } - }); - if (getUsageView(indicator) != null) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - showToolWindow(true); - } - }, myProject.getDisposed()); - } - Disposer.dispose(findUsagesStartedBalloon); - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - if (findStartedBalloonShown.get()) { - Balloon balloon = ToolWindowManager.getInstance(myProject).getToolWindowBalloon(ToolWindowId.FIND); - if (balloon != null) { - balloon.hide(); - } - } - } - }, myProject.getDisposed()); - } - - private void endSearchForUsages(@NotNull final AtomicBoolean findStartedBalloonShown) { - assert !ApplicationManager.getApplication().isDispatchThread() : Thread.currentThread(); - int usageCount = myUsageCountWithoutDefinition.get(); - if (usageCount == 0 && myProcessPresentation.isShowNotFoundMessage()) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - final List notFoundActions = myProcessPresentation.getNotFoundActions(); - final String message = UsageViewBundle.message("dialog.no.usages.found.in", - StringUtil.decapitalize(myPresentation.getUsagesString()), - myPresentation.getScopeText()); - - if (notFoundActions.isEmpty()) { - String[] lines = myProcessPresentation.isShowFindOptionsPrompt() ? new String[] {StringUtil.escapeXml(message), createOptionsHtml(mySearchFor)} : new String[]{StringUtil.escapeXml(message)}; - notifyByFindBalloon(createGotToOptionsListener(mySearchFor), - MessageType.INFO, myProcessPresentation, UsageViewManagerImpl.this.myProject, lines); - findStartedBalloonShown.set(false); - } - else { - List titles = new ArrayList(notFoundActions.size() + 1); - titles.add(UsageViewBundle.message("dialog.button.ok")); - for (Action action : notFoundActions) { - Object value = action.getValue(FindUsagesProcessPresentation.NAME_WITH_MNEMONIC_KEY); - if (value == null) value = action.getValue(Action.NAME); - - titles.add((String)value); - } - - int option = Messages.showDialog(myProject, message, UsageViewBundle.message("dialog.title.information"), - ArrayUtil.toStringArray(titles), 0, Messages.getInformationIcon()); - - if (option > 0) { - notFoundActions.get(option - 1).actionPerformed(new ActionEvent(this, 0, titles.get(option))); - } - } - } - }, ModalityState.NON_MODAL, myProject.getDisposed()); - } - else if (usageCount == 1 && !myProcessPresentation.isShowPanelIfOnlyOneUsage()) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - Usage usage = myFirstUsage.get(); - if (usage.canNavigate()) { - usage.navigate(true); - flashUsageScriptaculously(usage); - } - notifyByFindBalloon(createGotToOptionsListener(mySearchFor), - MessageType.INFO, myProcessPresentation, UsageViewManagerImpl.this.myProject,"Only one usage found.", createOptionsHtml( - mySearchFor)); - } - }, ModalityState.NON_MODAL, myProject.getDisposed()); - } - else { - final UsageViewImpl usageView = myUsageViewRef.get(); - if (usageView != null) { - usageView.drainQueuedUsageNodes(); - usageView.setSearchInProgress(false); - } - if (!myProcessPresentation.getLargeFiles().isEmpty()) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - notifyByFindBalloon(null, MessageType.INFO, myProcessPresentation, UsageViewManagerImpl.this.myProject); - } - }, ModalityState.NON_MODAL, myProject.getDisposed()); - } - } - - if (myListener != null) { - myListener.findingUsagesFinished(myUsageViewRef.get()); - } - } - } - - private static void notifyByFindBalloon(final HyperlinkListener listener, - @NotNull final MessageType info, - @NotNull FindUsagesProcessPresentation processPresentation, - @NotNull final Project project, - @NotNull String... sLines) { - com.intellij.usageView.UsageViewManager.getInstance(project); // in case tool window not registered - - final List lines = new ArrayList(Arrays.asList(sLines)); - final Collection largeFiles = processPresentation.getLargeFiles(); - List resultLines = new ArrayList(lines); - HyperlinkListener resultListener = listener; - if (!largeFiles.isEmpty()) { - String shortMessage = "(" - + UsageViewBundle.message("large.files.were.ignored", largeFiles.size()) + ")"; - - resultLines.add(shortMessage); - resultListener = new HyperlinkAdapter(){ - @Override - protected void hyperlinkActivated(HyperlinkEvent e) { - if (e.getDescription().equals(LARGE_FILES_HREF_TARGET)) { - String detailedMessage = detailedLargeFilesMessage(largeFiles); - List strings = new ArrayList(lines); - strings.add(detailedMessage); - ToolWindowManager.getInstance(project).notifyByBalloon(ToolWindowId.FIND, info, wrapInHtml(strings), AllIcons.Actions.Find, listener); - } - else if (listener != null) { - listener.hyperlinkUpdate(e); - } - } - }; - } - - ToolWindowManager.getInstance(project).notifyByBalloon(ToolWindowId.FIND, info, wrapInHtml(resultLines), AllIcons.Actions.Find, resultListener); - } - - @NotNull - private static String wrapInHtml(@NotNull List strings) { - return XmlStringUtil.wrapInHtml(StringUtil.join(strings, "
")); - } - - @NotNull - private static String detailedLargeFilesMessage(@NotNull Collection largeFiles) { - String message = ""; - if (largeFiles.size() == 1) { - final VirtualFile vFile = largeFiles.iterator().next().getVirtualFile(); - message += "File " + presentableFileInfo(vFile) + " is "; - } - else { - message += "Files
"; - - int counter = 0; - for (PsiFile file : largeFiles) { - final VirtualFile vFile = file.getVirtualFile(); - message += presentableFileInfo(vFile) + "
"; - if (counter++ > 10) break; - } - - message += "are "; - } - - message += "too large and cannot be scanned"; - return message; - } - - @NotNull - private static String presentableFileInfo(@NotNull VirtualFile vFile) { - return getPresentablePath(vFile) - + " (" - + presentableSize(getFileLength(vFile)) - + ")"; - } - - @NotNull - public static String presentableSize(long bytes) { - long megabytes = bytes / (1024 * 1024); - return UsageViewBundle.message("find.file.size.megabytes", Long.toString(megabytes)); - } - public static long getFileLength(@NotNull final VirtualFile virtualFile) { final long[] length = {-1L}; ApplicationManager.getApplication().runReadAction(new Runnable() { @@ -550,52 +256,22 @@ public class UsageViewManagerImpl extends UsageViewManager { } @NotNull - private static String getPresentablePath(@NotNull final VirtualFile virtualFile) { - return "'" + ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public String compute() { - return virtualFile.getPresentableUrl(); - } - }) + "'"; + public static String presentableSize(long bytes) { + long megabytes = bytes / (1024 * 1024); + return UsageViewBundle.message("find.file.size.megabytes", Long.toString(megabytes)); + } + + public static boolean isInScope(@NotNull Usage usage, @NotNull SearchScope searchScope) { + VirtualFile file = usage instanceof UsageInFile ? ((UsageInFile)usage).getFile() : usage instanceof PsiElementUsage ? PsiUtilCore + .getVirtualFile(((PsiElementUsage)usage).getElement()) : null; + return file != null && (searchScope instanceof LocalSearchScope + ? ((LocalSearchScope)searchScope).isInScope(file) : ((GlobalSearchScope)searchScope).contains(file)); } @NotNull - private HyperlinkListener createGotToOptionsListener(@NotNull final UsageTarget[] targets) { - return new HyperlinkAdapter() { - @Override - protected void hyperlinkActivated(HyperlinkEvent e) { - if (e.getDescription().equals(FIND_OPTIONS_HREF_TARGET)) { - FindManager.getInstance(myProject).showSettingsAndFindUsages(targets); - } - } - }; + public static String outOfScopeMessage(int nUsages, @NotNull SearchScope searchScope) { + return (nUsages == 1 ? "One usage is" : nUsages + " usages are") + + " out of scope '"+ searchScope.getDisplayName()+"'"; } - @NotNull - private static String createOptionsHtml(@NonNls UsageTarget[] searchFor) { - KeyboardShortcut shortcut = UsageViewImpl.getShowUsagesWithSettingsShortcut(searchFor); - String shortcutText = ""; - if (shortcut != null) { - shortcutText = " (" + KeymapUtil.getShortcutText(shortcut) + ")"; - } - return "Find Options..." + shortcutText; - } - - private static void flashUsageScriptaculously(@NotNull final Usage usage) { - if (!(usage instanceof UsageInfo2UsageAdapter)) { - return; - } - UsageInfo2UsageAdapter usageInfo = (UsageInfo2UsageAdapter)usage; - - Editor editor = usageInfo.openTextEditor(true); - if (editor == null) return; - TextAttributes attributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(CodeInsightColors.BLINKING_HIGHLIGHTS_ATTRIBUTES); - - RangeBlinker rangeBlinker = new RangeBlinker(editor, attributes, 6); - List segments = new ArrayList(); - CommonProcessors.CollectProcessor processor = new CommonProcessors.CollectProcessor(segments); - usageInfo.processRangeMarkers(processor); - rangeBlinker.resetMarkers(segments); - rangeBlinker.startBlinking(); - } } From 3c0499d5a1b522b07f7a6c264d5939e039396aab Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 30 Jun 2014 20:19:18 +0400 Subject: [PATCH 11/59] cleanup --- .../src/com/intellij/injected/editor/EditorWindowImpl.java | 2 +- .../src/com/intellij/openapi/editor/ex/util/EditorUtil.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/injected/editor/EditorWindowImpl.java b/platform/lang-impl/src/com/intellij/injected/editor/EditorWindowImpl.java index 0b077fa72fde..077c41e477ff 100644 --- a/platform/lang-impl/src/com/intellij/injected/editor/EditorWindowImpl.java +++ b/platform/lang-impl/src/com/intellij/injected/editor/EditorWindowImpl.java @@ -580,7 +580,7 @@ public class EditorWindowImpl extends UserDataHolderBase implements EditorWindow if (offsetInLine > end- lineStartOffset) offsetInLine = end - lineStartOffset; CharSequence text = myDocumentWindow.getCharsSequence(); - return EditorUtil.calcColumnNumber(this, text, lineStartOffset, lineStartOffset +offsetInLine, EditorUtil.getTabSize(myDelegate)); + return EditorUtil.calcColumnNumber(this, text, lineStartOffset, lineStartOffset +offsetInLine); } private int calcOffset(int col, int lineNumber, int lineStartOffset) { if (myDocumentWindow.getTextLength() == 0) return 0; diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java b/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java index caadfc8ae744..216429557cea 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java @@ -488,8 +488,6 @@ public final class EditorUtil { } if (editor == null || useOptimization) { - int shift = 0; - Document document = editor == null ? null : editor.getDocument(); if (document != null && start < offset-1 && document.getLineNumber(start) != document.getLineNumber(offset-1)) { String editorInfo = editor instanceof EditorImpl ? ". Editor info: " + ((EditorImpl)editor).dumpState() : ""; @@ -504,6 +502,7 @@ public final class EditorUtil { LOG, "detected incorrect offset -> column number calculation", "start: " + start + ", given offset: " + offset+", given tab size: " + tabSize + ". "+documentInfo+ editorInfo); } + int shift = 0; if (hasTabs) { for (int i = start; i < offset; i++) { char c = text.charAt(i); From 46883f265df7cb501003122688cc2d28b54d08d5 Mon Sep 17 00:00:00 2001 From: Vyacheslav Karpukhin Date: Tue, 1 Jul 2014 13:14:26 +0400 Subject: [PATCH 12/59] OC-6956 Using executor from environment for CloseAction in XDebugSessionTab --- .../com/intellij/xdebugger/impl/ui/XDebugSessionTab.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 ef0b72008cf7..ce349fccc292 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 @@ -168,9 +168,9 @@ public class XDebugSessionTab extends DebuggerSessionTabBase { } DefaultActionGroup leftToolbar = new DefaultActionGroup(); - final Executor executor = DefaultDebugExecutor.getDebugExecutorInstance(); + final Executor debugExecutor = DefaultDebugExecutor.getDebugExecutorInstance(); if (runner != null && environment != null) { - RestartAction restartAction = new RestartAction(executor, runner, myRunContentDescriptor, environment); + RestartAction restartAction = new RestartAction(debugExecutor, runner, myRunContentDescriptor, environment); leftToolbar.add(restartAction); restartAction.registerShortcut(myUi.getComponent()); @@ -221,8 +221,8 @@ public class XDebugSessionTab extends DebuggerSessionTabBase { leftToolbar.addSeparator(); leftToolbar.add(PinToolwindowTabAction.getPinAction()); - leftToolbar.add(new CloseAction(executor, myRunContentDescriptor, getProject())); - leftToolbar.add(new ContextHelpAction(executor.getHelpId())); + leftToolbar.add(new CloseAction(environment != null ? environment.getExecutor() : debugExecutor, myRunContentDescriptor, getProject())); + leftToolbar.add(new ContextHelpAction(debugExecutor.getHelpId())); DefaultActionGroup topToolbar = new DefaultActionGroup(); topToolbar.addAll(getCustomizedActionGroup(XDebuggerActions.TOOL_WINDOW_TOP_TOOLBAR_GROUP)); From 5f6b86282e9e8e0951f91716493513d9ac1bcf3b Mon Sep 17 00:00:00 2001 From: Vassiliy Date: Tue, 1 Jul 2014 13:45:49 +0400 Subject: [PATCH 13/59] IDEA-126752 Editor tooltips hide each other --- .../com/intellij/codeInsight/daemon/impl/DaemonListeners.java | 2 ++ 1 file changed, 2 insertions(+) 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 8c79df55ee7a..75a4fd410959 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 @@ -21,6 +21,7 @@ import com.intellij.codeHighlighting.Pass; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings; import com.intellij.codeInsight.hint.TooltipController; +import com.intellij.ide.IdeTooltipManager; import com.intellij.ide.PowerSaveMode; import com.intellij.ide.todo.TodoConfiguration; import com.intellij.openapi.Disposable; @@ -599,6 +600,7 @@ public class DaemonListeners implements Disposable { if (editor.offsetToLogicalPosition(offset).column != logical.column) return; // we are in virtual space HighlightInfo info = myDaemonCodeAnalyzer.findHighlightByOffset(editor.getDocument(), offset, false); if (info == null || info.getDescription() == null) return; + if (IdeTooltipManager.getInstance().hasCurrent()) return; DaemonTooltipUtil.showInfoTooltip(info, editor, offset); shown = true; } From 46072cc0b0f69de8f8e0e8c7d03895e511d95d75 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Tue, 1 Jul 2014 12:22:18 +0200 Subject: [PATCH 14/59] IDEA-126727 (Structural search: confusing search results for existing template) --- .../intellij/structuralsearch/JavaPredefinedConfigurations.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/structuralsearch/source/com/intellij/structuralsearch/JavaPredefinedConfigurations.java b/plugins/structuralsearch/source/com/intellij/structuralsearch/JavaPredefinedConfigurations.java index b0cf6c086a25..a82c941c0fa2 100644 --- a/plugins/structuralsearch/source/com/intellij/structuralsearch/JavaPredefinedConfigurations.java +++ b/plugins/structuralsearch/source/com/intellij/structuralsearch/JavaPredefinedConfigurations.java @@ -148,7 +148,7 @@ class JavaPredefinedConfigurations { createSearchTemplateInfo( SSRBundle.message("predefined.configuration.static.fields.without.final"), - "class '_Class {\n static '_Type 'Variable*:[ script( \"!__context__.hasModifierProperty(\"final\")\" ) ] = '_Init?;\n}", + "class '_Class {\n static '_Type 'Variable+:[ script( \"!__context__.hasModifierProperty(\"final\")\" ) ] = '_Init?;\n}", CLASS_TYPE ), From 9061d8c59904085c76cd336aa2b90ad6ebe273a8 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 30 Jun 2014 13:10:09 +0200 Subject: [PATCH 15/59] Cleanup (Junit4 migration; assertions) --- .../util/containers/ConcurrentMapsTest.java | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/platform/util/testSrc/com/intellij/util/containers/ConcurrentMapsTest.java b/platform/util/testSrc/com/intellij/util/containers/ConcurrentMapsTest.java index 31a4127080eb..7345bfaf7e3b 100644 --- a/platform/util/testSrc/com/intellij/util/containers/ConcurrentMapsTest.java +++ b/platform/util/testSrc/com/intellij/util/containers/ConcurrentMapsTest.java @@ -17,15 +17,18 @@ package com.intellij.util.containers; import com.intellij.openapi.util.text.StringUtil; import gnu.trove.TObjectHashingStrategy; -import junit.framework.TestCase; +import org.junit.Test; import java.lang.ref.SoftReference; import java.util.List; import java.util.Map; import java.util.Set; -public class ConcurrentMapsTest extends TestCase { - public static final TObjectHashingStrategy CUSTOM_STRATEGY = new TObjectHashingStrategy() { +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class ConcurrentMapsTest { + private static final TObjectHashingStrategy CUSTOM_STRATEGY = new TObjectHashingStrategy() { @Override public int computeHashCode(String object) { return Character.toLowerCase(object.charAt(object.length() - 1)); @@ -37,8 +40,9 @@ public class ConcurrentMapsTest extends TestCase { } }; + @Test public void testKeysRemovedWhenIdentityStrategyIsUsed() { - ConcurrentWeakHashMap map = new ConcurrentWeakHashMap(TObjectHashingStrategy.IDENTITY); + @SuppressWarnings("unchecked") ConcurrentWeakHashMap map = new ConcurrentWeakHashMap(TObjectHashingStrategy.IDENTITY); map.put(new Object(), new Object()); tryGcSoftlyReachableObjects(); // sometimes weak references are not collected under linux, try to stress gc to force them @@ -50,6 +54,7 @@ public class ConcurrentMapsTest extends TestCase { assertEquals(1, map.underlyingMapSize()); } + @Test public void testRemoveFromSoftEntrySet() { ConcurrentSoftHashMap map = new ConcurrentSoftHashMap(); map.put(this, this); @@ -61,6 +66,7 @@ public class ConcurrentMapsTest extends TestCase { assertTrue(map.isEmpty()); } + @Test public void testRemoveFromWeakEntrySet() { ConcurrentWeakHashMap map = new ConcurrentWeakHashMap(); map.put(this, this); @@ -72,6 +78,7 @@ public class ConcurrentMapsTest extends TestCase { assertTrue(map.isEmpty()); } + @Test public void testTossedWeakKeysAreRemoved() { ConcurrentWeakHashMap map = new ConcurrentWeakHashMap(); map.put(new Object(), new Object()); @@ -87,13 +94,14 @@ public class ConcurrentMapsTest extends TestCase { } public static void tryGcSoftlyReachableObjects() { - SoftReference reference = new SoftReference(new Object()); + SoftReference reference = new SoftReference(new Object()); List list = ContainerUtil.newArrayList(); while (reference.get() != null) { list.add(new SoftReference(new byte[(int)Runtime.getRuntime().freeMemory() / 2])); } } + @Test public void testTossedSoftKeysAreRemoved() { ConcurrentSoftHashMap map = new ConcurrentSoftHashMap(); map.put(new Object(), new Object()); @@ -108,6 +116,7 @@ public class ConcurrentMapsTest extends TestCase { assertEquals(1, map.underlyingMapSize()); } + @Test public void testTossedWeakValueIsRemoved() { ConcurrentWeakValueHashMap map = new ConcurrentWeakValueHashMap(); map.put(new Object(), new Object()); @@ -121,6 +130,7 @@ public class ConcurrentMapsTest extends TestCase { map.put(this, this); assertEquals(1, map.underlyingMapSize()); } + @Test public void testTossedSoftValueIsRemoved() { ConcurrentSoftValueHashMap map = new ConcurrentSoftValueHashMap(); map.put(new Object(), new Object()); @@ -135,6 +145,7 @@ public class ConcurrentMapsTest extends TestCase { assertEquals(1, map.underlyingMapSize()); } + @Test public void testCustomStrategy() { SoftHashMap map = new SoftHashMap(CUSTOM_STRATEGY); @@ -145,6 +156,7 @@ public class ConcurrentMapsTest extends TestCase { assertTrue(map.isEmpty()); } + @Test public void testCustomStrategyForConcurrentSoft() { ConcurrentSoftHashMap map = new ConcurrentSoftHashMap(CUSTOM_STRATEGY); @@ -156,6 +168,7 @@ public class ConcurrentMapsTest extends TestCase { assertTrue(map.isEmpty()); } + @Test public void testCustomStrategyForConcurrentWeakSoft() { ConcurrentWeakKeySoftValueHashMap map = new ConcurrentWeakKeySoftValueHashMap(1,1,1,CUSTOM_STRATEGY); @@ -167,6 +180,7 @@ public class ConcurrentMapsTest extends TestCase { assertTrue(map.isEmpty()); } + @Test public void testTossedSoftKeyAndValue() { SoftKeySoftValueHashMap map = new SoftKeySoftValueHashMap(); map.put(new Object(), new Object()); @@ -179,6 +193,7 @@ public class ConcurrentMapsTest extends TestCase { assertTrue(map.isEmpty()); } + @Test public void testTossedWeakKeyAndValue() { WeakKeyWeakValueHashMap map = new WeakKeyWeakValueHashMap(); map.put(new Object(), new Object()); From 77a6cc3d5143d3d72fd89d16e8940d6dc613b959 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Tue, 1 Jul 2014 15:03:33 +0400 Subject: [PATCH 16/59] cleanup --- .../src/com/intellij/openapi/ui/DialogWrapper.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java b/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java index f9df4e325dee..75cb4de7af74 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java @@ -76,7 +76,7 @@ import java.util.Set; public abstract class DialogWrapper { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.ui.DialogWrapper"); - public static enum IdeModalityType { + public enum IdeModalityType { IDE, PROJECT, MODELESS; @@ -839,7 +839,7 @@ public abstract class DialogWrapper { /** * Dispose the wrapped and releases all resources allocated be the wrapper to help - * more effecient garbage collection. You should never invoke this method twice or + * more efficient garbage collection. You should never invoke this method twice or * invoke any method of the wrapper after invocation of dispose. * * @throws IllegalStateException if the dialog is disposed not on the event dispatch thread From 6dbfc8bd55978b4fa150fe6a758d8c0bc7524624 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Tue, 1 Jul 2014 15:06:26 +0400 Subject: [PATCH 17/59] leakage fixed --- .../src/com/intellij/ide/projectWizard/NewProjectWizard.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/java/idea-ui/src/com/intellij/ide/projectWizard/NewProjectWizard.java b/java/idea-ui/src/com/intellij/ide/projectWizard/NewProjectWizard.java index e7e172c0c117..fbe8636ee360 100644 --- a/java/idea-ui/src/com/intellij/ide/projectWizard/NewProjectWizard.java +++ b/java/idea-ui/src/com/intellij/ide/projectWizard/NewProjectWizard.java @@ -21,6 +21,7 @@ import com.intellij.ide.util.newProjectWizard.StepSequence; import com.intellij.ide.util.projectWizard.ModuleWizardStep; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ui.configuration.ModulesProvider; +import com.intellij.openapi.util.Disposer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -46,6 +47,7 @@ public class NewProjectWizard extends AbstractProjectWizard { protected void init(@NotNull ModulesProvider modulesProvider) { myWizardContext.setNewWizard(true); ProjectTypeStep projectTypeStep = new ProjectTypeStep(myWizardContext, this, modulesProvider); + Disposer.register(getDisposable(), projectTypeStep); mySequence.addCommonStep(projectTypeStep); ChooseTemplateStep chooseTemplateStep = new ChooseTemplateStep(myWizardContext, projectTypeStep); mySequence.addCommonStep(chooseTemplateStep); From 65f0d0b054e2ca32f1d412dac6dbc3065f18dfc0 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Tue, 1 Jul 2014 15:49:47 +0400 Subject: [PATCH 18/59] fixed map renderer quoting and renderers test --- .../intellij/debugger/settings/NodeRendererSettings.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/NodeRendererSettings.java b/java/debugger/impl/src/com/intellij/debugger/settings/NodeRendererSettings.java index a43ca7e9eae3..e1d80414f0e6 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/NodeRendererSettings.java +++ b/java/debugger/impl/src/com/intellij/debugger/settings/NodeRendererSettings.java @@ -33,6 +33,7 @@ import com.intellij.openapi.components.*; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.*; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.CommonClassNames; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiElementFactory; @@ -546,7 +547,12 @@ public class NodeRendererSettings implements PersistentStateComponent { } static String constructLabelText(final String keylabel, final String valueLabel) { - return keylabel + " -> " + valueLabel; + StringBuilder sb = new StringBuilder(); + sb.append('\"').append(keylabel).append("\" -> "); + if (!StringUtil.isEmpty(valueLabel)) { + sb.append('\"').append(valueLabel).append('\"'); + } + return sb.toString(); } private static String getDescriptorLabel(final ValueDescriptorImpl keyDescriptor) { From 0b03569140da35816ab1e69aa5caa5884c8087a2 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Tue, 1 Jul 2014 16:06:01 +0400 Subject: [PATCH 19/59] [git] fix test: adjust implementations after changing method signatures --- .../branch/GitBranchWorkerTest.groovy | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/plugins/git4idea/tests/git4idea/branch/GitBranchWorkerTest.groovy b/plugins/git4idea/tests/git4idea/branch/GitBranchWorkerTest.groovy index 982bcb7d7fec..5ccf63eaa7c2 100644 --- a/plugins/git4idea/tests/git4idea/branch/GitBranchWorkerTest.groovy +++ b/plugins/git4idea/tests/git4idea/branch/GitBranchWorkerTest.groovy @@ -205,7 +205,7 @@ class GitBranchWorkerTest extends GitPlatformTest { boolean notificationShown = false; checkoutOrMerge operation, "feature", [ - showUntrackedFilesNotification : { String s, Collection c -> notificationShown = true } + showUntrackedFilesNotification: { String s, VirtualFile root, Collection c -> notificationShown = true } ] assertTrue "Untracked files notification was not shown", notificationShown @@ -224,15 +224,15 @@ class GitBranchWorkerTest extends GitPlatformTest { def untracked = ["untracked.txt"] untrackedFileOverwrittenBy(myCommunity, "feature", untracked) - Collection untrackedFiles = null; + Collection untrackedPaths = null; checkoutOrMerge operation, "feature", [ - showUntrackedFilesDialogWithRollback : { String s, String p, Collection files -> untrackedFiles = files; false } + showUntrackedFilesDialogWithRollback: { + String s, String p, VirtualFile root, Collection files -> untrackedPaths = files; false + } ] - assertTrue "Untracked files dialog was not shown", untrackedFiles != null - assertEquals "Incorrect set of untracked files was shown in the dialog", - untracked, - untrackedFiles.collect { FileUtil.getRelativePath(myCommunity.root.path, it.path, '/'.toCharacter()) } + assertTrue "Untracked files dialog was not shown", untrackedPaths != null + assertEquals "Incorrect set of untracked files was shown in the dialog", untracked.asList(), untrackedPaths.asList() } public void "test checkout with local changes overwritten by checkout should show smart checkout dialog"() { @@ -252,7 +252,7 @@ class GitBranchWorkerTest extends GitPlatformTest { List changes = null; checkoutOrMerge(operation, "feature", [ - showSmartOperationDialog: { Project p, List cs, String op, boolean force -> + showSmartOperationDialog: { Project p, List cs, Collection paths, String op, boolean force -> changes = cs DialogWrapper.CANCEL_EXIT_CODE } @@ -349,7 +349,9 @@ class GitBranchWorkerTest extends GitPlatformTest { prepareLocalChangesOverwrittenBy(myUltimate) checkoutOrMerge(operation, "feature", [ - showSmartOperationDialog : { Project p, List cs, String op, boolean f -> GitSmartOperationDialog.CANCEL_EXIT_CODE }, + showSmartOperationDialog: { Project p, List cs, Collection paths, String op, boolean f + -> GitSmartOperationDialog.CANCEL_EXIT_CODE + }, ] as GitBranchUiHandler ) assertNull "Notification was unexpectedly shown:" + myVcsNotifier.lastNotification, myVcsNotifier.lastNotification @@ -372,8 +374,10 @@ class GitBranchWorkerTest extends GitPlatformTest { def rollbackMsg = null checkoutOrMerge(operation, "feature", [ - showSmartOperationDialog : { Project p, List cs, String op, boolean f -> GitSmartOperationDialog.CANCEL_EXIT_CODE }, - notifyErrorWithRollbackProposal: { String t, String m, String rp -> rollbackMsg = m ; false } + showSmartOperationDialog : { + Project p, List cs, Collection paths, String op, boolean f -> GitSmartOperationDialog.CANCEL_EXIT_CODE + }, + notifyErrorWithRollbackProposal: { String t, String m, String rp -> rollbackMsg = m; false } ] as GitBranchUiHandler ) assertNotNull "Rollback proposal was not shown", rollbackMsg @@ -384,7 +388,7 @@ class GitBranchWorkerTest extends GitPlatformTest { prepareLocalChangesOverwrittenBy(myUltimate) def uiHandler = [ - showSmartOperationDialog: { Project p, List cs, String op, boolean force -> + showSmartOperationDialog: { Project p, List cs, Collection paths, String op, boolean force -> GitSmartOperationDialog.FORCE_EXIT_CODE; }, ] as GitBranchUiHandler From 90effe1da94a367ce449892fc09fd3dfe4d072df Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Tue, 1 Jul 2014 14:19:21 +0200 Subject: [PATCH 20/59] continue WEB-1828 fix changelive message response reader --- .../protocolReader/FieldProcessor.java | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/FieldProcessor.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/FieldProcessor.java index 92a3a6bf0c78..eabc8d8e4337 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/FieldProcessor.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/FieldProcessor.java @@ -60,9 +60,23 @@ class FieldProcessor { private MethodHandler processFieldGetterMethod(Method m, String fieldName) { Type genericReturnType = m.getGenericReturnType(); - boolean nullable = m.getAnnotation(JsonNullable.class) != null || - (genericReturnType == String.class && ((m.getAnnotation(JsonField.class) != null && m.getAnnotation(JsonField.class).optional()) - || m.getAnnotation(JsonOptionalField.class) != null)); + boolean nullable; + if (m.getAnnotation(JsonNullable.class) != null) { + nullable = true; + } + else if (genericReturnType == String.class || genericReturnType == Enum.class) { + JsonField jsonField = m.getAnnotation(JsonField.class); + if (jsonField != null) { + nullable = jsonField.optional() && !jsonField.allowAnyPrimitiveValue() && !jsonField.allowAnyPrimitiveValueAndMap(); + } + else { + nullable = m.getAnnotation(JsonOptionalField.class) != null; + } + } + else { + nullable = false; + } + ValueReader fieldTypeParser = reader.getFieldTypeParser(genericReturnType, nullable, false, m); if (fieldTypeParser != InterfaceReader.VOID_PARSER) { fieldLoaders.add(new FieldLoader(fieldName, fieldTypeParser)); From 787aa21c10cdbc27d558bc3e821532523b0f5bb0 Mon Sep 17 00:00:00 2001 From: Sergey Simonchik Date: Tue, 1 Jul 2014 16:29:41 +0400 Subject: [PATCH 21/59] IDEA-126767 ComponentWithBrowseButton is 1px smaller from left and right (CR-IC-5672) --- .../src/com/intellij/openapi/ui/ComponentWithBrowseButton.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/platform/platform-api/src/com/intellij/openapi/ui/ComponentWithBrowseButton.java b/platform/platform-api/src/com/intellij/openapi/ui/ComponentWithBrowseButton.java index 602615a656e2..219a5524e011 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/ComponentWithBrowseButton.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/ComponentWithBrowseButton.java @@ -74,9 +74,6 @@ public class ComponentWithBrowseButton extends JPanel i if (ApplicationManager.getApplication() != null) { // avoid crash at design time new MyDoClickAction(myBrowseButton).registerShortcut(myComponent); } - if (UIUtil.isUnderIntelliJLaF() || UIUtil.isUnderDarcula()) { - setBorder(new EmptyBorder(0, 1, 0, 1)); - } } public final Comp getChildComponent() { From 082bc5d1aba44455fd95d21a961210a3b45648d3 Mon Sep 17 00:00:00 2001 From: Vassiliy Date: Tue, 1 Jul 2014 16:48:36 +0400 Subject: [PATCH 22/59] Failed build http://buildserver.labs.intellij.net/viewLog.html?buildId=4363868&tab=buildResultsDiv&buildTypeId=TC_Trunk_DistParts_StandaloneJps --- build/scripts/layouts.gant | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/scripts/layouts.gant b/build/scripts/layouts.gant index 2c34d769898c..0867214460f6 100644 --- a/build/scripts/layouts.gant +++ b/build/scripts/layouts.gant @@ -770,7 +770,7 @@ def layoutJps(String home, String targetDir, String buildNumber, Closure additio include(name: "jdom.jar") include(name: "jna.jar") include(name: "trove4j.jar") - include(name: "asm4-all.jar") + include(name: "asm-all.jar") include(name: "nanoxml-*.jar") include(name: "protobuf-*.jar") include(name: "cli-parser-*.jar") From b0b8c0d9f9d7f94590efa04fda52d3642d7bcfe2 Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Tue, 1 Jul 2014 16:59:47 +0400 Subject: [PATCH 23/59] IDEA-121056, EA-55083 - fix exception during multi-caret editing --- .../intellij/openapi/editor/impl/CaretImpl.java | 6 +++++- .../editor/impl/softwrap/SoftWrapHelper.java | 14 +++++++------- .../openapi/editor/EditorMultiCaretTest.java | 15 +++++++++++++++ 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java index 5910830e6385..5f248b6e5959 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java @@ -561,7 +561,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret { myEditor.updateCaretCursor(); requestRepaint(oldInfo); - if (locateBeforeSoftWrap && SoftWrapHelper.isCaretAfterSoftWrap(myEditor)) { + if (locateBeforeSoftWrap && SoftWrapHelper.isCaretAfterSoftWrap(this)) { int lineToUse = myVisibleCaret.line - 1; if (lineToUse >= 0) { final VisualPosition visualPosition = new VisualPosition(lineToUse, EditorUtil.getLastVisualLineColumnNumber(myEditor, lineToUse)); @@ -1451,6 +1451,10 @@ public class CaretImpl extends UserDataHolderBase implements Caret { return marker != null && marker.isValid() && isVirtualSelectionEnabled() && myEndVirtualOffset > myStartVirtualOffset; } + public EditorImpl getEditor() { + return myEditor; + } + /** * Encapsulates information about target vertical range info - its 'y' coordinate and height in pixels. */ diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/SoftWrapHelper.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/SoftWrapHelper.java index a3dd31e80a53..baf9477d1e9f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/SoftWrapHelper.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/SoftWrapHelper.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,9 +15,9 @@ */ package com.intellij.openapi.editor.impl.softwrap; -import com.intellij.openapi.editor.CaretModel; import com.intellij.openapi.editor.SoftWrap; import com.intellij.openapi.editor.SoftWrapModel; +import com.intellij.openapi.editor.impl.CaretImpl; import com.intellij.openapi.editor.impl.EditorImpl; /** @@ -48,18 +48,18 @@ public class SoftWrapHelper { * @return true if caret offset of the given editor points to visual position that belongs to * visual line where soft wrap end is located */ - public static boolean isCaretAfterSoftWrap(EditorImpl editor) { - CaretModel caretModel = editor.getCaretModel(); - if (!caretModel.isUpToDate()) { + public static boolean isCaretAfterSoftWrap(CaretImpl caret) { + if (!caret.isUpToDate()) { return false; } + EditorImpl editor = caret.getEditor(); SoftWrapModel softWrapModel = editor.getSoftWrapModel(); - int offset = caretModel.getOffset(); + int offset = caret.getOffset(); SoftWrap softWrap = softWrapModel.getSoftWrap(offset); if (softWrap == null) { return false; } - return editor.offsetToVisualLine(offset) == caretModel.getVisualPosition().line; + return editor.offsetToVisualLine(offset) == caret.getVisualPosition().line; } } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorMultiCaretTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorMultiCaretTest.java index 1c05f47b16ed..26be81d2f341 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorMultiCaretTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorMultiCaretTest.java @@ -21,6 +21,7 @@ import com.intellij.openapi.editor.ex.EditorSettingsExternalizable; import com.intellij.openapi.editor.impl.AbstractEditorTest; import com.intellij.openapi.keymap.Keymap; import com.intellij.openapi.keymap.KeymapManager; +import com.intellij.testFramework.EditorTestUtil; import com.intellij.testFramework.TestFileType; import java.awt.event.InputEvent; @@ -305,4 +306,18 @@ public class EditorMultiCaretTest extends AbstractEditorTest { "brown\n" + "fox"); } + + public void testCaretPositionsRecalculationOnDocumentChange() throws Exception { + init("\n" + + "word\n" + + "some long prefix word-suffix", TestFileType.TEXT); + EditorTestUtil.configureSoftWraps(myEditor, 17); // wrapping right before 'word-suffix' + + delete(); + + checkResultByText("\n" + + "\n" + + "some long prefix -suffix"); + verifySoftWrapPositions(19); + } } From 69c691b3ec640e746da1538115a3c732866ffd5e Mon Sep 17 00:00:00 2001 From: Andrey Starovoyt Date: Tue, 1 Jul 2014 14:47:46 +0200 Subject: [PATCH 24/59] CR-IU-770 --- .../src/org/jetbrains/debugger/HasUrl.java | 25 +++++++++++++++++++ .../src/org/jetbrains/debugger/Script.java | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 platform/script-debugger/backend/src/org/jetbrains/debugger/HasUrl.java diff --git a/platform/script-debugger/backend/src/org/jetbrains/debugger/HasUrl.java b/platform/script-debugger/backend/src/org/jetbrains/debugger/HasUrl.java new file mode 100644 index 000000000000..56f51c5d6d51 --- /dev/null +++ b/platform/script-debugger/backend/src/org/jetbrains/debugger/HasUrl.java @@ -0,0 +1,25 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.debugger; + +import com.intellij.util.Url; +import org.jetbrains.annotations.NotNull; + + +public interface HasUrl { + @NotNull + Url getUrl(); +} diff --git a/platform/script-debugger/backend/src/org/jetbrains/debugger/Script.java b/platform/script-debugger/backend/src/org/jetbrains/debugger/Script.java index 354a51387a50..e44d308977d3 100755 --- a/platform/script-debugger/backend/src/org/jetbrains/debugger/Script.java +++ b/platform/script-debugger/backend/src/org/jetbrains/debugger/Script.java @@ -6,7 +6,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.debugger.sourcemap.SourceMap; -public interface Script extends UserDataHolderEx { +public interface Script extends UserDataHolderEx, HasUrl { void setSourceMap(SourceMap sourceMap); enum Type { From 3b3f0ee7941016a65a1e3603805cd4b3a6485d22 Mon Sep 17 00:00:00 2001 From: Valentin Fondaratov Date: Tue, 1 Jul 2014 17:35:52 +0400 Subject: [PATCH 25/59] make runExecuteAction not final; move ruby debugger console execution away from EDT --- .../intellij/execution/console/ConsoleExecuteAction.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/execution/console/ConsoleExecuteAction.java b/platform/lang-impl/src/com/intellij/execution/console/ConsoleExecuteAction.java index 00c717faf9df..495a13614005 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/ConsoleExecuteAction.java +++ b/platform/lang-impl/src/com/intellij/execution/console/ConsoleExecuteAction.java @@ -162,16 +162,9 @@ public class ConsoleExecuteAction extends DumbAwareAction { protected void beforeExecution(@NotNull LanguageConsoleImpl console) { } - protected boolean shouldExecute(@NotNull LanguageConsoleImpl console) { + protected void runExecuteAction(@NotNull LanguageConsoleImpl console, @Nullable LanguageConsoleView consoleView) { //noinspection deprecation beforeExecution(console); - return true; - } - - final void runExecuteAction(@NotNull LanguageConsoleImpl console, @Nullable LanguageConsoleView consoleView) { - if (!shouldExecute(console)) { - return; - } String text = console.prepareExecuteAction(myAddToHistory, myPreserveMarkup, true); ((UndoManagerImpl)UndoManager.getInstance(console.getProject())).invalidateActionsFor(DocumentReferenceManager.getInstance().create(console.getCurrentEditor().getDocument())); From d1cf801bc7565158ba59892c6e558f4e7feb168c Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Tue, 1 Jul 2014 12:37:52 +0200 Subject: [PATCH 26/59] testdata for IDEA-126109 --- .../lambda/newLambda/IDEA126109.java | 26 +++++++++++++++++++ .../lambda/NewLambdaHighlightingTest.java | 4 +++ 2 files changed, 30 insertions(+) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA126109.java diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA126109.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA126109.java new file mode 100644 index 000000000000..0fd7c685535a --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA126109.java @@ -0,0 +1,26 @@ +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +class Test { + void foo(final Stream stream) { + final Map> mapByFirstLetter = stream.collect(Collectors.groupingBy(p -> "" + p.name.charAt(0))); + + final String vV = mapByFirstLetter.values().stream().map(lp -> lp.stream().map(p -> p.name) + .collect(Collectors.joining("/","<",">"))) .collect(Collectors.joining(" : ")); + + final String vV2 = mapByFirstLetter.values().stream() + .map(lp -> lp.stream().map(Person::getName).collect(Collectors.joining("/","<",">"))) + .collect(Collectors.joining(" : ")); + System.out.println("mapByFirstLetter2 : "+ vV2); + } + + public static class Person { + private String name; + public Person(String name) { + this.name = name; + } + public String getName() {return name;} + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java index f4ff8e530a91..df8c50339f35 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java @@ -234,6 +234,10 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(); } + public void testIDEA126109() throws Exception { + doTest(); + } + private void doTest() { doTest(false); } From a549b93a6dc0329ab76b301e201d9b6fb2a3a1f4 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Tue, 1 Jul 2014 15:24:43 +0200 Subject: [PATCH 27/59] coverage: proceed deprecated asm 5 methods --- .../coverage-common/lib/coverage-agent.jar | Bin 33257 -> 33257 bytes plugins/coverage-common/lib/coverage-src.zip | Bin 45669 -> 45363 bytes plugins/coverage-common/lib/coverage-util.jar | Bin 21179 -> 21179 bytes plugins/coverage-common/lib/instrumenter.jar | Bin 57061 -> 57181 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/plugins/coverage-common/lib/coverage-agent.jar b/plugins/coverage-common/lib/coverage-agent.jar index 0fbfdbefffeb1375d6f83bca977c513f0d4db6b5..2f403fef94ba5e9407a4e766dada5f757356181a 100644 GIT binary patch delta 577 zcmaFa%=EIEi8sKTnT3mifrEjeq4MEGUJd42AZ2lexvKKvWOhb*Fs;d`0j5J3wZU`~ zqY0SS@z~shJ8^GPzOvJ6NDv$A|^Y*kF(b(JX0v zg&8dJ!EB8%m@(h03#?|cj=v>XAjAJFL~TM)5GzOoD5Ev`KqI>2KZb`x)OkmhLmYB6 z+Kd~l;a}QIuu-qlPk>F>yfwF%lNlIllU>U#K*2V-q1+y<@=&=xnEnD32U(?GVGX8p zD_p>|L!I>G^A&m^_N2-PuuybmG??C583m@rs=~o^K~+4MzElN~H>ie)cU42wJ+F=d z%e&R2g6VZNIbd40HXTg2*Fw}isf`5l9qK&6bWdFZn0{Xu2c`q+A>woDA@=>NPXmjm TH^hSJ;|&mT%|?iQ9gT?q*IDz% delta 577 zcmaFa%=EIEi8sKTnT3mifrEjeV9BzHyc*2;K+56_bIy`wli3;N!L%l$2AB?E)CSW{ zj3!`O$6ssm0$EnL85|5iU7No$=JN6a87{)RjMTdr7#L1YZje=-Jfl)*@-qG@AdQ=C z1c`u?_hyy9U~SnV}n5&M6;yv z6=tx=2eUQ8V8(o}F0h)(I{ubmfeinz5VZ+GL98GVpp4e!1C8j8{}>()QRf|14spoQ zXftlGhJR@-+wVETPs9GDKMhltOqhuHV8J`F6M U-Vh6>k2gTXH5(!Jbu=ad07X9RegFUf diff --git a/plugins/coverage-common/lib/coverage-src.zip b/plugins/coverage-common/lib/coverage-src.zip index 437732eb20e24be5211a91943b447dbcb1bdd553..c094a3a80b9d5a9a43105f8ad089f1403c1f519e 100644 GIT binary patch literal 45363 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 B@ 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 literal 45669 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 diff --git a/plugins/coverage-common/lib/coverage-util.jar b/plugins/coverage-common/lib/coverage-util.jar index 0260a9abc16959bde968798e79f420c6f829df7c..dbfe4a3786ecf367bbe6d5269f30cdf7511eb7d8 100644 GIT binary patch delta 404 zcmdnJlyUb`M&1B#W)?061`Y;>hRTN%c{P}8fs{ora}|&}ArGcrX@IE7qKw*L+L_S= zOjj{lg6VCHt{{5zKgPFAV8%NZ9SB2~{UU_%k+YH$ER`$FCje&DDX)S^X{&u@28$?b zi9yuZ7z;9jMFLE+Siy|Fmi-VBf9pjoV39BO(JX>MOI=cY%Ek=z)8v(279dYee&S^h(mPqrTOUkEcw2z!$==pr`l7cBn3nMI z1k))#p?C@1F*yPxxnpX|sS% WFnuVX5lp)ULg-V0)nL9yP%!|Qn5NkP delta 404 zcmdnJlyUb`M&1B#W)?061`Y;>f+fo)@@g>W11XDM<{Th(LLN-L(g0DDMH#ihv@@d# zn66^91k>9XT|xBbe~fRLz>Ie+IuM2|`$Y)jBWEQiSSnYTPXNrQQ(gs;(pLM*3>Hz= z5`(C*F&1P5iv*Ztv4ReyLzO-aidYpYYEH(`Esk WVERx%BbaszgwUq~tHFGapke^3nxU-# diff --git a/plugins/coverage-common/lib/instrumenter.jar b/plugins/coverage-common/lib/instrumenter.jar index 8552a4fe9390d75e33beba7db9d6091695b4ed32..54953f575420d92a449aa18bdae7dc5d80a1d4f0 100644 GIT binary patch delta 10478 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 From 5ddf0278883a9c0587441c831383cd31784ce53e Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Tue, 1 Jul 2014 16:13:25 +0200 Subject: [PATCH 28/59] skip separators when adding actions from action group --- .../src/com/intellij/ui/ToolbarDecorator.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/platform/platform-api/src/com/intellij/ui/ToolbarDecorator.java b/platform/platform-api/src/com/intellij/ui/ToolbarDecorator.java index 24cb28001fed..80e3d1eec7fb 100644 --- a/platform/platform-api/src/com/intellij/ui/ToolbarDecorator.java +++ b/platform/platform-api/src/com/intellij/ui/ToolbarDecorator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,10 +15,7 @@ */ package com.intellij.ui; -import com.intellij.openapi.actionSystem.ActionGroup; -import com.intellij.openapi.actionSystem.ActionToolbar; -import com.intellij.openapi.actionSystem.ActionToolbarPosition; -import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.SystemInfo; @@ -296,7 +293,9 @@ public abstract class ToolbarDecorator implements CommonActionsPanel.ListenerFac public ToolbarDecorator setActionGroup(@NotNull ActionGroup actionGroup) { AnAction[] actions = actionGroup.getChildren(null); for (AnAction action : actions) { - addExtraAction(AnActionButton.fromAction(action)); + if (!(action instanceof Separator)) { + addExtraAction(AnActionButton.fromAction(action)); + } } return this; } From 366a5c995a226c4c3b5ca2e0aa2ce9ce8bce5bf2 Mon Sep 17 00:00:00 2001 From: Michael Golubev Date: Tue, 1 Jul 2014 16:11:52 +0200 Subject: [PATCH 29/59] CR-IC-5617 - mark old method as deprecated --- .../remoteServer/runtime/deployment/ServerRuntimeInstance.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/ServerRuntimeInstance.java b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/ServerRuntimeInstance.java index 93dfe954431f..3f5e4ba42b0b 100644 --- a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/ServerRuntimeInstance.java +++ b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/ServerRuntimeInstance.java @@ -21,6 +21,9 @@ public abstract class ServerRuntimeInstance { return getDeploymentName(source); } + /** + * @deprecated use {@link #getDeploymentName(com.intellij.remoteServer.configuration.deployment.DeploymentSource, D configuration)} instead + */ @NotNull public String getDeploymentName(@NotNull DeploymentSource source) { return source.getPresentableName(); From 11b0389cc2a4ab928d3a424a43b5cda77d84c521 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Tue, 1 Jul 2014 16:28:25 +0200 Subject: [PATCH 30/59] make constant accessible from EngravedLabel --- platform/util/src/com/intellij/ui/EngravedTextGraphics.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/util/src/com/intellij/ui/EngravedTextGraphics.java b/platform/util/src/com/intellij/ui/EngravedTextGraphics.java index f47072f423a8..916bde842c3b 100644 --- a/platform/util/src/com/intellij/ui/EngravedTextGraphics.java +++ b/platform/util/src/com/intellij/ui/EngravedTextGraphics.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,7 @@ import java.awt.*; import java.text.AttributedCharacterIterator; public class EngravedTextGraphics extends Graphics2DDelegate { - private static final Color SHADOW_COLOR = Gray._250.withAlpha(140); + public static final Color SHADOW_COLOR = Gray._250.withAlpha(140); private static final boolean ALLOW_ENGRAVEMENT = SystemInfo.isMac; private Color myShadowColor; private int myXOffset; From 8fedc560c5a115693257f619f91409e0044b2e0e Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Tue, 1 Jul 2014 16:28:57 +0200 Subject: [PATCH 31/59] allow to set shadow color --- .../src/com/intellij/ui/EngravedLabel.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/platform/util/src/com/intellij/ui/EngravedLabel.java b/platform/util/src/com/intellij/ui/EngravedLabel.java index fdf098a52c4b..ec4fc8afef8c 100644 --- a/platform/util/src/com/intellij/ui/EngravedLabel.java +++ b/platform/util/src/com/intellij/ui/EngravedLabel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,6 +28,8 @@ import java.awt.*; * @author max */ public class EngravedLabel extends JLabel { + private Color myShadowColor = EngravedTextGraphics.SHADOW_COLOR; + public EngravedLabel(String text) { super(text); setOpaque(false); @@ -38,7 +40,18 @@ public class EngravedLabel extends JLabel { } @Override - protected void paintComponent(Graphics g) { - super.paintComponent(UIUtil.isUnderDarcula() ? g : new EngravedTextGraphics((Graphics2D)g)); + protected void paintComponent(Graphics graphics) { + if (!UIUtil.isUnderDarcula()) { + graphics = new EngravedTextGraphics((Graphics2D)graphics, 0, 1, getShadowColor()); + } + super.paintComponent(graphics); + } + + public Color getShadowColor() { + return myShadowColor == null ? EngravedTextGraphics.SHADOW_COLOR : myShadowColor; + } + + public void setShadowColor(Color shadowColor) { + myShadowColor = shadowColor; } } From f2a456c302e2bcda79bf6418e1b520faf35b63ff Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Tue, 1 Jul 2014 16:31:02 +0200 Subject: [PATCH 32/59] new Project Settings dialog UI key --- platform/platform-resources-en/src/misc/registry.properties | 2 ++ 1 file changed, 2 insertions(+) diff --git a/platform/platform-resources-en/src/misc/registry.properties b/platform/platform-resources-en/src/misc/registry.properties index 2d803f5fe361..dad0fd91d83d 100644 --- a/platform/platform-resources-en/src/misc/registry.properties +++ b/platform/platform-resources-en/src/misc/registry.properties @@ -402,3 +402,5 @@ console.too.much.text.buffer.ratio=10 console.too.much.text.buffer.ratio.description=Used for disabling of console processing(console filters for highlights, foldings...),\n\ when there is too much of text to process.\n\ The ratio is used against the console cycle buffer size (idea.cycle.buffer.size/theRatio=maxTextLength). +ide.new.project.settings=false +ide.new.project.settings.description=Temporary key for new project settings dialog UI From 9cb6e62a08a93ecab22c357d69d43c6c2fab6d09 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Tue, 1 Jul 2014 16:41:15 +0200 Subject: [PATCH 33/59] don't show find usages on toolbar in new project settings dialog --- .../projectRoot/BaseStructureConfigurable.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/BaseStructureConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/BaseStructureConfigurable.java index bf4f67c0c824..b88f92474fcf 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/BaseStructureConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/BaseStructureConfigurable.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,6 +38,8 @@ import com.intellij.openapi.ui.NamedConfigurable; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.registry.Registry; import com.intellij.packaging.artifacts.Artifact; import com.intellij.ui.TreeSpeedSearch; import com.intellij.ui.awt.RelativePoint; @@ -300,7 +302,9 @@ public abstract class BaseStructureConfigurable extends MasterDetailsComponent i result.addAll(copyActions); result.add(Separator.getInstance()); - result.add(new MyFindUsagesAction(myTree)); + if (fromPopup || !(SystemInfo.isMac && Registry.is("ide.new.project.settings"))) { + result.add(new MyFindUsagesAction(myTree)); + } return result; From 0922b7859de038d6b889c62df021d68959f1802d Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Tue, 1 Jul 2014 16:44:29 +0200 Subject: [PATCH 34/59] don't show collapse/expand actions on toolbar in new project settings dialog --- .../projectRoot/ModuleStructureConfigurable.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java index 44d7820feb88..1c313c1077ee 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -53,7 +53,9 @@ import com.intellij.openapi.ui.*; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.NullableComputable; +import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; @@ -149,7 +151,9 @@ public class ModuleStructureConfigurable extends BaseStructureConfigurable imple final ArrayList result = super.createActions(fromPopup); result.add(Separator.getInstance()); result.add(new MyGroupAction()); - addCollapseExpandActions(result); + if (fromPopup || !(SystemInfo.isMac && Registry.is("ide.new.project.settings"))) { + addCollapseExpandActions(result); + } return result; } From 63dc0bad1445e605929fa5b95a8bba902d941b53 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 1 Jul 2014 14:33:45 +0200 Subject: [PATCH 35/59] @NotNull --- .../src/com/intellij/openapi/ui/MasterDetailsComponent.java | 1 + .../platform-api/src/com/intellij/ui/treeStructure/Tree.java | 1 + 2 files changed, 2 insertions(+) diff --git a/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java b/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java index 0003e717b35c..252a20495556 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java @@ -270,6 +270,7 @@ public abstract class MasterDetailsComponent implements Configurable, DetailsCom return new Dimension(800, 600); } + @NotNull public JComponent createComponent() { reInitWholePanelIfNeeded(); diff --git a/platform/platform-api/src/com/intellij/ui/treeStructure/Tree.java b/platform/platform-api/src/com/intellij/ui/treeStructure/Tree.java index 0f62f53dab8c..169b5d57479b 100644 --- a/platform/platform-api/src/com/intellij/ui/treeStructure/Tree.java +++ b/platform/platform-api/src/com/intellij/ui/treeStructure/Tree.java @@ -753,6 +753,7 @@ public class Tree extends JTree implements ComponentWithEmptyText, ComponentWith UIUtil.setLineStyleAngled(this); } + @NotNull public T[] getSelectedNodes(Class nodeType, @Nullable NodeFilter filter) { TreePath[] paths = getSelectionPaths(); if (paths == null) return (T[])Array.newInstance(nodeType, 0); From 344174fc7e3bbfb3f5c9e1191ddde79e0c810e7a Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Tue, 1 Jul 2014 17:09:31 +0200 Subject: [PATCH 36/59] make some methods accessible outside the class --- .../src/com/intellij/ui/SeparatorWithText.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/platform/platform-api/src/com/intellij/ui/SeparatorWithText.java b/platform/platform-api/src/com/intellij/ui/SeparatorWithText.java index 059875a4acfc..2633ef31c9f3 100644 --- a/platform/platform-api/src/com/intellij/ui/SeparatorWithText.java +++ b/platform/platform-api/src/com/intellij/ui/SeparatorWithText.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,8 @@ import com.intellij.util.ui.UIUtil; import javax.swing.*; import java.awt.*; -import static javax.swing.SwingConstants.*; +import static javax.swing.SwingConstants.CENTER; +import static javax.swing.SwingConstants.LEFT; public class SeparatorWithText extends JComponent { @@ -34,11 +35,11 @@ public class SeparatorWithText extends JComponent { setFont(getFont().deriveFont(Font.BOLD)); } - private static int getVgap() { + protected static int getVgap() { return UIUtil.isUnderNativeMacLookAndFeel() ? 1 : 3; } - private static int getHgap() { + protected static int getHgap() { return 3; } @@ -109,6 +110,10 @@ public class SeparatorWithText extends JComponent { } } + protected String getCaption() { + return myCaption; + } + public void setCaption(String captionAboveOf) { myCaption = captionAboveOf; } From 07e53959630dee381c6989c3941ebe835b339f74 Mon Sep 17 00:00:00 2001 From: Sergey Ignatov Date: Tue, 1 Jul 2014 19:17:16 +0400 Subject: [PATCH 37/59] improve java string literal tokenizer: don't show typos twice for injected code --- .../intellij/spellchecker/LiteralExpressionTokenizer.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/java/java-impl/src/com/intellij/spellchecker/LiteralExpressionTokenizer.java b/java/java-impl/src/com/intellij/spellchecker/LiteralExpressionTokenizer.java index 77246ec92763..2eade6903cd2 100644 --- a/java/java-impl/src/com/intellij/spellchecker/LiteralExpressionTokenizer.java +++ b/java/java-impl/src/com/intellij/spellchecker/LiteralExpressionTokenizer.java @@ -17,8 +17,10 @@ package com.intellij.spellchecker; import com.intellij.codeInsight.AnnotationUtil; import com.intellij.psi.JavaTokenType; +import com.intellij.psi.PsiLanguageInjectionHost; import com.intellij.psi.PsiLiteralExpression; import com.intellij.psi.PsiModifierListOwner; +import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import com.intellij.psi.impl.source.tree.java.PsiLiteralExpressionImpl; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.spellchecker.inspections.PlainTextSplitter; @@ -30,8 +32,6 @@ import org.jetbrains.annotations.NotNull; import java.util.Collections; /** - * Created by IntelliJ IDEA. - * * @author shkate@jetbrains.com */ public class LiteralExpressionTokenizer extends Tokenizer { @@ -42,6 +42,8 @@ public class LiteralExpressionTokenizer extends Tokenizer return; // not a string literal } + if (InjectedLanguageUtil.hasInjections((PsiLanguageInjectionHost)element)) return; + final PsiModifierListOwner listOwner = PsiTreeUtil.getParentOfType(element, PsiModifierListOwner.class); if (listOwner != null && AnnotationUtil.isAnnotated(listOwner, Collections.singleton(AnnotationUtil.NON_NLS), false, false)) { return; From 2860b4df882bd14e55ac5eee4e1b6b10f171dea1 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Tue, 1 Jul 2014 19:25:55 +0400 Subject: [PATCH 38/59] [git] Fix NPE: use before revision if there is no after revision Can happen if the file was deleted in the selected commit. --- .../changes/GitCommittedChangeListProvider.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/plugins/git4idea/src/git4idea/changes/GitCommittedChangeListProvider.java b/plugins/git4idea/src/git4idea/changes/GitCommittedChangeListProvider.java index baf835820ddb..f1ab1d476c6f 100644 --- a/plugins/git4idea/src/git4idea/changes/GitCommittedChangeListProvider.java +++ b/plugins/git4idea/src/git4idea/changes/GitCommittedChangeListProvider.java @@ -22,6 +22,7 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.changes.Change; +import com.intellij.openapi.vcs.changes.ContentRevision; import com.intellij.openapi.vcs.changes.committed.DecoratorManager; import com.intellij.openapi.vcs.changes.committed.VcsCommittedListsZipper; import com.intellij.openapi.vcs.changes.committed.VcsCommittedViewAuxiliary; @@ -197,7 +198,14 @@ public class GitCommittedChangeListProvider implements CommittedChangesProvider< final Collection changes = commit.getChanges(); if (changes.size() == 1) { - return Pair.create(commit, changes.iterator().next().getAfterRevision().getFile()); + Change change = changes.iterator().next(); + ContentRevision revision = change.getAfterRevision(); + if (revision == null) { + revision = change.getBeforeRevision(); + } + assert revision != null : "Revision can't be null in " + change; + FilePath filePathInRevision = revision.getFile(); + return Pair.create(commit, filePathInRevision); } for (Change change : changes) { if (change.getAfterRevision() != null && FileUtil.filesEqual(filePath.getIOFile(), change.getAfterRevision().getFile().getIOFile())) { From 7be7a24449d9a6ebd65e93f5f28e7c9069517947 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Tue, 1 Jul 2014 18:04:12 +0400 Subject: [PATCH 39/59] diff: fix ErrorStripeTooltip for changed lines * do not operate with Document.*line* without reason * do not forget that lines in Document counted from 0 * use better description for deleted lines --- .../src/messages/VcsBundle.properties | 2 ++ .../openapi/vcs/ex/LineStatusTracker.java | 25 +++++++++++-------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/platform/platform-resources-en/src/messages/VcsBundle.properties b/platform/platform-resources-en/src/messages/VcsBundle.properties index 594db771aa60..5bd7b463c794 100644 --- a/platform/platform-resources-en/src/messages/VcsBundle.properties +++ b/platform/platform-resources-en/src/messages/VcsBundle.properties @@ -138,6 +138,8 @@ button.configure=&Configure VCS... action.name.rollback=Rollback command.name.rollback.change=Rollback Change action.name.show.difference=Show Difference +tooltip.text.line.before.deleted=Line before {0} deleted +tooltip.text.lines.before.deleted={1} lines before {0} deleted tooltip.text.line.changed=Line {0} changed tooltip.text.lines.changed=Lines {0}-{1} changed dialog.title.diff.for.range=Diff for Range diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java index d8b931009f43..8b9884502755 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java @@ -173,14 +173,12 @@ public class LineStatusTracker { @SuppressWarnings({"AutoBoxing"}) private RangeHighlighter createHighlighter(final Range range) { LOG.assertTrue(!myReleased, "Already released"); - int first = - range.getOffset1() >= myDocument.getLineCount() ? myDocument.getTextLength() : myDocument.getLineStartOffset(range.getOffset1()); - int second = - range.getOffset2() >= myDocument.getLineCount() ? myDocument.getTextLength() : myDocument.getLineStartOffset(range.getOffset2()); + TextRange textRange = getCurrentTextRange(range); final RangeHighlighter highlighter = DocumentMarkupModel.forDocument(myDocument, myProject, true) - .addRangeHighlighter(first, second, HighlighterLayer.FIRST - 1, null, HighlighterTargetArea.LINES_IN_RANGE); + .addRangeHighlighter(textRange.getStartOffset(), textRange.getEndOffset(), HighlighterLayer.FIRST - 1, null, + HighlighterTargetArea.LINES_IN_RANGE); final TextAttributes attr = LineStatusTrackerDrawing.getAttributesFor(range); highlighter.setErrorStripeMarkColor(attr.getErrorStripeColor()); highlighter.setThinErrorStripeMark(true); @@ -188,14 +186,21 @@ public class LineStatusTracker { highlighter.setGreedyToRight(true); highlighter.setLineMarkerRenderer(LineStatusTrackerDrawing.createRenderer(range, this)); highlighter.setEditorFilter(MarkupEditorFilterFactory.createIsNotDiffFilter()); - final int line1 = myDocument.getLineNumber(first); - final int line2 = myDocument.getLineNumber(second); + final String tooltip; - if (line1 == line2) { - tooltip = VcsBundle.message("tooltip.text.line.changed", line1); + if (range.getOffset1() == range.getOffset2()) { + if (range.getUOffset1() + 1 == range.getUOffset2()) { + tooltip = VcsBundle.message("tooltip.text.line.before.deleted", range.getOffset1() + 1); + } + else { + tooltip = VcsBundle.message("tooltip.text.lines.before.deleted", range.getOffset1() + 1, range.getUOffset2() - range.getUOffset1()); + } + } + else if (range.getOffset1() + 1 == range.getOffset2()) { + tooltip = VcsBundle.message("tooltip.text.line.changed", range.getOffset1() + 1); } else { - tooltip = VcsBundle.message("tooltip.text.lines.changed", line1, line2); + tooltip = VcsBundle.message("tooltip.text.lines.changed", range.getOffset1() + 1, range.getOffset2()); } highlighter.setErrorStripeTooltip(tooltip); From 8d4b8c38e415542c0a621b1fe6523658c9a6c78e Mon Sep 17 00:00:00 2001 From: Evgeny Pasynkov Date: Tue, 1 Jul 2014 17:36:34 +0200 Subject: [PATCH 40/59] ability to override errors firing --- .../intellij/openapi/module/impl/ModuleManagerImpl.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModuleManagerImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModuleManagerImpl.java index 1dcc6c8ef248..c19ba91e3346 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModuleManagerImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModuleManagerImpl.java @@ -282,7 +282,7 @@ public abstract class ModuleManagerImpl extends ModuleManager implements Project } } - fireErrors(errors); + onModuleLoadErrors(errors); showUnknownModuleTypeNotification(modulesWithUnknownTypes); @@ -321,7 +321,7 @@ public abstract class ModuleManagerImpl extends ModuleManager implements Project } } - private void fireErrors(final List errors) { + protected void onModuleLoadErrors(final List errors) { if (errors.isEmpty()) return; myModuleModel.myModulesCache = null; @@ -337,6 +337,10 @@ public abstract class ModuleManagerImpl extends ModuleManager implements Project } } + fireModuleLoadErrors(errors); + } + + protected void fireModuleLoadErrors(List errors) { if (ApplicationManager.getApplication().isHeadlessEnvironment()) { throw new RuntimeException(errors.get(0).getDescription()); } From 93ef0105463bf82e7b0529916f812b37e28b3f7c Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Tue, 1 Jul 2014 17:53:28 +0200 Subject: [PATCH 41/59] use engraved separator for new project settings --- .../popup/list/GroupedItemsListRenderer.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ui/popup/list/GroupedItemsListRenderer.java b/platform/platform-impl/src/com/intellij/ui/popup/list/GroupedItemsListRenderer.java index 30c609029630..72f2e1dc3b37 100644 --- a/platform/platform-impl/src/com/intellij/ui/popup/list/GroupedItemsListRenderer.java +++ b/platform/platform-impl/src/com/intellij/ui/popup/list/GroupedItemsListRenderer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,8 +16,11 @@ package com.intellij.ui.popup.list; import com.intellij.openapi.ui.popup.ListItemDescriptor; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.ui.EngravedLabel; import com.intellij.ui.ErrorLabel; +import com.intellij.ui.Gray; import com.intellij.ui.GroupedElementsRenderer; import com.intellij.ui.components.panels.OpaquePanel; @@ -55,15 +58,21 @@ public class GroupedItemsListRenderer extends GroupedElementsRenderer.List imple @Override protected JComponent createItemComponent() { - myTextLabel = new ErrorLabel(); - myTextLabel.setOpaque(true); - myTextLabel.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); + if (Registry.is("ide.new.project.settings")) { + myTextLabel = new EngravedLabel(); + myTextLabel.setFont(myTextLabel.getFont().deriveFont(Font.BOLD)); + myTextLabel.setForeground(Gray._240); + } else { + myTextLabel = new ErrorLabel(); + myTextLabel.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); + } + myTextLabel.setOpaque(true); return layoutComponent(myTextLabel); } protected final JComponent layoutComponent(JComponent middleItemComponent) { - JPanel result = new OpaquePanel(new BorderLayout(4, 4), Color.white); + JPanel result = new OpaquePanel(Registry.is("ide.new.project.settings") ? new BorderLayout(0, 0) : new BorderLayout(4, 4), Color.white); myNextStepLabel = new JLabel(); myNextStepLabel.setOpaque(true); From 40d74ea23875b6213e04434862b7f238ae0c717c Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Tue, 1 Jul 2014 17:54:03 +0200 Subject: [PATCH 42/59] use custom separators for new project settings --- .../intellij/ui/GroupedElementsRenderer.java | 51 +++++++++++++++---- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/platform/platform-api/src/com/intellij/ui/GroupedElementsRenderer.java b/platform/platform-api/src/com/intellij/ui/GroupedElementsRenderer.java index 2293d45bf329..3ddbf47028f4 100644 --- a/platform/platform-api/src/com/intellij/ui/GroupedElementsRenderer.java +++ b/platform/platform-api/src/com/intellij/ui/GroupedElementsRenderer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,9 @@ */ package com.intellij.ui; +import com.intellij.openapi.util.registry.Registry; import com.intellij.ui.components.panels.OpaquePanel; +import com.intellij.util.ui.GraphicsUtil; import com.intellij.util.ui.UIUtil; import javax.swing.*; @@ -24,16 +26,43 @@ import javax.swing.border.EmptyBorder; import javax.swing.tree.TreeCellRenderer; import java.awt.*; +import static javax.swing.SwingConstants.CENTER; +import static javax.swing.SwingConstants.LEFT; + public abstract class GroupedElementsRenderer { public static final Color POPUP_SEPARATOR_FOREGROUND = new JBColor(Color.gray.brighter(), Gray._43); public static final Color POPUP_SEPARATOR_TEXT_FOREGROUND = Color.gray; public static final Color SELECTED_FRAME_FOREGROUND = Color.black; - protected SeparatorWithText mySeparatorComponent = new SeparatorWithText(); + protected SeparatorWithText mySeparatorComponent = new SeparatorWithText() { + @Override + protected void paintComponent(Graphics g) { + if (Registry.is("ide.new.project.settings")) { + g.setColor(POPUP_SEPARATOR_FOREGROUND); + Rectangle viewR = new Rectangle(0, getVgap(), getWidth() - 1, getHeight() - getVgap() - 1); + Rectangle iconR = new Rectangle(); + Rectangle textR = new Rectangle(); + String s = SwingUtilities + .layoutCompoundLabel(g.getFontMetrics(), getCaption(), null, CENTER, + LEFT, + CENTER, + LEFT, + viewR, iconR, textR, 0); + GraphicsUtil.setupAAPainting(g); + g.setColor(Gray._255.withAlpha(80)); + g.drawString(s, textR.x + 10, textR.y + 1 + g.getFontMetrics().getAscent()); + g.setColor(new Color(0x5F6D7B)); + g.drawString(s, textR.x + 10, textR.y + g.getFontMetrics().getAscent()); + } else { + super.paintComponent(g); + } + } + }; + protected JComponent myComponent; protected MyComponent myRendererComponent; - protected ErrorLabel myTextLabel; + protected JLabel myTextLabel; public GroupedElementsRenderer() { @@ -58,14 +87,16 @@ public abstract class GroupedElementsRenderer { myTextLabel.setIcon(icon); myTextLabel.setDisabledIcon(disabledIcon); + if (myTextLabel instanceof EngravedLabel) { + ((EngravedLabel)myTextLabel).setShadowColor(isSelected ? UIUtil.getTreeSelectionBackground() : null); + } if (isSelected) { - myComponent.setBorder(getSelectedBorder()); + //myComponent.setBorder(getSelectedBorder()); setSelected(myComponent); setSelected(myTextLabel); - } - else { - myComponent.setBorder(getBorder()); + } else { + //myComponent.setBorder(getBorder()); setDeselected(myComponent); setDeselected(myTextLabel); } @@ -98,7 +129,7 @@ public abstract class GroupedElementsRenderer { protected final void setDeselected(JComponent aComponent) { aComponent.setBackground(getBackground()); - aComponent.setForeground(getForeground()); + aComponent.setForeground(Registry.is("ide.new.project.settings") ? Gray._60 : getForeground()); } protected abstract Color getSelectionBackground(); @@ -139,12 +170,12 @@ public abstract class GroupedElementsRenderer { } @Override - protected final Color getBackground() { + protected Color getBackground() { return UIUtil.getListBackground(); } @Override - protected final Color getForeground() { + protected Color getForeground() { return UIUtil.getListForeground(); } } From 85da044664a9df5b845497e9740e975b72cafee8 Mon Sep 17 00:00:00 2001 From: Sergey Simonchik Date: Tue, 1 Jul 2014 19:54:16 +0400 Subject: [PATCH 43/59] better name http://crucible.labs.intellij.net/cru/CR-IC-5600#c27839 --- .../EnvironmentVariablesComponent.java | 28 +++++++++---------- ...ntVariablesTextFieldWithBrowseButton.java} | 20 +++++-------- 2 files changed, 20 insertions(+), 28 deletions(-) rename platform/lang-api/src/com/intellij/execution/configuration/{EnvironmentVariablesTextField.java => EnvironmentVariablesTextFieldWithBrowseButton.java} (90%) diff --git a/platform/lang-api/src/com/intellij/execution/configuration/EnvironmentVariablesComponent.java b/platform/lang-api/src/com/intellij/execution/configuration/EnvironmentVariablesComponent.java index f022608750f4..21c7deabff9f 100644 --- a/platform/lang-api/src/com/intellij/execution/configuration/EnvironmentVariablesComponent.java +++ b/platform/lang-api/src/com/intellij/execution/configuration/EnvironmentVariablesComponent.java @@ -43,30 +43,30 @@ public class EnvironmentVariablesComponent extends LabeledComponent envs) { - myEnvsTextField.setEnvs(envs); + myEnvVars.setEnvs(envs); } @NotNull public Map getEnvs() { - return myEnvsTextField.getEnvs(); + return myEnvVars.getEnvs(); } public boolean isPassParentEnvs() { - return myEnvsTextField.isPassParentEnvs(); + return myEnvVars.isPassParentEnvs(); } public void setPassParentEnvs(final boolean passParentEnvs) { - myEnvsTextField.setPassParentEnvs(passParentEnvs); + myEnvVars.setPassParentEnvs(passParentEnvs); } public static void readExternal(Element element, Map envs) { @@ -93,12 +93,10 @@ public class EnvironmentVariablesComponent extends LabeledComponent envs, final String val) { if (val != null) { final String[] envVars = val.split(";"); - if (envVars != null) { - for (String envVar : envVars) { - final int idx = envVar.indexOf('='); - if (idx > -1) { - envs.put(envVar.substring(0, idx), idx < envVar.length() - 1 ? envVar.substring(idx + 1) : ""); - } + for (String envVar : envVars) { + final int idx = envVar.indexOf('='); + if (idx > -1) { + envs.put(envVar.substring(0, idx), idx < envVar.length() - 1 ? envVar.substring(idx + 1) : ""); } } } @@ -134,11 +132,11 @@ public class EnvironmentVariablesComponent extends LabeledComponent myEnvs = new THashMap(); private boolean myPassParentEnvs; private final List myListeners = ContainerUtil.createLockFreeCopyOnWriteList(); - public EnvironmentVariablesTextField() { - myEnvsTextField = new TextFieldWithBrowseButton(); - myEnvsTextField.setEditable(false); - myEnvsTextField.addActionListener(new ActionListener() { + public EnvironmentVariablesTextFieldWithBrowseButton() { + super(); + setEditable(false); + addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { new MyEnvironmentVariablesDialog().show(); @@ -52,11 +51,6 @@ public class EnvironmentVariablesTextField { }); } - @NotNull - public TextFieldWithBrowseButton getComponent() { - return myEnvsTextField; - } - @NotNull public Map getEnvs() { return myEnvs; @@ -66,7 +60,7 @@ public class EnvironmentVariablesTextField { myEnvs.clear(); myEnvs.putAll(envs); String envsStr = stringifyEnvs(myEnvs); - myEnvsTextField.setText(envsStr); + setText(envsStr); } @NotNull @@ -115,7 +109,7 @@ public class EnvironmentVariablesTextField { private final JPanel myWholePanel = new JPanel(new BorderLayout()); protected MyEnvironmentVariablesDialog() { - super(myEnvsTextField, true); + super(EnvironmentVariablesTextFieldWithBrowseButton.this, true); myEnvVariablesTable = new EnvVariablesTable(); List envVariables = ContainerUtil.newArrayList(); for (Map.Entry entry : myEnvs.entrySet()) { From dcfae0d5c64b6c51e11fa8185f4a5d9c61fadd11 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Tue, 1 Jul 2014 17:55:02 +0200 Subject: [PATCH 44/59] buttonless dialog for new project settings --- .../actions/ShowStructureSettingsAction.java | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/java/idea-ui/src/com/intellij/ide/actions/ShowStructureSettingsAction.java b/java/idea-ui/src/com/intellij/ide/actions/ShowStructureSettingsAction.java index 9b803f5d8d6e..36cd7430b827 100644 --- a/java/idea-ui/src/com/intellij/ide/actions/ShowStructureSettingsAction.java +++ b/java/idea-ui/src/com/intellij/ide/actions/ShowStructureSettingsAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,13 +18,19 @@ package com.intellij.ide.actions; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.options.ShowSettingsUtil; +import com.intellij.openapi.options.ex.SingleConfigurableEditor; import com.intellij.openapi.options.newEditor.OptionsEditorDialog; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.roots.ui.configuration.ProjectStructureConfigurable; +import com.intellij.openapi.util.registry.Registry; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.border.Border; +import javax.swing.border.EmptyBorder; public class ShowStructureSettingsAction extends AnAction implements DumbAware { public void actionPerformed(AnActionEvent e) { @@ -33,6 +39,23 @@ public class ShowStructureSettingsAction extends AnAction implements DumbAware { project = ProjectManager.getInstance().getDefaultProject(); } - ShowSettingsUtil.getInstance().editConfigurable(project, OptionsEditorDialog.DIMENSION_KEY, ProjectStructureConfigurable.getInstance(project)); + if (Registry.is("ide.new.project.settings")) { + new SingleConfigurableEditor(project, ProjectStructureConfigurable.getInstance(project), OptionsEditorDialog.DIMENSION_KEY) { + @Nullable + @Override + protected Border createContentPaneBorder() { + return new EmptyBorder(0,0,0,0); + } + + @Nullable + @Override + protected JComponent createSouthPanel() { + return null; + } + }.show(); + } else { + ShowSettingsUtil + .getInstance().editConfigurable(project, OptionsEditorDialog.DIMENSION_KEY, ProjectStructureConfigurable.getInstance(project)); + } } } \ No newline at end of file From b0765e8ada1b75205daf0ba30b40367bc3325051 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Tue, 1 Jul 2014 17:56:27 +0200 Subject: [PATCH 45/59] use thin splitters --- .../ProjectStructureConfigurable.java | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java index af34e4092d32..d007c3650642 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,11 +38,13 @@ import com.intellij.openapi.roots.ui.configuration.artifacts.ArtifactsStructureC import com.intellij.openapi.roots.ui.configuration.projectRoot.*; import com.intellij.openapi.ui.DetailsComponent; import com.intellij.openapi.ui.MasterDetailsComponent; -import com.intellij.openapi.ui.Splitter; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.wm.ex.IdeFocusTraversalPolicy; import com.intellij.packaging.artifacts.Artifact; +import com.intellij.ui.Gray; +import com.intellij.ui.JBSplitter; import com.intellij.ui.components.panels.Wrapper; import com.intellij.ui.navigation.BackAction; import com.intellij.ui.navigation.ForwardAction; @@ -67,7 +69,7 @@ public class ProjectStructureConfigurable extends BaseConfigurable implements Se public static final DataKey KEY = DataKey.create("ProjectStructureConfiguration"); protected final UIState myUiState = new UIState(); - private Splitter mySplitter; + private JBSplitter mySplitter; private JComponent myToolbarComponent; @NonNls public static final String CATEGORY = "category"; private JComponent myToFocus; @@ -173,8 +175,16 @@ public class ProjectStructureConfigurable extends BaseConfigurable implements Se public JComponent createComponent() { myComponent = new MyPanel(); - mySplitter = new Splitter(false, .15f); + mySplitter = new JBSplitter(false, .15f); + mySplitter.setSplitterProportionKey("ProjectStructure.TopLevelElements"); mySplitter.setHonorComponentsMinimumSize(true); + if (Registry.is("ide.new.project.settings")) { + mySplitter.setDividerWidth(1); + mySplitter.setShowDividerIcon(false); + mySplitter.getDivider().setBackground(Gray._153.withAlpha(128)); + mySplitter.setShowDividerControls(false); + mySplitter.setOrientation(mySplitter.getOrientation()); + } initSidePanel(); @@ -192,7 +202,11 @@ public class ProjectStructureConfigurable extends BaseConfigurable implements Se final ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, toolbarGroup, true); toolbar.setTargetComponent(myComponent); myToolbarComponent = toolbar.getComponent(); - left.add(myToolbarComponent, BorderLayout.NORTH); + if (Registry.is("ide.new.project.settings")) { + left.setBackground(new Color(0xD2D6DD)); + } else { + left.add(myToolbarComponent, BorderLayout.NORTH); + } left.add(mySidePanel, BorderLayout.CENTER); mySplitter.setFirstComponent(left); From 067d2127d0d718f43339a3b8b53e7b5d2a61e509 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Tue, 1 Jul 2014 18:08:06 +0200 Subject: [PATCH 46/59] use toolbar decorator in case of new project settings dialog --- .../openapi/ui/MasterDetailsComponent.java | 44 ++++++++++++++++--- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java b/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java index 0003e717b35c..7597bd4bd46c 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,6 +29,7 @@ import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Conditions; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.*; import com.intellij.ui.navigation.History; @@ -46,6 +47,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import javax.swing.border.EmptyBorder; import javax.swing.tree.*; import java.awt.*; import java.util.*; @@ -61,7 +63,7 @@ public abstract class MasterDetailsComponent implements Configurable, DetailsCom protected static final Icon COPY_ICON = PlatformIcons.COPY_ICON; protected NamedConfigurable myCurrentConfigurable; - private final Splitter mySplitter = new Splitter(false, .2f); + private final JBSplitter mySplitter; @NonNls public static final String TREE_OBJECT = "treeObject"; @NonNls public static final String TREE_NAME = "treeName"; @@ -79,7 +81,7 @@ public abstract class MasterDetailsComponent implements Configurable, DetailsCom public void queryPlace(@NotNull final Place place) { } }); - private JScrollPane myMaster; + private JComponent myMaster; public void setHistory(final History history) { myHistory = history; @@ -128,6 +130,18 @@ public abstract class MasterDetailsComponent implements Configurable, DetailsCom protected MasterDetailsComponent(MasterDetailsState state) { myState = state; + + mySplitter = new JBSplitter(false, .2f); + mySplitter.setSplitterProportionKey("ProjectStructure.SecondLevelElements"); + mySplitter.setHonorComponentsMinimumSize(true); + if (Registry.is("ide.new.project.settings")) { + mySplitter.setDividerWidth(1); + mySplitter.setShowDividerIcon(false); + mySplitter.getDivider().setBackground(Gray._153.withAlpha(128)); + mySplitter.setShowDividerControls(false); + mySplitter.setOrientation(mySplitter.getOrientation()); + } + installAutoScroll(); reInitWholePanelIfNeeded(); } @@ -163,8 +177,18 @@ public abstract class MasterDetailsComponent implements Configurable, DetailsCom } }; - left.add(myNorthPanel, BorderLayout.NORTH); - myMaster = ScrollPaneFactory.createScrollPane(myTree); + if (Registry.is("ide.new.project.settings")) { + ToolbarDecorator decorator = ToolbarDecorator.createDecorator(myTree); + DefaultActionGroup group = createToolbarActionGroup(); + if (group != null) { + decorator.setActionGroup(group); + } + //left.add(myNorthPanel, BorderLayout.NORTH); + myMaster = decorator.setPanelBorder(new EmptyBorder(0, 0, 0, 0)).createPanel(); + } else { + left.add(myNorthPanel, BorderLayout.NORTH); + myMaster = ScrollPaneFactory.createScrollPane(myTree); + } left.add(myMaster, BorderLayout.CENTER); mySplitter.setFirstComponent(left); @@ -245,7 +269,7 @@ public abstract class MasterDetailsComponent implements Configurable, DetailsCom return myHistory == null || !myHistory.isNavigatingNow(); } - private void initToolbar() { + protected DefaultActionGroup createToolbarActionGroup() { final ArrayList actions = createActions(false); if (actions != null) { final DefaultActionGroup group = new DefaultActionGroup(); @@ -257,6 +281,14 @@ public abstract class MasterDetailsComponent implements Configurable, DetailsCom group.add(action); } } + return group; + } + return null; + } + + private void initToolbar() { + DefaultActionGroup group = createToolbarActionGroup(); + if (group != null) { final JComponent component = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, group, true).getComponent(); myNorthPanel.add(component, BorderLayout.NORTH); } From d0aee360d51674dd2aadf956156bbb61f0c9b280 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Tue, 1 Jul 2014 18:08:54 +0200 Subject: [PATCH 47/59] bg color for new project settings dialog --- .../roots/ui/configuration/SidePanel.java | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/SidePanel.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/SidePanel.java index 193ce66a8f36..a2d1e4e0489d 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/SidePanel.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/SidePanel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,14 +17,17 @@ package com.intellij.openapi.roots.ui.configuration; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.ui.popup.ListItemDescriptor; +import com.intellij.openapi.util.registry.Registry; import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.components.JBList; import com.intellij.ui.navigation.History; import com.intellij.ui.navigation.Place; import com.intellij.ui.popup.list.GroupedItemsListRenderer; +import com.intellij.util.ui.EmptyIcon; import org.jetbrains.annotations.NotNull; import javax.swing.*; +import javax.swing.border.EmptyBorder; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import java.awt.*; @@ -52,7 +55,10 @@ public class SidePanel extends JPanel { myModel = new DefaultListModel(); myList = new JBList(myModel); - + if (Registry.is("ide.new.project.settings")) { + myList.setBackground(new Color(0xD2D6DD)); + myList.setBorder(new EmptyBorder(5, 0, 0, 0)); + } final ListItemDescriptor descriptor = new ListItemDescriptor() { @Override public String getTextFor(final Object value) { @@ -66,7 +72,7 @@ public class SidePanel extends JPanel { @Override public Icon getIconFor(final Object value) { - return null; + return Registry.is("ide.new.project.settings") ? EmptyIcon.create(16, 20) : null; //return myPlace2Presentation.get(value).getIcon(); } @@ -78,14 +84,22 @@ public class SidePanel extends JPanel { @Override public String getCaptionAboveOf(final Object value) { - return myIndex2Separator.get(myPlaces.indexOf(value)); + String text = myIndex2Separator.get(myPlaces.indexOf(value)); + return text != null && Registry.is("ide.new.project.settings") ? text.toUpperCase() : text; } }; - myList.setCellRenderer(new GroupedItemsListRenderer(descriptor)); + myList.setCellRenderer(new GroupedItemsListRenderer(descriptor) { + { + mySeparatorComponent.setCaptionCentered(false); + } + @Override + protected Color getBackground() { + return Registry.is("ide.new.project.settings") ? new Color(0xD2D6DD) : super.getBackground(); + } + }); - - add(ScrollPaneFactory.createScrollPane(myList), BorderLayout.CENTER); + add(ScrollPaneFactory.createScrollPane(myList, Registry.is("ide.new.project.settings")), BorderLayout.CENTER); myList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); myList.addListSelectionListener(new ListSelectionListener() { From 993860912bcfd6498b9b5b77f2988d97888ecb04 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Tue, 1 Jul 2014 18:10:28 +0200 Subject: [PATCH 48/59] cleanup for new project settings dialog --- .../openapi/roots/ui/configuration/ModuleEditor.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleEditor.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleEditor.java index 14c5fba1ded9..10df2939f6e7 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleEditor.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleEditor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,6 +37,7 @@ import com.intellij.openapi.roots.impl.libraries.LibraryEx; import com.intellij.openapi.roots.impl.libraries.LibraryTableBase; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.roots.libraries.LibraryTable; +import com.intellij.openapi.util.registry.Registry; import com.intellij.ui.navigation.History; import com.intellij.ui.navigation.Place; import com.intellij.util.EventDispatcher; @@ -238,9 +239,10 @@ public abstract class ModuleEditor implements Place.Navigator, Disposable { createEditors(getModule()); - JPanel northPanel = new JPanel(new GridBagLayout()); - - myGenericSettingsPanel.add(northPanel, BorderLayout.NORTH); + if (!Registry.is("ide.new.project.settings")) { + JPanel northPanel = new JPanel(new GridBagLayout()); + myGenericSettingsPanel.add(northPanel, BorderLayout.NORTH); + } final JComponent component = createCenterPanel(); myGenericSettingsPanel.add(component, BorderLayout.CENTER); From 3bc3af598b5d4a5af4b7b208df28fee45b5d2913 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 1 Jul 2014 16:53:14 +0200 Subject: [PATCH 49/59] diagnostics for EA-57731 - assert: PsiFileFactoryImpl.markGenerated --- .../src/com/intellij/psi/impl/PsiFileFactoryImpl.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platform/core-impl/src/com/intellij/psi/impl/PsiFileFactoryImpl.java b/platform/core-impl/src/com/intellij/psi/impl/PsiFileFactoryImpl.java index a24a942bcfea..1933626770dc 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/PsiFileFactoryImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/PsiFileFactoryImpl.java @@ -114,6 +114,9 @@ public class PsiFileFactoryImpl extends PsiFileFactory { final PsiFile psiFile = viewProvider.getPsi(language); if (psiFile != null) { if (markAsCopy) { + if (psiFile.getNode() == null) { + throw new AssertionError("No node for file " + psiFile + "; language=" + language); + } markGenerated(psiFile); } return psiFile; From 5e9762adfb7fcb7116a1fd24da449e341f2294b5 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 1 Jul 2014 17:13:35 +0200 Subject: [PATCH 50/59] LookupOffsets.updateLookupStart: ensure offset bounds instead of assertions (EA-49467, EA-47632) --- .../com/intellij/codeInsight/lookup/impl/LookupOffsets.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupOffsets.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupOffsets.java index 28d3aff18665..fe53f1796dbd 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupOffsets.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupOffsets.java @@ -51,10 +51,7 @@ public class LookupOffsets { private void updateLookupStart(int minPrefixLength) { int offset = getPivotOffset(); int start = offset - minPrefixLength - myAdditionalPrefix.length() + myRemovedPrefix; - if (start < 0) { - LOG.error("Invalid start offset: o=" + offset + ", mpl=" + minPrefixLength + ", ap=" + myAdditionalPrefix + ", rp=" + myRemovedPrefix); - return; - } + start = Math.max(Math.min(start, myEditor.getDocument().getTextLength()), 0); if (myLookupStartMarker != null) { if (myLookupStartMarker.isValid() && myLookupStartMarker.getStartOffset() == start && myLookupStartMarker.getEndOffset() == start) { return; From fc9caebfe2892a7e07bdb8a3364d649f7e8d07f9 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 1 Jul 2014 17:22:27 +0200 Subject: [PATCH 51/59] diagnostics for EA-55898 - assert: TemplateLanguageStructureViewBuilder. --- .../TemplateLanguageStructureViewBuilder.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/structureView/impl/TemplateLanguageStructureViewBuilder.java b/platform/lang-impl/src/com/intellij/ide/structureView/impl/TemplateLanguageStructureViewBuilder.java index 83174587bf01..849b01b703b9 100644 --- a/platform/lang-impl/src/com/intellij/ide/structureView/impl/TemplateLanguageStructureViewBuilder.java +++ b/platform/lang-impl/src/com/intellij/ide/structureView/impl/TemplateLanguageStructureViewBuilder.java @@ -60,9 +60,7 @@ public abstract class TemplateLanguageStructureViewBuilder implements StructureV myVirtualFile = psiElement.getContainingFile().getVirtualFile(); myProject = psiElement.getProject(); - final TemplateLanguageFileViewProvider provider = getViewProvider(); - assert provider != null; - myTemplateDataLanguage = provider.getTemplateDataLanguage(); + myTemplateDataLanguage = getNotNullViewProvider().getTemplateDataLanguage(); } private void updateAfterPsiChange() { @@ -115,6 +113,15 @@ public abstract class TemplateLanguageStructureViewBuilder implements StructureV return provider instanceof TemplateLanguageFileViewProvider ? (TemplateLanguageFileViewProvider)provider : null; } + @NotNull + private TemplateLanguageFileViewProvider getNotNullViewProvider() { + final FileViewProvider provider = PsiManager.getInstance(myProject).findViewProvider(myVirtualFile); + if (provider == null || !(provider instanceof TemplateLanguageFileViewProvider)) { + throw new AssertionError("Not a template view provider for " + myVirtualFile + ": " + provider); + } + return (TemplateLanguageFileViewProvider)provider; + } + private void updateBaseLanguageView() { if (myBaseStructureViewDescriptor == null || !myProject.isOpen()) return; final StructureViewComponent view = (StructureViewComponent)myBaseStructureViewDescriptor.structureView; @@ -158,8 +165,7 @@ public abstract class TemplateLanguageStructureViewBuilder implements StructureV public StructureView createStructureView(FileEditor fileEditor, @NotNull Project project) { myFileEditor = fileEditor; List viewDescriptors = new ArrayList(); - final TemplateLanguageFileViewProvider provider = getViewProvider(); - assert provider != null; + final TemplateLanguageFileViewProvider provider = getNotNullViewProvider(); final StructureViewComposite.StructureViewDescriptor structureViewDescriptor = createMainView(fileEditor, provider.getPsi(provider.getBaseLanguage())); if (structureViewDescriptor != null) viewDescriptors.add(structureViewDescriptor); From fa18e78ca3bfbe6f01254cf63e245cf9bd04b6c5 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 1 Jul 2014 17:42:14 +0200 Subject: [PATCH 52/59] ensure JavaCompletionContributor commits the document after auto-import, cleanup (EA-52975) --- .../completion/JavaCompletionContributor.java | 22 +++++++++------ .../CompletionInitializationContext.java | 12 ++++++--- .../completion/CodeCompletionHandlerBase.java | 27 ++++++++++--------- 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java index 47cf86819c0f..7310227a80f0 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java @@ -53,6 +53,7 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.PsiUtilCore; import com.intellij.util.Consumer; +import com.intellij.util.ObjectUtils; import com.intellij.util.PairConsumer; import com.intellij.util.ProcessingContext; import org.jetbrains.annotations.NotNull; @@ -340,6 +341,7 @@ public class JavaCompletionContributor extends CompletionContributor { } final Object[] variants = reference.getVariants(); + //noinspection ConstantConditions if (variants == null) { LOG.error("Reference=" + reference); } @@ -365,6 +367,7 @@ public class JavaCompletionContributor extends CompletionContributor { } else { + //noinspection deprecation LookupElement element = LookupItemUtil.objectToLookupItem(completion); usedWords.add(element.getLookupString()); result.addElement(element); @@ -434,7 +437,7 @@ public class JavaCompletionContributor extends CompletionContributor { private static void completeAnnotationAttributeName(CompletionResultSet result, PsiElement insertedElement, CompletionParameters parameters) { PsiNameValuePair pair = PsiTreeUtil.getParentOfType(insertedElement, PsiNameValuePair.class); - PsiAnnotationParameterList parameterList = (PsiAnnotationParameterList)pair.getParent(); + PsiAnnotationParameterList parameterList = (PsiAnnotationParameterList)ObjectUtils.assertNotNull(pair).getParent(); PsiAnnotation anno = (PsiAnnotation)parameterList.getParent(); boolean showClasses = psiElement().afterLeaf("(").accepts(insertedElement); PsiClass annoClass = null; @@ -507,7 +510,7 @@ public class JavaCompletionContributor extends CompletionContributor { if (psiElement().withParent(psiReferenceExpression().withFirstChild(psiReferenceExpression().referencing(psiClass()))).accepts(position)) { if (CompletionUtil.shouldShowFeature(parameters, JavaCompletionFeatures.GLOBAL_MEMBER_NAME)) { final String shortcut = getActionShortcut(IdeActions.ACTION_CODE_COMPLETION); - if (shortcut != null) { + if (StringUtil.isNotEmpty(shortcut)) { return "Pressing " + shortcut + " twice without a class qualifier would show all accessible static methods"; } } @@ -517,7 +520,7 @@ public class JavaCompletionContributor extends CompletionContributor { if (parameters.getCompletionType() != CompletionType.SMART && shouldSuggestSmartCompletion(parameters.getPosition())) { if (CompletionUtil.shouldShowFeature(parameters, CodeCompletionFeatures.EDITING_COMPLETION_SMARTTYPE_GENERAL)) { final String shortcut = getActionShortcut(IdeActions.ACTION_SMART_TYPE_COMPLETION); - if (shortcut != null) { + if (StringUtil.isNotEmpty(shortcut)) { return CompletionBundle.message("completion.smart.hint", shortcut); } } @@ -528,7 +531,7 @@ public class JavaCompletionContributor extends CompletionContributor { if (psiTypes.length > 0) { if (CompletionUtil.shouldShowFeature(parameters, JavaCompletionFeatures.SECOND_SMART_COMPLETION_TOAR)) { final String shortcut = getActionShortcut(IdeActions.ACTION_SMART_TYPE_COMPLETION); - if (shortcut != null) { + if (StringUtil.isNotEmpty(shortcut)) { for (final PsiType psiType : psiTypes) { final PsiType type = PsiUtil.extractIterableTypeParameter(psiType, false); if (type != null) { @@ -539,7 +542,7 @@ public class JavaCompletionContributor extends CompletionContributor { } if (CompletionUtil.shouldShowFeature(parameters, JavaCompletionFeatures.SECOND_SMART_COMPLETION_ASLIST)) { final String shortcut = getActionShortcut(IdeActions.ACTION_SMART_TYPE_COMPLETION); - if (shortcut != null) { + if (StringUtil.isNotEmpty(shortcut)) { for (final PsiType psiType : psiTypes) { if (psiType instanceof PsiArrayType) { final PsiType componentType = ((PsiArrayType)psiType).getComponentType(); @@ -553,7 +556,7 @@ public class JavaCompletionContributor extends CompletionContributor { if (CompletionUtil.shouldShowFeature(parameters, JavaCompletionFeatures.SECOND_SMART_COMPLETION_CHAIN)) { final String shortcut = getActionShortcut(IdeActions.ACTION_SMART_TYPE_COMPLETION); - if (shortcut != null) { + if (StringUtil.isNotEmpty(shortcut)) { return CompletionBundle.message("completion.smart.chain.hint", shortcut); } } @@ -639,9 +642,12 @@ public class JavaCompletionContributor extends CompletionContributor { final PsiFile file = context.getFile(); if (file instanceof PsiJavaFile) { - JavaCompletionUtil.initOffsets(file, context.getOffsetMap()); + if (context.getInvocationCount() > 0) { + autoImport(file, context.getStartOffset() - 1, context.getEditor()); + PsiDocumentManager.getInstance(context.getProject()).commitDocument(context.getEditor().getDocument()); + } - autoImport(file, context.getStartOffset() - 1, context.getEditor()); + JavaCompletionUtil.initOffsets(file, context.getOffsetMap()); if (context.getCompletionType() == CompletionType.BASIC) { if (semicolonNeeded(context.getEditor(), file, context.getStartOffset())) { diff --git a/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionInitializationContext.java b/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionInitializationContext.java index 7cf2c7d7db11..624d60fd8688 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionInitializationContext.java +++ b/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionInitializationContext.java @@ -21,6 +21,7 @@ import com.intellij.openapi.editor.SelectionModel; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiFile; import com.intellij.psi.util.PsiUtilBase; +import com.intellij.util.ObjectUtils; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -40,13 +41,15 @@ public class CompletionInitializationContext { private final Editor myEditor; private final PsiFile myFile; private final CompletionType myCompletionType; + private final int myInvocationCount; private final OffsetMap myOffsetMap; private String myDummyIdentifier = DUMMY_IDENTIFIER; - public CompletionInitializationContext(final Editor editor, final PsiFile file, final CompletionType completionType) { + public CompletionInitializationContext(final Editor editor, final PsiFile file, final CompletionType completionType, int invocationCount) { myEditor = editor; myFile = file; myCompletionType = completionType; + myInvocationCount = invocationCount; myOffsetMap = new OffsetMap(editor.getDocument()); myOffsetMap.addOffset(START_OFFSET, calcStartOffset(editor)); @@ -79,7 +82,7 @@ public class CompletionInitializationContext { @NotNull public Language getPositionLanguage() { - return PsiUtilBase.getLanguageInEditor(getEditor(), getProject()); + return ObjectUtils.assertNotNull(PsiUtilBase.getLanguageInEditor(getEditor(), getProject())); } public String getDummyIdentifier() { @@ -127,9 +130,12 @@ public class CompletionInitializationContext { return getIdentifierEndOffset(); } + public int getInvocationCount() { + return myInvocationCount; + } + /** * Mark the offset up to which the text will be deleted if a completion variant is selected using Replace character (Tab) - * @param idEnd */ public void setReplacementOffset(int idEnd) { myOffsetMap.addOffset(IDENTIFIER_END_OFFSET, idEnd); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java index 0685c53c2ad7..31a79bab98bb 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java @@ -135,19 +135,18 @@ public class CodeCompletionHandlerBase { } */ - int newTime = phase.newCompletionStarted(time, repeated); + final int newTime = phase.newCompletionStarted(time, repeated); if (invokedExplicitly) { time = newTime; } + final int invocationCount = time; if (CompletionServiceImpl.isPhase(CompletionPhase.InsertedSingleItem.class)) { CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion); } CompletionServiceImpl.assertPhase(CompletionPhase.NoCompletion.getClass(), CompletionPhase.CommittingDocuments.class); - if (time > 1) { - if (myCompletionType == CompletionType.BASIC) { - FeatureUsageTracker.getInstance().triggerFeatureUsed(CodeCompletionFeatures.SECOND_BASIC_COMPLETION); - } + if (invocationCount > 1 && myCompletionType == CompletionType.BASIC) { + FeatureUsageTracker.getInstance().triggerFeatureUsed(CodeCompletionFeatures.SECOND_BASIC_COMPLETION); } final CompletionInitializationContext[] initializationContext = {null}; @@ -168,7 +167,7 @@ public class CodeCompletionHandlerBase { psiFile.putUserData(PsiFileEx.BATCH_REFERENCE_PROCESSING, Boolean.TRUE); CompletionAssertions.assertCommitSuccessful(editor, psiFile); - initializationContext[0] = runContributorsBeforeCompletion(editor, psiFile); + initializationContext[0] = runContributorsBeforeCompletion(editor, psiFile, invocationCount); } }; ApplicationManager.getApplication().runWriteAction(runnable); @@ -184,12 +183,12 @@ public class CodeCompletionHandlerBase { CommandProcessor.getInstance().executeCommand(project, initCmd, null, null); } - insertDummyIdentifier(initializationContext[0], hasModifiers, time); + insertDummyIdentifier(initializationContext[0], hasModifiers, invocationCount); } - private CompletionInitializationContext runContributorsBeforeCompletion(Editor editor, PsiFile psiFile) { + private CompletionInitializationContext runContributorsBeforeCompletion(Editor editor, PsiFile psiFile, int invocationCount) { final Ref current = Ref.create(null); - CompletionInitializationContext context = new CompletionInitializationContext(editor, psiFile, myCompletionType) { + CompletionInitializationContext context = new CompletionInitializationContext(editor, psiFile, myCompletionType, invocationCount) { CompletionContributor dummyIdentifierChanger; @Override @@ -759,10 +758,12 @@ public class CodeCompletionHandlerBase { } if (context.getCompletionChar() == Lookup.COMPLETE_STATEMENT_SELECT_CHAR) { final Language language = PsiUtilBase.getLanguageInEditor(editor, project); - final List processors = SmartEnterProcessors.INSTANCE.forKey(language); - if (processors.size() > 0) { - for (SmartEnterProcessor processor : processors) { - processor.process(project, editor, indicator.getParameters().getOriginalFile()); + if (language != null) { + final List processors = SmartEnterProcessors.INSTANCE.forKey(language); + if (processors.size() > 0) { + for (SmartEnterProcessor processor : processors) { + processor.process(project, editor, indicator.getParameters().getOriginalFile()); + } } } } From 9f597478198bb597629a5487a0bcd8b121a28ac4 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 1 Jul 2014 17:58:41 +0200 Subject: [PATCH 53/59] insert no generics if PsiTypeLookupItem insertion found no context (EA-54627) --- .../intellij/codeInsight/lookup/PsiTypeLookupItem.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/lookup/PsiTypeLookupItem.java b/java/java-impl/src/com/intellij/codeInsight/lookup/PsiTypeLookupItem.java index 49befb363437..a6d734b92d8e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/lookup/PsiTypeLookupItem.java +++ b/java/java-impl/src/com/intellij/codeInsight/lookup/PsiTypeLookupItem.java @@ -103,10 +103,11 @@ public class PsiTypeLookupItem extends LookupItem { myImportFixer.handleInsert(context, this); PsiElement position = context.getFile().findElementAt(context.getStartOffset()); - assert position != null; - int genericsStart = context.getTailOffset(); - context.getDocument().insertString(genericsStart, JavaCompletionUtil.escapeXmlIfNeeded(context, calcGenerics(position, context))); - JavaCompletionUtil.shortenReference(context.getFile(), genericsStart - 1); + if (position != null) { + int genericsStart = context.getTailOffset(); + context.getDocument().insertString(genericsStart, JavaCompletionUtil.escapeXmlIfNeeded(context, calcGenerics(position, context))); + JavaCompletionUtil.shortenReference(context.getFile(), genericsStart - 1); + } int tail = context.getTailOffset(); String braces = StringUtil.repeat("[]", getBracketsCount()); From 826d3cf54e6217719e35f7caf547d4a10d28c0ef Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Tue, 1 Jul 2014 18:15:41 +0200 Subject: [PATCH 54/59] remove panel title for the new project settings dialog --- .../com/intellij/openapi/ui/DetailsComponent.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/platform/platform-api/src/com/intellij/openapi/ui/DetailsComponent.java b/platform/platform-api/src/com/intellij/openapi/ui/DetailsComponent.java index 5eb15bd9d3cf..5bbd3d12da6a 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/DetailsComponent.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/DetailsComponent.java @@ -16,6 +16,7 @@ package com.intellij.openapi.ui; +import com.intellij.openapi.util.registry.Registry; import com.intellij.ui.components.panels.NonOpaquePanel; import com.intellij.ui.components.panels.Wrapper; import com.intellij.util.ArrayUtil; @@ -44,13 +45,13 @@ public class DetailsComponent { private final NonOpaquePanel myBanner; private String[] myBannerText; - private boolean myDetailsEnabled = true; + private boolean myDetailsEnabled = !Registry.is("ide.new.project.settings"); private String[] myPrefix; private String[] myText; private final Wrapper myContentGutter = new Wrapper(); - private boolean myPaintBorder = true; + private boolean myPaintBorder = !Registry.is("ide.new.project.settings"); public DetailsComponent() { myComponent = new JPanel(new BorderLayout()) { @@ -109,7 +110,9 @@ public class DetailsComponent { myBanner = new NonOpaquePanel(new BorderLayout()); myBannerLabel = new Banner(); - myBanner.add(myBannerLabel, BorderLayout.CENTER); + if (!Registry.is("ide.new.project.settings")) { + myBanner.add(myBannerLabel, BorderLayout.CENTER); + } myEmptyContentLabel = new JLabel("", SwingConstants.CENTER); @@ -167,7 +170,11 @@ public class DetailsComponent { myContent.setBorder(new EmptyBorder(UIUtil.PANEL_REGULAR_INSETS)); } else { - myContent.setBorder(null); + if (Registry.is("ide.new.project.settings")) { + myContent.setBorder(new EmptyBorder(16, 10, 16, 10)); + } else { + myContent.setBorder(null); + } } } From 4970925f69e95916187b345622b1f3896ae5cae5 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Tue, 1 Jul 2014 20:09:50 +0400 Subject: [PATCH 55/59] increase responsiveness in remote debugging - increased priority for hints and watches calculation --- .../com/intellij/debugger/engine/JavaDebuggerEvaluator.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebuggerEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebuggerEvaluator.java index 4104000a0b27..e37576bae8f4 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebuggerEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebuggerEvaluator.java @@ -20,7 +20,6 @@ import com.intellij.debugger.engine.evaluation.TextWithImportsImpl; import com.intellij.debugger.engine.events.DebuggerContextCommandImpl; import com.intellij.debugger.impl.EditorTextProvider; import com.intellij.debugger.ui.impl.watch.WatchItemDescriptor; -import com.intellij.debugger.ui.tree.render.DescriptorLabelListener; import com.intellij.openapi.editor.Document; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; @@ -60,6 +59,11 @@ public class JavaDebuggerEvaluator extends XDebuggerEvaluator { @NotNull final XEvaluationCallback callback, @Nullable XSourcePosition expressionPosition) { myDebugProcess.getManagerThread().schedule(new DebuggerContextCommandImpl(myDebugProcess.getDebuggerContext()) { + @Override + public Priority getPriority() { + return Priority.NORMAL; + } + @Override public void threadAction() { WatchItemDescriptor descriptor = new WatchItemDescriptor(myDebugProcess.getProject(), TextWithImportsImpl.fromXExpression( From 44356f2c9e1f730aeafebc3a5793ef1c61f6b09b Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Tue, 1 Jul 2014 20:56:12 +0400 Subject: [PATCH 56/59] fixed IOOBE --- .../intellij/debugger/actions/JavaSmartStepIntoHandler.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java index 8904331bfaba..48efa9ac87dc 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java @@ -80,7 +80,8 @@ public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler { //noinspection unchecked final List targets = new OrderedSet(); - final Range lines = new Range(doc.getLineNumber(element.getTextOffset()), doc.getLineNumber(element.getTextOffset() + element.getTextLength())); + TextRange textRange = element.getTextRange(); + final Range lines = new Range(doc.getLineNumber(textRange.getStartOffset()), doc.getLineNumber(textRange.getEndOffset())); final PsiElementVisitor methodCollector = new JavaRecursiveElementVisitor() { final Stack myContextStack = new Stack(); From e7924c8c682bd09ea6625fc36b64b043ee57a613 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Tue, 1 Jul 2014 19:30:35 +0200 Subject: [PATCH 57/59] EA-57784 (behavior restored; diagnostic added) --- .../util/src/com/intellij/util/lang/JarLoader.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/platform/util/src/com/intellij/util/lang/JarLoader.java b/platform/util/src/com/intellij/util/lang/JarLoader.java index a088275a7913..15556a8d0a52 100644 --- a/platform/util/src/com/intellij/util/lang/JarLoader.java +++ b/platform/util/src/com/intellij/util/lang/JarLoader.java @@ -58,8 +58,17 @@ class JarLoader extends Loader { } void preloadClasses() { + ZipFile zipFile; + + try { + zipFile = acquireZipFile(); + } + catch (Exception e) { + LOG.debug("url: " + myURL, e); + return; + } + try { - ZipFile zipFile = acquireZipFile(); try { JarMemoryLoader loader = JarMemoryLoader.load(zipFile, getBaseURL()); if (loader != null) { From 8911feabc5c85cd2568eed51a9d002a21753a7b5 Mon Sep 17 00:00:00 2001 From: Yaroslav Lepenkin Date: Wed, 2 Jul 2014 00:07:00 +0400 Subject: [PATCH 58/59] IDEA-126753 Parameters names hints not shown for negative numbers --- .../folding/impl/JavaFoldingBuilderBase.java | 19 +++++++++++++-- .../folding/JavaFoldingTest.groovy | 23 +++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java b/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java index e165ba718467..b88cc90e4b74 100644 --- a/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java +++ b/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java @@ -48,6 +48,7 @@ import com.intellij.psi.util.PsiUtilCore; import com.intellij.util.Function; import com.intellij.util.ObjectUtils; import com.intellij.util.text.CharArrayUtil; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -703,7 +704,7 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem else if (element instanceof PsiComment) { return settings.isCollapseEndOfLineComments(); } - else if (element instanceof PsiLiteralExpression + else if (isLiteralExpression(element) && element.getParent() instanceof PsiExpressionList && (element.getParent().getParent() instanceof PsiCallExpression || element.getParent().getParent() instanceof PsiAnonymousClass)) { @@ -775,7 +776,7 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem for (int i = 0; i < callArguments.length; i++) { PsiExpression callArgument = callArguments[i]; - if (callArgument instanceof PsiLiteralExpression) { + if (isLiteralExpression(callArgument)) { if (!isResolved) { PsiMethod method = expression.resolveMethod(); isResolved = true; @@ -799,6 +800,20 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem } } + @Contract("null -> false") + private static boolean isLiteralExpression(@Nullable PsiElement callArgument) { + if (callArgument instanceof PsiLiteralExpression) + return true; + + if (callArgument instanceof PsiPrefixExpression) { + PsiPrefixExpression expr = (PsiPrefixExpression)callArgument; + IElementType tokenType = expr.getOperationTokenType(); + return JavaTokenType.MINUS.equals(tokenType) && expr.getOperand() instanceof PsiLiteralExpression; + } + + return false; + } + private boolean addClosureFolding(final PsiClass aClass, final Document document, final List foldElements, @NotNull Set processedComments, final boolean quick) { if (!JavaCodeFoldingSettings.getInstance().isCollapseLambdas()) { diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy index c68fb5a7cc43..78629192782f 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy @@ -698,6 +698,29 @@ public class CharSymbol { assert regions[2].placeholderText == "fast: false" } + public void "test inline negative numbers (IDEA-126753)"() { + def text = """ +public class CharSymbol { + + public void main() { + Object obj = new Object(); + count(-1, obj); + } + + public void count(int test, Object obj) { + Object tmp = obj; + boolean isFast = false; + } +} +""" + configure text + def regions = myFixture.editor.foldingModel.allFoldRegions.sort { it.startOffset } + assert regions.size() == 3 + + checkRangeOffsetByPositionInText(regions[1], text, "-1") + assert regions[1].placeholderText == "test: -1" + } + public void "test inline constructor literal arguments names"() { def text = """ public class Test { From 44cc819cbe4722582593a6b3047074323beb66f2 Mon Sep 17 00:00:00 2001 From: Yaroslav Lepenkin Date: Wed, 2 Jul 2014 02:29:57 +0400 Subject: [PATCH 59/59] JavaRearranger: register field initialization dependencies only if otherwise fields will be placed in not valid order (IDEA-125099, IDEA-123875) --- .../arrangement/JavaArrangementParseInfo.java | 5 ++ .../codeStyle/arrangement/JavaRearranger.java | 26 +++++++-- .../JavaRearrangerFieldReferenceTest.groovy | 56 ++++++++++++++++++- 3 files changed, 79 insertions(+), 8 deletions(-) diff --git a/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaArrangementParseInfo.java b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaArrangementParseInfo.java index 9664bc223f8f..f042bb316c40 100644 --- a/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaArrangementParseInfo.java +++ b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaArrangementParseInfo.java @@ -229,4 +229,9 @@ public class JavaArrangementParseInfo { public List getFieldDependencyRoots() { return new FieldDependenciesManager(myFieldDependencies, myFields).getRoots(); } + + @NotNull + public Collection getFields() { + return myFields.values(); + } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaRearranger.java b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaRearranger.java index 6ec40043433e..9e23eadc3073 100644 --- a/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaRearranger.java +++ b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaRearranger.java @@ -27,6 +27,7 @@ import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; +import com.intellij.psi.codeStyle.arrangement.engine.ArrangementEngine; import com.intellij.psi.codeStyle.arrangement.group.ArrangementGroupingRule; import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryMatcher; import com.intellij.psi.codeStyle.arrangement.match.StdArrangementEntryMatcher; @@ -34,8 +35,6 @@ import com.intellij.psi.codeStyle.arrangement.match.StdArrangementMatchRule; import com.intellij.psi.codeStyle.arrangement.model.ArrangementAtomMatchCondition; import com.intellij.psi.codeStyle.arrangement.model.ArrangementCompositeMatchCondition; import com.intellij.psi.codeStyle.arrangement.model.ArrangementMatchCondition; -import com.intellij.psi.codeStyle.arrangement.std.ArrangementColorsAware; -import com.intellij.psi.codeStyle.arrangement.std.ArrangementStandardSettingsAware; import com.intellij.psi.codeStyle.arrangement.std.*; import com.intellij.util.containers.ContainerUtilRt; import org.jetbrains.annotations.NotNull; @@ -46,10 +45,10 @@ import java.util.*; import java.util.List; import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.EntryType.*; +import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.General.*; import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.Grouping.*; import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.Modifier.*; import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.Order.*; -import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.General.*; /** * @author Denis Zhdanov @@ -250,19 +249,34 @@ public class JavaRearranger implements Rearranger, setupOverriddenMethods(parseInfo); } } - setupFieldInitializationDependencies(parseInfo.getFieldDependencyRoots()); + List fieldDependencyRoots = parseInfo.getFieldDependencyRoots(); + if (!fieldDependencyRoots.isEmpty()) { + setupFieldInitializationDependencies(fieldDependencyRoots, settings, parseInfo); + } return parseInfo.getEntries(); } - public void setupFieldInitializationDependencies(@NotNull List fieldDependencyRoots) { + public void setupFieldInitializationDependencies(@NotNull List fieldDependencyRoots, + @NotNull ArrangementSettings settings, + @NotNull JavaArrangementParseInfo parseInfo) + { + Collection fields = parseInfo.getFields(); + List arrangedFields = ArrangementEngine.arrange(fields, settings.getSections(), settings.getRulesSortedByPriority(), null); + for (ArrangementEntryDependencyInfo root : fieldDependencyRoots) { JavaElementArrangementEntry anchorField = root.getAnchorEntry(); + final int anchorEntryIndex = arrangedFields.indexOf(anchorField); + for (ArrangementEntryDependencyInfo fieldInInitializerInfo : root.getDependentEntriesInfos()) { - anchorField.addDependency(fieldInInitializerInfo.getAnchorEntry()); + JavaElementArrangementEntry fieldInInitializer = fieldInInitializerInfo.getAnchorEntry(); + if (arrangedFields.indexOf(fieldInInitializer) > anchorEntryIndex) { + anchorField.addDependency(fieldInInitializer); + } } } } + @Override public int getBlankLines(@NotNull CodeStyleSettings settings, @Nullable JavaElementArrangementEntry parent, diff --git a/java/java-tests/testSrc/com/intellij/psi/codeStyle/arrangement/JavaRearrangerFieldReferenceTest.groovy b/java/java-tests/testSrc/com/intellij/psi/codeStyle/arrangement/JavaRearrangerFieldReferenceTest.groovy index 302f1b331530..d11a34f6e376 100644 --- a/java/java-tests/testSrc/com/intellij/psi/codeStyle/arrangement/JavaRearrangerFieldReferenceTest.groovy +++ b/java/java-tests/testSrc/com/intellij/psi/codeStyle/arrangement/JavaRearrangerFieldReferenceTest.groovy @@ -328,9 +328,61 @@ class Second extends First { ) } + void "test IDEA-123875"() { + doTest( + initial: '''\ +public class RearrangeFail { + public static final byte[] ENTITIES_END = "".getBytes(); + private final Element entitiesEndElement = new Element(ENTITIES_END); - - + public static final byte[] ENTITIES_START = "".getBytes(); + private final Element entitiesStartElement = new Element(ENTITIES_START); } +''', + expected: '''\ +public class RearrangeFail { + + public static final byte[] ENTITIES_END = "".getBytes(); + public static final byte[] ENTITIES_START = "".getBytes(); + private final Element entitiesEndElement = new Element(ENTITIES_END); + private final Element entitiesStartElement = new Element(ENTITIES_START); + +} +''', + rules: [ + rule(PUBLIC, STATIC, FINAL), + rule(PRIVATE), + ] + ) + } + + void "test IDEA-125099"() { + doTest( + initial: '''\ +public class test { + + private int a = 2; + + public static final String TEST = "1"; + public static final String SHOULD_BE_IN_BETWEEN = "2"; + public static final String USERS_ROLE_ID_COLUMN = TEST; +} +''', + expected: '''\ +public class test { + + public static final String TEST = "1"; + public static final String SHOULD_BE_IN_BETWEEN = "2"; + public static final String USERS_ROLE_ID_COLUMN = TEST; + private int a = 2; +} +''', + rules: [ + rule(PUBLIC, STATIC, FINAL), + rule(PRIVATE) + ] + ) + } +}