diff options
Diffstat (limited to 'plugins/properties')
31 files changed, 1092 insertions, 135 deletions
diff --git a/plugins/properties/properties-psi-api/resources/messages/PropertiesBundle.properties b/plugins/properties/properties-psi-api/resources/messages/PropertiesBundle.properties index 61b69161c5e3..f8439f059b7e 100644 --- a/plugins/properties/properties-psi-api/resources/messages/PropertiesBundle.properties +++ b/plugins/properties/properties-psi-api/resources/messages/PropertiesBundle.properties @@ -52,5 +52,8 @@ resource.bundle.renamer.dialog.description=Rename resource bundle properties fil resource.bundle.renamer.entity.name=Resource bundle resource.bundle.renamer.option=Rename bound &resource bundle +combine.properties.files.prompt.text=Combine properties files to resource bundle with bundle base name +combine.properties.files.title=Combine to Resource Bundle + inline.property.refactoring=Inline Property inline.property.confirmation=Inline property ''{0}'' with value ''{1}''? diff --git a/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/PropertiesUtil.java b/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/PropertiesUtil.java index bb9b9449166f..0867b6b5faa1 100644 --- a/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/PropertiesUtil.java +++ b/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/PropertiesUtil.java @@ -16,16 +16,14 @@ package com.intellij.lang.properties; import com.intellij.lang.properties.psi.PropertiesFile; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectRootManager; -import com.intellij.openapi.util.NullableComputable; 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 com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -38,8 +36,8 @@ import java.util.regex.Pattern; * @author cdr */ public class PropertiesUtil { - private final static Pattern LOCALE_PATTERN = Pattern.compile("(_[a-zA-Z]{2,8}(_[a-zA-Z]{2}|[0-9]{3})?(_[\\w\\-]+)?)\\.[^_]+$"); - private final static Locale DEFAULT_LOCALE = new Locale("", "", ""); + public final static Pattern LOCALE_PATTERN = Pattern.compile("(_[a-zA-Z]{2,8}(_[a-zA-Z]{2}|[0-9]{3})?(_[\\w\\-]+)?)\\.[^_]+$"); + public static final Set<Character> BASE_NAME_BORDER_CHAR = ContainerUtil.newHashSet('-', '_', '.'); /** @@ -59,12 +57,28 @@ public class PropertiesUtil { } @NotNull - public static String getBaseName(@NotNull PsiFile file) { - return getBaseName(file.getContainingFile().getVirtualFile()); + public static String getDefaultBaseName(final Collection<PropertiesFile> files) { + String commonPrefix = null; + for (PropertiesFile file : files) { + final String baseName = file.getVirtualFile().getNameWithoutExtension(); + if (commonPrefix == null) { + commonPrefix = baseName; + } else { + commonPrefix = StringUtil.commonPrefix(commonPrefix, baseName); + if (commonPrefix.isEmpty()) { + break; + } + } + } + assert commonPrefix != null; + if (!commonPrefix.isEmpty() && BASE_NAME_BORDER_CHAR.contains(commonPrefix.charAt(commonPrefix.length() - 1))) { + commonPrefix = commonPrefix.substring(0, commonPrefix.length() - 1); + } + return commonPrefix; } @NotNull - public static String getBaseName(@NotNull VirtualFile file) { + public static String getDefaultBaseName(@NotNull final VirtualFile file) { final String name = file.getName(); final Matcher matcher = LOCALE_PATTERN.matcher(name); final String baseNameWithExtension; @@ -105,44 +119,21 @@ public class PropertiesUtil { return null; } - @Nullable - public static String getFullName(final PropertiesFile propertiesFile) { - return ApplicationManager.getApplication().runReadAction(new NullableComputable<String>() { - public String compute() { - PsiDirectory directory = propertiesFile.getParent(); - String packageQualifiedName = getPackageQualifiedName(directory); - if (packageQualifiedName == null) { - return null; - } - StringBuilder qName = new StringBuilder(packageQualifiedName); - if (qName.length() > 0) { - qName.append("."); - } - qName.append(getBaseName(propertiesFile.getContainingFile())); - return qName.toString(); - } - }); - } - + /** + * @deprecated use PropertiesUtil.findAllProperties(ResourceBundle resourceBundle, String key) + */ @NotNull - public static Locale getLocale(final VirtualFile propertiesFile) { - String name = propertiesFile.getName(); - final Matcher matcher = LOCALE_PATTERN.matcher(name); - if (matcher.find()) { - String rawLocale = matcher.group(1); - String[] splittedRawLocale = rawLocale.split("_"); - if (splittedRawLocale.length > 1 && splittedRawLocale[1].length() == 2) { - final String language = splittedRawLocale[1]; - final String country = splittedRawLocale.length > 2 ? splittedRawLocale[2] : ""; - final String variant = splittedRawLocale.length > 3 ? splittedRawLocale[3] : ""; - return new Locale(language, country, variant); - } + @Deprecated + public static List<IProperty> findAllProperties(Project project, @NotNull ResourceBundle resourceBundle, String key) { + List<IProperty> result = new SmartList<IProperty>(); + List<PropertiesFile> propertiesFiles = resourceBundle.getPropertiesFiles(); + for (PropertiesFile propertiesFile : propertiesFiles) { + result.addAll(propertiesFile.findPropertiesByKey(key)); } - return DEFAULT_LOCALE; + return result; } - @NotNull - public static List<IProperty> findAllProperties(Project project, @NotNull ResourceBundle resourceBundle, String key) { + public static List<IProperty> findAllProperties(@NotNull ResourceBundle resourceBundle, String key) { List<IProperty> result = new SmartList<IProperty>(); List<PropertiesFile> propertiesFiles = resourceBundle.getPropertiesFiles(); for (PropertiesFile propertiesFile : propertiesFiles) { diff --git a/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/ResourceBundle.java b/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/ResourceBundle.java index 7ea56269949d..b53cdae358f0 100644 --- a/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/ResourceBundle.java +++ b/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/ResourceBundle.java @@ -26,8 +26,8 @@ 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 org.jetbrains.annotations.Nullable; import java.util.List; @@ -38,26 +38,34 @@ public abstract class ResourceBundle { public abstract List<PropertiesFile> getPropertiesFiles(); /** - * @deprecated, use getPropertiesFiles() instead this method + * @deprecated use getPropertiesFiles() instead this method */ @Deprecated @NotNull - public abstract List<PropertiesFile> getPropertiesFiles(final Project project); + public List<PropertiesFile> getPropertiesFiles(final Project project) { + return getPropertiesFiles(); + } @NotNull public abstract PropertiesFile getDefaultPropertiesFile(); /** - * @deprecated, use getDefaultPropertiesFile() instead this method + * @deprecated use getDefaultPropertiesFile() instead this method */ @Deprecated @NotNull - public abstract PropertiesFile getDefaultPropertiesFile(final Project project); + public PropertiesFile getDefaultPropertiesFile(final Project project) { + return getDefaultPropertiesFile(); + } @NotNull public abstract String getBaseName(); - @NotNull + /** + * @return null if resource bundle is not default ( == instance of ResourceBundleImpl) + */ + @Deprecated + @Nullable public abstract VirtualFile getBaseDirectory(); @NotNull diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/BundleNameEvaluator.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/BundleNameEvaluator.java index ebe28b38b37e..52b57238d138 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/BundleNameEvaluator.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/BundleNameEvaluator.java @@ -37,7 +37,7 @@ public interface BundleNameEvaluator { if (qName.length() > 0) { qName.append("."); } - qName.append(PropertiesUtil.getBaseName(psiFile)); + qName.append(ResourceBundleManager.getInstance(psiFile.getProject()).getBaseName(psiFile)); return qName.toString(); } return null; diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/CustomResourceBundle.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/CustomResourceBundle.java new file mode 100644 index 000000000000..d712dc3d8655 --- /dev/null +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/CustomResourceBundle.java @@ -0,0 +1,109 @@ +/* + * 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.psi.PropertiesFile; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileManager; +import com.intellij.psi.PsiManager; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * @author Dmitry Batkovich + */ +public class CustomResourceBundle extends ResourceBundle { + private final static Logger LOG = Logger.getInstance(CustomResourceBundle.class); + + private final List<PropertiesFile> myFiles; + private final String myBaseName; + + private CustomResourceBundle(final List<PropertiesFile> files, final @NotNull String baseName) { + LOG.assertTrue(!files.isEmpty()); + myFiles = new ArrayList<PropertiesFile>(files); + Collections.sort(myFiles, new Comparator<PropertiesFile>() { + @Override + public int compare(PropertiesFile f1, PropertiesFile f2) { + return f1.getName().compareTo(f2.getName()); + } + }); + myBaseName = baseName; + } + + public static CustomResourceBundle fromState(final CustomResourceBundleState state, final Project project) { + final PsiManager psiManager = PsiManager.getInstance(project); + final List<PropertiesFile> files = + ContainerUtil.map(state.getFiles(VirtualFileManager.getInstance()), new Function<VirtualFile, PropertiesFile>() { + @Override + public PropertiesFile fun(VirtualFile virtualFile) { + return PropertiesImplUtil.getPropertiesFile(psiManager.findFile(virtualFile)); + } + }); + return files.size() < 2 ? null : new CustomResourceBundle(files, state.getBaseName()); + } + + @NotNull + @Override + public List<PropertiesFile> getPropertiesFiles() { + return myFiles; + } + + @NotNull + @Override + public PropertiesFile getDefaultPropertiesFile() { + return ContainerUtil.getFirstItem(myFiles); + } + + @NotNull + @Override + public String getBaseName() { + return myBaseName; + } + + @Nullable + @Override + public VirtualFile getBaseDirectory() { + return null; + } + + @NotNull + @Override + public Project getProject() { + return getDefaultPropertiesFile().getProject(); + } + + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final CustomResourceBundle resourceBundle = (CustomResourceBundle)o; + return resourceBundle.getPropertiesFiles().equals(resourceBundle.getPropertiesFiles()) && + resourceBundle.getBaseName().equals(getBaseName()); + } + + public int hashCode() { + return myFiles.hashCode() * 31 + myBaseName.hashCode(); + } +} diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/CustomResourceBundleState.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/CustomResourceBundleState.java new file mode 100644 index 000000000000..9be149d6a4db --- /dev/null +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/CustomResourceBundleState.java @@ -0,0 +1,93 @@ +/* + * 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.openapi.util.Condition; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileManager; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.HashSet; +import com.intellij.util.xmlb.annotations.AbstractCollection; +import com.intellij.util.xmlb.annotations.Property; +import com.intellij.util.xmlb.annotations.Tag; +import com.intellij.util.xmlb.annotations.Transient; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +/** + * @author Dmitry Batkovich + */ +@Tag("custom-resource-bundle") +public class CustomResourceBundleState { + + @Property(surroundWithTag = false) + @AbstractCollection(surroundWithTag = false, elementTag = "file", elementValueAttribute = "value") + public Set<String> myFileUrls = new HashSet<String>(); + + @Tag("base-name") + public String myBaseName; + + @Transient + @NotNull + public String getBaseName() { + return myBaseName; + } + + public Set<String> getFileUrls() { + return myFileUrls; + } + + public List<VirtualFile> getFiles(@NotNull final VirtualFileManager manager) { + return ContainerUtil.mapNotNull(getFileUrls(), new Function<String, VirtualFile>() { + @Override + public VirtualFile fun(String url) { + return manager.findFileByUrl(url); + } + }); + } + + @Nullable + public CustomResourceBundleState removeNonExistentFiles(final VirtualFileManager virtualFileManager) { + final List<String> existentFiles = ContainerUtil.filter(myFileUrls, new Condition<String>() { + @Override + public boolean value(String url) { + return virtualFileManager.findFileByUrl(url) != null; + } + }); + if (existentFiles.isEmpty()) { + return null; + } + final CustomResourceBundleState customResourceBundleState = new CustomResourceBundleState(); + customResourceBundleState.myFileUrls.addAll(existentFiles); + customResourceBundleState.myBaseName = myBaseName; + return customResourceBundleState; + } + + public CustomResourceBundleState addAll(final Collection<String> urls) { + myFileUrls.addAll(urls); + return this; + } + + public CustomResourceBundleState setBaseName(String baseName) { + myBaseName = baseName; + return this; + } +} diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/PropertiesImplUtil.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/PropertiesImplUtil.java index f667b1a93da0..15e73791f8ea 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/PropertiesImplUtil.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/PropertiesImplUtil.java @@ -15,6 +15,7 @@ */ package com.intellij.lang.properties; +import com.intellij.lang.HtmlScriptContentProvider; import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.lang.properties.psi.PropertyKeyIndex; import com.intellij.lang.properties.xml.XmlPropertiesFileImpl; @@ -48,7 +49,23 @@ public class PropertiesImplUtil extends PropertiesUtil { if (!containingFile.isValid()) { return EmptyResourceBundle.getInstance(); } - final String baseName = getBaseName(containingFile); + final ResourceBundleManager manager = ResourceBundleManager.getInstance(representative.getProject()); + final CustomResourceBundle customResourceBundle = + manager.getCustomResourceBundle(representative); + if (customResourceBundle != null) { + return customResourceBundle; + } + + final VirtualFile virtualFile = representative.getVirtualFile(); + if (virtualFile == null) { + return EmptyResourceBundle.getInstance(); + } + if (manager.isDefaultDissociated(virtualFile)) { + return new ResourceBundleImpl(representative); + } + + + final String baseName = manager.getBaseName(containingFile); final PsiDirectory directory = ApplicationManager.getApplication().runReadAction(new Computable<PsiDirectory>() { @Nullable public PsiDirectory compute() { @@ -61,14 +78,9 @@ public class PropertiesImplUtil extends PropertiesUtil { @Nullable private static ResourceBundle getResourceBundle(@NotNull final String baseName, @NotNull final PsiDirectory baseDirectory) { PropertiesFile defaultPropertiesFile = null; - final PsiFile[] files = ApplicationManager.getApplication().runReadAction(new Computable<PsiFile[]>() { - @Override - public PsiFile[] compute() { - return baseDirectory.getFiles(); - } - }); - for (final PsiFile psiFile : files) { - if (baseName.equals(getBaseName(psiFile))) { + final ResourceBundleManager bundleBaseNameManager = ResourceBundleManager.getInstance(baseDirectory.getProject()); + for (final PsiFile psiFile : baseDirectory.getFiles()) { + if (baseName.equals(bundleBaseNameManager.getBaseName(psiFile))) { final PropertiesFile propertiesFile = getPropertiesFile(psiFile); if (propertiesFile != null) { if (defaultPropertiesFile == null || defaultPropertiesFile.getName().compareTo(propertiesFile.getName()) > 0) { diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleImpl.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleImpl.java index ca5c8aa39a36..bad9957f7523 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleImpl.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleImpl.java @@ -27,6 +27,7 @@ import com.intellij.psi.PsiFile; import com.intellij.util.SmartList; import org.jetbrains.annotations.NotNull; +import java.util.Collections; import java.util.List; public class ResourceBundleImpl extends ResourceBundle { @@ -39,12 +40,15 @@ public class ResourceBundleImpl extends ResourceBundle { @NotNull @Override public List<PropertiesFile> getPropertiesFiles() { + if (ResourceBundleManager.getInstance(getProject()).isDefaultDissociated(myDefaultPropertiesFile.getVirtualFile())) { + return Collections.singletonList(myDefaultPropertiesFile); + } PsiFile[] children = myDefaultPropertiesFile.getParent().getFiles(); final String baseName = getBaseName(); List<PropertiesFile> result = new SmartList<PropertiesFile>(); for (PsiFile file : children) { if (!file.isValid() || file.getVirtualFile().getExtension() == null) continue; - if (Comparing.strEqual(PropertiesUtil.getBaseName(file), baseName)) { + if (Comparing.strEqual(PropertiesUtil.getDefaultBaseName(file.getVirtualFile()), baseName)) { PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile(file); if (propertiesFile != null) { result.add(propertiesFile); @@ -56,26 +60,14 @@ public class ResourceBundleImpl extends ResourceBundle { @NotNull @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 PropertiesUtil.getBaseName(myDefaultPropertiesFile.getContainingFile()); + return ResourceBundleManager.getInstance(getProject()).getBaseName(myDefaultPropertiesFile.getContainingFile()); } @NotNull diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleManager.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleManager.java new file mode 100644 index 000000000000..a01c123f8763 --- /dev/null +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleManager.java @@ -0,0 +1,256 @@ +/* + * 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.psi.PropertiesFile; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.components.*; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.NullableComputable; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.*; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Locale; +import java.util.regex.Matcher; + +/** + * @author Dmitry Batkovich + */ +@State( + name = "ResourceBundleManager", + storages = { + @Storage(file = StoragePathMacros.PROJECT_FILE), + @Storage(file = StoragePathMacros.PROJECT_CONFIG_DIR + "/resourceBundles.xml", scheme = StorageScheme.DIRECTORY_BASED) + }) +public class ResourceBundleManager implements PersistentStateComponent<ResourceBundleManagerState> { + private final static Logger LOG = Logger.getInstance(ResourceBundleManager.class); + private final static Locale DEFAULT_LOCALE = new Locale("", "", ""); + + private ResourceBundleManagerState myState = new ResourceBundleManagerState(); + + public ResourceBundleManager(final PsiManager manager) { + manager.addPsiTreeChangeListener(new PsiTreeChangeAdapter() { + @Override + public void childMoved(@NotNull PsiTreeChangeEvent event) { + final PsiElement child = event.getChild(); + if (!(child instanceof PsiFile)) { + return; + } + final PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile((PsiFile)child); + if (propertiesFile == null) { + return; + } + final String oldParentUrl = getUrl(event.getOldParent()); + final String newParentUrl = getUrl(event.getNewParent()); + if (oldParentUrl == null || newParentUrl == null) { + return; + } + final String newUrl = propertiesFile.getVirtualFile().getUrl(); + final String oldUrl = oldParentUrl + newUrl.substring(newParentUrl.length()); + if (myState.getDissociatedFiles().remove(oldUrl)) { + myState.getDissociatedFiles().add(newUrl); + } + + for (CustomResourceBundleState customResourceBundleState : myState.getCustomResourceBundles()) { + if (customResourceBundleState.getFileUrls().remove(oldUrl)) { + customResourceBundleState.getFileUrls().add(newUrl); + break; + } + } + } + + @Nullable + private String getUrl(PsiElement element) { + return !(element instanceof PsiDirectory) ? null : ((PsiDirectory)element).getVirtualFile().getUrl(); + } + + @Override + public void childReplaced(@NotNull PsiTreeChangeEvent event) { + super.childReplaced(event); + } + + @Override + public void beforeChildMovement(@NotNull PsiTreeChangeEvent event) { + super.beforeChildMovement(event); + } + + @Override + public void propertyChanged(@NotNull PsiTreeChangeEvent event) { + super.propertyChanged(event); + } + + @Override + public void childRemoved(@NotNull PsiTreeChangeEvent event) { + final PsiElement child = event.getChild(); + if (!(child instanceof PsiFile)) { + return; + } + PropertiesFile file = PropertiesImplUtil.getPropertiesFile((PsiFile)child); + if (file == null) { + return; + } + final VirtualFile virtualFile = file.getVirtualFile(); + final String url = virtualFile.getUrl(); + myState.getDissociatedFiles().remove(url); + for (CustomResourceBundleState customResourceBundleState : myState.getCustomResourceBundles()) { + if (customResourceBundleState.getFileUrls().remove(url)) { + if (customResourceBundleState.getFileUrls().size() < 2) { + myState.getCustomResourceBundles().remove(customResourceBundleState); + } + break; + } + } + } + }); + } + + public static ResourceBundleManager getInstance(final Project project) { + return ServiceManager.getService(project, ResourceBundleManager.class); + } + + @Nullable + public String getFullName(final @NotNull PropertiesFile propertiesFile) { + return ApplicationManager.getApplication().runReadAction(new NullableComputable<String>() { + public String compute() { + final PsiDirectory directory = propertiesFile.getParent(); + final String packageQualifiedName = PropertiesUtil.getPackageQualifiedName(directory); + if (packageQualifiedName == null) { + return null; + } + final StringBuilder qName = new StringBuilder(packageQualifiedName); + if (qName.length() > 0) { + qName.append("."); + } + qName.append(getBaseName(propertiesFile.getContainingFile())); + return qName.toString(); + } + }); + } + + @NotNull + public Locale getLocale(final @NotNull VirtualFile propertiesFile) { + final String customResourceBundleName = getCustomResourceBundleName(propertiesFile); + + String name = propertiesFile.getName(); + if (customResourceBundleName != null) { + name = name.substring(customResourceBundleName.length()); + } + + final Matcher matcher = PropertiesUtil.LOCALE_PATTERN.matcher(name); + if (matcher.find()) { + final String rawLocale = matcher.group(1); + final String[] splittedRawLocale = rawLocale.split("_"); + if (splittedRawLocale.length > 1 && splittedRawLocale[1].length() >= 2) { + final String language = splittedRawLocale[1]; + final String country = splittedRawLocale.length > 2 ? splittedRawLocale[2] : ""; + final String variant = splittedRawLocale.length > 3 ? splittedRawLocale[3] : ""; + return new Locale(language, country, variant); + } + } + return DEFAULT_LOCALE; + } + + @NotNull + public String getBaseName(@NotNull final PsiFile file) { + return getBaseName(file.getVirtualFile()); + } + + @NotNull + private String getBaseName(@NotNull final VirtualFile file) { + final CustomResourceBundleState customResourceBundle = getCustomResourceBundleState(file); + if (customResourceBundle != null) { + return customResourceBundle.getBaseName(); + } + if (isDefaultDissociated(file)) { + return file.getNameWithoutExtension(); + } + return PropertiesUtil.getDefaultBaseName(file); + } + + + public void dissociateResourceBundle(final @NotNull ResourceBundle resourceBundle) { + if (resourceBundle instanceof CustomResourceBundle) { + final CustomResourceBundleState state = + getCustomResourceBundleState(resourceBundle.getDefaultPropertiesFile().getVirtualFile()); + LOG.assertTrue(state != null); + myState.getCustomResourceBundles().remove(state); + } else { + for (final PropertiesFile propertiesFile : resourceBundle.getPropertiesFiles()) { + final VirtualFile file = propertiesFile.getContainingFile().getVirtualFile(); + myState.getDissociatedFiles().add(file.getUrl()); + } + } + } + + public void combineToResourceBundle(final @NotNull List<PropertiesFile> propertiesFiles, final String baseName) { + myState.getCustomResourceBundles() + .add(new CustomResourceBundleState().addAll(ContainerUtil.map(propertiesFiles, new Function<PropertiesFile, String>() { + @Override + public String fun(PropertiesFile file) { + return file.getVirtualFile().getUrl(); + } + })).setBaseName(baseName)); + } + + @Nullable + public CustomResourceBundle getCustomResourceBundle(final @NotNull PropertiesFile file) { + final VirtualFile virtualFile = file.getVirtualFile(); + if (virtualFile == null) { + return null; + } + final CustomResourceBundleState state = getCustomResourceBundleState(virtualFile); + return state == null ? null : CustomResourceBundle.fromState(state, file.getProject()); + } + + public boolean isDefaultDissociated(final @NotNull VirtualFile virtualFile) { + final String url = virtualFile.getUrl(); + return myState.getDissociatedFiles().contains(url) || getCustomResourceBundleState(virtualFile) != null; + } + + @Nullable + private String getCustomResourceBundleName(final @NotNull VirtualFile virtualFile) { + final CustomResourceBundleState customResourceBundle = getCustomResourceBundleState(virtualFile); + return customResourceBundle == null ? null : customResourceBundle.getBaseName(); + } + + @Nullable + private CustomResourceBundleState getCustomResourceBundleState(final @NotNull VirtualFile virtualFile) { + final String url = virtualFile.getUrl(); + for (CustomResourceBundleState customResourceBundleState : myState.getCustomResourceBundles()) { + if (customResourceBundleState.getFileUrls().contains(url)) { + return customResourceBundleState; + } + } + return null; + } + + @Nullable + @Override + public ResourceBundleManagerState getState() { + return myState.isEmpty() ? null : myState; + } + + @Override + public void loadState(ResourceBundleManagerState state) { + myState = state.removeNonExistentFiles(); + } +} diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleManagerState.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleManagerState.java new file mode 100644 index 000000000000..c4d1e5c5cb2d --- /dev/null +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleManagerState.java @@ -0,0 +1,72 @@ +/* + * 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.openapi.vfs.VirtualFileManager; +import com.intellij.util.containers.HashSet; +import com.intellij.util.xmlb.annotations.AbstractCollection; +import com.intellij.util.xmlb.annotations.Property; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * @author Dmitry Batkovich + */ +public class ResourceBundleManagerState { + + @Property(surroundWithTag = false) + @AbstractCollection(elementValueAttribute = "url", elementTag = "file", surroundWithTag = false) + public Set<String> myDissociatedFiles = new HashSet<String>(); + + @Property(surroundWithTag = false) + @AbstractCollection(elementTag = "custom-rb", surroundWithTag = false) + public List<CustomResourceBundleState> myCustomResourceBundles = new ArrayList<CustomResourceBundleState>(); + + public Set<String> getDissociatedFiles() { + return myDissociatedFiles; + } + + public List<CustomResourceBundleState> getCustomResourceBundles() { + return myCustomResourceBundles; + } + + public boolean isEmpty() { + return myCustomResourceBundles.isEmpty() && myDissociatedFiles.isEmpty(); + } + + public ResourceBundleManagerState removeNonExistentFiles() { + final ResourceBundleManagerState newState = new ResourceBundleManagerState(); + + final VirtualFileManager virtualFileManager = VirtualFileManager.getInstance(); + + for (final String dissociatedFileUrl : myDissociatedFiles) { + if (virtualFileManager.findFileByUrl(dissociatedFileUrl) != null) { + newState.myDissociatedFiles.add(dissociatedFileUrl); + } + } + + for (CustomResourceBundleState customResourceBundle : myCustomResourceBundles) { + final CustomResourceBundleState updatedCustomResourceBundle = customResourceBundle.removeNonExistentFiles(virtualFileManager); + if (updatedCustomResourceBundle != null) { + newState.myCustomResourceBundles.add(updatedCustomResourceBundle); + } + } + + return newState; + } +} diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundlePropertyStructureViewElement.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundlePropertyStructureViewElement.java index 724a794ca3bb..14cb1cb940c4 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundlePropertyStructureViewElement.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundlePropertyStructureViewElement.java @@ -20,11 +20,8 @@ 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.*; import com.intellij.lang.properties.ResourceBundle; -import com.intellij.lang.properties.psi.Property; import com.intellij.navigation.ColoredItemPresentation; import com.intellij.navigation.ItemPresentation; import com.intellij.openapi.editor.colors.EditorColorsManager; @@ -62,7 +59,7 @@ public class ResourceBundlePropertyStructureViewElement implements StructureView @Override public PsiElement[] getPsiElements() { - return new PsiElement[] {getProperty().getPsiElement()}; + return new PsiElement[] {getValue()}; } public void setPresentableName(final String presentableName) { @@ -70,8 +67,8 @@ public class ResourceBundlePropertyStructureViewElement implements StructureView } @Override - public Property getValue() { - return (Property)myProperty.getPsiElement(); + public PsiElement getValue() { + return myProperty.getPsiElement(); } @Override diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/psi/impl/PropertiesFileImpl.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/psi/impl/PropertiesFileImpl.java index 759ce6cb46fb..99d06e8da06b 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/psi/impl/PropertiesFileImpl.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/psi/impl/PropertiesFileImpl.java @@ -20,6 +20,7 @@ import com.intellij.lang.ASTFactory; import com.intellij.lang.ASTNode; import com.intellij.lang.properties.*; import com.intellij.lang.properties.ResourceBundle; +import com.intellij.lang.properties.ResourceBundleManager; import com.intellij.lang.properties.parsing.PropertiesElementTypes; import com.intellij.lang.properties.psi.PropertiesElementFactory; import com.intellij.lang.properties.psi.PropertiesFile; @@ -120,7 +121,7 @@ public class PropertiesFileImpl extends PsiFileBase implements PropertiesFile { @Override @NotNull public Locale getLocale() { - return PropertiesUtil.getLocale(getVirtualFile()); + return ResourceBundleManager.getInstance(getProject()).getLocale(getVirtualFile()); } @Override diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/xml/XmlPropertiesFileImpl.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/xml/XmlPropertiesFileImpl.java index 4b8953f47e9c..6c2453b94144 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/xml/XmlPropertiesFileImpl.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/xml/XmlPropertiesFileImpl.java @@ -17,8 +17,8 @@ package com.intellij.lang.properties.xml; import com.intellij.lang.properties.IProperty; import com.intellij.lang.properties.PropertiesImplUtil; -import com.intellij.lang.properties.PropertiesUtil; import com.intellij.lang.properties.ResourceBundle; +import com.intellij.lang.properties.ResourceBundleManager; import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.lang.properties.psi.Property; import com.intellij.openapi.project.Project; @@ -107,7 +107,7 @@ public class XmlPropertiesFileImpl extends XmlPropertiesFile { @NotNull @Override public Locale getLocale() { - return PropertiesUtil.getLocale(getVirtualFile()); + return ResourceBundleManager.getInstance(getProject()).getLocale(getVirtualFile()); } @NotNull diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/properties/PropertiesCoreEnvironment.java b/plugins/properties/properties-psi-impl/src/com/intellij/properties/PropertiesCoreEnvironment.java index f946e41c26ae..52d4d5934b40 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/properties/PropertiesCoreEnvironment.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/properties/PropertiesCoreEnvironment.java @@ -25,6 +25,7 @@ import com.intellij.lang.LanguageParserDefinitions; import com.intellij.lang.findUsages.LanguageFindUsages; import com.intellij.lang.folding.LanguageFolding; import com.intellij.lang.properties.*; +import com.intellij.lang.properties.ResourceBundleManager; import com.intellij.lang.properties.editor.PropertiesFoldingBuilder; import com.intellij.lang.properties.findUsages.PropertiesFindUsagesProvider; import com.intellij.lang.properties.parsing.PropertiesElementTypes; @@ -87,6 +88,7 @@ public class PropertiesCoreEnvironment { public ProjectEnvironment(CoreProjectEnvironment projectEnvironment) { projectEnvironment.getProject().registerService(PropertiesReferenceManager.class); projectEnvironment.getProject().registerService(PropertiesSeparatorManager.class); + projectEnvironment.getProject().registerService(ResourceBundleManager.class); } } } diff --git a/plugins/properties/src/META-INF/plugin.xml b/plugins/properties/src/META-INF/plugin.xml index 513678dcbf72..672add1a002d 100644 --- a/plugins/properties/src/META-INF/plugin.xml +++ b/plugins/properties/src/META-INF/plugin.xml @@ -34,6 +34,7 @@ implementationClass="com.intellij.lang.properties.PropertyManipulator"/> <projectService serviceInterface="com.intellij.lang.properties.structureView.PropertiesSeparatorManager" serviceImplementation="com.intellij.lang.properties.structureView.PropertiesSeparatorManager"/> + <projectService serviceImplementation="com.intellij.lang.properties.ResourceBundleManager"/> <codeInsight.wordCompletionFilter language="Properties" implementationClass="com.intellij.lang.properties.PropertiesWordCompletionFilter"/> <lang.psiStructureViewFactory language="Properties" @@ -98,6 +99,12 @@ </project-components> <actions> + <action id="DissociateResourceBundleAction" class="com.intellij.lang.properties.customizeActions.DissociateResourceBundleAction"> + <add-to-group group-id="ProjectViewPopupMenu"/> + </action> + <action id="CombinePropertiesFilesAction" class="com.intellij.lang.properties.customizeActions.CombinePropertiesFilesAction"> + <add-to-group group-id="ProjectViewPopupMenu"/> + </action> <action id="ChooseNextSubsequentPropertyValueEditorAction" class="com.intellij.lang.properties.editor.ChooseSubsequentPropertyValueEditorAction$Next" text="Choose Next Property Value Editor" diff --git a/plugins/properties/src/com/intellij/lang/properties/PropertiesFilesManager.java b/plugins/properties/src/com/intellij/lang/properties/PropertiesFilesManager.java index 60d337681a31..5477c137021e 100644 --- a/plugins/properties/src/com/intellij/lang/properties/PropertiesFilesManager.java +++ b/plugins/properties/src/com/intellij/lang/properties/PropertiesFilesManager.java @@ -20,7 +20,7 @@ import com.intellij.openapi.components.AbstractProjectComponent; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.encoding.EncodingManager; import com.intellij.psi.search.FileTypeIndex; @@ -44,20 +44,24 @@ public class PropertiesFilesManager extends AbstractProjectComponent { super(project); } + @Override public void projectOpened() { final PropertyChangeListener myListener = new PropertyChangeListener() { + @Override public void propertyChange(final PropertyChangeEvent evt) { String propertyName = evt.getPropertyName(); if (EncodingManager.PROP_NATIVE2ASCII_SWITCH.equals(propertyName) || EncodingManager.PROP_PROPERTIES_FILES_ENCODING.equals(propertyName) ) { DumbService.getInstance(myProject).smartInvokeLater(new Runnable(){ + @Override public void run() { ApplicationManager.getApplication().runWriteAction(new Runnable(){ + @Override public void run() { Collection<VirtualFile> filesToRefresh = FileBasedIndex.getInstance() .getContainingFiles(FileTypeIndex.NAME, PropertiesFileType.INSTANCE, GlobalSearchScope.allScope(myProject)); - VirtualFile[] virtualFiles = VfsUtil.toVirtualFileArray(filesToRefresh); + VirtualFile[] virtualFiles = VfsUtilCore.toVirtualFileArray(filesToRefresh); FileDocumentManager.getInstance().saveAllDocuments(); //force to re-detect encoding @@ -75,6 +79,7 @@ public class PropertiesFilesManager extends AbstractProjectComponent { EncodingManager.getInstance().addPropertyChangeListener(myListener,myProject); } + @Override @NotNull public String getComponentName() { return "PropertiesFileManager"; diff --git a/plugins/properties/src/com/intellij/lang/properties/ResourceBundleReference.java b/plugins/properties/src/com/intellij/lang/properties/ResourceBundleReference.java index 5f708c3eda61..14ac858d9917 100644 --- a/plugins/properties/src/com/intellij/lang/properties/ResourceBundleReference.java +++ b/plugins/properties/src/com/intellij/lang/properties/ResourceBundleReference.java @@ -97,14 +97,14 @@ public class ResourceBundleReference extends PsiReferenceBase<PsiElement> implem if (!(element instanceof PropertiesFile)) { throw new IncorrectOperationException(); } - final String name = PropertiesUtil.getFullName((PropertiesFile)element); + final String name = ResourceBundleManager.getInstance(element.getProject()).getFullName((PropertiesFile)element); return super.handleElementRename(name); } public boolean isReferenceTo(PsiElement element) { if (element instanceof PropertiesFile) { - final String name = PropertiesUtil.getFullName((PropertiesFile)element); + final String name = ResourceBundleManager.getInstance(element.getProject()).getFullName((PropertiesFile)element); if (name != null && name.equals(myBundleName)) { return true; } diff --git a/plugins/properties/src/com/intellij/lang/properties/customizeActions/CombinePropertiesFilesAction.java b/plugins/properties/src/com/intellij/lang/properties/customizeActions/CombinePropertiesFilesAction.java new file mode 100644 index 000000000000..b90e74a2c767 --- /dev/null +++ b/plugins/properties/src/com/intellij/lang/properties/customizeActions/CombinePropertiesFilesAction.java @@ -0,0 +1,155 @@ +/* + * 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.customizeActions; + +import com.intellij.icons.AllIcons; +import com.intellij.ide.projectView.ProjectView; +import com.intellij.lang.properties.PropertiesBundle; +import com.intellij.lang.properties.PropertiesImplUtil; +import com.intellij.lang.properties.PropertiesUtil; +import com.intellij.lang.properties.ResourceBundle; +import com.intellij.lang.properties.ResourceBundleManager; +import com.intellij.lang.properties.editor.ResourceBundleAsVirtualFile; +import com.intellij.lang.properties.psi.PropertiesFile; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.LangDataKeys; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.InputValidatorEx; +import com.intellij.openapi.ui.Messages; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Dmitry Batkovich + */ +public class CombinePropertiesFilesAction extends AnAction { + + public CombinePropertiesFilesAction() { + super(PropertiesBundle.message("combine.properties.files.title"), null, AllIcons.FileTypes.Properties); + } + + @Override + public void actionPerformed(final AnActionEvent e) { + final List<PropertiesFile> propertiesFiles = getPropertiesFiles(e); + final String newBaseName = Messages.showInputDialog(propertiesFiles.get(0).getProject(), + PropertiesBundle.message("combine.properties.files.prompt.text"), + PropertiesBundle.message("combine.properties.files.title"), + Messages.getQuestionIcon(), + PropertiesUtil.getDefaultBaseName(propertiesFiles), + new MyInputValidator(propertiesFiles)); + if (newBaseName != null) { + final Project project = propertiesFiles.get(0).getProject(); + ResourceBundleManager.getInstance(project).combineToResourceBundle(propertiesFiles, newBaseName); + final ResourceBundle resourceBundle = propertiesFiles.get(0).getResourceBundle(); + FileEditorManager.getInstance(project).openFile(new ResourceBundleAsVirtualFile(resourceBundle), true); + ProjectView.getInstance(project).refresh(); + } + } + + @Override + public void update(final AnActionEvent e) { + final List<PropertiesFile> propertiesFiles = getPropertiesFiles(e); + boolean isAvailable = propertiesFiles != null && propertiesFiles.size() > 1; + if (isAvailable) { + for (PropertiesFile propertiesFile : propertiesFiles) { + if (propertiesFile.getResourceBundle().getPropertiesFiles().size() != 1) { + isAvailable = false; + break; + } + } + } + e.getPresentation().setVisible(isAvailable); + } + + @Nullable + private static List<PropertiesFile> getPropertiesFiles(AnActionEvent e) { + final PsiElement[] psiElements = e.getData(LangDataKeys.PSI_ELEMENT_ARRAY); + if (psiElements == null || psiElements.length == 0) { + return null; + } + final List<PropertiesFile> files = new ArrayList<PropertiesFile>(psiElements.length); + for (PsiElement psiElement : psiElements) { + if (!(psiElement instanceof PsiFile)) { + return null; + } + final PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile((PsiFile)psiElement); + if (propertiesFile == null) { + return null; + } + files.add(propertiesFile); + } + return files; + } + + @Override + public boolean isDumbAware() { + return true; + } + + private static class MyInputValidator implements InputValidatorEx { + private final List<PropertiesFile> myPropertiesFiles; + + private MyInputValidator(final List<PropertiesFile> propertiesFiles) { + myPropertiesFiles = propertiesFiles; + } + + @Override + public boolean checkInput(final String newBaseName) { + return !newBaseName.isEmpty() && checkBaseName(newBaseName) == null; + } + + @Override + public boolean canClose(final String newBaseName) { + return true; + } + + @Nullable + @Override + public String getErrorText(String inputString) { + return checkInput(inputString) ? null : String.format("Base name must be valid for file \'%s\'", checkBaseName(inputString).getFailedFile()); + } + + @Nullable + private BaseNameError checkBaseName(final String baseNameCandidate) { + for (PropertiesFile propertiesFile : myPropertiesFiles) { + final String name = propertiesFile.getVirtualFile().getName(); + if (!name.startsWith(baseNameCandidate) || !PropertiesUtil.BASE_NAME_BORDER_CHAR.contains(name.charAt(baseNameCandidate.length()))) { + return new BaseNameError(name); + } + } + return null; + } + + private static class BaseNameError { + + private final String myFailedFile; + + private BaseNameError(String failedFile) { + myFailedFile = failedFile; + } + + public String getFailedFile() { + return myFailedFile; + } + } + } +} diff --git a/plugins/properties/src/com/intellij/lang/properties/customizeActions/DissociateResourceBundleAction.java b/plugins/properties/src/com/intellij/lang/properties/customizeActions/DissociateResourceBundleAction.java new file mode 100644 index 000000000000..10041448d97c --- /dev/null +++ b/plugins/properties/src/com/intellij/lang/properties/customizeActions/DissociateResourceBundleAction.java @@ -0,0 +1,80 @@ +/* + * 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.customizeActions; + +import com.intellij.icons.AllIcons; +import com.intellij.ide.projectView.ProjectView; +import com.intellij.lang.properties.PropertiesImplUtil; +import com.intellij.lang.properties.ResourceBundle; +import com.intellij.lang.properties.ResourceBundleManager; +import com.intellij.lang.properties.editor.ResourceBundleAsVirtualFile; +import com.intellij.lang.properties.psi.PropertiesFile; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.Nullable; + +/** + * @author Dmitry Batkovich + */ +public class DissociateResourceBundleAction extends AnAction { + private static final String PRESENTATION_TEXT_TEMPLATE = "Dissociate Resource Bundle '%s'"; + + public DissociateResourceBundleAction() { + super(null, null, AllIcons.FileTypes.Properties); + } + + @Override + public void actionPerformed(final AnActionEvent e) { + final ResourceBundle resourceBundle = extractResourceBundle(e); + assert resourceBundle != null; + final Project project = resourceBundle.getProject(); + final FileEditorManager fileEditorManager = FileEditorManager.getInstance(project); + fileEditorManager.closeFile(new ResourceBundleAsVirtualFile(resourceBundle)); + for (final PropertiesFile propertiesFile : resourceBundle.getPropertiesFiles()) { + fileEditorManager.closeFile(propertiesFile.getVirtualFile()); + } + ResourceBundleManager.getInstance(e.getProject()).dissociateResourceBundle(resourceBundle); + ProjectView.getInstance(project).refresh(); + } + + @Override + public void update(final AnActionEvent e) { + final ResourceBundle resourceBundle = extractResourceBundle(e); + if (resourceBundle != null) { + e.getPresentation().setText(String.format(PRESENTATION_TEXT_TEMPLATE, resourceBundle.getBaseName()), false); + e.getPresentation().setVisible(true); + } else { + e.getPresentation().setVisible(false); + } + } + + @Nullable + private static ResourceBundle extractResourceBundle(final AnActionEvent event) { + final ResourceBundle[] data = event.getData(ResourceBundle.ARRAY_DATA_KEY); + if (data != null && data.length == 1 && data[0].getPropertiesFiles().size() > 1) { + return data[0]; + } + final PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile(event.getData(PlatformDataKeys.PSI_FILE)); + if (propertiesFile == null) { + return null; + } + final ResourceBundle resourceBundle = propertiesFile.getResourceBundle(); + return resourceBundle.getPropertiesFiles().size() > 1 ? resourceBundle : null; + } +} diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleAsVirtualFile.java b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleAsVirtualFile.java index 36915e7e6962..bae39bd9f2d0 100644 --- a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleAsVirtualFile.java +++ b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleAsVirtualFile.java @@ -23,14 +23,10 @@ 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; @@ -38,25 +34,15 @@ import java.io.OutputStream; @Presentation(icon = "AllIcons.Nodes.ResourceBundle") public class ResourceBundleAsVirtualFile extends VirtualFile { - private final VirtualFile myBasePropertiesFile; + private final ResourceBundle myResourceBundle; - private ResourceBundleAsVirtualFile(@NotNull final VirtualFile basePropertiesFile) { - myBasePropertiesFile = basePropertiesFile; + public ResourceBundleAsVirtualFile(@NotNull final ResourceBundle resourceBundle) { + myResourceBundle = resourceBundle; } @NotNull - 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); + public ResourceBundle getResourceBundle() { + return myResourceBundle; } @Override @@ -74,7 +60,7 @@ public class ResourceBundleAsVirtualFile extends VirtualFile { @Override @NotNull public String getName() { - return PropertiesUtil.getBaseName(myBasePropertiesFile); + return myResourceBundle.getBaseName(); } public boolean equals(final Object o) { @@ -83,13 +69,13 @@ public class ResourceBundleAsVirtualFile extends VirtualFile { final ResourceBundleAsVirtualFile resourceBundleAsVirtualFile = (ResourceBundleAsVirtualFile)o; - if (!myBasePropertiesFile.equals(resourceBundleAsVirtualFile.myBasePropertiesFile)) return false; + if (!myResourceBundle.equals(resourceBundleAsVirtualFile.myResourceBundle)) return false; return true; } public int hashCode() { - return myBasePropertiesFile.hashCode(); + return myResourceBundle.hashCode(); } @Override @@ -114,7 +100,7 @@ public class ResourceBundleAsVirtualFile extends VirtualFile { @Override public VirtualFile getParent() { - return myBasePropertiesFile.getParent(); + return myResourceBundle.getBaseDirectory(); } @Override diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java index 39e9ed67e7b2..27deebbff2af 100644 --- a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java +++ b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java @@ -170,7 +170,7 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit TreeElement[] children = myStructureViewComponent.getTreeModel().getRoot().getChildren(); if (children.length != 0) { TreeElement child = children[0]; - String propName = ((ResourceBundlePropertyStructureViewElement)child).getValue().getUnescapedKey(); + String propName = ((ResourceBundlePropertyStructureViewElement)child).getProperty().getUnescapedKey(); setState(new ResourceBundleEditorState(propName)); } myDataProviderPanel = new DataProviderPanel(splitPanel); @@ -248,7 +248,7 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit DefaultMutableTreeNode node = toCheck.pop(); final ResourceBundleEditorViewElement element = getSelectedElement(node); String value = element instanceof ResourceBundlePropertyStructureViewElement - ? ((ResourceBundlePropertyStructureViewElement)element).getValue().getUnescapedKey() + ? ((ResourceBundlePropertyStructureViewElement)element).getProperty().getUnescapedKey() : null; if (propertyName.equals(value)) { nodeToSelect = node; diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditorProvider.java b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditorProvider.java index fdbc2c0c5e59..d70dd358a9a9 100644 --- a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditorProvider.java +++ b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditorProvider.java @@ -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(project); + resourceBundle = ((ResourceBundleAsVirtualFile)file).getResourceBundle(); } else { PsiFile psiFile = PsiManager.getInstance(project).findFile(file); diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleStructureViewComponent.java b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleStructureViewComponent.java index da376abe05b2..f950f613ecb9 100644 --- a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleStructureViewComponent.java +++ b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleStructureViewComponent.java @@ -72,7 +72,7 @@ class ResourceBundleStructureViewComponent extends PropertiesGroupingStructureVi public Object getData(final String dataId) { if (CommonDataKeys.VIRTUAL_FILE.is(dataId)) { - return ResourceBundleAsVirtualFile.fromResourceBundle(myResourceBundle); + return new ResourceBundleAsVirtualFile(myResourceBundle); } else if (PlatformDataKeys.FILE_EDITOR.is(dataId)) { return getFileEditor(); } else if (LangDataKeys.PSI_ELEMENT_ARRAY.is(dataId)) { diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleUtil.java b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleUtil.java index e4a35e7e677c..51c3764b7f2e 100644 --- a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleUtil.java +++ b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleUtil.java @@ -56,7 +56,7 @@ public class ResourceBundleUtil { } final Project project = CommonDataKeys.PROJECT.getData(dataContext); if (virtualFile instanceof ResourceBundleAsVirtualFile && project != null) { - return ((ResourceBundleAsVirtualFile)virtualFile).getResourceBundle(project); + return ((ResourceBundleAsVirtualFile)virtualFile).getResourceBundle(); } if (project != null) { final PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile); diff --git a/plugins/properties/src/com/intellij/lang/properties/projectView/CustomResourceBundlePropertiesFileNode.java b/plugins/properties/src/com/intellij/lang/properties/projectView/CustomResourceBundlePropertiesFileNode.java new file mode 100644 index 000000000000..605b8c843a47 --- /dev/null +++ b/plugins/properties/src/com/intellij/lang/properties/projectView/CustomResourceBundlePropertiesFileNode.java @@ -0,0 +1,56 @@ +/* + * 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.projectView; + +import com.intellij.ide.projectView.PresentationData; +import com.intellij.ide.projectView.ViewSettings; +import com.intellij.ide.projectView.impl.nodes.PsiFileNode; +import com.intellij.lang.properties.PropertiesBundle; +import com.intellij.lang.properties.PropertiesImplUtil; +import com.intellij.lang.properties.ResourceBundle; +import com.intellij.lang.properties.psi.PropertiesFile; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Comparing; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import com.intellij.ui.SimpleTextAttributes; + +/** + * @author Dmitry Batkovich + */ +public class CustomResourceBundlePropertiesFileNode extends PsiFileNode { + public CustomResourceBundlePropertiesFileNode(Project project, PsiFile value, ViewSettings viewSettings) { + super(project, value, viewSettings); + setUpdateCount(-1); + } + + @Override + public void update(PresentationData data) { + super.update(data); + final PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile(getValue()); + assert propertiesFile != null; + final ResourceBundle resourceBundle = propertiesFile.getResourceBundle(); + data.setLocationString(PropertiesBundle.message("project.view.resource.bundle.tree.node.text", resourceBundle.getBaseName())); + } + + @Override + public boolean equals(Object object) { + if (!(object instanceof CustomResourceBundlePropertiesFileNode)) { + return false; + } + return Comparing.equal(getValue(), ((CustomResourceBundlePropertiesFileNode)object).getValue()); + } +} diff --git a/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleGrouper.java b/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleGrouper.java index 0ac072c062c2..f6f268df3597 100644 --- a/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleGrouper.java +++ b/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleGrouper.java @@ -18,6 +18,7 @@ package com.intellij.lang.properties.projectView; import com.intellij.ide.projectView.TreeStructureProvider; import com.intellij.ide.projectView.ViewSettings; import com.intellij.ide.util.treeView.AbstractTreeNode; +import com.intellij.lang.properties.CustomResourceBundle; import com.intellij.lang.properties.PropertiesImplUtil; import com.intellij.lang.properties.ResourceBundle; import com.intellij.lang.properties.psi.PropertiesFile; @@ -83,6 +84,10 @@ public class ResourceBundleGrouper implements TreeStructureProvider, DumbAware { ResourceBundle bundle = propertiesFile.getResourceBundle(); if (childBundles.get(bundle).size() != 1) { continue; + } else if (bundle instanceof CustomResourceBundle) { + final CustomResourceBundlePropertiesFileNode node = + new CustomResourceBundlePropertiesFileNode(myProject, (PsiFile)f, settings); + result.add(node); } } } diff --git a/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleNode.java b/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleNode.java index a415e4544aa0..b9f61643095d 100644 --- a/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleNode.java +++ b/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleNode.java @@ -86,7 +86,7 @@ public class ResourceBundleNode extends ProjectViewNode<ResourceBundle>{ } public void navigate(final boolean requestFocus) { - OpenFileDescriptor descriptor = new OpenFileDescriptor(getProject(), ResourceBundleAsVirtualFile.fromResourceBundle(getValue())); + OpenFileDescriptor descriptor = new OpenFileDescriptor(getProject(), new ResourceBundleAsVirtualFile(getValue())); FileEditorManager.getInstance(getProject()).openTextEditor(descriptor, requestFocus); } diff --git a/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/RenamePropertyProcessor.java b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/RenamePropertyProcessor.java index f3c81736673f..6f0d52f1c294 100644 --- a/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/RenamePropertyProcessor.java +++ b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/RenamePropertyProcessor.java @@ -46,7 +46,7 @@ public class RenamePropertyProcessor extends RenamePsiElementProcessor { allRenames.clear(); 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()); + final List<IProperty> properties = PropertiesUtil.findAllProperties(resourceBundle, property.getUnescapedKey()); for (final IProperty toRename : properties) { allRenames.put(toRename.getPsiElement(), e.getValue()); } diff --git a/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenamer.java b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenamer.java index ab1b4391b0f6..000f72ef5ae3 100644 --- a/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenamer.java +++ b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenamer.java @@ -16,7 +16,7 @@ package com.intellij.lang.properties.refactoring.rename; import com.intellij.lang.properties.PropertiesBundle; -import com.intellij.lang.properties.PropertiesUtil; +import com.intellij.lang.properties.ResourceBundleManager; import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiNamedElement; @@ -28,7 +28,10 @@ import org.jetbrains.annotations.NonNls; */ public class ResourceBundleRenamer extends AutomaticRenamer { + private final ResourceBundleManager myResourceBundleManager; + public ResourceBundleRenamer(final PropertiesFile propertiesFile, final String newName) { + myResourceBundleManager = ResourceBundleManager.getInstance(propertiesFile.getProject()); for (final PropertiesFile file : propertiesFile.getResourceBundle().getPropertiesFiles()) { if (file.equals(propertiesFile)) { continue; @@ -41,12 +44,12 @@ public class ResourceBundleRenamer extends AutomaticRenamer { @Override protected String nameToCanonicalName(@NonNls final String name, final PsiNamedElement element) { - return PropertiesUtil.getBaseName((PsiFile)element); + return myResourceBundleManager.getBaseName((PsiFile)element); } @Override protected String canonicalNameToName(@NonNls final String canonicalName, final PsiNamedElement element) { - final String oldCanonicalName = PropertiesUtil.getBaseName((PsiFile)element); + final String oldCanonicalName = myResourceBundleManager.getBaseName((PsiFile)element); final String oldName = element.getName(); assert oldName != null; return canonicalName + oldName.substring(oldCanonicalName.length()); diff --git a/plugins/properties/testSrc/com/intellij/lang/properties/CustomResourceBundleTest.java b/plugins/properties/testSrc/com/intellij/lang/properties/CustomResourceBundleTest.java new file mode 100644 index 000000000000..69e8621ac8db --- /dev/null +++ b/plugins/properties/testSrc/com/intellij/lang/properties/CustomResourceBundleTest.java @@ -0,0 +1,139 @@ +/* + * 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.psi.PropertiesFile; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesProcessor; +import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; + +import java.io.IOException; +import java.util.Locale; + +import static com.intellij.util.containers.ContainerUtil.list; +import static com.intellij.util.containers.ContainerUtil.map; + +/** + * @author Dmitry Batkovich + */ +public class CustomResourceBundleTest extends LightPlatformCodeInsightFixtureTestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + ResourceBundleManager.getInstance(getProject()).loadState(new ResourceBundleManagerState()); + } + + public void testDissociateDefaultBaseName() { + final PsiFile file = myFixture.addFileToProject("some_property_file.properties", ""); + final PsiFile file2 = myFixture.addFileToProject("some_property_filee.properties", ""); + final PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile(file); + assertNotNull(propertiesFile); + final ResourceBundle resourceBundle = propertiesFile.getResourceBundle(); + final ResourceBundleManager resourceBundleBaseNameManager = ResourceBundleManager.getInstance(getProject()); + resourceBundleBaseNameManager.dissociateResourceBundle(resourceBundle); + for (final PsiFile psiFile : list(file, file2)) { + assertEquals(psiFile.getVirtualFile().getNameWithoutExtension(), resourceBundleBaseNameManager.getBaseName(psiFile)); + final PropertiesFile somePropertyFile = PropertiesImplUtil.getPropertiesFile(file); + assertNotNull(somePropertyFile); + assertOneElement(somePropertyFile.getResourceBundle().getPropertiesFiles()); + } + } + + public void testCombineToCustomResourceBundleAndDissociateAfter() { + final PropertiesFile file = PropertiesImplUtil.getPropertiesFile(myFixture.addFileToProject("resources-dev/my-app-dev.properties", "")); + final PropertiesFile file2 = PropertiesImplUtil.getPropertiesFile(myFixture.addFileToProject("resources-prod/my-app-prod.properties", "")); + assertNotNull(file); + assertNotNull(file2); + assertOneElement(file.getResourceBundle().getPropertiesFiles()); + assertOneElement(file2.getResourceBundle().getPropertiesFiles()); + + final ResourceBundleManager resourceBundleBaseNameManager = ResourceBundleManager.getInstance(getProject()); + final String newBaseName = "my-app"; + resourceBundleBaseNameManager.combineToResourceBundle(list(file, file2), newBaseName); + final ResourceBundle resourceBundle = file.getResourceBundle(); + assertEquals(2, resourceBundle.getPropertiesFiles().size()); + assertEquals(newBaseName, resourceBundle.getBaseName()); + + resourceBundleBaseNameManager.dissociateResourceBundle(resourceBundle); + assertOneElement(file.getResourceBundle().getPropertiesFiles()); + assertOneElement(file2.getResourceBundle().getPropertiesFiles()); + } + + public void testCustomResourceBundleFilesMovedOrDeleted() throws IOException { + final PropertiesFile file = PropertiesImplUtil.getPropertiesFile(myFixture.addFileToProject("resources-dev/my-app-dev.properties", "")); + final PropertiesFile file2 = PropertiesImplUtil.getPropertiesFile(myFixture.addFileToProject("resources-dev/my-app-test.properties", "")); + final PropertiesFile file3 = PropertiesImplUtil.getPropertiesFile(myFixture.addFileToProject("resources-prod/my-app-prod.properties", "")); + assertNotNull(file); + assertNotNull(file2); + assertNotNull(file3); + assertOneElement(file.getResourceBundle().getPropertiesFiles()); + assertOneElement(file2.getResourceBundle().getPropertiesFiles()); + assertOneElement(file3.getResourceBundle().getPropertiesFiles()); + final ResourceBundleManager resourceBundleBaseNameManager = ResourceBundleManager.getInstance(getProject()); + resourceBundleBaseNameManager.combineToResourceBundle(list(file, file2, file3), "my-app"); + + assertSize(3, file.getResourceBundle().getPropertiesFiles()); + + final PsiDirectory newDir = PsiManager.getInstance(getProject()).findDirectory(myFixture.getTempDirFixture().findOrCreateDir("new-resources-dir")); + new MoveFilesOrDirectoriesProcessor(getProject(), new PsiElement[] {file2.getContainingFile()}, newDir, false, false, null, null).run(); + file3.getContainingFile().delete(); + + assertSize(2, file.getResourceBundle().getPropertiesFiles()); + + final ResourceBundleManagerState state = ResourceBundleManager.getInstance(getProject()).getState(); + assertNotNull(state); + assertSize(1, state.getCustomResourceBundles()); + assertSize(2, state.getCustomResourceBundles().get(0).getFileUrls()); + } + + public void testLocaleIfCanExtractFromCustomResourceBundle() { + final PsiFile file = myFixture.addFileToProject("Base_Page.properties", ""); + final PsiFile file2 = myFixture.addFileToProject("Base_Page_en.properties", ""); + final ResourceBundleManager resourceBundleBaseNameManager = ResourceBundleManager.getInstance(getProject()); + final PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile(file); + assertNotNull(propertiesFile); + resourceBundleBaseNameManager.dissociateResourceBundle(propertiesFile.getResourceBundle()); + resourceBundleBaseNameManager.combineToResourceBundle(map(list(file, file2), new Function<PsiFile, PropertiesFile>() { + @Override + public PropertiesFile fun(final PsiFile psiFile) { + return PropertiesImplUtil.getPropertiesFile(psiFile); + } + }), "Base_Page"); + final PropertiesFile propertiesFile2 = PropertiesImplUtil.getPropertiesFile(file2); + assertNotNull(propertiesFile2); + final Locale locale = propertiesFile2.getLocale(); + assertEquals("en", locale.getLanguage()); + } + + public void testSuggestedCustomResourceBundleName() { + final PsiFile file = myFixture.addFileToProject("Base_Page.properties", ""); + final PsiFile file2 = myFixture.addFileToProject("Base_Page_en.properties", ""); + final String baseName = + PropertiesUtil.getDefaultBaseName(ContainerUtil.map(list(file, file2), new Function<PsiFile, PropertiesFile>() { + @Override + public PropertiesFile fun(PsiFile psiFile) { + return PropertiesImplUtil.getPropertiesFile(file); + } + })); + assertEquals("Base_Page", baseName); + } +} diff --git a/plugins/properties/testSrc/com/intellij/lang/properties/PropertiesUtilTest.java b/plugins/properties/testSrc/com/intellij/lang/properties/PropertiesUtilTest.java index 20c44e9f47e0..44765f96fc69 100644 --- a/plugins/properties/testSrc/com/intellij/lang/properties/PropertiesUtilTest.java +++ b/plugins/properties/testSrc/com/intellij/lang/properties/PropertiesUtilTest.java @@ -15,12 +15,7 @@ */ 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 @@ -59,18 +54,8 @@ public class PropertiesUtilTest extends LightPlatformCodeInsightFixtureTestCase assertBaseNameEquals("Base_Properties.utf8.properties", "Base_Properties.utf8"); } - public void _test1() { - assertBaseNameEquals("Base_Page_fr.utf8.properties", "Base_Page.utf8"); - } - public void _test2() { - assertBaseNameEquals("Base_Page_en.utf8.properties", "Base_Page.utf8"); - } - public void _test3() { - assertBaseNameEquals("Base_Page.utf8.properties", "Base_Page.utf8"); - } - private void assertBaseNameEquals(final String propertyFileName, final String expectedBaseName) { - final String actualBaseName = PropertiesUtil.getBaseName(myFixture.configureByText(propertyFileName, "")); + final String actualBaseName = ResourceBundleManager.getInstance(getProject()).getBaseName(myFixture.configureByText(propertyFileName, "")); assertEquals(expectedBaseName, actualBaseName); } } |