diff options
author | Tor Norbye <tnorbye@google.com> | 2011-07-14 15:35:14 -0700 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2011-07-14 16:53:15 -0700 |
commit | 271993a2368361fb1f67ea9c1388a352e9df43f5 (patch) | |
tree | 1bae0f8abda3625b9e63e0f099819b4b54681698 | |
parent | 654dc86699080b7c7b9931ad35f823c848eb2e9c (diff) | |
download | sdk-271993a2368361fb1f67ea9c1388a352e9df43f5.zip sdk-271993a2368361fb1f67ea9c1388a352e9df43f5.tar.gz sdk-271993a2368361fb1f67ea9c1388a352e9df43f5.tar.bz2 |
Sort XML attributes logically
This changeset modifies the layout editor such that it writes
attributes in a certain order:
* id
* style
* layout_width
* layout_height
* other layout_ attributes, sorted alphabetically
* other attributes, sorted alphabetically
The layout editor will produce attributes in this order when
- New widgets are dragged into the layout
- Widgets are moved in the layout
- It will also insert attributes in the right place when they are set
as the result of (for example) using the context menu actions.
Note that this ordering is applied unconditionally - there is no user
setting to turn it off. However, note that the current behavior is
random - moving a view for example will scramble the attributes (in an
order which is related to hashkeys in a map), so the option would be
"sort attributes logically" versus "sort attributes randomly"; if we
want an option to "leave attribute order alone" that will need to be
implemented.
Limitations:
- This does not yet modify the formatter to reorganize attributes.
Thus, Ctrl-Shift-F to reformat the XML will not change attribute
order.
- It does not fix the problem that the XML model updater does not
respect the formatting settings (such as one newline per attribute)
when manipulating attributes.
This will be addressed/worked around in subsequent CLs.
Implementation Note:
The Eclipse XML model updater will unconditionally *append* any new
attributes. We take advantage of this to perform attribute sorting by
ensuring that we always insert new attributes in the right order. We
also check for existing attributes and any which fall
lexicographically later than the new attributes are removed and
reinserted in the right sequence. In order to avoid performing these
removals and additions repeatedly on a node when we set multiple
attributes, and to avoid flushing attribute changes *immediately*
(which was the case until this), we now queue up all pending attribute
values in the nodes and apply them at the end when all attribute
changes for a given node are known.
Change-Id: If39f8c29f26e281f7c6622a31e11ba49724d274a
11 files changed, 277 insertions, 21 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ClipboardSupport.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ClipboardSupport.java index f3582ec..c778271 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ClipboardSupport.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ClipboardSupport.java @@ -16,8 +16,8 @@ package com.android.ide.eclipse.adt.internal.editors.layout.gle2; import com.android.ide.common.api.IDragElement; -import com.android.ide.common.api.INode; import com.android.ide.common.api.IDragElement.IDragAttribute; +import com.android.ide.common.api.INode; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils; import com.android.ide.eclipse.adt.internal.editors.descriptors.XmlnsAttributeDescriptor; @@ -226,6 +226,7 @@ public class ClipboardSupport { List<INode> children = entry.getValue(); assert children != null && children.size() > 0; rulesEngine.callOnRemovingChildren(editor, parent, children); + parent.applyPendingChanges(); } for (SelectionItem cs : selection) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/MoveGesture.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/MoveGesture.java index c8fab84..45e0234 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/MoveGesture.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/MoveGesture.java @@ -361,6 +361,7 @@ public class MoveGesture extends DropGesture { mFeedback, new Point(canvasPoint.x, canvasPoint.y), insertType); + mTargetNode.applyPendingChanges(); // Clean up drag if applicable if (event.detail == DND.DROP_MOVE) { GlobalCanvasDragInfo.getInstance().removeSource(); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlineDropListener.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlineDropListener.java index 5f516d5..cf09160 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlineDropListener.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlineDropListener.java @@ -130,6 +130,7 @@ import java.util.Set; Object sourceCanvas = GlobalCanvasDragInfo.getInstance().getSourceCanvas(); boolean createNew = event.detail == DND.DROP_COPY || sourceCanvas != canvas; BaseLayoutRule.insertAt(targetNode, elements, createNew, indexFinal); + targetNode.applyPendingChanges(); // Clean up drag if applicable if (event.detail == DND.DROP_MOVE) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlinePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlinePage.java index cafcc13..7c0a365 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlinePage.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlinePage.java @@ -838,6 +838,7 @@ public class OutlinePage extends ContentOutlinePage canvas.getRulesEngine().setInsertType(insertType); int index = target.getSecond(); BaseLayoutRule.insertAt(targetNode, elements, false, index); + targetNode.applyPendingChanges(); canvas.getClipboardSupport().deleteSelection("Remove", dragSelection); } }); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleAttribute.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleAttribute.java index fef1a56..4233208 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleAttribute.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleAttribute.java @@ -16,7 +16,6 @@ package com.android.ide.eclipse.adt.internal.editors.layout.gle2; -import com.android.ide.common.api.IDragElement.IDragAttribute; import com.android.ide.common.api.INode.IAttribute; import java.util.regex.Matcher; @@ -33,7 +32,7 @@ import java.util.regex.Pattern; * For a more detailed explanation of the purpose of this class, * please see {@link SimpleXmlTransfer}. */ -public class SimpleAttribute implements IDragAttribute, IAttribute { +public class SimpleAttribute implements IAttribute { private final String mName; private final String mValue; private final String mUri; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleElement.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleElement.java index 20a8433..cf42077 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleElement.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleElement.java @@ -20,6 +20,7 @@ import com.android.ide.common.api.IDragElement; import com.android.ide.common.api.Rect; import java.util.ArrayList; +import java.util.List; /** * Represents an XML element with a name, attributes and inner elements. @@ -39,8 +40,8 @@ public class SimpleElement implements IDragElement { private final String mParentFqcn; private final Rect mBounds; private final Rect mParentBounds; - private final ArrayList<IDragAttribute> mAttributes = new ArrayList<IDragAttribute>(); - private final ArrayList<IDragElement> mElements = new ArrayList<IDragElement>(); + private final List<IDragAttribute> mAttributes = new ArrayList<IDragAttribute>(); + private final List<IDragElement> mElements = new ArrayList<IDragElement>(); private IDragAttribute[] mCachedAttributes = null; private IDragElement[] mCachedElements = null; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/NodeProxy.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/NodeProxy.java index c4c050a..b27954e 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/NodeProxy.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/NodeProxy.java @@ -43,7 +43,9 @@ import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * @@ -53,6 +55,8 @@ public class NodeProxy implements INode { private final UiViewElementNode mNode; private final Rect mBounds; private final NodeFactory mFactory; + /** Map from URI to Map(key=>value) (where no namespace uses "" as a key) */ + private Map<String, Map<String, String>> mPendingAttributes; /** * Creates a new {@link INode} that wraps an {@link UiViewElementNode} that is @@ -208,6 +212,7 @@ public class NodeProxy implements INode { // Finally execute the closure that will act on the XML c.handle(NodeProxy.this); + applyPendingChanges(); } }); } @@ -295,9 +300,24 @@ public class NodeProxy implements INode { public boolean setAttribute(String uri, String name, String value) { checkEditOK(); - UiAttributeNode attr = mNode.setAttributeValue(name, uri, value, true /* override */); - mNode.commitDirtyAttributesToXml(); + + if (uri == null) { + uri = ""; //$NON-NLS-1$ + } + + Map<String, String> map = null; + if (mPendingAttributes == null) { + // Small initial size: we don't expect many different namespaces + mPendingAttributes = new HashMap<String, Map<String, String>>(3); + } else { + map = mPendingAttributes.get(uri); + } + if (map == null) { + map = new HashMap<String, String>(); + mPendingAttributes.put(uri, map); + } + map.put(name, value); return attr != null; } @@ -309,6 +329,16 @@ public class NodeProxy implements INode { return null; } + if (mPendingAttributes != null) { + Map<String, String> map = mPendingAttributes.get(uri == null ? "" : uri); //$NON-NLS-1$ + if (map != null) { + String value = map.get(attrName); + if (value != null) { + return value; + } + } + } + if (uiNode.getXmlNode() != null) { Node xmlNode = uiNode.getXmlNode(); if (xmlNode != null) { @@ -413,4 +443,25 @@ public class NodeProxy implements INode { ); } + /** + * If there are any pending changes in these nodes, apply them now + * + * @return true if any modifications were made + */ + public boolean applyPendingChanges() { + boolean modified = false; + + // Flush all pending attributes + if (mPendingAttributes != null) { + mNode.commitDirtyAttributesToXml(); + modified = true; + mPendingAttributes = null; + + } + for (INode child : getChildren()) { + modified |= ((NodeProxy) child).applyPendingChanges(); + } + + return modified; + } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java index deb566e..5b2d430 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java @@ -555,6 +555,10 @@ public class RulesEngine { if (childRule != null) { childRule.onCreate(newNode, parentNode, insertType); } + + if (parentNode != null) { + ((NodeProxy) parentNode).applyPendingChanges(); + } } /** diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiAttributeNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiAttributeNode.java index 9c822f6..94cea34 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiAttributeNode.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiAttributeNode.java @@ -16,6 +16,12 @@ package com.android.ide.eclipse.adt.internal.editors.uimodel; +import static com.android.ide.common.layout.LayoutConstants.ATTR_ID; +import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_HEIGHT; +import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_PREFIX; +import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_WIDTH; +import static com.android.ide.common.layout.LayoutConstants.ATTR_STYLE; + import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor; import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor; @@ -23,6 +29,8 @@ import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.forms.IManagedForm; import org.w3c.dom.Node; +import java.util.Comparator; + /** * Represents an XML attribute that can be modified by the XML editor's user interface. * <p/> @@ -32,7 +40,7 @@ import org.w3c.dom.Node; * This is an abstract class. Derived classes must implement the creation of the UI * and manage its synchronization with the XML. */ -public abstract class UiAttributeNode { +public abstract class UiAttributeNode implements Comparable<UiAttributeNode> { private AttributeDescriptor mDescriptor; private UiElementNode mUiParent; @@ -73,12 +81,14 @@ public abstract class UiAttributeNode { * <p/> * Subclasses should set the to true as a result of user interaction with the widgets in * the section and then should set to false when the commit() method completed. + * + * @param isDirty the new value to set the dirty-flag to */ public void setDirty(boolean isDirty) { - boolean old_value = mIsDirty; + boolean wasDirty = mIsDirty; mIsDirty = isDirty; // TODO: for unknown attributes, getParent() != null && getParent().getEditor() != null - if (old_value != isDirty) { + if (wasDirty != isDirty) { AndroidXmlEditor editor = getUiParent().getEditor(); if (editor != null) { editor.editorDirtyStateChanged(); @@ -141,9 +151,9 @@ public abstract class UiAttributeNode { * so it will call this to refresh the attribute anyway. It's up to the * UI implementation to minimize refreshes. * - * @param xml_attribute_node + * @param node the node to read the value from */ - public abstract void updateValue(Node xml_attribute_node); + public abstract void updateValue(Node node); /** * Called by the user interface when the editor is saved or its state changed @@ -160,4 +170,63 @@ public abstract class UiAttributeNode { * </ul> */ public abstract void commit(); + + // ---- Implements Comparable ---- + public int compareTo(UiAttributeNode o) { + return compareAttributes(mDescriptor.getXmlLocalName(), o.mDescriptor.getXmlLocalName()); + } + + /** + * Returns {@link Comparator} values for ordering attributes in the following + * order: + * <ul> + * <li> id + * <li> style + * <li> layout_width + * <li> layout_height + * <li> other layout params, sorted alphabetically + * <li> other attributes, sorted alphabetically + * </ul> + * + * @param name1 the first attribute name to compare + * @param name2 the second attribute name to compare + * @return a negative number if name1 should be ordered before name2 + */ + public static int compareAttributes(String name1, String name2) { + int priority1 = getAttributePriority(name1); + int priority2 = getAttributePriority(name2); + if (priority1 != priority2) { + return priority1 - priority2; + } + + // Sort remaining attributes alphabetically + return name1.compareTo(name2); + } + + /** Returns a sorting priority for the given attribute name */ + private static int getAttributePriority(String name) { + if (ATTR_ID.equals(name)) { + return 10; + } + + if (ATTR_STYLE.equals(name)) { + return 20; + } + + if (name.startsWith(ATTR_LAYOUT_PREFIX)) { + // Width and height are special cased because we (a) want width and height + // before the other layout attributes, and (b) we want width to sort before height + // even though it comes after it alphabetically. + if (name.equals(ATTR_LAYOUT_WIDTH)) { + return 30; + } + if (name.equals(ATTR_LAYOUT_HEIGHT)) { + return 40; + } + + return 50; + } + + return 60; + } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiElementNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiElementNode.java index 3f7fadd..37273eb 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiElementNode.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiElementNode.java @@ -1045,6 +1045,8 @@ public class UiElementNode implements IPropertySource { // Set all initial attributes in the XML node if they are not empty. // Iterate on the descriptor list to get the desired order and then use the // internal values, if any. + List<UiAttributeNode> addAttributes = new ArrayList<UiAttributeNode>(); + for (AttributeDescriptor attrDesc : getAttributeDescriptors()) { if (attrDesc instanceof XmlnsAttributeDescriptor) { XmlnsAttributeDescriptor desc = (XmlnsAttributeDescriptor) attrDesc; @@ -1055,10 +1057,31 @@ public class UiElementNode implements IPropertySource { mXmlNode.getAttributes().setNamedItemNS(attr); } else { UiAttributeNode uiAttr = getInternalUiAttributes().get(attrDesc); - commitAttributeToXml(uiAttr, uiAttr.getCurrentValue()); + + // Don't apply the attribute immediately, instead record this attribute + // such that we can gather all attributes and sort them first. + // This is necessary because the XML model will *append* all attributes + // so we want to add them in a particular order. + // (Note that we only have to worry about UiAttributeNodes with non null + // values, since this is a new node and we therefore don't need to attempt + // to remove existing attributes) + String value = uiAttr.getCurrentValue(); + if (value != null && value.length() > 0) { + addAttributes.add(uiAttr); + } } } + // Sort and apply the attributes in order, because the Eclipse XML model will always + // append the XML attributes, so by inserting them in our desired order they will + // appear that way in the XML + Collections.sort(addAttributes); + + for (UiAttributeNode node : addAttributes) { + commitAttributeToXml(node, node.getCurrentValue()); + node.setDirty(false); + } + if (mUiParent != null) { mUiParent.formatOnInsert(this); } @@ -1518,12 +1541,18 @@ public class UiElementNode implements IPropertySource { if (doc != null) { Attr attr; if (attrNsUri != null && attrNsUri.length() > 0) { - attr = doc.createAttributeNS(attrNsUri, attrLocalName); - attr.setPrefix(lookupNamespacePrefix(element, attrNsUri)); - attrMap.setNamedItemNS(attr); + attr = (Attr) attrMap.getNamedItemNS(attrNsUri, attrLocalName); + if (attr == null) { + attr = doc.createAttributeNS(attrNsUri, attrLocalName); + attr.setPrefix(lookupNamespacePrefix(element, attrNsUri)); + attrMap.setNamedItemNS(attr); + } } else { - attr = doc.createAttribute(attrLocalName); - attrMap.setNamedItem(attr); + attr = (Attr) attrMap.getNamedItem(attrLocalName); + if (attr == null) { + attr = doc.createAttribute(attrLocalName); + attrMap.setNamedItem(attr); + } } attr.setValue(newValue); return true; @@ -1549,14 +1578,110 @@ public class UiElementNode implements IPropertySource { * @return True if one or more values were actually modified or removed, * false if nothing changed. */ + @SuppressWarnings("null") // Eclipse is confused by the logic and gets it wrong public boolean commitDirtyAttributesToXml() { boolean result = false; + List<UiAttributeNode> dirtyAttributes = new ArrayList<UiAttributeNode>(); for (UiAttributeNode uiAttr : getAllUiAttributes()) { if (uiAttr.isDirty()) { - result |= commitAttributeToXml(uiAttr, uiAttr.getCurrentValue()); - uiAttr.setDirty(false); + String value = uiAttr.getCurrentValue(); + if (value != null && value.length() > 0) { + // Defer the new attributes: set these last and in order + dirtyAttributes.add(uiAttr); + } else { + result |= commitAttributeToXml(uiAttr, value); + uiAttr.setDirty(false); + } } } + if (dirtyAttributes.size() > 0) { + result = true; + + Collections.sort(dirtyAttributes); + + // The Eclipse XML model will *always* append new attributes. + // Therefore, if any of the dirty attributes are new, they will appear + // after any existing, clean attributes on the element. To fix this, + // we need to first remove any of these attributes, then insert them + // back in the right order. + Node element = prepareCommit(); + if (element == null) { + return result; + } + + String firstName = dirtyAttributes.get(0).getDescriptor().getXmlLocalName(); + NamedNodeMap attributes = ((Element) element).getAttributes(); + List<Attr> move = new ArrayList<Attr>(); + for (int i = 0, n = attributes.getLength(); i < n; i++) { + Attr attribute = (Attr) attributes.item(i); + if (UiAttributeNode.compareAttributes(attribute.getLocalName(), firstName) > 0) { + move.add(attribute); + } + } + + for (Attr attribute : move) { + if (attribute.getNamespaceURI() != null) { + attributes.removeNamedItemNS(attribute.getNamespaceURI(), + attribute.getLocalName()); + } else { + attributes.removeNamedItem(attribute.getName()); + } + } + + // Merge back the removed DOM attribute nodes and the new UI attribute nodes. + // In cases where the attribute DOM name and the UI attribute names equal, + // skip the DOM nodes and just apply the UI attributes. + int domAttributeIndex = 0; + int domAttributeIndexMax = move.size(); + int uiAttributeIndex = 0; + int uiAttributeIndexMax = dirtyAttributes.size(); + + while (true) { + Attr domAttribute; + UiAttributeNode uiAttribute; + + int compare; + if (uiAttributeIndex < uiAttributeIndexMax) { + if (domAttributeIndex < domAttributeIndexMax) { + domAttribute = move.get(domAttributeIndex); + uiAttribute = dirtyAttributes.get(uiAttributeIndex); + + String domAttributeName = domAttribute.getLocalName(); + String uiAttributeName = uiAttribute.getDescriptor().getXmlLocalName(); + compare = UiAttributeNode.compareAttributes(domAttributeName, + uiAttributeName); + } else { + compare = 1; + uiAttribute = dirtyAttributes.get(uiAttributeIndex); + domAttribute = null; + } + } else if (domAttributeIndex < domAttributeIndexMax) { + compare = -1; + domAttribute = move.get(domAttributeIndex); + uiAttribute = null; + } else { + break; + } + + if (compare < 0) { + if (domAttribute.getNamespaceURI() != null) { + attributes.setNamedItemNS(domAttribute); + } else { + attributes.setNamedItem(domAttribute); + } + domAttributeIndex++; + } else { + assert compare >= 0; + if (compare == 0) { + domAttributeIndex++; + } + commitAttributeToXml(uiAttribute, uiAttribute.getCurrentValue()); + uiAttribute.setDirty(false); + uiAttributeIndex++; + } + } + } + return result; } diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestAttribute.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestAttribute.java index fc59ba8..7ff425f 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestAttribute.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestAttribute.java @@ -17,6 +17,7 @@ package com.android.ide.common.layout; import com.android.ide.common.api.IDragElement.IDragAttribute; import com.android.ide.common.api.INode.IAttribute; +import com.android.ide.eclipse.adt.internal.editors.uimodel.UiAttributeNode; /** Test/mock implementation of {@link IAttribute} and {@link IDragAttribute} */ public class TestAttribute implements IAttribute, IDragAttribute { @@ -50,5 +51,7 @@ public class TestAttribute implements IAttribute, IDragAttribute { return "TestAttribute [name=" + mName + ", uri=" + mUri + ", value=" + mValue + "]"; } - + public int compareTo(IDragAttribute o) { + return UiAttributeNode.compareAttributes(mName, o.getName()); + } }
\ No newline at end of file |