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
17package com.android.ide.eclipse.adt.internal.editors.uimodel;
18
19import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
20import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
21import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils;
22import com.android.ide.eclipse.adt.internal.editors.descriptors.TextAttributeDescriptor;
23import com.android.ide.eclipse.adt.internal.editors.ui.SectionHelper;
24
25import org.eclipse.swt.events.DisposeEvent;
26import org.eclipse.swt.events.DisposeListener;
27import org.eclipse.swt.events.ModifyEvent;
28import org.eclipse.swt.events.ModifyListener;
29import org.eclipse.swt.layout.GridData;
30import org.eclipse.swt.widgets.Composite;
31import org.eclipse.swt.widgets.Text;
32import org.eclipse.ui.forms.IManagedForm;
33import org.eclipse.ui.forms.widgets.TableWrapData;
34
35/**
36 * Represents an XML attribute in that can be modified using a simple text field
37 * in the XML editor's user interface.
38 * <p/>
39 * The XML attribute has no default value. When unset, the text field is blank.
40 * When updating the XML, if the field is empty, the attribute will be removed
41 * from the XML element.
42 * <p/>
43 * See {@link UiAttributeNode} for more information.
44 */
45public class UiTextAttributeNode extends UiAbstractTextAttributeNode {
46
47    /** Text field */
48    private Text mText;
49    /** The managed form, set only once createUiControl has been called. */
50    private IManagedForm mManagedForm;
51
52    public UiTextAttributeNode(AttributeDescriptor attributeDescriptor, UiElementNode uiParent) {
53        super(attributeDescriptor, uiParent);
54    }
55
56    /* (non-java doc)
57     * Creates a label widget and an associated text field.
58     * <p/>
59     * As most other parts of the android manifest editor, this assumes the
60     * parent uses a table layout with 2 columns.
61     */
62    @Override
63    public void createUiControl(Composite parent, IManagedForm managedForm) {
64        setManagedForm(managedForm);
65        TextAttributeDescriptor desc = (TextAttributeDescriptor) getDescriptor();
66        Text text = SectionHelper.createLabelAndText(parent, managedForm.getToolkit(),
67                desc.getUiName(), getCurrentValue(),
68                DescriptorsUtils.formatTooltip(desc.getTooltip()));
69
70        setTextWidget(text);
71    }
72
73    /**
74     * No completion values for this UI attribute.
75     *
76     * {@inheritDoc}
77     */
78    @Override
79    public String[] getPossibleValues(String prefix) {
80        return null;
81    }
82
83    /**
84     * Sets the internal managed form.
85     * This is usually set by createUiControl.
86     */
87    protected void setManagedForm(IManagedForm managedForm) {
88         mManagedForm = managedForm;
89    }
90
91    /**
92     * @return The managed form, set only once createUiControl has been called.
93     */
94    protected IManagedForm getManagedForm() {
95        return mManagedForm;
96    }
97
98    /* (non-java doc)
99     * Returns if the attribute node is valid, and its UI has been created.
100     */
101    @Override
102    public boolean isValid() {
103        return mText != null;
104    }
105
106    @Override
107    public String getTextWidgetValue() {
108        if (mText != null) {
109            return mText.getText();
110        }
111
112        return null;
113    }
114
115    @Override
116    public void setTextWidgetValue(String value) {
117        if (mText != null) {
118            mText.setText(value);
119        }
120    }
121
122    /**
123     * Sets the Text widget object, and prepares it to handle modification and synchronization
124     * with the XML node.
125     * @param textWidget
126     */
127    protected final void setTextWidget(Text textWidget) {
128        mText = textWidget;
129
130        if (textWidget != null) {
131            // Sets the with hint for the text field. Derived classes can always override it.
132            // This helps the grid layout to resize correctly on smaller screen sizes.
133            Object data = textWidget.getLayoutData();
134            if (data == null) {
135            } else if (data instanceof GridData) {
136                ((GridData)data).widthHint = AndroidXmlEditor.TEXT_WIDTH_HINT;
137            } else if (data instanceof TableWrapData) {
138                ((TableWrapData)data).maxWidth = 100;
139            }
140
141            mText.addModifyListener(new ModifyListener() {
142                /**
143                 * Sent when the text is modified, whether by the user via manual
144                 * input or programmatic input via setText().
145                 * <p/>
146                 * Simply mark the attribute as dirty if it really changed.
147                 * The container SectionPart will collect these flag and manage them.
148                 */
149                @Override
150                public void modifyText(ModifyEvent e) {
151                    if (!isInInternalTextModification() &&
152                            !isDirty() &&
153                            mText != null &&
154                            getCurrentValue() != null &&
155                            !mText.getText().equals(getCurrentValue())) {
156                        setDirty(true);
157                    }
158                }
159            });
160
161            // Remove self-reference when the widget is disposed
162            mText.addDisposeListener(new DisposeListener() {
163                @Override
164                public void widgetDisposed(DisposeEvent e) {
165                    mText = null;
166                }
167            });
168        }
169
170        onAddValidators(mText);
171    }
172
173    /**
174     * Called after the text widget as been created.
175     * <p/>
176     * Derived classes typically want to:
177     * <li> Create a new {@link ModifyListener} and attach it to the given {@link Text} widget.
178     * <li> In the modify listener, call getManagedForm().getMessageManager().addMessage()
179     *      and getManagedForm().getMessageManager().removeMessage() as necessary.
180     * <li> Call removeMessage in a new text.addDisposeListener.
181     * <li> Call the validator once to setup the initial messages as needed.
182     * <p/>
183     * The base implementation does nothing.
184     *
185     * @param text The {@link Text} widget to validate.
186     */
187    protected void onAddValidators(Text text) {
188    }
189
190    /**
191     * Returns the text widget.
192     */
193    protected final Text getTextWidget() {
194        return mText;
195    }
196}
197