diff options
Diffstat (limited to 'plugins/properties/src/com/intellij/lang/properties')
20 files changed, 927 insertions, 420 deletions
diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/ChooseSubsequentPropertyValueEditorAction.java b/plugins/properties/src/com/intellij/lang/properties/editor/ChooseSubsequentPropertyValueEditorAction.java new file mode 100644 index 000000000000..5b60f854dbaf --- /dev/null +++ b/plugins/properties/src/com/intellij/lang/properties/editor/ChooseSubsequentPropertyValueEditorAction.java @@ -0,0 +1,58 @@ +/* + * 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.actionSystem.*; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.util.Key; + +/** + * @author Dmitry Batkovich + */ +public class ChooseSubsequentPropertyValueEditorAction extends AnAction { + public static final Key<Editor> NEXT_EDITOR_KEY = Key.create("resourceBundleEditor.nextEditor"); + public static final Key<Editor> PREV_EDITOR_KEY = Key.create("resourceBundleEditor.prevEditor"); + + public final boolean myNext; + + public static class Next extends ChooseSubsequentPropertyValueEditorAction { + public Next() { + super(true); + } + } + + public static class Prev extends ChooseSubsequentPropertyValueEditorAction { + public Prev() { + super(false); + } + } + + private ChooseSubsequentPropertyValueEditorAction(final boolean next) { + myNext = next; + } + + @Override + public void actionPerformed(final AnActionEvent e) { + final Editor editor = e.getData(CommonDataKeys.EDITOR); + if (editor == null) { + return; + } + final Editor newFocusEditor = editor.getUserData(myNext ? NEXT_EDITOR_KEY : PREV_EDITOR_KEY); + if (newFocusEditor != null) { + newFocusEditor.getContentComponent().requestFocus(); + } + } +} diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/NewPropertyAction.java b/plugins/properties/src/com/intellij/lang/properties/editor/NewPropertyAction.java new file mode 100644 index 000000000000..d25b780bd769 --- /dev/null +++ b/plugins/properties/src/com/intellij/lang/properties/editor/NewPropertyAction.java @@ -0,0 +1,138 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.lang.properties.editor; + +import com.intellij.icons.AllIcons; +import com.intellij.lang.properties.PropertiesBundle; +import com.intellij.lang.properties.ResourceBundle; +import com.intellij.lang.properties.psi.PropertiesFile; +import com.intellij.lang.properties.structureView.PropertiesPrefixGroup; +import com.intellij.openapi.actionSystem.ActionPlaces; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.command.CommandProcessor; +import com.intellij.openapi.fileEditor.FileEditor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.InputValidator; +import com.intellij.openapi.ui.Messages; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** +* @author Dmitry Batkovich +*/ +class NewPropertyAction extends AnAction { + public NewPropertyAction() { + super("New Property", null, AllIcons.General.Add); + } + + @Override + public void actionPerformed(final AnActionEvent e) { + final Project project = getEventProject(e); + if (project == null) { + return; + } + final FileEditor editor = PlatformDataKeys.FILE_EDITOR.getData(e.getDataContext()); + if (editor == null || !(editor instanceof ResourceBundleEditor)) { + return; + } + final ResourceBundleEditor resourceBundleEditor = (ResourceBundleEditor)editor; + + final String prefix; + final String separator; + final String place = e.getPlace(); + if (ActionPlaces.STRUCTURE_VIEW_TOOLBAR.equals(place)) { + prefix = null; + separator = null; + } else { + final ResourceBundleEditorViewElement selectedElement = resourceBundleEditor.getSelectedElement(); + if (selectedElement == null) { + return; + } + if (selectedElement instanceof PropertiesPrefixGroup) { + final PropertiesPrefixGroup group = (PropertiesPrefixGroup)selectedElement; + prefix = group.getPrefix(); + separator = group.getSeparator(); + } + else if (selectedElement instanceof ResourceBundlePropertyStructureViewElement || + selectedElement instanceof ResourceBundleFileStructureViewElement) { + prefix = null; + separator = null; + } + else { + throw new IllegalStateException("unsupported type: " + selectedElement.getClass()); + } + } + final ResourceBundle resourceBundle = resourceBundleEditor.getResourceBundle(); + + Messages.showInputDialog(project, + PropertiesBundle.message("new.property.dialog.name.prompt.text"), + PropertiesBundle.message("new.property.dialog.title"), + Messages.getQuestionIcon(), + null, + new NewPropertyNameValidator(resourceBundle, prefix, separator)); + } + + private static class NewPropertyNameValidator implements InputValidator { + private final @NotNull ResourceBundle myResourceBundle; + private final @Nullable String myPrefix; + private final @Nullable String mySeparator; + + + public NewPropertyNameValidator(final @NotNull ResourceBundle resourceBundle, + final @Nullable String prefix, + final @Nullable String separator) { + myResourceBundle = resourceBundle; + myPrefix = prefix; + mySeparator = separator; + } + + @Override + public boolean checkInput(final String inputString) { + return true; + } + + @Override + public boolean canClose(final String inputString) { + final String newPropertyName = myPrefix == null ? inputString : (myPrefix + mySeparator + inputString); + + for (final PropertiesFile propertiesFile : myResourceBundle.getPropertiesFiles()) { + for (final String propertyName : propertiesFile.getNamesMap().keySet()) { + if (newPropertyName.equals(propertyName)) { + Messages.showErrorDialog("Can't add new property. Property with key \'" + newPropertyName + "\' already exists.", "New Property"); + return false; + } + } + } + + final PropertiesFile defaultPropertiesFile = myResourceBundle.getDefaultPropertiesFile(); + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + CommandProcessor.getInstance().runUndoTransparentAction(new Runnable() { + @Override + public void run() { + defaultPropertiesFile.addProperty(newPropertyName, ""); + } + }); + } + }); + return true; + } + } +} diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/PropertiesGroupingStructureViewComponent.java b/plugins/properties/src/com/intellij/lang/properties/editor/PropertiesGroupingStructureViewComponent.java index 8765943c7c4a..733f229bc687 100644 --- a/plugins/properties/src/com/intellij/lang/properties/editor/PropertiesGroupingStructureViewComponent.java +++ b/plugins/properties/src/com/intellij/lang/properties/editor/PropertiesGroupingStructureViewComponent.java @@ -32,6 +32,7 @@ import java.util.Set; * @author cdr */ public class PropertiesGroupingStructureViewComponent extends StructureViewComponent { + protected PropertiesGroupingStructureViewComponent(Project project, FileEditor editor, PropertiesGroupingStructureViewModel structureViewModel) { diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java index 5abeb70cf985..0176aa38fc6e 100644 --- a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java +++ b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java @@ -36,6 +36,7 @@ import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.command.undo.UndoConstants; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.colors.EditorColorsManager; @@ -68,7 +69,8 @@ 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.*; @@ -100,8 +102,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(); @@ -116,7 +118,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); @@ -128,9 +130,18 @@ 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())) { + + if (e.getOldLeadSelectionPath() != null) { + for (Map.Entry<PropertiesFile, Editor> entry : myEditors.entrySet()) { + if (entry.getValue() == mySelectedEditor) { + writeEditorPropertyValue(mySelectedEditor, entry.getKey(), selectedPropertyName); + break; + } + } + } + selectedPropertyName = getSelectedPropertyName(); selectedPropertiesFile = getSelectedPropertiesFile(); selectionChanged(); @@ -151,7 +162,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); @@ -159,6 +170,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(); @@ -192,6 +207,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; @@ -262,17 +280,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) { + private void writeEditorPropertyValue(final Editor editor, final PropertiesFile propertiesFile, final @Nullable String propertyName) { final String currentValue = editor.getDocument().getText(); - final String selectedProperty = getSelectedPropertyName(); - assert selectedProperty != null; + final String currentSelectedProperty = propertyName == null ? getSelectedPropertyName() : propertyName; + + assert currentSelectedProperty != null; ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override @@ -280,10 +305,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); @@ -314,16 +339,26 @@ 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); releaseAllEditors(); myTitledPanels.clear(); int y = 0; + Editor previousEditor = null; + Editor firstEditor = null; for (final PropertiesFile propertiesFile : propertiesFiles) { final Editor editor = createEditor(); final Editor oldEditor = myEditors.put(propertiesFile, editor); + if (firstEditor == null) { + firstEditor = editor; + } + if (previousEditor != null) { + editor.putUserData(ChooseSubsequentPropertyValueEditorAction.PREV_EDITOR_KEY, previousEditor); + previousEditor.putUserData(ChooseSubsequentPropertyValueEditorAction.NEXT_EDITOR_KEY, editor); + } + previousEditor = editor; if (oldEditor != null) { EditorFactory.getInstance().releaseEditor(oldEditor); } @@ -335,9 +370,10 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit @Override public void focusLost(final Editor eventEditor) { - writeEditorPropertyValue(editor, propertiesFile); + writeEditorPropertyValue(editor, propertiesFile, null); } }); + editor.getDocument().putUserData(UndoConstants.DONT_RECORD_UNDO, Boolean.TRUE); gc.gridx = 0; gc.gridy = y++; gc.gridheight = 1; @@ -375,6 +411,10 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit valuesPanelComponent.add(comp, gc); } + if (previousEditor != null) { + previousEditor.putUserData(ChooseSubsequentPropertyValueEditorAction.NEXT_EDITOR_KEY, firstEditor); + firstEditor.putUserData(ChooseSubsequentPropertyValueEditorAction.PREV_EDITOR_KEY, previousEditor); + } gc.gridx = 0; gc.gridy = y; @@ -524,7 +564,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(); @@ -532,6 +572,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() { @@ -673,7 +722,7 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit if (mySelectedEditor != null) { for (final Map.Entry<PropertiesFile, Editor> entry : myEditors.entrySet()) { if (mySelectedEditor.equals(entry.getValue())) { - writeEditorPropertyValue(mySelectedEditor, entry.getKey()); + writeEditorPropertyValue(mySelectedEditor, entry.getKey(), null); } } } @@ -693,23 +742,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; diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditorProvider.java b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditorProvider.java index f29a9cbb7b7a..fdbc2c0c5e59 100644 --- a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditorProvider.java +++ b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditorProvider.java @@ -42,7 +42,7 @@ public class ResourceBundleEditorProvider extends FileTypeFactory implements Fil if (!file.isValid()) return false; PsiFile psiFile = PsiManager.getInstance(project).findFile(file); PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile(psiFile); - return propertiesFile != null && propertiesFile.getResourceBundle().getPropertiesFiles(project).size() > 1; + return propertiesFile != null && propertiesFile.getResourceBundle().getPropertiesFiles().size() > 1; } @Override @@ -50,7 +50,7 @@ public class ResourceBundleEditorProvider extends FileTypeFactory implements Fil public FileEditor createEditor(@NotNull Project project, @NotNull final VirtualFile file){ ResourceBundle resourceBundle; if (file instanceof ResourceBundleAsVirtualFile) { - resourceBundle = ((ResourceBundleAsVirtualFile)file).getResourceBundle(); + resourceBundle = ((ResourceBundleAsVirtualFile)file).getResourceBundle(project); } else { PsiFile psiFile = PsiManager.getInstance(project).findFile(file); @@ -60,7 +60,7 @@ public class ResourceBundleEditorProvider extends FileTypeFactory implements Fil resourceBundle = PropertiesImplUtil.getPropertiesFile(psiFile).getResourceBundle(); } - return new ResourceBundleEditor(project, resourceBundle); + return new ResourceBundleEditor(resourceBundle); } @Override diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleStructureViewComponent.java b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleStructureViewComponent.java index 9289eb24a4cb..ee8e47a446e4 100644 --- a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleStructureViewComponent.java +++ b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleStructureViewComponent.java @@ -15,25 +15,118 @@ */ package com.intellij.lang.properties.editor; +import com.intellij.find.findUsages.PsiElement2UsageTargetAdapter; +import com.intellij.ide.CopyProvider; +import com.intellij.ide.DeleteProvider; +import com.intellij.lang.properties.IProperty; import com.intellij.lang.properties.ResourceBundle; -import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.lang.properties.psi.PropertiesFile; +import com.intellij.lang.properties.psi.Property; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.ide.CopyPasteManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiNamedElement; +import com.intellij.psi.util.PsiUtilBase; +import com.intellij.psi.util.PsiUtilCore; +import com.intellij.refactoring.safeDelete.SafeDeleteHandler; +import com.intellij.ui.PopupHandler; +import com.intellij.usages.UsageTarget; +import com.intellij.usages.UsageView; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; + +import java.awt.datatransfer.StringSelection; +import java.util.ArrayList; +import java.util.List; /** * @author cdr */ class ResourceBundleStructureViewComponent extends PropertiesGroupingStructureViewComponent { + private final static Logger LOG = Logger.getInstance(ResourceBundleStructureViewComponent.class); + private final ResourceBundle myResourceBundle; - public ResourceBundleStructureViewComponent(Project project, ResourceBundle resourceBundle, ResourceBundleEditor editor) { - super(project, editor, new ResourceBundleStructureViewModel(project, resourceBundle)); + public ResourceBundleStructureViewComponent(final ResourceBundle resourceBundle, final ResourceBundleEditor editor) { + super(resourceBundle.getProject(), editor, new ResourceBundleStructureViewModel(resourceBundle)); myResourceBundle = resourceBundle; + tunePopupActionGroup(); } - public Object getData(String dataId) { + @Override + protected void addGroupByActions(final DefaultActionGroup result) { + super.addGroupByActions(result); + result.add(new NewPropertyAction(), Constraints.FIRST); + } + + private void tunePopupActionGroup() { + final DefaultActionGroup propertiesPopupGroup = new DefaultActionGroup(); + propertiesPopupGroup.copyFromGroup((DefaultActionGroup)ActionManager.getInstance().getAction(IdeActions.GROUP_STRUCTURE_VIEW_POPUP)); + propertiesPopupGroup.add(Separator.getInstance(), Constraints.FIRST); + propertiesPopupGroup.add(new NewPropertyAction(), Constraints.FIRST); + PopupHandler.installPopupHandler(getTree(), propertiesPopupGroup, IdeActions.GROUP_STRUCTURE_VIEW_POPUP, ActionManager.getInstance()); + } + + public Object getData(final String dataId) { if (CommonDataKeys.VIRTUAL_FILE.is(dataId)) { - return new ResourceBundleAsVirtualFile(myResourceBundle); + return ResourceBundleAsVirtualFile.fromResourceBundle(myResourceBundle); + } else if (PlatformDataKeys.FILE_EDITOR.is(dataId)) { + return getFileEditor(); + } else if (LangDataKeys.PSI_ELEMENT_ARRAY.is(dataId)) { + final ResourceBundleEditorViewElement selectedElement = ((ResourceBundleEditor)getFileEditor()).getSelectedElement(); + if (selectedElement != null) { + final Project project = CommonDataKeys.PROJECT.getData(this); + if (project != null) { + final PsiElement[] psiElements = selectedElement.getPsiElements(project); + if (psiElements != null) { + return psiElements; + } + } + } + } else if (PlatformDataKeys.DELETE_ELEMENT_PROVIDER.is(dataId)) { + final PsiElement[] psiElements = LangDataKeys.PSI_ELEMENT_ARRAY.getData(this); + if (psiElements != null && psiElements.length > 0) { + return new PsiElementsDeleteProvider(psiElements); + } + } else if (UsageView.USAGE_TARGETS_KEY.is(dataId)) { + final PsiElement[] chosenElements = (PsiElement[]) getData(LangDataKeys.PSI_ELEMENT_ARRAY.getName()); + if (chosenElements != null) { + final UsageTarget[] usageTargets = new UsageTarget[chosenElements.length]; + for (int i = 0; i < chosenElements.length; i++) { + usageTargets[i] = new PsiElement2UsageTargetAdapter(chosenElements[i]); + } + return usageTargets; + } + } else if (PlatformDataKeys.COPY_PROVIDER.is(dataId)) { + return new CopyProvider() { + @Override + public void performCopy(@NotNull final DataContext dataContext) { + final PsiElement[] selectedPsiElements = (PsiElement[])getData(LangDataKeys.PSI_ELEMENT_ARRAY.getName()); + if (selectedPsiElements != null) { + final List<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; + } + } } diff --git a/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleDeleteProvider.java b/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleDeleteProvider.java index 7ba44a86c2bd..a681e10f3af1 100644 --- a/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleDeleteProvider.java +++ b/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleDeleteProvider.java @@ -48,7 +48,7 @@ class ResourceBundleDeleteProvider implements DeleteProvider { public void deleteElement(@NotNull DataContext dataContext) { final Project project = CommonDataKeys.PROJECT.getData(dataContext); - List<PropertiesFile> propertiesFiles = myResourceBundle.getPropertiesFiles(project); + List<PropertiesFile> propertiesFiles = myResourceBundle.getPropertiesFiles(); assert project != null; new SafeDeleteHandler().invoke(project, ContainerUtil.map2Array(propertiesFiles, PsiElement.class, MAPPER), dataContext); } diff --git a/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleMoveProvider.java b/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleMoveProvider.java index a2b1b621f068..d61282aefba2 100644 --- a/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleMoveProvider.java +++ b/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleMoveProvider.java @@ -57,7 +57,7 @@ public class ResourceBundleMoveProvider extends MoveHandlerDelegate { final ResourceBundle[] bundles = ResourceBundle.ARRAY_DATA_KEY.getData(dataContext); LOG.assertTrue(bundles != null); for (ResourceBundle bundle : bundles) { - List<PropertiesFile> propertiesFiles = bundle.getPropertiesFiles(CommonDataKeys.PROJECT.getData(dataContext)); + List<PropertiesFile> propertiesFiles = bundle.getPropertiesFiles(); for (PropertiesFile propertiesFile : propertiesFiles) { filesOrDirs.add(propertiesFile.getContainingFile()); } diff --git a/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleNode.java b/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleNode.java index 7de856226e01..a415e4544aa0 100644 --- a/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleNode.java +++ b/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleNode.java @@ -25,9 +25,7 @@ import com.intellij.ide.projectView.ProjectViewNode; import com.intellij.ide.projectView.ViewSettings; import com.intellij.ide.projectView.impl.nodes.PsiFileNode; import com.intellij.ide.util.treeView.AbstractTreeNode; -import com.intellij.lang.properties.PropertiesBundle; -import com.intellij.lang.properties.PropertiesImplUtil; -import com.intellij.lang.properties.ResourceBundle; +import com.intellij.lang.properties.*; import com.intellij.lang.properties.editor.ResourceBundleAsVirtualFile; import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.openapi.fileEditor.FileEditorManager; @@ -50,7 +48,7 @@ public class ResourceBundleNode extends ProjectViewNode<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); } diff --git a/plugins/properties/src/com/intellij/lang/properties/refactoring/PropertyRenameHandler.java b/plugins/properties/src/com/intellij/lang/properties/refactoring/PropertyRenameHandler.java deleted file mode 100644 index 99355d34bc6e..000000000000 --- a/plugins/properties/src/com/intellij/lang/properties/refactoring/PropertyRenameHandler.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.lang.properties.refactoring; - -import com.intellij.codeInsight.TargetElementUtilBase; -import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.actionSystem.LangDataKeys; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.ScrollType; -import com.intellij.openapi.project.Project; -import com.intellij.psi.*; -import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference; -import com.intellij.refactoring.rename.PsiElementRenameHandler; -import com.intellij.lang.properties.references.PropertyReferenceBase; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * @author Dmitry Avdeev - */ -public class PropertyRenameHandler extends PsiElementRenameHandler { - - public boolean isAvailableOnDataContext(final DataContext dataContext) { - final Editor editor = LangDataKeys.EDITOR.getData(dataContext); - if (editor != null) { - if (getPsiElement(editor) != null) return true; - } - return false; - } - - @Nullable - private static PsiElement getPsiElement(final Editor editor) { - final PsiReference reference = TargetElementUtilBase.findReference(editor); - if (reference instanceof PropertyReferenceBase) { - final ResolveResult[] resolveResults = ((PropertyReferenceBase)reference).multiResolve(false); - return resolveResults.length > 0 ? resolveResults[0].getElement() : null; - } else if (reference instanceof PsiMultiReference) { - final PsiReference[] references = ((PsiMultiReference)reference).getReferences(); - for (PsiReference psiReference : references) { - if (psiReference instanceof PropertyReferenceBase) { - final ResolveResult[] resolveResults = ((PropertyReferenceBase)psiReference).multiResolve(false); - if (resolveResults.length > 0) return resolveResults[0].getElement(); - } - } - } - return null; - } - - @Override - public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file, final DataContext dataContext) { - PsiElement element = getPsiElement(editor); - editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); - final PsiElement nameSuggestionContext = file.findElementAt(editor.getCaretModel().getOffset()); - invoke(element, project, nameSuggestionContext, editor); - } -} diff --git a/plugins/properties/src/com/intellij/lang/properties/refactoring/ResourceBundleKeyRenameHandler.java b/plugins/properties/src/com/intellij/lang/properties/refactoring/ResourceBundleKeyRenameHandler.java deleted file mode 100644 index 7d7dbc14aead..000000000000 --- a/plugins/properties/src/com/intellij/lang/properties/refactoring/ResourceBundleKeyRenameHandler.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2000-2014 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.lang.properties.refactoring; - -import com.intellij.lang.properties.IProperty; -import com.intellij.lang.properties.PropertiesBundle; -import com.intellij.lang.properties.ResourceBundle; -import com.intellij.lang.properties.editor.ResourceBundleEditor; -import com.intellij.lang.properties.editor.ResourceBundleEditorUtil; -import com.intellij.lang.properties.editor.ResourceBundleUtil; -import com.intellij.lang.properties.psi.PropertiesFile; -import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.fileEditor.FileEditorStateLevel; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.InputValidator; -import com.intellij.openapi.ui.Messages; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.refactoring.rename.RenameHandler; -import com.intellij.util.containers.HashSet; -import org.jetbrains.annotations.NotNull; - -import java.util.Set; - -/** - * Encapsulates logic of renaming resource bundle property key. - * - * @author Denis Zhdanov - * @since 11/9/10 4:13 PM - */ -public class ResourceBundleKeyRenameHandler implements RenameHandler { - - @Override - public boolean isAvailableOnDataContext(DataContext dataContext) { - ResourceBundleEditor editor = ResourceBundleEditorUtil.getEditor(dataContext); - if (editor == null) { - return false; - } - return editor.getState(FileEditorStateLevel.NAVIGATION).getPropertyName() != null; - } - - @Override - public boolean isRenaming(DataContext dataContext) { - return isAvailableOnDataContext(dataContext); - } - - @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) { - ResourceBundleEditor bundleEditor = ResourceBundleEditorUtil.getEditor(dataContext); - if (bundleEditor == null) { - return; - } - - String propertyName = bundleEditor.getState(FileEditorStateLevel.NAVIGATION).getPropertyName(); - if (propertyName == null) { - return; - } - - ResourceBundle bundle = ResourceBundleUtil.getResourceBundleFromDataContext(dataContext); - if (bundle == null) { - return; - } - Messages.showInputDialog(project, PropertiesBundle.message("rename.bundle.enter.new.resource.bundle.key.name.prompt.text"), - PropertiesBundle.message("rename.resource.bundle.key.dialog.title"), Messages.getQuestionIcon(), propertyName, - new ResourceBundleKeyRenameValidator(project, bundleEditor, bundle, propertyName)); - } - - @Override - public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, DataContext dataContext) { - invoke(project, null, null, dataContext); - } - - private static class ResourceBundleKeyRenameValidator implements InputValidator { - - private final Set<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; - } - } -} diff --git a/plugins/properties/src/com/intellij/lang/properties/refactoring/ResourceBundleRenameHandler.java b/plugins/properties/src/com/intellij/lang/properties/refactoring/ResourceBundleRenameHandler.java deleted file mode 100644 index fe555a7a2ca7..000000000000 --- a/plugins/properties/src/com/intellij/lang/properties/refactoring/ResourceBundleRenameHandler.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright 2000-2014 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Alexey - */ -package com.intellij.lang.properties.refactoring; - -import com.intellij.codeInsight.FileModificationService; -import com.intellij.lang.properties.PropertiesBundle; -import com.intellij.lang.properties.ResourceBundle; -import com.intellij.lang.properties.editor.ResourceBundleAsVirtualFile; -import com.intellij.lang.properties.editor.ResourceBundleEditor; -import com.intellij.lang.properties.editor.ResourceBundleEditorUtil; -import com.intellij.lang.properties.editor.ResourceBundleUtil; -import com.intellij.lang.properties.psi.PropertiesFile; -import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.fileEditor.FileEditorStateLevel; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.InputValidator; -import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.refactoring.rename.RenameHandler; -import com.intellij.refactoring.rename.RenameProcessor; -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.util.List; - -public class ResourceBundleRenameHandler implements RenameHandler { - private static final Logger LOG = Logger.getInstance("#" + ResourceBundleRenameHandler.class.getName()); - - public boolean isAvailableOnDataContext(DataContext dataContext) { - final Project project = CommonDataKeys.PROJECT.getData(dataContext); - if (project == null) { - return false; - } - final ResourceBundle bundle = ResourceBundleUtil.getResourceBundleFromDataContext(dataContext); - if (bundle == null) { - return false; - } - - final VirtualFile virtualFile = CommonDataKeys.VIRTUAL_FILE.getData(dataContext); - - ResourceBundleEditor editor = ResourceBundleEditorUtil.getEditor(dataContext); - return (editor == null || editor.getState(FileEditorStateLevel.NAVIGATION).getPropertyName() == null /* user selected non-bundle key element */) - && bundle.getPropertiesFiles(project).size() > 1 && (virtualFile instanceof ResourceBundleAsVirtualFile || virtualFile == null); - } - - public boolean isRenaming(DataContext dataContext) { - return isAvailableOnDataContext(dataContext); - } - - public void invoke(@NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) { - ResourceBundle resourceBundle = ResourceBundleUtil.getResourceBundleFromDataContext(dataContext); - - assert resourceBundle != null; - Messages.showInputDialog(project, - PropertiesBundle.message("rename.bundle.enter.new.resource.bundle.base.name.prompt.text"), - PropertiesBundle.message("rename.resource.bundle.dialog.title"), - Messages.getQuestionIcon(), - resourceBundle.getBaseName(), - new MyInputValidator(project, resourceBundle)); - } - - public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, DataContext dataContext) { - invoke(project, null, null, dataContext); - } - - private static class MyInputValidator implements InputValidator { - private final Project myProject; - private final ResourceBundle myResourceBundle; - - public MyInputValidator(final Project project, final ResourceBundle resourceBundle) { - myProject = project; - myResourceBundle = resourceBundle; - } - - public boolean checkInput(String inputString) { - return inputString.indexOf(File.separatorChar) < 0 && inputString.indexOf('/') < 0; - } - - public boolean canClose(final String inputString) { - return doRename(inputString); - } - private boolean doRename(final String inputString) { - final List<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; - } - } -}
\ No newline at end of file diff --git a/plugins/properties/src/com/intellij/lang/properties/refactoring/RenamePropertyProcessor.java b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/RenamePropertyProcessor.java index 6bdaa0957133..f3c81736673f 100644 --- a/plugins/properties/src/com/intellij/lang/properties/refactoring/RenamePropertyProcessor.java +++ b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/RenamePropertyProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,12 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.lang.properties.refactoring; +package com.intellij.lang.properties.refactoring.rename; import com.intellij.lang.properties.IProperty; import com.intellij.lang.properties.PropertiesUtil; import com.intellij.lang.properties.ResourceBundle; import com.intellij.lang.properties.psi.PropertiesFile; +import com.intellij.lang.properties.refactoring.PropertiesRefactoringSettings; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.psi.PsiElement; import com.intellij.refactoring.rename.RenamePsiElementProcessor; @@ -26,6 +28,7 @@ import com.intellij.refactoring.rename.UnresolvableCollisionUsageInfo; import com.intellij.usageView.UsageInfo; import org.jetbrains.annotations.NotNull; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -36,12 +39,17 @@ public class RenamePropertyProcessor extends RenamePsiElementProcessor { public void prepareRenaming(final PsiElement element, final String newName, final Map<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"; + } + }); + } } } } diff --git a/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleFromEditorRenameHandler.java b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleFromEditorRenameHandler.java new file mode 100644 index 000000000000..0c04bec80620 --- /dev/null +++ b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleFromEditorRenameHandler.java @@ -0,0 +1,120 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Alexey + */ +package com.intellij.lang.properties.refactoring.rename; + +import com.intellij.ide.util.treeView.smartTree.TreeElement; +import com.intellij.lang.properties.ResourceBundle; +import com.intellij.lang.properties.editor.*; +import com.intellij.lang.properties.structureView.PropertiesPrefixGroup; +import com.intellij.lang.properties.structureView.PropertiesStructureViewElement; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.command.CommandProcessor; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.fileEditor.FileEditor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.refactoring.rename.RenameHandler; +import com.intellij.util.NullableFunction; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * @author Dmitry Batkovich + */ +public class ResourceBundleFromEditorRenameHandler implements RenameHandler { + + @Override + public boolean isAvailableOnDataContext(DataContext dataContext) { + final Project project = CommonDataKeys.PROJECT.getData(dataContext); + if (project == null) { + return false; + } + final ResourceBundle bundle = ResourceBundleUtil.getResourceBundleFromDataContext(dataContext); + if (bundle == null) { + return false; + } + final FileEditor fileEditor = PlatformDataKeys.FILE_EDITOR.getData(dataContext); + if (fileEditor == null || !(fileEditor instanceof ResourceBundleEditor)) { + return false; + } + final VirtualFile virtualFile = CommonDataKeys.VIRTUAL_FILE.getData(dataContext); + return !(virtualFile == null || !(virtualFile instanceof ResourceBundleAsVirtualFile)); + } + + @Override + public boolean isRenaming(DataContext dataContext) { + return isAvailableOnDataContext(dataContext); + } + + @Override + public void invoke(final @NotNull Project project, Editor editor, final PsiFile file, DataContext dataContext) { + final ResourceBundleEditor resourceBundleEditor = (ResourceBundleEditor)PlatformDataKeys.FILE_EDITOR.getData(dataContext); + assert resourceBundleEditor != null; + final ResourceBundleEditorViewElement selectedElement = resourceBundleEditor.getSelectedElement(); + if (selectedElement != null) { + CommandProcessor.getInstance().runUndoTransparentAction(new Runnable() { + @Override + public void run() { + if (selectedElement instanceof PropertiesPrefixGroup) { + final PropertiesPrefixGroup group = (PropertiesPrefixGroup)selectedElement; + ResourceBundleRenameUtil.renameResourceBundleKeySection(getPsiElementsFromGroup(group), + group.getPresentableName(), + group.getPrefix().length() - group.getPresentableName().length()); + } else if (selectedElement instanceof ResourceBundlePropertyStructureViewElement) { + final PsiElement psiElement = ((ResourceBundlePropertyStructureViewElement)selectedElement).getProperty().getPsiElement(); + ResourceBundleRenameUtil.renameResourceBundleKey(psiElement, project); + } else if (selectedElement instanceof ResourceBundleFileStructureViewElement) { + ResourceBundleRenameUtil.renameResourceBundleBaseName(((ResourceBundleFileStructureViewElement)selectedElement).getValue(), project); + } else { + throw new IllegalStateException("unsupported type: " + selectedElement.getClass()); + } + } + }); + } + } + + @Override + public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, DataContext dataContext) { + invoke(project, null, null, dataContext); + } + + private static List<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; + } + }); + } +} diff --git a/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleFromProjectViewRenameHandler.java b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleFromProjectViewRenameHandler.java new file mode 100644 index 000000000000..f2cbca033b6b --- /dev/null +++ b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleFromProjectViewRenameHandler.java @@ -0,0 +1,65 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.lang.properties.refactoring.rename; + +import com.intellij.lang.properties.ResourceBundle; +import com.intellij.lang.properties.editor.*; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.refactoring.RefactoringActionHandlerFactory; +import com.intellij.refactoring.rename.RenameHandler; +import org.jetbrains.annotations.NotNull; + +/** + * @author Dmitry Batkovich + */ +public class ResourceBundleFromProjectViewRenameHandler implements RenameHandler { + + @Override + public boolean isAvailableOnDataContext(DataContext dataContext) { + final Project project = CommonDataKeys.PROJECT.getData(dataContext); + if (project == null) { + return false; + } + final ResourceBundle bundle = ResourceBundleUtil.getResourceBundleFromDataContext(dataContext); + if (bundle == null || bundle.getPropertiesFiles().size() < 2) { + return false; + } + return PlatformDataKeys.FILE_EDITOR.getData(dataContext) == null && CommonDataKeys.VIRTUAL_FILE.getData(dataContext) == null; + } + + @Override + public boolean isRenaming(DataContext dataContext) { + return isAvailableOnDataContext(dataContext); + } + + @Override + public void invoke(final @NotNull Project project, Editor editor, final PsiFile file, DataContext dataContext) { + final ResourceBundle resourceBundle = ResourceBundleUtil.getResourceBundleFromDataContext(dataContext); + assert resourceBundle != null; + RefactoringActionHandlerFactory.getInstance().createRenameHandler().invoke(project, new PsiElement[] {resourceBundle.getDefaultPropertiesFile().getContainingFile()}, dataContext); + } + + @Override + public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, DataContext dataContext) { + invoke(project, null, null, dataContext); + } +} diff --git a/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenameUtil.java b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenameUtil.java new file mode 100644 index 000000000000..79694f7ae35a --- /dev/null +++ b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenameUtil.java @@ -0,0 +1,152 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.lang.properties.refactoring.rename; + +import com.intellij.codeInsight.FileModificationService; +import com.intellij.lang.properties.PropertiesBundle; +import com.intellij.lang.properties.ResourceBundle; +import com.intellij.lang.properties.psi.PropertiesFile; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.InputValidator; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiNamedElement; +import com.intellij.refactoring.rename.PsiElementRenameHandler; +import com.intellij.refactoring.rename.RenameProcessor; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.List; + +/** + * @author Dmitry Batkovich + */ +public class ResourceBundleRenameUtil { + private final static Logger LOG = Logger.getInstance(ResourceBundleRenameUtil.class); + + public static void renameResourceBundleKey(final @NotNull PsiElement psiElement, final @NotNull Project project) { + PsiElementRenameHandler.invoke(psiElement, project, psiElement.getContainingFile(), null); + } + + public static void renameResourceBundleBaseName(final @NotNull ResourceBundle resourceBundle, final @NotNull Project project) { + Messages.showInputDialog(project, PropertiesBundle.message("rename.bundle.enter.new.resource.bundle.base.name.prompt.text"), + PropertiesBundle.message("rename.resource.bundle.dialog.title"), Messages.getQuestionIcon(), + resourceBundle.getBaseName(), new ResourceBundleBaseNameInputValidator(project, resourceBundle)); + } + + public static void renameResourceBundleKeySection(final List<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; + } + } +} diff --git a/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenamer.java b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenamer.java new file mode 100644 index 000000000000..ab1b4391b0f6 --- /dev/null +++ b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenamer.java @@ -0,0 +1,74 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.lang.properties.refactoring.rename; + +import com.intellij.lang.properties.PropertiesBundle; +import com.intellij.lang.properties.PropertiesUtil; +import com.intellij.lang.properties.psi.PropertiesFile; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiNamedElement; +import com.intellij.refactoring.rename.naming.AutomaticRenamer; +import org.jetbrains.annotations.NonNls; + +/** + * @author Dmitry Batkovich + */ +public class ResourceBundleRenamer extends AutomaticRenamer { + + public ResourceBundleRenamer(final PropertiesFile propertiesFile, final String newName) { + for (final PropertiesFile file : propertiesFile.getResourceBundle().getPropertiesFiles()) { + if (file.equals(propertiesFile)) { + continue; + } + final PsiFile containingFile = file.getContainingFile(); + myElements.add(containingFile); + } + suggestAllNames(propertiesFile.getName(), newName); + } + + @Override + protected String nameToCanonicalName(@NonNls final String name, final PsiNamedElement element) { + return PropertiesUtil.getBaseName((PsiFile)element); + } + + @Override + protected String canonicalNameToName(@NonNls final String canonicalName, final PsiNamedElement element) { + final String oldCanonicalName = PropertiesUtil.getBaseName((PsiFile)element); + final String oldName = element.getName(); + assert oldName != null; + return canonicalName + oldName.substring(oldCanonicalName.length()); + } + + @Override + public boolean isSelectedByDefault() { + return true; + } + + @Override + public String getDialogTitle() { + return PropertiesBundle.message("resource.bundle.renamer"); + } + + @Override + public String getDialogDescription() { + return PropertiesBundle.message("resource.bundle.renamer.dialog.description"); + } + + @Override + public String entityName() { + return PropertiesBundle.message("resource.bundle.renamer.entity.name"); + } +} diff --git a/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenamerFactory.java b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenamerFactory.java new file mode 100644 index 000000000000..ec4bd31acbf3 --- /dev/null +++ b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenamerFactory.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.lang.properties.refactoring.rename; + +import com.intellij.lang.properties.PropertiesBundle; +import com.intellij.lang.properties.PropertiesImplUtil; +import com.intellij.lang.properties.psi.PropertiesFile; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.refactoring.rename.naming.AutomaticRenamer; +import com.intellij.refactoring.rename.naming.AutomaticRenamerFactory; +import com.intellij.usageView.UsageInfo; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +/** + * @author Dmitry Batkovich + */ +public class ResourceBundleRenamerFactory implements AutomaticRenamerFactory { + @Override + public boolean isApplicable(final PsiElement element) { + if (!(element instanceof PsiFile)) { + return false; + } + return PropertiesImplUtil.isPropertiesFile((PsiFile)element); + } + + + @Nullable + @Override + public String getOptionName() { + return PropertiesBundle.message("resource.bundle.renamer.option"); + } + + @Override + public boolean isEnabled() { + return true; + } + + @Override + public void setEnabled(final boolean enabled) { + } + + @Override + public AutomaticRenamer createRenamer(final PsiElement element, final String newName, final Collection<UsageInfo> usages) { + final PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile((PsiFile)element); + assert propertiesFile != null; + return new ResourceBundleRenamer(propertiesFile, newName); + } +} diff --git a/plugins/properties/src/com/intellij/lang/properties/references/I18nizeQuickFixDialog.java b/plugins/properties/src/com/intellij/lang/properties/references/I18nizeQuickFixDialog.java index b19510be034b..f044a6db681c 100644 --- a/plugins/properties/src/com/intellij/lang/properties/references/I18nizeQuickFixDialog.java +++ b/plugins/properties/src/com/intellij/lang/properties/references/I18nizeQuickFixDialog.java @@ -275,7 +275,7 @@ public class I18nizeQuickFixDialog extends DialogWrapper implements I18nizeQuick private void propertiesFileChanged() { PropertiesFile propertiesFile = getPropertiesFile(); boolean hasResourceBundle = - propertiesFile != null && propertiesFile.getResourceBundle().getPropertiesFiles(propertiesFile.getProject()).size() > 1; + propertiesFile != null && propertiesFile.getResourceBundle().getPropertiesFiles().size() > 1; myUseResourceBundle.setEnabled(hasResourceBundle); } @@ -497,7 +497,7 @@ public class I18nizeQuickFixDialog extends DialogWrapper implements I18nizeQuick if (propertiesFile == null) return Collections.emptySet(); Collection<PropertiesFile> propertiesFiles; if (isUseResourceBundle()) { - propertiesFiles = propertiesFile.getResourceBundle().getPropertiesFiles(myProject); + propertiesFiles = propertiesFile.getResourceBundle().getPropertiesFiles(); } else { propertiesFiles = Collections.singleton(propertiesFile); diff --git a/plugins/properties/src/com/intellij/lang/properties/references/PropertiesCompletionContributor.java b/plugins/properties/src/com/intellij/lang/properties/references/PropertiesCompletionContributor.java index e356771d5812..5502ec336566 100644 --- a/plugins/properties/src/com/intellij/lang/properties/references/PropertiesCompletionContributor.java +++ b/plugins/properties/src/com/intellij/lang/properties/references/PropertiesCompletionContributor.java @@ -30,9 +30,11 @@ import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; -import com.intellij.util.*; +import com.intellij.util.ArrayUtil; +import com.intellij.util.NullableFunction; +import com.intellij.util.PlatformIcons; +import com.intellij.util.ProcessingContext; import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.FilteringIterator; import org.jetbrains.annotations.NotNull; import java.util.Arrays; @@ -55,12 +57,11 @@ public class PropertiesCompletionContributor extends CompletionContributor { }); } - private static final Condition<PsiReference> PROPERTY_REFERENCE = FilteringIterator.instanceOf(PropertyReference.class); - private void doAdd(CompletionParameters parameters, final CompletionResultSet result) { + private static void doAdd(CompletionParameters parameters, final CompletionResultSet result) { PsiElement position = parameters.getPosition(); PsiReference[] references = ArrayUtil.mergeArrays(position.getReferences(), position.getParent().getReferences()); - PropertyReference propertyReference = (PropertyReference)ContainerUtil.find(references, PROPERTY_REFERENCE); - if (propertyReference != null) { + PropertyReference propertyReference = ContainerUtil.findInstance(references, PropertyReference.class); + if (propertyReference != null && !hasMoreImportantReference(references, propertyReference)) { final int startOffset = parameters.getOffset(); PsiElement element = propertyReference.getElement(); final int offsetInElement = startOffset - element.getTextRange().getStartOffset(); @@ -69,17 +70,16 @@ public class PropertiesCompletionContributor extends CompletionContributor { LookupElement[] variants = getVariants(propertyReference); result.withPrefixMatcher(prefix).addAllElements(Arrays.asList(variants)); - if (variants.length != 0) { - result.stopHere(); - } } - //if (parameters.isExtendedCompletion()) { - // CompletionService.getCompletionService().getVariantsFromContributors(parameters.delegateToClassName(), null, new Consumer<CompletionResult>() { - // public void consume(final CompletionResult completionResult) { - // result.passResult(completionResult); - // } - // }); - //} + } + + private static boolean hasMoreImportantReference(PsiReference[] references, PropertyReference propertyReference) { + return propertyReference.isSoft() && ContainerUtil.or(references, new Condition<PsiReference>() { + @Override + public boolean value(PsiReference reference) { + return !reference.isSoft(); + } + }); } public static final LookupElementRenderer<LookupElement> LOOKUP_ELEMENT_RENDERER = new LookupElementRenderer<LookupElement>() { |