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.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
20 import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
21 import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils;
22 import com.android.ide.eclipse.adt.internal.editors.descriptors.TextAttributeDescriptor;
23 import com.android.ide.eclipse.adt.internal.editors.ui.SectionHelper;
24 
25 import org.eclipse.swt.events.DisposeEvent;
26 import org.eclipse.swt.events.DisposeListener;
27 import org.eclipse.swt.events.ModifyEvent;
28 import org.eclipse.swt.events.ModifyListener;
29 import org.eclipse.swt.layout.GridData;
30 import org.eclipse.swt.widgets.Composite;
31 import org.eclipse.swt.widgets.Text;
32 import org.eclipse.ui.forms.IManagedForm;
33 import 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  */
45 public 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 
UiTextAttributeNode(AttributeDescriptor attributeDescriptor, UiElementNode uiParent)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
createUiControl(Composite parent, IManagedForm managedForm)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
getPossibleValues(String prefix)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      */
setManagedForm(IManagedForm managedForm)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      */
getManagedForm()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
isValid()102     public boolean isValid() {
103         return mText != null;
104     }
105 
106     @Override
getTextWidgetValue()107     public String getTextWidgetValue() {
108         if (mText != null) {
109             return mText.getText();
110         }
111 
112         return null;
113     }
114 
115     @Override
setTextWidgetValue(String value)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      */
setTextWidget(Text textWidget)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      */
onAddValidators(Text text)187     protected void onAddValidators(Text text) {
188     }
189 
190     /**
191      * Returns the text widget.
192      */
getTextWidget()193     protected final Text getTextWidget() {
194         return mText;
195     }
196 }
197