Home | History | Annotate | Download | only in properties
      1 /*
      2  * Copyright (C) 2012 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 package com.android.ide.eclipse.adt.internal.editors.layout.properties;
     17 
     18 import static com.android.SdkConstants.ATTR_LAYOUT_MARGIN;
     19 import static com.android.SdkConstants.ATTR_LAYOUT_RESOURCE_PREFIX;
     20 
     21 import com.android.annotations.NonNull;
     22 import com.android.annotations.Nullable;
     23 import com.android.ide.common.api.IAttributeInfo;
     24 import com.android.ide.eclipse.adt.AdtPlugin;
     25 import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlEditor;
     26 import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
     27 import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils;
     28 import com.android.ide.eclipse.adt.internal.editors.layout.gle2.GraphicalEditorPart;
     29 import com.android.ide.eclipse.adt.internal.editors.layout.gle2.ViewHierarchy;
     30 import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode;
     31 
     32 import org.eclipse.jface.fieldassist.IContentProposal;
     33 import org.eclipse.jface.fieldassist.IContentProposalProvider;
     34 import org.eclipse.jface.viewers.ILabelProvider;
     35 import org.eclipse.jface.viewers.LabelProvider;
     36 import org.eclipse.swt.graphics.Image;
     37 import org.eclipse.ui.views.properties.IPropertyDescriptor;
     38 import org.eclipse.wb.internal.core.model.property.Property;
     39 import org.eclipse.wb.internal.core.model.property.editor.PropertyEditor;
     40 import org.eclipse.wb.internal.core.model.property.table.PropertyTooltipProvider;
     41 import org.eclipse.wb.internal.core.model.property.table.PropertyTooltipTextProvider;
     42 import org.w3c.dom.Attr;
     43 import org.w3c.dom.Element;
     44 
     45 import java.util.Map;
     46 
     47 /**
     48  * An Android XML property
     49  */
     50 class XmlProperty extends Property {
     51     private PropertyFactory mFactory;
     52     final AttributeDescriptor mDescriptor;
     53     private UiViewElementNode mNode;
     54     private Property mParent;
     55 
     56     XmlProperty(
     57             @NonNull PropertyEditor editor,
     58             @NonNull PropertyFactory factory,
     59             @NonNull UiViewElementNode node,
     60             @NonNull AttributeDescriptor descriptor) {
     61         super(editor);
     62         mFactory = factory;
     63         mNode = node;
     64         mDescriptor = descriptor;
     65     }
     66 
     67     @NonNull
     68     public PropertyFactory getFactory() {
     69         return mFactory;
     70     }
     71 
     72     @NonNull
     73     public UiViewElementNode getNode() {
     74         return mNode;
     75     }
     76 
     77     @NonNull
     78     public AttributeDescriptor getDescriptor() {
     79         return mDescriptor;
     80     }
     81 
     82     @Override
     83     @NonNull
     84     public String getName() {
     85         return mDescriptor.getXmlLocalName();
     86     }
     87 
     88     @Override
     89     @NonNull
     90     public String getTitle() {
     91         String name = mDescriptor.getXmlLocalName();
     92         int nameLength = name.length();
     93 
     94         if (name.startsWith(ATTR_LAYOUT_RESOURCE_PREFIX)) {
     95             if (name.startsWith(ATTR_LAYOUT_MARGIN)
     96                     && nameLength > ATTR_LAYOUT_MARGIN.length()) {
     97                 name = name.substring(ATTR_LAYOUT_MARGIN.length());
     98             } else {
     99                 name = name.substring(ATTR_LAYOUT_RESOURCE_PREFIX.length());
    100             }
    101         }
    102 
    103         // Capitalize
    104         name = DescriptorsUtils.capitalize(name);
    105 
    106         // If we're nested within a complex property, say "Line Spacing", don't
    107         // include "Line Spacing " as a prefix for each property here
    108         if (mParent != null) {
    109             String parentTitle = mParent.getTitle();
    110             if (name.startsWith(parentTitle)) {
    111                 int parentTitleLength = parentTitle.length();
    112                 if (parentTitleLength < nameLength) {
    113                     if (nameLength > parentTitleLength &&
    114                             Character.isWhitespace(name.charAt(parentTitleLength))) {
    115                         parentTitleLength++;
    116                     }
    117                     name = name.substring(parentTitleLength);
    118                 }
    119             }
    120         }
    121 
    122         return name;
    123     }
    124 
    125     @Override
    126     public <T> T getAdapter(Class<T> adapter) {
    127         // tooltip
    128         if (adapter == PropertyTooltipProvider.class) {
    129             return adapter.cast(new PropertyTooltipTextProvider() {
    130                 @Override
    131                 protected String getText(Property p) throws Exception {
    132                     if (mDescriptor instanceof IPropertyDescriptor) {
    133                         IPropertyDescriptor d = (IPropertyDescriptor) mDescriptor;
    134                         return d.getDescription();
    135                     }
    136 
    137                     return null;
    138                 }
    139             });
    140         } else if (adapter == IContentProposalProvider.class) {
    141             IAttributeInfo info = mDescriptor.getAttributeInfo();
    142             if (info != null) {
    143                 return adapter.cast(new PropertyValueCompleter(this));
    144             }
    145             // Fallback: complete values on resource values
    146             return adapter.cast(new ResourceValueCompleter(this));
    147         } else if (adapter == ILabelProvider.class) {
    148             return adapter.cast(new LabelProvider() {
    149                 @Override
    150               public Image getImage(Object element) {
    151                   return AdtPlugin.getAndroidLogo();
    152               }
    153 
    154               @Override
    155               public String getText(Object element) {
    156                   return ((IContentProposal) element).getLabel();
    157               }
    158             });
    159         }
    160         return super.getAdapter(adapter);
    161     }
    162 
    163     @Override
    164     public boolean isModified() throws Exception {
    165         Object s = null;
    166         try {
    167             Element element = (Element) mNode.getXmlNode();
    168             if (element == null) {
    169                 return false;
    170             }
    171             String name = mDescriptor.getXmlLocalName();
    172             String uri = mDescriptor.getNamespaceUri();
    173             if (uri != null) {
    174                 return element.hasAttributeNS(uri, name);
    175             } else {
    176                 return element.hasAttribute(name);
    177             }
    178         } catch (Exception e) {
    179             // pass
    180         }
    181         return s != null && s.toString().length() > 0;
    182     }
    183 
    184     @Nullable
    185     public String getStringValue() {
    186         Element element = (Element) mNode.getXmlNode();
    187         if (element == null) {
    188             return null;
    189         }
    190         String name = mDescriptor.getXmlLocalName();
    191         String uri = mDescriptor.getNamespaceUri();
    192         Attr attr;
    193         if (uri != null) {
    194             attr = element.getAttributeNodeNS(uri, name);
    195         } else {
    196             attr = element.getAttributeNode(name);
    197         }
    198         if (attr != null) {
    199             return attr.getValue();
    200         }
    201 
    202         Object viewObject = getFactory().getCurrentViewObject();
    203         if (viewObject != null) {
    204             GraphicalEditorPart graphicalEditor = getGraphicalEditor();
    205             if (graphicalEditor == null) {
    206                 return null;
    207             }
    208             ViewHierarchy views = graphicalEditor.getCanvasControl().getViewHierarchy();
    209             Map<String, String> defaultProperties = views.getDefaultProperties(viewObject);
    210             if (defaultProperties != null) {
    211                 return defaultProperties.get(name);
    212             }
    213         }
    214 
    215         return null;
    216     }
    217 
    218     @Override
    219     @Nullable
    220     public Object getValue() throws Exception {
    221         return getStringValue();
    222     }
    223 
    224     @Override
    225     public void setValue(Object value) throws Exception {
    226         CommonXmlEditor editor = getXmlEditor();
    227         if (editor == null) {
    228             return;
    229         }
    230         final String attribute = mDescriptor.getXmlLocalName();
    231         final String xmlValue = value != null && value != UNKNOWN_VALUE ? value.toString() : null;
    232         editor.wrapUndoEditXmlModel(
    233                 String.format("Set \"%1$s\" to \"%2$s\"", attribute, xmlValue),
    234                 new Runnable() {
    235             @Override
    236             public void run() {
    237                 mNode.setAttributeValue(attribute,
    238                         mDescriptor.getNamespaceUri(), xmlValue, true /*override*/);
    239                 mNode.commitDirtyAttributesToXml();
    240             }
    241         });
    242     }
    243 
    244     @Override
    245     @NonNull
    246     public Property getComposite(Property[] properties) {
    247         return XmlPropertyComposite.create(properties);
    248     }
    249 
    250     @Nullable
    251     GraphicalEditorPart getGraphicalEditor() {
    252         return mFactory.getGraphicalEditor();
    253     }
    254 
    255     @Nullable
    256     CommonXmlEditor getXmlEditor() {
    257         GraphicalEditorPart graphicalEditor = getGraphicalEditor();
    258         if (graphicalEditor != null) {
    259             return graphicalEditor.getEditorDelegate().getEditor();
    260         }
    261 
    262         return null;
    263     }
    264 
    265     @Nullable
    266     public Property getParent() {
    267         return mParent;
    268     }
    269 
    270     public void setParent(@Nullable Property parent) {
    271         mParent = parent;
    272     }
    273 
    274     @Override
    275     public String toString() {
    276         return getName() + ":" + getPriority();
    277     }
    278 }
    279