diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/NodeProxy.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/NodeProxy.java | 517 |
1 files changed, 0 insertions, 517 deletions
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 deleted file mode 100644 index 19d5e16b0..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/NodeProxy.java +++ /dev/null @@ -1,517 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php - * - * 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.android.ide.eclipse.adt.internal.editors.layout.gre; - -import com.android.annotations.NonNull; -import com.android.annotations.Nullable; -import com.android.ide.common.api.IAttributeInfo; -import com.android.ide.common.api.INode; -import com.android.ide.common.api.INodeHandler; -import com.android.ide.common.api.Margins; -import com.android.ide.common.api.Rect; -import com.android.ide.common.resources.platform.AttributeInfo; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor; -import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor; -import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils; -import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate; -import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor; -import com.android.ide.eclipse.adt.internal.editors.layout.gle2.CanvasViewInfo; -import com.android.ide.eclipse.adt.internal.editors.layout.gle2.SimpleAttribute; -import com.android.ide.eclipse.adt.internal.editors.layout.gle2.SwtUtils; -import com.android.ide.eclipse.adt.internal.editors.layout.gle2.ViewHierarchy; -import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode; -import com.android.ide.eclipse.adt.internal.editors.uimodel.UiAttributeNode; -import com.android.ide.eclipse.adt.internal.editors.uimodel.UiDocumentNode; -import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode; -import com.android.ide.eclipse.adt.internal.project.SupportLibraryHelper; - -import org.eclipse.core.resources.IProject; -import org.eclipse.swt.graphics.Rectangle; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * - */ -public class NodeProxy implements INode { - private static final Margins NO_MARGINS = new Margins(0, 0, 0, 0); - 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 - * actually valid in the current UI/XML model. The view may not be part of the canvas - * yet (e.g. if it has just been dynamically added and the canvas hasn't reloaded yet.) - * <p/> - * This method is package protected. To create a node, please use {@link NodeFactory} instead. - * - * @param uiNode The node to wrap. - * @param bounds The bounds of a the view in the canvas. Must be either: <br/> - * - a valid rect for a view that is actually in the canvas <br/> - * - <b>*or*</b> null (or an invalid rect) for a view that has just been added dynamically - * to the model. We never store a null bounds rectangle in the node, a null rectangle - * will be converted to an invalid rectangle. - * @param factory A {@link NodeFactory} to create unique children nodes. - */ - /*package*/ NodeProxy(UiViewElementNode uiNode, Rectangle bounds, NodeFactory factory) { - mNode = uiNode; - mFactory = factory; - if (bounds == null) { - mBounds = new Rect(); - } else { - mBounds = SwtUtils.toRect(bounds); - } - } - - @Override - public @NonNull Rect getBounds() { - return mBounds; - } - - @Override - public @NonNull Margins getMargins() { - ViewHierarchy viewHierarchy = mFactory.getCanvas().getViewHierarchy(); - CanvasViewInfo view = viewHierarchy.findViewInfoFor(this); - if (view != null) { - Margins margins = view.getMargins(); - if (margins != null) { - return margins; - } - } - - return NO_MARGINS; - } - - - @Override - public int getBaseline() { - ViewHierarchy viewHierarchy = mFactory.getCanvas().getViewHierarchy(); - CanvasViewInfo view = viewHierarchy.findViewInfoFor(this); - if (view != null) { - return view.getBaseline(); - } - - return -1; - } - - /** - * Updates the bounds of this node proxy. Bounds cannot be null, but it can be invalid. - * This is a package-protected method, only the {@link NodeFactory} uses this method. - */ - /*package*/ void setBounds(Rectangle bounds) { - SwtUtils.set(mBounds, bounds); - } - - /** - * Returns the {@link UiViewElementNode} corresponding to this - * {@link NodeProxy}. - * - * @return The {@link UiViewElementNode} corresponding to this - * {@link NodeProxy} - */ - public UiViewElementNode getNode() { - return mNode; - } - - @Override - public @NonNull String getFqcn() { - if (mNode != null) { - ElementDescriptor desc = mNode.getDescriptor(); - if (desc instanceof ViewElementDescriptor) { - return ((ViewElementDescriptor) desc).getFullClassName(); - } - } - - return ""; - } - - - // ---- Hierarchy handling ---- - - - @Override - public INode getRoot() { - if (mNode != null) { - UiElementNode p = mNode.getUiRoot(); - // The node root should be a document. Instead what we really mean to - // return is the top level view element. - if (p instanceof UiDocumentNode) { - List<UiElementNode> children = p.getUiChildren(); - if (children.size() > 0) { - p = children.get(0); - } - } - - // Cope with a badly structured XML layout - while (p != null && !(p instanceof UiViewElementNode)) { - p = p.getUiNextSibling(); - } - - if (p == mNode) { - return this; - } - if (p instanceof UiViewElementNode) { - return mFactory.create((UiViewElementNode) p); - } - } - - return null; - } - - @Override - public INode getParent() { - if (mNode != null) { - UiElementNode p = mNode.getUiParent(); - if (p instanceof UiViewElementNode) { - return mFactory.create((UiViewElementNode) p); - } - } - - return null; - } - - @Override - public @NonNull INode[] getChildren() { - if (mNode != null) { - List<UiElementNode> uiChildren = mNode.getUiChildren(); - List<INode> nodes = new ArrayList<INode>(uiChildren.size()); - for (UiElementNode uiChild : uiChildren) { - if (uiChild instanceof UiViewElementNode) { - nodes.add(mFactory.create((UiViewElementNode) uiChild)); - } - } - - return nodes.toArray(new INode[nodes.size()]); - } - - return new INode[0]; - } - - - // ---- XML Editing --- - - @Override - public void editXml(@NonNull String undoName, final @NonNull INodeHandler c) { - final AndroidXmlEditor editor = mNode.getEditor(); - - if (editor != null) { - // Create an undo edit XML wrapper, which takes a runnable - editor.wrapUndoEditXmlModel( - undoName, - new Runnable() { - @Override - public void run() { - // Here editor.isEditXmlModelPending returns true and it - // is safe to edit the model using any method from INode. - - // Finally execute the closure that will act on the XML - c.handle(NodeProxy.this); - applyPendingChanges(); - } - }); - } - } - - private void checkEditOK() { - final AndroidXmlEditor editor = mNode.getEditor(); - if (!editor.isEditXmlModelPending()) { - throw new RuntimeException("Error: XML edit call without using INode.editXml!"); - } - } - - @Override - public @NonNull INode appendChild(@NonNull String viewFqcn) { - return insertOrAppend(viewFqcn, -1); - } - - @Override - public @NonNull INode insertChildAt(@NonNull String viewFqcn, int index) { - return insertOrAppend(viewFqcn, index); - } - - @Override - public void removeChild(@NonNull INode node) { - checkEditOK(); - - ((NodeProxy) node).mNode.deleteXmlNode(); - } - - private INode insertOrAppend(String viewFqcn, int index) { - checkEditOK(); - - AndroidXmlEditor editor = mNode.getEditor(); - if (editor != null) { - // Possibly replace the tag with a compatibility version if the - // minimum SDK requires it - IProject project = editor.getProject(); - if (project != null) { - viewFqcn = SupportLibraryHelper.getTagFor(project, viewFqcn); - } - } - - // Find the descriptor for this FQCN - ViewElementDescriptor vd = getFqcnViewDescriptor(viewFqcn); - if (vd == null) { - warnPrintf("Can't create a new %s element", viewFqcn); - return null; - } - - final UiElementNode uiNew; - if (index == -1) { - // Append at the end. - uiNew = mNode.appendNewUiChild(vd); - } else { - // Insert at the requested position or at the end. - int n = mNode.getUiChildren().size(); - if (index < 0 || index >= n) { - uiNew = mNode.appendNewUiChild(vd); - } else { - uiNew = mNode.insertNewUiChild(index, vd); - } - } - - // Set default attributes -- but only for new widgets (not when moving or copying) - RulesEngine engine = null; - LayoutEditorDelegate delegate = LayoutEditorDelegate.fromEditor(editor); - if (delegate != null) { - engine = delegate.getRulesEngine(); - } - if (engine == null || engine.getInsertType().isCreate()) { - // TODO: This should probably use IViewRule#getDefaultAttributes() at some point - DescriptorsUtils.setDefaultLayoutAttributes(uiNew, false /*updateLayout*/); - } - - Node xmlNode = uiNew.createXmlNode(); - - if (!(uiNew instanceof UiViewElementNode) || xmlNode == null) { - // Both things are not supposed to happen. When they do, we're in big trouble. - // We don't really know how to revert the state at this point and the UI model is - // now out of sync with the XML model. - // Panic ensues. - // The best bet is to abort now. The edit wrapper will release the edit and the - // XML/UI should get reloaded properly (with a likely invalid XML.) - warnPrintf("Failed to create a new %s element", viewFqcn); - throw new RuntimeException("XML node creation failed."); //$NON-NLS-1$ - } - - UiViewElementNode uiNewView = (UiViewElementNode) uiNew; - NodeProxy newNode = mFactory.create(uiNewView); - - if (engine != null) { - engine.callCreateHooks(editor, this, newNode, null); - } - - return newNode; - } - - @Override - public boolean setAttribute( - @Nullable String uri, - @NonNull String name, - @Nullable String value) { - checkEditOK(); - UiAttributeNode attr = mNode.setAttributeValue(name, uri, value, true /* override */); - - 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; - } - - @Override - public String getStringAttr(@Nullable String uri, @NonNull String attrName) { - UiElementNode uiNode = mNode; - - if (attrName == null) { - 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) { - NamedNodeMap nodeAttributes = xmlNode.getAttributes(); - if (nodeAttributes != null) { - Node attr = nodeAttributes.getNamedItemNS(uri, attrName); - if (attr != null) { - return attr.getNodeValue(); - } - } - } - } - return null; - } - - @Override - public IAttributeInfo getAttributeInfo(@Nullable String uri, @NonNull String attrName) { - UiElementNode uiNode = mNode; - - if (attrName == null) { - return null; - } - - for (AttributeDescriptor desc : uiNode.getAttributeDescriptors()) { - String dUri = desc.getNamespaceUri(); - String dName = desc.getXmlLocalName(); - if ((uri == null && dUri == null) || (uri != null && uri.equals(dUri))) { - if (attrName.equals(dName)) { - return desc.getAttributeInfo(); - } - } - } - - return null; - } - - @Override - public @NonNull IAttributeInfo[] getDeclaredAttributes() { - - AttributeDescriptor[] descs = mNode.getAttributeDescriptors(); - int n = descs.length; - IAttributeInfo[] infos = new AttributeInfo[n]; - - for (int i = 0; i < n; i++) { - infos[i] = descs[i].getAttributeInfo(); - } - - return infos; - } - - @Override - public @NonNull List<String> getAttributeSources() { - ElementDescriptor descriptor = mNode.getDescriptor(); - if (descriptor instanceof ViewElementDescriptor) { - return ((ViewElementDescriptor) descriptor).getAttributeSources(); - } else { - return Collections.emptyList(); - } - } - - @Override - public @NonNull IAttribute[] getLiveAttributes() { - UiElementNode uiNode = mNode; - - if (uiNode.getXmlNode() != null) { - Node xmlNode = uiNode.getXmlNode(); - if (xmlNode != null) { - NamedNodeMap nodeAttributes = xmlNode.getAttributes(); - if (nodeAttributes != null) { - - int n = nodeAttributes.getLength(); - IAttribute[] result = new IAttribute[n]; - for (int i = 0; i < n; i++) { - Node attr = nodeAttributes.item(i); - String uri = attr.getNamespaceURI(); - String name = attr.getLocalName(); - String value = attr.getNodeValue(); - - result[i] = new SimpleAttribute(uri, name, value); - } - return result; - } - } - } - - return new IAttribute[0]; - - } - - @Override - public String toString() { - return "NodeProxy [node=" + mNode + ", bounds=" + mBounds + "]"; - } - - // --- internal helpers --- - - /** - * Helper methods that returns a {@link ViewElementDescriptor} for the requested FQCN. - * Will return null if we can't find that FQCN or we lack the editor/data/descriptors info - * (which shouldn't really happen since at this point the SDK should be fully loaded and - * isn't reloading, or we wouldn't be here editing XML for a layout rule.) - */ - private ViewElementDescriptor getFqcnViewDescriptor(String fqcn) { - LayoutEditorDelegate delegate = LayoutEditorDelegate.fromEditor(mNode.getEditor()); - if (delegate != null) { - return delegate.getFqcnViewDescriptor(fqcn); - } - - return null; - } - - private void warnPrintf(String msg, Object...params) { - AdtPlugin.printToConsole( - mNode == null ? "" : mNode.getDescriptor().getXmlLocalName(), - String.format(msg, params) - ); - } - - /** - * 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; - } -} |