Home | History | Annotate | Download | only in uimodel
      1 /*
      2  * Copyright (C) 2008 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 package com.android.ide.eclipse.adt.internal.editors.layout.uimodel;
     18 
     19 import static com.android.SdkConstants.ANDROID_NS_NAME;
     20 import static com.android.SdkConstants.ANDROID_URI;
     21 import static com.android.SdkConstants.ATTR_CLASS;
     22 import static com.android.SdkConstants.ATTR_ORIENTATION;
     23 import static com.android.SdkConstants.FQCN_FRAME_LAYOUT;
     24 import static com.android.SdkConstants.LINEAR_LAYOUT;
     25 import static com.android.SdkConstants.VALUE_VERTICAL;
     26 import static com.android.SdkConstants.VIEW_TAG;
     27 
     28 import com.android.ide.eclipse.adt.AdtPlugin;
     29 import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
     30 import com.android.ide.eclipse.adt.internal.editors.IconFactory;
     31 import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
     32 import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
     33 import com.android.ide.eclipse.adt.internal.editors.descriptors.XmlnsAttributeDescriptor;
     34 import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
     35 import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors;
     36 import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor;
     37 import com.android.ide.eclipse.adt.internal.editors.uimodel.UiDocumentNode;
     38 import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
     39 import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
     40 import com.android.ide.eclipse.adt.internal.sdk.Sdk;
     41 import com.android.sdklib.IAndroidTarget;
     42 
     43 import org.eclipse.core.resources.IMarker;
     44 import org.eclipse.core.resources.IProject;
     45 import org.eclipse.swt.graphics.Image;
     46 import org.w3c.dom.Element;
     47 import org.w3c.dom.Node;
     48 
     49 /**
     50  * Specialized version of {@link UiElementNode} for the {@link ViewElementDescriptor}s.
     51  */
     52 public class UiViewElementNode extends UiElementNode {
     53 
     54     /** An AttributeDescriptor array that depends on the current UiParent. */
     55     private AttributeDescriptor[] mCachedAttributeDescriptors;
     56 
     57     public UiViewElementNode(ViewElementDescriptor elementDescriptor) {
     58         super(elementDescriptor);
     59     }
     60 
     61     /**
     62      * Returns an AttributeDescriptor array that depends on the current UiParent.
     63      * <p/>
     64      * The array merges both "direct" attributes with the descriptor layout attributes.
     65      * The array instance is cached and cleared if the UiParent is changed.
     66      */
     67     @Override
     68     public AttributeDescriptor[] getAttributeDescriptors() {
     69         if (!getDescriptor().syncAttributes()) {
     70             mCachedAttributeDescriptors = null;
     71         }
     72         if (mCachedAttributeDescriptors != null) {
     73             return mCachedAttributeDescriptors;
     74         }
     75 
     76         UiElementNode ui_parent = getUiParent();
     77         AttributeDescriptor[] direct_attrs = super.getAttributeDescriptors();
     78         mCachedAttributeDescriptors = direct_attrs;
     79 
     80         // Compute layout attributes: These depend on the *parent* this widget is within
     81         AttributeDescriptor[] layout_attrs = null;
     82         boolean need_xmlns = false;
     83 
     84         if (ui_parent instanceof UiDocumentNode) {
     85             // Limitation: right now the layout behaves as if everything was
     86             // owned by a FrameLayout.
     87             // TODO replace by something user-configurable.
     88 
     89             IProject project = getEditor().getProject();
     90             if (project != null) {
     91                 Sdk currentSdk = Sdk.getCurrent();
     92                 if (currentSdk != null) {
     93                     IAndroidTarget target = currentSdk.getTarget(project);
     94                     if (target != null) {
     95                         AndroidTargetData data = currentSdk.getTargetData(target);
     96                         if (data != null) {
     97                             LayoutDescriptors descriptors = data.getLayoutDescriptors();
     98                             ViewElementDescriptor desc =
     99                                 descriptors.findDescriptorByClass(FQCN_FRAME_LAYOUT);
    100                             if (desc != null) {
    101                                 layout_attrs = desc.getLayoutAttributes();
    102                                 need_xmlns = true;
    103                             }
    104                         }
    105                     }
    106                 }
    107             }
    108         } else if (ui_parent instanceof UiViewElementNode) {
    109             layout_attrs =
    110                 ((ViewElementDescriptor) ui_parent.getDescriptor()).getLayoutAttributes();
    111         }
    112 
    113         if (layout_attrs == null || layout_attrs.length == 0) {
    114             return mCachedAttributeDescriptors;
    115         }
    116 
    117         mCachedAttributeDescriptors =
    118             new AttributeDescriptor[direct_attrs.length +
    119                                     layout_attrs.length +
    120                                     (need_xmlns ? 1 : 0)];
    121         System.arraycopy(direct_attrs, 0,
    122                 mCachedAttributeDescriptors, 0,
    123                 direct_attrs.length);
    124         System.arraycopy(layout_attrs, 0,
    125                 mCachedAttributeDescriptors, direct_attrs.length,
    126                 layout_attrs.length);
    127         if (need_xmlns) {
    128             AttributeDescriptor desc = new XmlnsAttributeDescriptor(ANDROID_NS_NAME, ANDROID_URI);
    129             mCachedAttributeDescriptors[direct_attrs.length + layout_attrs.length] = desc;
    130         }
    131 
    132         return mCachedAttributeDescriptors;
    133     }
    134 
    135     public Image getIcon() {
    136         ElementDescriptor desc = getDescriptor();
    137         if (desc != null) {
    138             Image img = null;
    139             // Special case for the common case of vertical linear layouts:
    140             // show vertical linear icon (the default icon shows horizontal orientation)
    141             String uiName = desc.getUiName();
    142             IconFactory icons = IconFactory.getInstance();
    143             if (uiName.equals(LINEAR_LAYOUT)) {
    144                 Element e = (Element) getXmlNode();
    145                 if (VALUE_VERTICAL.equals(e.getAttributeNS(ANDROID_URI, ATTR_ORIENTATION))) {
    146                     IconFactory factory = icons;
    147                     img = factory.getIcon("VerticalLinearLayout"); //$NON-NLS-1$
    148                 }
    149             } else if (uiName.equals(VIEW_TAG)) {
    150                 Node xmlNode = getXmlNode();
    151                 if (xmlNode instanceof Element) {
    152                     String className = ((Element) xmlNode).getAttribute(ATTR_CLASS);
    153                     if (className != null && className.length() > 0) {
    154                         int index = className.lastIndexOf('.');
    155                         if (index != -1) {
    156                             className = "customView"; //$NON-NLS-1$
    157                         }
    158                         img = icons.getIcon(className);
    159                     }
    160                 }
    161 
    162                 if (img == null) {
    163                     // Can't have both view.png and View.png; issues on case sensitive vs
    164                     // case insensitive file systems
    165                     img = icons.getIcon("View"); //$NON-NLS-1$
    166                 }
    167             }
    168             if (img == null) {
    169                 img = desc.getGenericIcon();
    170             }
    171 
    172             if (img != null) {
    173                 AndroidXmlEditor editor = getEditor();
    174                 if (editor != null) {
    175                     LayoutEditorDelegate delegate = LayoutEditorDelegate.fromEditor(editor);
    176                     if (delegate != null) {
    177                         IMarker marker = delegate.getIssueForNode(this);
    178                         if (marker != null) {
    179                             int severity = marker.getAttribute(IMarker.SEVERITY, 0);
    180                             if (severity == IMarker.SEVERITY_ERROR) {
    181                                 return icons.addErrorIcon(img);
    182                             } else {
    183                                 return icons.addWarningIcon(img);
    184                             }
    185                         }
    186                     }
    187                 }
    188 
    189                 return img;
    190             }
    191 
    192             return img;
    193         }
    194 
    195         return AdtPlugin.getAndroidLogo();
    196     }
    197 
    198     /**
    199      * Sets the parent of this UI node.
    200      * <p/>
    201      * Also removes the cached AttributeDescriptor array that depends on the current UiParent.
    202      */
    203     @Override
    204     protected void setUiParent(UiElementNode parent) {
    205         super.setUiParent(parent);
    206         mCachedAttributeDescriptors = null;
    207     }
    208 }
    209