Home | History | Annotate | Download | only in gscripts
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Eclipse Public License, Version 1.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.eclipse.org/org/documents/epl-v10.php
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 
     18 package com.android.ide.eclipse.adt.editors.layout.gscripts;
     19 
     20 import com.android.ide.eclipse.adt.editors.layout.gscripts.IDragElement.IDragAttribute;
     21 
     22 import groovy.lang.Closure;
     23 
     24 
     25 /**
     26  * Represents a view in the XML layout being edited.
     27  * Each view or layout maps to exactly one XML node, thus the name.
     28  * <p/>
     29  * The primordial characteristic of a node is the fully qualified View class name that
     30  * it represents (a.k.a FQCN), for example "android.view.View" or "android.widget.Button".
     31  * <p/>
     32  * There are 2 kind of nodes:
     33  * - Nodes matching a view actually rendered in the layout canvas have a valid "bounds"
     34  *   rectangle that describe their position in pixels in the canvas. <br/>
     35  * - Nodes created by IViewRule scripts but not yet rendered have an invalid bounds rectangle
     36  *   since they only exist in the uncommitted XML model and not yet in the rendered View model.
     37  */
     38 public interface INode {
     39 
     40     /**
     41      * Returns the bounds of this node.
     42      * <p/>
     43      * The bounds are valid when this node maps a view that is already rendered.
     44      * Typically, if the node is the target of a drag'n'drop operation then you can be
     45      * guaranteed that its bounds are known and thus are valid.
     46      * <p/>
     47      * However the bounds are invalid (e.g. not known yet) for new XML elements
     48      * that have just been created, e.g. by the {@link #appendChild(String)} method.
     49      *
     50      * @return A non-null rectangle, in canvas coordinates.
     51      */
     52     Rect getBounds();
     53 
     54 
     55     // ---- Hierarchy handling ----
     56 
     57     /**
     58      * Returns the root element of the view hierarchy. This may be this node if this is
     59      * the root element. It can also be null when the current node is not yet or no
     60      * longer attached to the hierarchy.
     61      */
     62     INode getRoot();
     63 
     64     /**
     65      * Returns the parent node of this node, corresponding to the parent view in the layout.
     66      * The returned parent can be null when the node is the root element, or when the node is
     67      * not yet or no longer attached to the hierarchy.
     68      */
     69     INode getParent();
     70 
     71     /**
     72      * Returns the list of valid children nodes. The list can be empty but not null.
     73      */
     74     INode[] getChildren();
     75 
     76 
     77     // ---- XML Editing ---
     78 
     79     /**
     80      * Absolutely <em>all</em> calls that are going to edit the XML must be wrapped
     81      * by an editXml() call. This call creates both an undo context wrapper and an
     82      * edit-XML wrapper.
     83      *
     84      * @param undoName The UI name that will be given to the undo action.
     85      * @param closure The code to execute. The closure receives this INode itself as argument.
     86      */
     87     void editXml(String undoName, final Closure closure);
     88 
     89     // TODO define an exception that methods below will throw if editXml() is not wrapping
     90     // these calls.
     91 
     92     /**
     93      * Creates a new XML element as a child of this node's XML element.
     94      * <p/>
     95      * For this to work, the editor must have a descriptor for the given FQCN.
     96      * <p/>
     97      * This call must be done in the context of editXml().
     98      *
     99      * @param viewFqcn The FQCN of the element to create. The actual XML local name will
    100      *  depend on whether this is an Android view or a custom project view.
    101      * @return The node for the newly created element. Can be null if we failed to create it.
    102      */
    103     INode appendChild(String viewFqcn);
    104 
    105     /**
    106      * Creates a new XML element as a child of this node's XML element and inserts
    107      * it at the specified position in the children list.
    108      * <p/>
    109      * For this to work, the editor must have a descriptor for the given FQCN.
    110      * <p/>
    111      * This call must be done in the context of editXml().
    112      *
    113      * @param viewFqcn The FQCN of the element to create. The actual XML local name will
    114      *  depend on whether this is an Android view or a custom project view.
    115      * @param index Index of the child to insert before. If the index is out of bounds
    116      *  (less than zero or larger that current last child), appends at the end.
    117      * @return The node for the newly created element. Can be null if we failed to create it.
    118      */
    119     INode insertChildAt(String viewFqcn, int index);
    120 
    121     /**
    122      * Sets an attribute for the underlying XML element.
    123      * Attributes are not written immediately -- instead the XML editor batches edits and
    124      * then commits them all together at once later.
    125      * <p/>
    126      * Custom attributes will be created on the fly.
    127      * <p/>
    128      * Passing an empty value actually <em>removes</em> an attribute from the XML.
    129      * <p/>
    130      * This call must be done in the context of editXml().
    131      *
    132      * @param uri The XML namespace URI of the attribute.
    133      * @param localName The XML <em>local</em> name of the attribute to set.
    134      * @param value It's value. Cannot be null. An empty value <em>removes</em> the attribute.
    135      * @return Whether the attribute was actually set or not.
    136      */
    137     boolean setAttribute(String uri, String localName, String value);
    138 
    139     /**
    140      * Returns a given XML attribute.
    141      * <p/>
    142      * This looks up an attribute in the <em>current</em> XML source, not the in-memory model.
    143      * That means that if called in the context of {@link #editXml(String, Closure)}, the value
    144      * returned here is not affected by {@link #setAttribute(String, String, String)} until
    145      * the editXml closure is completed and the actual XML is updated.
    146      *
    147      * @param uri The XML name-space URI of the attribute.
    148      * @param attrName The <em>local</em> name of the attribute.
    149      * @return the attribute as a {@link String}, if it exists, or <code>null</code>.
    150      */
    151     String getStringAttr(String uri, String attrName);
    152 
    153     /**
    154      * Returns the {@link IAttributeInfo} for a given attribute.
    155      * <p/>
    156      * The information is useful to determine the format of an attribute (e.g. reference, string,
    157      * float, enum, flag, etc.) and in the case of enums and flags also gives the possible values.
    158      * <p/>
    159      * Note: in Android resources, an enum can only take one of the possible values (e.g.
    160      * "visibility" can be either "visible" or "none"), whereas a flag can accept one or more
    161      * value (e.g. "align" can be "center_vertical|center_horizontal".)
    162      * <p/>
    163      * Note that this method does not handle custom non-android attributes. It may either
    164      * return null for these or it may return a synthetic "string" format attribute depending
    165      * on how the attribute was loaded.
    166      *
    167      * @param uri The XML name-space URI of the attribute.
    168      * @param attrName The <em>local</em> name of the attribute.
    169      * @return the {@link IAttributeInfo} if the attribute is known, or <code>null</code>.
    170      */
    171     public IAttributeInfo getAttributeInfo(String uri, String attrName);
    172 
    173 
    174     /**
    175      * Returns the list of all attributes defined in the XML for this node.
    176      * <p/>
    177      * This looks up an attribute in the <em>current</em> XML source, not the in-memory model.
    178      * That means that if called in the context of {@link #editXml(String, Closure)}, the value
    179      * returned here is not affected by {@link #setAttribute(String, String, String)} until
    180      * the editXml closure is completed and the actual XML is updated.
    181      *
    182      * @return A non-null possible-empty list of {@link IAttribute}.
    183      */
    184     public IAttribute[] getAttributes();
    185 
    186     // -----------
    187 
    188     /** TODO: this is a hack. Shouldn't be here but instead part of some kind of helper
    189      *  given to IViewRule implementations.
    190      */
    191     void debugPrintf(String msg, Object...params);
    192 
    193     // -----------
    194 
    195     /**
    196      * An XML attribute in an {@link INode}.
    197      * <p/>
    198      * The attribute is always represented by a namespace URI, a name and a value.
    199      * The name cannot be empty.
    200      * The namespace URI can be empty for an attribute without a namespace but is never null.
    201      * The value can be empty but cannot be null.
    202      */
    203     public static interface IAttribute extends IDragAttribute { }
    204 }
    205