Home | History | Annotate | Download | only in uimodel
      1 /*
      2  * Copyright (C) 2007 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.uimodel;
     18 
     19 import com.android.SdkConstants;
     20 import com.android.ide.eclipse.adt.AdtPlugin;
     21 import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
     22 import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
     23 import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils;
     24 import com.android.ide.eclipse.adt.internal.editors.descriptors.ListAttributeDescriptor;
     25 import com.android.ide.eclipse.adt.internal.editors.descriptors.TextAttributeDescriptor;
     26 import com.android.ide.eclipse.adt.internal.editors.ui.SectionHelper;
     27 import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
     28 
     29 import org.eclipse.core.runtime.IStatus;
     30 import org.eclipse.swt.SWT;
     31 import org.eclipse.swt.events.DisposeEvent;
     32 import org.eclipse.swt.events.DisposeListener;
     33 import org.eclipse.swt.events.ModifyEvent;
     34 import org.eclipse.swt.events.ModifyListener;
     35 import org.eclipse.swt.events.SelectionAdapter;
     36 import org.eclipse.swt.events.SelectionEvent;
     37 import org.eclipse.swt.widgets.Combo;
     38 import org.eclipse.swt.widgets.Composite;
     39 import org.eclipse.swt.widgets.Label;
     40 import org.eclipse.ui.forms.IManagedForm;
     41 import org.eclipse.ui.forms.widgets.FormToolkit;
     42 import org.eclipse.ui.forms.widgets.TableWrapData;
     43 
     44 /**
     45  * Represents an XML attribute which has possible built-in values, and can be modified by
     46  * an editable Combo box.
     47  * <p/>
     48  * See {@link UiTextAttributeNode} for more information.
     49  */
     50 public class UiListAttributeNode extends UiAbstractTextAttributeNode {
     51 
     52     protected Combo mCombo;
     53 
     54     public UiListAttributeNode(ListAttributeDescriptor attributeDescriptor,
     55             UiElementNode uiParent) {
     56         super(attributeDescriptor, uiParent);
     57     }
     58 
     59     /* (non-java doc)
     60      * Creates a label widget and an associated text field.
     61      * <p/>
     62      * As most other parts of the android manifest editor, this assumes the
     63      * parent uses a table layout with 2 columns.
     64      */
     65     @Override
     66     public final void createUiControl(final Composite parent, IManagedForm managedForm) {
     67         FormToolkit toolkit = managedForm.getToolkit();
     68         TextAttributeDescriptor desc = (TextAttributeDescriptor) getDescriptor();
     69 
     70         Label label = toolkit.createLabel(parent, desc.getUiName());
     71         label.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE));
     72         SectionHelper.addControlTooltip(label, DescriptorsUtils.formatTooltip(desc.getTooltip()));
     73 
     74         int style = SWT.DROP_DOWN;
     75         mCombo = new Combo(parent, style);
     76         TableWrapData twd = new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.MIDDLE);
     77         twd.maxWidth = 100;
     78         mCombo.setLayoutData(twd);
     79 
     80         fillCombo();
     81 
     82         setTextWidgetValue(getCurrentValue());
     83 
     84         mCombo.addModifyListener(new ModifyListener() {
     85             /**
     86              * Sent when the text is modified, whether by the user via manual
     87              * input or programmatic input via setText().
     88              */
     89             @Override
     90             public void modifyText(ModifyEvent e) {
     91                 onComboChange();
     92             }
     93         });
     94 
     95         mCombo.addSelectionListener(new SelectionAdapter() {
     96             /** Sent when the text is changed from a list selection. */
     97             @Override
     98             public void widgetSelected(SelectionEvent e) {
     99                 onComboChange();
    100             }
    101         });
    102 
    103         // Remove self-reference when the widget is disposed
    104         mCombo.addDisposeListener(new DisposeListener() {
    105             @Override
    106             public void widgetDisposed(DisposeEvent e) {
    107                 mCombo = null;
    108             }
    109         });
    110     }
    111 
    112     protected void fillCombo() {
    113         String[] values = getPossibleValues(null);
    114 
    115         if (values == null) {
    116             AdtPlugin.log(IStatus.ERROR,
    117                     "FrameworkResourceManager did not provide values yet for %1$s",
    118                     getDescriptor().getXmlLocalName());
    119         } else {
    120             for (String value : values) {
    121                 mCombo.add(value);
    122             }
    123         }
    124     }
    125 
    126     /**
    127      * Get the list values, either from the initial values set in the attribute
    128      * or by querying the framework resource parser.
    129      *
    130      * {@inheritDoc}
    131      */
    132     @Override
    133     public String[] getPossibleValues(String prefix) {
    134         AttributeDescriptor descriptor = getDescriptor();
    135         UiElementNode uiParent = getUiParent();
    136 
    137         String attr_name = descriptor.getXmlLocalName();
    138         String element_name = uiParent.getDescriptor().getXmlName();
    139 
    140         // FrameworkResourceManager expects a specific prefix for the attribute.
    141         String nsPrefix = "";
    142         if (SdkConstants.NS_RESOURCES.equals(descriptor.getNamespaceUri())) {
    143             nsPrefix = SdkConstants.ANDROID_NS_NAME + ':';
    144         } else if (SdkConstants.XMLNS_URI.equals(descriptor.getNamespaceUri())) {
    145             nsPrefix = SdkConstants.XMLNS_PREFIX;
    146         }
    147         attr_name = nsPrefix + attr_name;
    148 
    149         String[] values = null;
    150 
    151         if (descriptor instanceof ListAttributeDescriptor &&
    152                 ((ListAttributeDescriptor) descriptor).getValues() != null) {
    153             // Get enum values from the descriptor
    154             values = ((ListAttributeDescriptor) descriptor).getValues();
    155         }
    156 
    157         if (values == null) {
    158             // or from the AndroidTargetData
    159             UiElementNode uiNode = getUiParent();
    160             AndroidXmlEditor editor = uiNode.getEditor();
    161             AndroidTargetData data = editor.getTargetData();
    162             if (data != null) {
    163                 // get the great-grand-parent descriptor.
    164 
    165                 // the parent should always exist.
    166                 UiElementNode grandParentNode = uiParent.getUiParent();
    167 
    168                 String greatGrandParentNodeName = null;
    169                 if (grandParentNode != null) {
    170                     UiElementNode greatGrandParentNode = grandParentNode.getUiParent();
    171                     if (greatGrandParentNode != null) {
    172                         greatGrandParentNodeName =
    173                             greatGrandParentNode.getDescriptor().getXmlName();
    174                     }
    175                 }
    176 
    177                 values = data.getAttributeValues(element_name, attr_name, greatGrandParentNodeName);
    178             }
    179         }
    180 
    181         return values;
    182     }
    183 
    184     @Override
    185     public String getTextWidgetValue() {
    186         if (mCombo != null) {
    187             return mCombo.getText();
    188         }
    189 
    190         return null;
    191     }
    192 
    193     @Override
    194     public final boolean isValid() {
    195         return mCombo != null;
    196     }
    197 
    198     @Override
    199     public void setTextWidgetValue(String value) {
    200         if (mCombo != null) {
    201             mCombo.setText(value);
    202         }
    203     }
    204 
    205     /**
    206      * Handles Combo change, either from text edit or from selection change.
    207      * <p/>
    208      * Simply mark the attribute as dirty if it really changed.
    209      * The container SectionPart will collect these flag and manage them.
    210      */
    211     private void onComboChange() {
    212         if (!isInInternalTextModification() &&
    213                 !isDirty() &&
    214                 mCombo != null &&
    215                 getCurrentValue() != null &&
    216                 !mCombo.getText().equals(getCurrentValue())) {
    217             setDirty(true);
    218         }
    219     }
    220 }
    221