mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
XmlPropertiesFiles inserts property in alpha-order if it is possible
This commit is contained in:
+119
-26
@@ -33,7 +33,10 @@ import com.intellij.psi.util.CachedValuesManager;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.reference.SoftLazyValue;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import gnu.trove.THashMap;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
@@ -47,29 +50,54 @@ import java.util.*;
|
||||
* Date: 7/26/11
|
||||
*/
|
||||
public class XmlPropertiesFileImpl extends XmlPropertiesFile {
|
||||
|
||||
private static final Key<CachedValue<PropertiesFile>> KEY = Key.create("xml properties file");
|
||||
private final XmlFile myFile;
|
||||
private final SoftLazyValue<MultiMap<String, IProperty>> myPropertiesMap = new SoftLazyValue<MultiMap<String, IProperty>>() {
|
||||
private final SoftLazyValue<Info> myInfo = new SoftLazyValue<Info>() {
|
||||
@NotNull
|
||||
@Override
|
||||
protected MultiMap<String, IProperty> compute() {
|
||||
XmlTag rootTag = myFile.getRootTag();
|
||||
if (rootTag == null) {
|
||||
return MultiMap.emptyInstance();
|
||||
}
|
||||
|
||||
XmlTag[] entries = rootTag.findSubTags("entry");
|
||||
MultiMap<String, IProperty> map = new MultiMap<String, IProperty>();
|
||||
|
||||
for (XmlTag entry : entries) {
|
||||
XmlProperty property = new XmlProperty(entry, XmlPropertiesFileImpl.this);
|
||||
map.putValue(property.getKey(), property);
|
||||
}
|
||||
return map;
|
||||
protected Info compute() {
|
||||
return new Info();
|
||||
}
|
||||
};
|
||||
|
||||
private class Info {
|
||||
private final MultiMap<String, IProperty> myPropertiesMap = MultiMap.create();
|
||||
private List<IProperty> myPropertiesOrder;
|
||||
private boolean mySorted;
|
||||
|
||||
public Info() {
|
||||
XmlTag rootTag = myFile.getRootTag();
|
||||
final List<IProperty> propertiesOrder = new ArrayList<IProperty>();
|
||||
if (rootTag != null) {
|
||||
XmlTag[] entries = rootTag.findSubTags("entry");
|
||||
for (XmlTag entry : entries) {
|
||||
XmlProperty property = new XmlProperty(entry, XmlPropertiesFileImpl.this);
|
||||
propertiesOrder.add(property);
|
||||
myPropertiesMap.putValue(property.getKey(), property);
|
||||
}
|
||||
}
|
||||
mySorted = PropertiesImplUtil.isAlphaSorted(propertiesOrder);
|
||||
myPropertiesOrder = mySorted ? propertiesOrder : null;
|
||||
}
|
||||
|
||||
public void setSorted(boolean sorted) {
|
||||
mySorted = sorted;
|
||||
myPropertiesOrder = null;
|
||||
}
|
||||
|
||||
public MultiMap<String, IProperty> getPropertiesMap() {
|
||||
return myPropertiesMap;
|
||||
}
|
||||
|
||||
public List<IProperty> getPropertiesOrder() {
|
||||
return myPropertiesOrder;
|
||||
}
|
||||
|
||||
public boolean isSorted() {
|
||||
return mySorted;
|
||||
}
|
||||
}
|
||||
|
||||
private XmlPropertiesFileImpl(XmlFile file) {
|
||||
myFile = file;
|
||||
}
|
||||
@@ -83,19 +111,19 @@ public class XmlPropertiesFileImpl extends XmlPropertiesFile {
|
||||
@NotNull
|
||||
@Override
|
||||
public List<IProperty> getProperties() {
|
||||
return new ArrayList<IProperty>(myPropertiesMap.getValue().values());
|
||||
return new ArrayList<IProperty>(myInfo.getValue().getPropertiesMap().values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public IProperty findPropertyByKey(@NotNull @NonNls String key) {
|
||||
Collection<IProperty> properties = myPropertiesMap.getValue().get(key);
|
||||
Collection<IProperty> properties = myInfo.getValue().getPropertiesMap().get(key);
|
||||
return properties.isEmpty() ? null : properties.iterator().next();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<IProperty> findPropertiesByKey(@NotNull @NonNls String key) {
|
||||
return new ArrayList<IProperty>(myPropertiesMap.getValue().get(key));
|
||||
return new ArrayList<IProperty>(myInfo.getValue().getPropertiesMap().get(key));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -122,22 +150,62 @@ public class XmlPropertiesFileImpl extends XmlPropertiesFile {
|
||||
|
||||
@Override
|
||||
public IProperty addPropertyAfter(String key, String value, Property anchor) {
|
||||
return null;
|
||||
return addPropertyAfterAndCheckAlphaSorting(key, value, anchor, true, true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public IProperty addPropertyAfterAndCheckAlphaSorting(String key, String value, @Nullable IProperty anchor, boolean addToEnd, boolean checkAlphaSorting) {
|
||||
final XmlTag anchorTag = anchor == null ? null : (XmlTag)anchor.getPsiElement();
|
||||
final XmlTag rootTag = myFile.getRootTag();
|
||||
final XmlTag entry = createPropertyTag(key, value);
|
||||
final XmlTag addedEntry = (XmlTag) (anchorTag == null ? myFile.getRootTag().addSubTag(entry, !addToEnd) : rootTag.addAfter(entry, anchorTag));
|
||||
final XmlProperty property = new XmlProperty(addedEntry, this);
|
||||
myInfo.getValue().getPropertiesMap().putValue(key, property);
|
||||
if (checkAlphaSorting) {
|
||||
checkAlphaSorting(property);
|
||||
}
|
||||
return property;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public IProperty addProperty(String key, String value) {
|
||||
final XmlTag entry = createPropertyTag(key, value);
|
||||
if (myInfo.getValue().isSorted()) {
|
||||
final XmlProperty dummyProperty = new XmlProperty(entry, this);
|
||||
final int insertIndex = Collections.binarySearch(myInfo.getValue().getPropertiesOrder(), dummyProperty, new Comparator<IProperty>() {
|
||||
@Override
|
||||
public int compare(IProperty p1, IProperty p2) {
|
||||
final String k1 = p1.getKey();
|
||||
final String k2 = p2.getKey();
|
||||
return k1.compareTo(k2);
|
||||
}
|
||||
});
|
||||
final IProperty insertPosition;
|
||||
final IProperty inserted;
|
||||
if (insertIndex == -1) {
|
||||
inserted = addPropertyAfterAndCheckAlphaSorting(key, value, null, false, false);
|
||||
myInfo.getValue().getPropertiesOrder().add(0, inserted);
|
||||
}
|
||||
else {
|
||||
final int position = insertIndex < 0 ? -insertIndex - 2 : insertIndex;
|
||||
insertPosition = myInfo.getValue().getPropertiesOrder().get(position);
|
||||
inserted = addPropertyAfterAndCheckAlphaSorting(key, value, insertPosition, false, false);
|
||||
myInfo.getValue().getPropertiesOrder().add(position + 1, inserted);
|
||||
}
|
||||
return inserted;
|
||||
} else {
|
||||
return addPropertyAfterAndCheckAlphaSorting(key, value, null, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
private XmlTag createPropertyTag(final String key, final String value) {
|
||||
XmlTag rootTag = myFile.getRootTag();
|
||||
XmlTag entry = rootTag.createChildTag("entry", "", value, false);
|
||||
entry.setAttribute("key", key);
|
||||
rootTag.addSubTag(entry, false);
|
||||
final XmlProperty property = new XmlProperty(entry, this);
|
||||
myPropertiesMap.getValue().putValue(key, property);
|
||||
return property;
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
public static PropertiesFile getPropertiesFile(final PsiFile file) {
|
||||
CachedValuesManager manager = CachedValuesManager.getManager(file.getProject());
|
||||
if (file instanceof XmlFile) {
|
||||
@@ -194,7 +262,7 @@ public class XmlPropertiesFileImpl extends XmlPropertiesFile {
|
||||
|
||||
@Override
|
||||
public boolean isAlphaSorted() {
|
||||
return PropertiesImplUtil.isAlphaSorted(getProperties());
|
||||
return myInfo.getValue().isSorted();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -213,4 +281,29 @@ public class XmlPropertiesFileImpl extends XmlPropertiesFile {
|
||||
public int hashCode() {
|
||||
return myFile.hashCode();
|
||||
}
|
||||
|
||||
private void checkAlphaSorting(final IProperty property) {
|
||||
if (myInfo.getValue().isSorted()) {
|
||||
final String key = property.getKey();
|
||||
final XmlTag prev = getSibling((XmlTag)property.getPsiElement(), true);
|
||||
final String prevKey = prev == null ? null : new XmlProperty(prev, this).getKey();
|
||||
if (prevKey != null && key != null && prevKey.compareTo(key) > 0) {
|
||||
myInfo.getValue().setSorted(false);
|
||||
} else {
|
||||
final XmlTag next = getSibling((XmlTag)property.getPsiElement(), false);
|
||||
final String nextKey = next == null ? null : new XmlProperty(next, this).getKey();
|
||||
if (nextKey != null && key != null && nextKey.compareTo(key) < 0) {
|
||||
myInfo.getValue().setSorted(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static XmlTag getSibling(final XmlTag entry, final boolean prev) {
|
||||
XmlTag sibling = (XmlTag)(prev ? entry.getPrevSibling() : entry.getNextSibling());
|
||||
while (sibling != null && !"entry".equals(sibling.getName())) {
|
||||
sibling = (XmlTag)(prev ? sibling.getPrevSibling() : sibling.getNextSibling());
|
||||
}
|
||||
return sibling;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
|
||||
<properties>
|
||||
<comment>Hi</comment>
|
||||
<entry key="c">bar</entry>
|
||||
<entry key="m">baz</entry>
|
||||
</properties>
|
||||
@@ -9,6 +9,8 @@ import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.testFramework.PlatformTestCase;
|
||||
import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -81,6 +83,23 @@ public class XmlPropertiesTest extends LightPlatformCodeInsightFixtureTestCase {
|
||||
assertEquals("vvv", property2.getValue());
|
||||
}
|
||||
|
||||
public void testAddPropertyInAlphaOrder() {
|
||||
final PsiFile psiFile = myFixture.configureByFile("bar.xml");
|
||||
final PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile(psiFile);
|
||||
assertNotNull(propertiesFile);
|
||||
|
||||
WriteCommandAction.runWriteCommandAction(getProject(), new Runnable() {
|
||||
public void run() {
|
||||
propertiesFile.addProperty("d", "vvv");
|
||||
propertiesFile.addProperty("a", "vvv");
|
||||
propertiesFile.addProperty("l", "vvv");
|
||||
propertiesFile.addProperty("v", "vvv");
|
||||
}
|
||||
});
|
||||
assertTrue(propertiesFile.isAlphaSorted());
|
||||
assertTrue(PropertiesImplUtil.getPropertiesFile(psiFile).isAlphaSorted());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return PluginPathManager.getPluginHomePath("properties") + "/testData/xml/";
|
||||
|
||||
Reference in New Issue
Block a user