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
This commit is contained in:
Dmitry Batkovich
2014-07-01 12:03:29 +04:00
parent 0c7bece7c9
commit 29487068f7
46 changed files with 1286 additions and 636 deletions
@@ -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;
}
@@ -144,7 +144,7 @@ public class InconsistentResourceBundleInspection extends GlobalSimpleInspection
ResourceBundle resourceBundle = propertiesFile.getResourceBundle();
assert visitedBundles != null;
if (!visitedBundles.add(resourceBundle)) return;
List<PropertiesFile> files = resourceBundle.getPropertiesFiles(manager.getProject());
List<PropertiesFile> files = resourceBundle.getPropertiesFiles();
if (files.size() < 2) return;
BidirectionalMap<PropertiesFile, PropertiesFile> parents = new BidirectionalMap<PropertiesFile, PropertiesFile>();
for (PropertiesFile f : files) {
@@ -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
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
@@ -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<PropertiesFile> getPropertiesFiles(final Project project) {
@Override
public List<PropertiesFile> getPropertiesFiles() {
return Collections.emptyList();
}
@NotNull
public PropertiesFile getDefaultPropertiesFile(final Project project) {
@Override
public List<PropertiesFile> 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() {
@@ -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<PropertiesFile> 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<PropertiesFile> 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<String>() {
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<IProperty> findAllProperties(Project project, @NotNull ResourceBundle resourceBundle, String key) {
List<IProperty> result = new SmartList<IProperty>();
List<PropertiesFile> propertiesFiles = resourceBundle.getPropertiesFiles(project);
List<PropertiesFile> propertiesFiles = resourceBundle.getPropertiesFiles();
for (PropertiesFile propertiesFile : propertiesFiles) {
result.addAll(propertiesFile.findPropertiesByKey(key));
}
@@ -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<ResourceBundle[]> ARRAY_DATA_KEY = DataKey.create("resource.bundle.array");
@NotNull
public abstract List<PropertiesFile> getPropertiesFiles();
/**
* @deprecated, use getPropertiesFiles() instead this method
*/
@Deprecated
@NotNull
public abstract List<PropertiesFile> 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();
}
@@ -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;
@@ -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<PsiDirectory>() {
final String baseName = getBaseName(containingFile);
final PsiDirectory directory = ApplicationManager.getApplication().runReadAction(new Computable<PsiDirectory>() {
@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<IProperty> 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);
}
}
@@ -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<PropertiesFile> getPropertiesFiles(final Project project) {
VirtualFile[] children = myBaseDirectory.getChildren();
@Override
public List<PropertiesFile> getPropertiesFiles() {
PsiFile[] children = myDefaultPropertiesFile.getParent().getFiles();
final String baseName = getBaseName();
List<PropertiesFile> result = new SmartList<PropertiesFile>();
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<PropertiesFile> files = getPropertiesFiles(project);
// put default properties file first
ContainerUtil.quickSort(files, new Comparator<PropertiesFile>() {
public int compare(final PropertiesFile o1, final PropertiesFile o2) {
return Comparing.compare(o1.getName(), o2.getName());
}
});
return files.get(0);
@Override
public List<PropertiesFile> 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;
}
}
@@ -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
@@ -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);
}
@@ -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<PropertiesFile> propertiesFiles = myResourceBundle.getPropertiesFiles(myProject);
List<PropertiesFile> propertiesFiles = myResourceBundle.getPropertiesFiles();
Map<String, IProperty> propertyNames = new LinkedHashMap<String, IProperty>();
for (PropertiesFile propertiesFile : propertiesFiles) {
List<IProperty> properties = propertiesFile.getProperties();
for (IProperty property : properties) {
String name = property.getUnescapedKey();
String name = property.getKey();
if (!propertyNames.containsKey(name)) {
propertyNames.put(name, property);
}
}
}
List<StructureViewTreeElement> result = new ArrayList<StructureViewTreeElement>(propertyNames.size());
for (String property : propertyNames.keySet()) {
//result.add(new PropertiesStructureViewElement(property));
result.add(new ResourceBundlePropertyStructureViewElement(myProject, myResourceBundle, property));
for (Map.Entry<String, IProperty> 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<PropertiesFile> propertiesFiles = getValue().getPropertiesFiles();
return ContainerUtil.map2Array(propertiesFiles, new PsiElement[propertiesFiles.size()], new Function<PropertiesFile, PsiElement>() {
@Override
public PsiElement fun(PropertiesFile propertiesFile) {
return propertiesFile.getContainingFile();
}
});
}
public void navigate(boolean requestFocus) {
}
@@ -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;
}
}
@@ -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
@@ -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) {
@@ -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
@@ -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.
@@ -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<PropertiesFileImpl> {
public class PropertiesFileStructureViewElement extends PsiTreeElementBase<PropertiesFileImpl> implements ResourceBundleEditorViewElement {
protected PropertiesFileStructureViewElement(PropertiesFileImpl propertiesFile) {
super(propertiesFile);
@@ -48,6 +51,11 @@ public class PropertiesFileStructureViewElement extends PsiTreeElementBase<Prope
return elements;
}
@Override
public PsiElement[] getPsiElements(@NotNull Project project) {
return new PsiElement[] {getValue()};
}
public String getPresentableText() {
return getElement().getName();
}
@@ -37,7 +37,7 @@ import java.util.Comparator;
*/
public class PropertiesFileStructureViewModel extends TextEditorBasedStructureViewModel implements PropertiesGroupingStructureViewModel {
private final PropertiesFileImpl myPropertiesFile;
private final GroupByWordPrefixes myGroupByWordPrefixes;
private final GroupByWordPrefixes myByWordPrefixesGrouper;
@NonNls public static final String KIND_SORTER_ID = "KIND_SORTER";
private static final Sorter KIND_SORTER = new Sorter() {
@NotNull
@@ -70,17 +70,17 @@ public class PropertiesFileStructureViewModel extends TextEditorBasedStructureVi
public PropertiesFileStructureViewModel(final PropertiesFileImpl root) {
super(root);
myPropertiesFile = root;
String separator = PropertiesSeparatorManager.getInstance().getSeparator(root.getProject(), root.getVirtualFile());
myGroupByWordPrefixes = new GroupByWordPrefixes(separator);
String separator = PropertiesSeparatorManager.getInstance(root.getProject()).getSeparator(root.getResourceBundle());
myByWordPrefixesGrouper = new GroupByWordPrefixes(separator);
}
public void setSeparator(String separator) {
myGroupByWordPrefixes.setSeparator(separator);
PropertiesSeparatorManager.getInstance().setSeparator(myPropertiesFile.getVirtualFile(), separator);
myByWordPrefixesGrouper.setSeparator(separator);
PropertiesSeparatorManager.getInstance(myPropertiesFile.getProject()).setSeparator(myPropertiesFile.getResourceBundle(), separator);
}
public String getSeparator() {
return myGroupByWordPrefixes.getSeparator();
return myByWordPrefixesGrouper.getSeparator();
}
@NotNull
@@ -90,7 +90,7 @@ public class PropertiesFileStructureViewModel extends TextEditorBasedStructureVi
@NotNull
public Grouper[] getGroupers() {
return new Grouper[]{myGroupByWordPrefixes};
return new Grouper[]{myByWordPrefixesGrouper};
}
@NotNull
@@ -19,11 +19,18 @@ import com.intellij.icons.AllIcons;
import com.intellij.ide.util.treeView.smartTree.Group;
import com.intellij.ide.util.treeView.smartTree.TreeElement;
import com.intellij.lang.properties.IProperty;
import com.intellij.lang.properties.editor.ResourceBundleEditorViewElement;
import com.intellij.lang.properties.editor.ResourceBundlePropertyStructureViewElement;
import com.intellij.navigation.ItemPresentation;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.util.Function;
import com.intellij.util.NullableFunction;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.ArrayList;
@@ -33,19 +40,36 @@ import java.util.List;
/**
* @author cdr
*/
public class PropertiesPrefixGroup implements Group {
public class PropertiesPrefixGroup implements Group, ResourceBundleEditorViewElement {
private final Collection<TreeElement> myProperties;
private final @NotNull String myPrefix;
private final String myPresentableName;
private final @NotNull String mySeparator;
public PropertiesPrefixGroup(final Collection<TreeElement> properties, String prefix, String presentableName, final String separator) {
public PropertiesPrefixGroup(final Collection<TreeElement> 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<PsiElement> elements = ContainerUtil.mapNotNull(getChildren(), new NullableFunction<TreeElement, PsiElement>() {
@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) {
@@ -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<Element> {
@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<VirtualFile, String> mySeparators = new THashMap<VirtualFile, String>();
private final Map<String, String> mySeparators = new THashMap<String, String>();
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<PropertiesFile> 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<PropertiesFile>();
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<IProperty> properties = propertiesFile.getProperties();
for (IProperty property : properties) {
@@ -119,8 +106,10 @@ public class PropertiesSeparatorManager implements PersistentStateComponent<Elem
return Character.toString(mostProbableChar[0]);
}
public void setSeparator(VirtualFile file, String separator) {
mySeparators.put(file, separator);
public void setSeparator(ResourceBundle resourceBundle, String separator) {
if (resourceBundle instanceof ResourceBundleImpl) {
mySeparators.put(((ResourceBundleImpl)resourceBundle).getUrl(), separator);
}
}
public void loadState(final Element element) {
@@ -132,16 +121,9 @@ public class PropertiesSeparatorManager implements PersistentStateComponent<Elem
if (separator == null) {
continue;
}
VirtualFile file;
ResourceBundle resourceBundle = ResourceBundleImpl.createByUrl(url);
ResourceBundle resourceBundle = PropertiesImplUtil.createByUrl(url, myProject);
if (resourceBundle != null) {
file = new ResourceBundleAsVirtualFile(resourceBundle);
}
else {
file = VirtualFileManager.getInstance().findFileByUrl(url);
}
if (file != null) {
mySeparators.put(file, separator);
mySeparators.put(url, separator);
}
}
}
@@ -178,16 +160,8 @@ public class PropertiesSeparatorManager implements PersistentStateComponent<Elem
public Element getState() {
Element element = new Element("PropertiesSeparatorManager");
for (VirtualFile file : mySeparators.keySet()) {
String url;
if (file instanceof ResourceBundleAsVirtualFile) {
ResourceBundle resourceBundle = ((ResourceBundleAsVirtualFile)file).getResourceBundle();
url = ((ResourceBundleImpl)resourceBundle).getUrl();
}
else {
url = file.getUrl();
}
String separator = mySeparators.get(file);
for (final String url: mySeparators.keySet()) {
String separator = mySeparators.get(url);
StringBuilder encoded = new StringBuilder(separator.length());
for (int i=0;i<separator.length();i++) {
char c = separator.charAt(i);
@@ -16,8 +16,11 @@
package com.intellij.lang.properties.structureView;
import com.intellij.ide.structureView.StructureViewTreeElement;
import com.intellij.lang.properties.editor.ResourceBundleEditorViewElement;
import com.intellij.lang.properties.psi.Property;
import com.intellij.navigation.ItemPresentation;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
@@ -25,7 +28,7 @@ import javax.swing.*;
/**
* @author max
*/
public class PropertiesStructureViewElement implements StructureViewTreeElement {
public class PropertiesStructureViewElement implements StructureViewTreeElement, ResourceBundleEditorViewElement {
private final Property myProperty;
private String myPresentableName;
@@ -54,6 +57,11 @@ public class PropertiesStructureViewElement implements StructureViewTreeElement
return EMPTY_ARRAY;
}
@Override
public PsiElement[] getPsiElements(@NotNull Project project) {
return new PsiElement[] {getValue()};
}
@NotNull
public ItemPresentation getPresentation() {
return new ItemPresentation() {
@@ -101,7 +101,7 @@ public class XmlPropertiesFileImpl extends XmlPropertiesFile {
@NotNull
@Override
public ResourceBundle getResourceBundle() {
return PropertiesImplUtil.getResourceBundle(getContainingFile());
return PropertiesImplUtil.getResourceBundle(this);
}
@NotNull
@@ -63,7 +63,6 @@ public class PropertiesCoreEnvironment {
appEnvironment.registerApplicationService(PropertiesQuickFixFactory.class, new EmptyPropertiesQuickFixFactory());
appEnvironment.registerApplicationService(PropertiesRefactoringSettings.class, new PropertiesRefactoringSettings());
appEnvironment.registerApplicationService(PropertiesSeparatorManager.class, new PropertiesSeparatorManager());
appEnvironment.addExplicitExtension(LanguageAnnotators.INSTANCE, PropertiesLanguage.INSTANCE, new PropertiesAnnotator());
appEnvironment.addExplicitExtension(LanguageFindUsages.INSTANCE, PropertiesLanguage.INSTANCE, new PropertiesFindUsagesProvider());
@@ -87,6 +86,7 @@ public class PropertiesCoreEnvironment {
public static class ProjectEnvironment {
public ProjectEnvironment(CoreProjectEnvironment projectEnvironment) {
projectEnvironment.getProject().registerService(PropertiesReferenceManager.class);
projectEnvironment.getProject().registerService(PropertiesSeparatorManager.class);
}
}
}
+5 -5
View File
@@ -32,7 +32,7 @@
implementationClass="com.intellij.lang.properties.PropertyValueManipulator"/>
<lang.elementManipulator forClass="com.intellij.lang.properties.psi.impl.PropertyImpl"
implementationClass="com.intellij.lang.properties.PropertyManipulator"/>
<applicationService serviceInterface="com.intellij.lang.properties.structureView.PropertiesSeparatorManager"
<projectService serviceInterface="com.intellij.lang.properties.structureView.PropertiesSeparatorManager"
serviceImplementation="com.intellij.lang.properties.structureView.PropertiesSeparatorManager"/>
<codeInsight.wordCompletionFilter language="Properties"
implementationClass="com.intellij.lang.properties.PropertiesWordCompletionFilter"/>
@@ -44,11 +44,11 @@
<enterHandlerDelegate implementation="com.intellij.codeInsight.editorActions.enter.EnterInPropertiesFileHandler"/>
<lang.parserDefinition language="Properties" implementationClass="com.intellij.lang.properties.parsing.PropertiesParserDefinition"/>
<renameHandler implementation="com.intellij.lang.properties.refactoring.ResourceBundleRenameHandler"/>
<renameHandler implementation="com.intellij.lang.properties.refactoring.ResourceBundleKeyRenameHandler"/>
<renameHandler implementation="com.intellij.lang.properties.refactoring.PropertyRenameHandler"/>
<renameHandler implementation="com.intellij.lang.properties.refactoring.rename.ResourceBundleFromEditorRenameHandler"/>
<renameHandler implementation="com.intellij.lang.properties.refactoring.rename.ResourceBundleFromProjectViewRenameHandler"/>
<automaticRenamerFactory implementation="com.intellij.lang.properties.refactoring.rename.ResourceBundleRenamerFactory"/>
<renamePsiElementProcessor implementation="com.intellij.lang.properties.refactoring.rename.RenamePropertyProcessor"/>
<stubElementTypeHolder class="com.intellij.lang.properties.parsing.PropertiesElementTypes"/>
<renamePsiElementProcessor implementation="com.intellij.lang.properties.refactoring.RenamePropertyProcessor"/>
<lang.commenter language="Properties" implementationClass="com.intellij.lang.properties.PropertiesCommenter"/>
<stubIndex implementation="com.intellij.lang.properties.psi.PropertyKeyIndex"/>
<lang.namesValidator language="Properties" implementationClass="com.intellij.lang.properties.PropertiesNamesValidator"/>
@@ -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<PropertiesFile> propertiesFiles = bundle.getPropertiesFiles(myProject);
final List<PropertiesFile> 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<PropertiesFile> propertiesFiles = resourceBundle.getPropertiesFiles(myProject);
List<PropertiesFile> 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)};
}
}
@@ -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;
}
}
}
@@ -32,6 +32,7 @@ import java.util.Set;
* @author cdr
*/
public class PropertiesGroupingStructureViewComponent extends StructureViewComponent {
protected PropertiesGroupingStructureViewComponent(Project project,
FileEditor editor,
PropertiesGroupingStructureViewModel structureViewModel) {
@@ -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<PropertiesFile, Editor> myEditors;
private String myOldPropertyName;
private final ResourceBundle myResourceBundle;
private final Map<PropertiesFile, JPanel> 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<PropertiesFile> propertiesFiles = myResourceBundle.getPropertiesFiles(myProject);
List<PropertiesFile> 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<PropertiesFile, Editor> 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.
* <p/>
* <b>Note:</b> 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;
@@ -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
@@ -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<String> names = new ArrayList<String>(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<PropertiesFile> bundlePropertiesFiles = myResourceBundle.getPropertiesFiles();
final List<PsiElement> toDelete = new ArrayList<PsiElement>();
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;
}
}
}
@@ -48,7 +48,7 @@ class ResourceBundleDeleteProvider implements DeleteProvider {
public void deleteElement(@NotNull DataContext dataContext) {
final Project project = CommonDataKeys.PROJECT.getData(dataContext);
List<PropertiesFile> propertiesFiles = myResourceBundle.getPropertiesFiles(project);
List<PropertiesFile> propertiesFiles = myResourceBundle.getPropertiesFiles();
assert project != null;
new SafeDeleteHandler().invoke(project, ContainerUtil.map2Array(propertiesFiles, PsiElement.class, MAPPER), dataContext);
}
@@ -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<PropertiesFile> propertiesFiles = bundle.getPropertiesFiles(CommonDataKeys.PROJECT.getData(dataContext));
List<PropertiesFile> propertiesFiles = bundle.getPropertiesFiles();
for (PropertiesFile propertiesFile : propertiesFiles) {
filesOrDirs.add(propertiesFile.getContainingFile());
}
@@ -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<ResourceBundle>{
@NotNull
public Collection<AbstractTreeNode> getChildren() {
List<PropertiesFile> propertiesFiles = getValue().getPropertiesFiles(myProject);
List<PropertiesFile> propertiesFiles = getValue().getPropertiesFiles();
Collection<AbstractTreeNode> children = new ArrayList<AbstractTreeNode>();
for (PropertiesFile propertiesFile : propertiesFiles) {
AbstractTreeNode node = new PsiFileNode(myProject, propertiesFile.getContainingFile(), getSettings());
@@ -63,11 +61,11 @@ public class ResourceBundleNode extends ProjectViewNode<ResourceBundle>{
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<PropertiesFile> list = getValue().getPropertiesFiles(myProject);
final List<PropertiesFile> list = getValue().getPropertiesFiles();
if (!list.isEmpty()) {
return list.get(0).getVirtualFile();
}
@@ -88,7 +86,7 @@ public class ResourceBundleNode extends ProjectViewNode<ResourceBundle>{
}
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);
}
@@ -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);
}
}
@@ -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<String> myExistingProperties = new HashSet<String>();
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;
}
}
}
@@ -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<PropertiesFile> 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;
}
}
}
@@ -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<PsiElement, String> allRenames) {
IProperty property = (IProperty) element;
ResourceBundle resourceBundle = property.getPropertiesFile().getResourceBundle();
List<IProperty> properties = PropertiesUtil.findAllProperties(element.getProject(), resourceBundle, property.getUnescapedKey());
final Project project = element.getProject();
ResourceBundle resourceBundle = ((IProperty) element).getPropertiesFile().getResourceBundle();
final Map<PsiElement, String> allRenamesCopy = new LinkedHashMap<PsiElement, String>(allRenames);
allRenames.clear();
for (IProperty otherProperty : properties) {
allRenames.put(otherProperty.getPsiElement(), newName);
for (final Map.Entry<PsiElement, String> e : allRenamesCopy.entrySet()) {
final IProperty property = (IProperty) e.getKey();
final List<IProperty> 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<? extends PsiElement, String> allRenames,
List<UsageInfo> 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<? extends PsiElement, String> 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";
}
});
}
}
}
}
@@ -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<PsiElement> getPsiElementsFromGroup(final PropertiesPrefixGroup propertiesPrefixGroup) {
return ContainerUtil.mapNotNull(propertiesPrefixGroup.getChildren(), new NullableFunction<TreeElement, PsiElement>() {
@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;
}
});
}
}
@@ -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);
}
}
@@ -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<PsiElement> 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<PsiElement> myPsiElements;
private final String mySection;
private final int mySectionPosition;
private final Project myProject;
private ResourceBundleKeySectionInputValidator(final List<PsiElement> 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<PropertiesFile> 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;
}
}
}
@@ -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");
}
}
@@ -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<UsageInfo> usages) {
final PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile((PsiFile)element);
assert propertiesFile != null;
return new ResourceBundleRenamer(propertiesFile, newName);
}
}
@@ -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<PropertiesFile> propertiesFiles;
if (isUseResourceBundle()) {
propertiesFiles = propertiesFile.getResourceBundle().getPropertiesFiles(myProject);
propertiesFiles = propertiesFile.getResourceBundle().getPropertiesFiles();
}
else {
propertiesFiles = Collections.singleton(propertiesFile);
@@ -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);
}
}
@@ -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", "ke<caret>y=en_value");
myFixture.renameElementAtCaret("new_key");
assertEquals(toCheckFile.getText(), "new_key=value");
}
}