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