resource bundle editor: allow to insert new property after selected one IDEA-160539
authorDmitry Batkovich <dmitry.batkovich@jetbrains.com>
Wed, 14 Sep 2016 14:47:21 +0000 (17:47 +0300)
committerDmitry Batkovich <dmitry.batkovich@jetbrains.com>
Wed, 14 Sep 2016 14:47:21 +0000 (17:47 +0300)
plugins/properties/properties-psi-api/resources/messages/PropertiesBundle.properties
plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundleFileStructureViewElement.java
plugins/properties/src/com/intellij/lang/properties/editor/NewPropertyAction.java
plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java
plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundlePropertiesUpdateManager.java

index 7ec03ad5923aa9d33022fe5f7e8594449c3f9955..0772f4cb094f3a81b8ef1bfca4f3688b99a9925f 100644 (file)
@@ -43,7 +43,8 @@ options.properties.attribute.descriptor.valid.string.escape=Valid string escape
 options.properties.attribute.descriptor.invalid.string.escape=Invalid string escape
 
 new.property.dialog.title=New Property Key
-new.property.dialog.name.prompt.text=Enter new property key name
+new.property.dialog.name.prompt.text=Enter new property key name:
+new.property.dialog.checkbox.text=Insert after selected property
 
 resource.bundle.renamer=Rename Resource Bundle Properties Files
 resource.bundle.renamer.dialog.description=Rename resource bundle properties files with the following names to:
index 6caf5e828137eb2331dc092ece23a26295b80bc9..d2af3f6dcc2edfe27c82f652415e42c764979c67 100644 (file)
@@ -43,7 +43,7 @@ public class ResourceBundleFileStructureViewElement implements StructureViewTree
   private final ResourceBundle myResourceBundle;
 
   private volatile boolean myShowOnlyIncomplete;
-  private final Map<String, ResourceBundlePropertyStructureViewElement> myElements = ContainerUtil.newHashMap();
+  private final Map<String, ResourceBundlePropertyStructureViewElement> myElements = ContainerUtil.newLinkedHashMap();
 
   public ResourceBundleFileStructureViewElement(final ResourceBundle resourceBundle) {
     myResourceBundle = resourceBundle;
@@ -83,7 +83,12 @@ public class ResourceBundleFileStructureViewElement implements StructureViewTree
       myElements.remove(remain);
     }
 
-    return myElements.values().toArray(new StructureViewTreeElement[myElements.size()]);
+    StructureViewTreeElement[] result = new StructureViewTreeElement[propertyNames.size()];
+    int i = 0;
+    for (String key : propertyNames.keySet()) {
+      result[i++] = myElements.get(key);
+    }
+    return result;
   }
 
   public static MultiMap<String, IProperty> getPropertiesMap(ResourceBundle resourceBundle, boolean onlyIncomplete) {
index 983bb5c3e6ba5b0f7ec77fe0406e479269c375cd..94b971c6f080a503afb9a2af147bda5007c209db 100644 (file)
@@ -16,6 +16,8 @@
 package com.intellij.lang.properties.editor;
 
 import com.intellij.icons.AllIcons;
+import com.intellij.ide.util.PropertiesComponent;
+import com.intellij.lang.properties.IProperty;
 import com.intellij.lang.properties.PropertiesBundle;
 import com.intellij.lang.properties.ResourceBundle;
 import com.intellij.lang.properties.psi.PropertiesFile;
@@ -23,12 +25,14 @@ import com.intellij.lang.properties.structureView.PropertiesPrefixGroup;
 import com.intellij.openapi.actionSystem.*;
 import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.command.WriteCommandAction;
+import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.editor.Editor;
 import com.intellij.openapi.fileEditor.FileEditor;
 import com.intellij.openapi.fileEditor.FileEditorManager;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.ui.InputValidator;
 import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.Pair;
 import com.intellij.openapi.vfs.ReadonlyStatusHandler;
 import com.intellij.openapi.vfs.VirtualFile;
 import org.jetbrains.annotations.NotNull;
@@ -38,6 +42,9 @@ import org.jetbrains.annotations.Nullable;
 * @author Dmitry Batkovich
 */
 class NewPropertyAction extends AnAction {
+  private final static Logger LOG = Logger.getInstance(NewPropertyAction.class);
+
+  private final static String ADD_NEW_PROPERTY_AFTER_SELECTED_PROP = "add.property.after.selected";
 
   private final boolean myEnabledForce;
 
@@ -111,12 +118,60 @@ class NewPropertyAction extends AnAction {
         throw new IllegalStateException("unsupported type: " + selectedElement.getClass());
       }
     }
-    Messages.showInputDialog(project,
-                             PropertiesBundle.message("new.property.dialog.name.prompt.text"),
-                             PropertiesBundle.message("new.property.dialog.title"),
-                             Messages.getQuestionIcon(),
-                             null,
-                             new NewPropertyNameValidator(resourceBundleEditor, prefix, separator));
+
+    final ResourceBundlePropertiesUpdateManager propertiesUpdateManager = resourceBundleEditor.getPropertiesInsertDeleteManager();
+    final NewPropertyNameValidator nameValidator = new NewPropertyNameValidator(resourceBundleEditor, prefix, separator);
+    final String keyToInsert;
+
+    final IProperty anchor;
+    IProperty selectedProperty = resourceBundleEditor.getSelectedProperty();
+    if (propertiesUpdateManager.isAlphaSorted() || !propertiesUpdateManager.isSorted() || selectedProperty == null) {
+      keyToInsert = Messages.showInputDialog(project,
+                                             PropertiesBundle.message("new.property.dialog.name.prompt.text"),
+                                             PropertiesBundle.message("new.property.dialog.title"),
+                                             Messages.getQuestionIcon(),
+                                             null,
+                                             nameValidator);
+      anchor = null;
+    } else {
+      final Pair<String, Boolean> keyNameAndInsertPlaceModification =
+        Messages.showInputDialogWithCheckBox(PropertiesBundle.message("new.property.dialog.name.prompt.text"),
+                                             PropertiesBundle.message("new.property.dialog.title"),
+                                             PropertiesBundle.message("new.property.dialog.checkbox.text"),
+                                             PropertiesComponent.getInstance().getBoolean(ADD_NEW_PROPERTY_AFTER_SELECTED_PROP, false),
+                                             true,
+                                             Messages.getQuestionIcon(),
+                                             null,
+                                             nameValidator);
+      keyToInsert = keyNameAndInsertPlaceModification.getFirst();
+      final Boolean insertAfterSelecterProperty = keyNameAndInsertPlaceModification.getSecond();
+      PropertiesComponent.getInstance().setValue(ADD_NEW_PROPERTY_AFTER_SELECTED_PROP, insertAfterSelecterProperty, false);
+      anchor = insertAfterSelecterProperty ? selectedProperty : null;
+    }
+    if (keyToInsert != null) {
+      final ResourceBundlePropertiesUpdateManager updateManager = resourceBundleEditor.getPropertiesInsertDeleteManager();
+      final Runnable insertionAction = () -> {
+        if (anchor == null) {
+          updateManager.insertNewProperty(keyToInsert, "");
+        } else {
+          final String anchorKey = anchor.getKey();
+          LOG.assertTrue(anchorKey != null);
+          updateManager.insertAfter(keyToInsert, "", anchorKey);
+        }
+      };
+      ResourceBundleEditor finalResourceBundleEditor = resourceBundleEditor;
+      ApplicationManager.getApplication().runWriteAction(() -> {
+        WriteCommandAction.runWriteCommandAction(bundle.getProject(), insertionAction);
+        finalResourceBundleEditor.flush();
+      });
+
+      resourceBundleEditor.updateTreeRoot();
+      resourceBundleEditor
+        .getStructureViewComponent()
+        .getTreeBuilder()
+        .queueUpdate()
+        .doWhenDone(() -> finalResourceBundleEditor.selectProperty(keyToInsert));
+    }
   }
 
   @Override
@@ -160,14 +215,6 @@ class NewPropertyAction extends AnAction {
         }
       }
 
-      final Runnable action = () -> {
-        myResourceBundleEditor.getPropertiesInsertDeleteManager().insertNewProperty(newPropertyName, "");
-        myResourceBundleEditor.flush();
-      };
-      ApplicationManager.getApplication().runWriteAction(() -> WriteCommandAction.runWriteCommandAction(resourceBundle.getProject(), action));
-
-      myResourceBundleEditor.updateTreeRoot();
-      myResourceBundleEditor.selectProperty(newPropertyName);
       return true;
     }
   }
index fb619d7c27e0e24effcb53cf90e90267d43cb848..d36c3c586def9b3f1a9d7e7e8a4ae4a0a53c5fe6 100644 (file)
@@ -615,7 +615,7 @@ public class ResourceBundleEditor extends UserDataHolderBase implements Document
   }
 
   @Nullable
-  private IProperty getSelectedProperty() {
+  IProperty getSelectedProperty() {
     final Collection<DefaultMutableTreeNode> selectedNode = getSelectedNodes();
     if (selectedNode.isEmpty()) {
       return null;
index 7525df9f23389f6de459642f2074fee8e2135971..2d34a3de9342cb0559389861d1e173786885b088 100644 (file)
@@ -34,8 +34,8 @@ import com.intellij.util.IncorrectOperationException;
 import com.intellij.util.graph.CachingSemiGraph;
 import com.intellij.util.graph.DFSTBuilder;
 import com.intellij.util.graph.GraphGenerator;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
-import org.jetbrains.annotations.TestOnly;
 
 import java.util.*;
 
@@ -72,6 +72,17 @@ public class ResourceBundlePropertiesUpdateManager {
     }
   }
 
+  public void insertAfter(@NotNull String key, @NotNull String value, @NotNull String anchor) {
+    if (myAlphaSorted || !myOrdered) {
+      throw new IllegalStateException("Can't insert new properties by anchor while resource bundle is alpha-sorted");
+    }
+     final PropertiesFile file = myResourceBundle.getDefaultPropertiesFile();
+    final IProperty anchorProperty = file.findPropertyByKey(anchor);
+    file.addPropertyAfter(key, value, anchorProperty);
+    final int anchorIndex = myKeysOrder.indexOf(anchor);
+    myKeysOrder.add(anchorIndex + 1, key);
+  }
+
   public void insertOrUpdateTranslation(String key, String value, final PropertiesFile propertiesFile) throws IncorrectOperationException {
     final IProperty property = propertiesFile.findPropertyByKey(key);
     if (property != null) {
@@ -214,8 +225,11 @@ public class ResourceBundlePropertiesUpdateManager {
     }
   }
 
-  @TestOnly
   public boolean isAlphaSorted() {
     return myAlphaSorted;
   }
+
+  public boolean isSorted() {
+    return myOrdered;
+  }
 }