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.descriptors;
18 
19 import com.android.SdkConstants;
20 import com.android.annotations.NonNull;
21 import com.android.annotations.Nullable;
22 import com.android.ide.common.api.IAttributeInfo;
23 import com.android.ide.common.api.IAttributeInfo.Format;
24 import com.android.ide.eclipse.adt.internal.editors.ui.TextValueCellEditor;
25 import com.android.ide.eclipse.adt.internal.editors.uimodel.UiAttributeNode;
26 import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
27 import com.android.ide.eclipse.adt.internal.editors.uimodel.UiTextAttributeNode;
28 
29 import org.eclipse.jface.viewers.CellEditor;
30 import org.eclipse.jface.viewers.ILabelProvider;
31 import org.eclipse.swt.widgets.Composite;
32 import org.eclipse.swt.widgets.Control;
33 import org.eclipse.ui.views.properties.IPropertyDescriptor;
34 
35 import java.util.EnumSet;
36 import java.util.Locale;
37 
38 
39 /**
40  * Describes a textual XML attribute.
41  * <p/>
42  * Such an attribute has a tooltip and would typically be displayed by
43  * {@link UiTextAttributeNode} using a label widget and text field.
44  * <p/>
45  * This is the "default" kind of attribute. If in doubt, use this.
46  */
47 public class TextAttributeDescriptor extends AttributeDescriptor implements IPropertyDescriptor {
48     public static final String DEPRECATED_CATEGORY = "Deprecated";
49 
50     private String mUiName;
51     private String mTooltip;
52     private boolean mRequired;
53 
54     /**
55      * Creates a new {@link TextAttributeDescriptor}
56      *
57      * @param xmlLocalName The XML name of the attribute (case sensitive)
58      * @param nsUri The URI of the attribute. Can be null if attribute has no namespace.
59      *              See {@link SdkConstants#NS_RESOURCES} for a common value.
60      * @param attrInfo The {@link IAttributeInfo} of this attribute. Can't be null.
61      */
TextAttributeDescriptor( String xmlLocalName, String nsUri, IAttributeInfo attrInfo)62     public TextAttributeDescriptor(
63             String xmlLocalName,
64             String nsUri,
65             IAttributeInfo attrInfo) {
66         super(xmlLocalName, nsUri, attrInfo);
67     }
68 
69     /**
70      * @return The UI name of the attribute. Cannot be an empty string and cannot be null.
71      */
72     @NonNull
getUiName()73     public String getUiName() {
74         if (mUiName == null) {
75             IAttributeInfo info = getAttributeInfo();
76             if (info != null) {
77                 mUiName = DescriptorsUtils.prettyAttributeUiName(info.getName());
78                 if (mRequired) {
79                     mUiName += "*"; //$NON-NLS-1$
80                 }
81             } else {
82                 mUiName = getXmlLocalName();
83             }
84         }
85 
86         return mUiName;
87     }
88 
89 
90     /**
91      * Sets the UI name to be associated with this descriptor. This is usually
92      * computed lazily from the {@link #getAttributeInfo()} data, but for some
93      * hardcoded/builtin descriptor this is manually initialized.
94      *
95      * @param uiName the new UI name to be used
96      * @return this, for constructor setter chaining
97      */
setUiName(String uiName)98     public TextAttributeDescriptor setUiName(String uiName) {
99         mUiName = uiName;
100 
101         return this;
102     }
103 
104     /**
105      * Sets the tooltip to be associated with this descriptor. This is usually
106      * computed lazily from the {@link #getAttributeInfo()} data, but for some
107      * hardcoded/builtin descriptor this is manually initialized.
108      *
109      * @param tooltip the new tooltip to be used
110      * @return this, for constructor setter chaining
111      */
setTooltip(String tooltip)112     public TextAttributeDescriptor setTooltip(String tooltip) {
113         mTooltip = tooltip;
114 
115         return this;
116     }
117 
118     /**
119      * Sets whether this attribute is required
120      *
121      * @param required whether this attribute is required
122      * @return this, for constructor setter chaining
123      */
setRequired(boolean required)124     public TextAttributeDescriptor setRequired(boolean required) {
125         mRequired = required;
126 
127         return this;
128     }
129 
130     /**
131      * Returns whether this attribute is required
132      *
133      * @return whether this attribute is required
134      */
isRequired()135     public boolean isRequired() {
136         return mRequired;
137     }
138 
139     /**
140      * The tooltip string is either null or a non-empty string.
141      * <p/>
142      * The tooltip is based on the Javadoc of the attribute and already processed via
143      * {@link DescriptorsUtils#formatTooltip(String)} to be displayed right away as
144      * a UI tooltip.
145      * <p/>
146      * An empty string is converted to null, to match the behavior of setToolTipText() in
147      * {@link Control}.
148      *
149      * @return A non-empty tooltip string or null
150      */
151     @Nullable
getTooltip()152     public String getTooltip() {
153         if (mTooltip == null) {
154             IAttributeInfo info = getAttributeInfo();
155             if (info == null) {
156                 mTooltip = "";
157                 return mTooltip;
158             }
159 
160             String tooltip = null;
161             String rawTooltip = info.getJavaDoc();
162             if (rawTooltip == null) {
163                 rawTooltip = "";
164             }
165 
166             String deprecated = info.getDeprecatedDoc();
167             if (deprecated != null) {
168                 if (rawTooltip.length() > 0) {
169                     rawTooltip += "@@"; //$NON-NLS-1$ insert a break
170                 }
171                 rawTooltip += "* Deprecated";
172                 if (deprecated.length() != 0) {
173                     rawTooltip += ": " + deprecated;                            //$NON-NLS-1$
174                 }
175                 if (deprecated.length() == 0 || !deprecated.endsWith(".")) {    //$NON-NLS-1$
176                     rawTooltip += ".";                                          //$NON-NLS-1$
177                 }
178             }
179 
180             // Add the known types to the tooltip
181             EnumSet<Format> formats_list = info.getFormats();
182             int flen = formats_list.size();
183             if (flen > 0) {
184                 StringBuilder sb = new StringBuilder();
185                 if (rawTooltip != null && rawTooltip.length() > 0) {
186                     sb.append(rawTooltip);
187                     sb.append(" ");     //$NON-NLS-1$
188                 }
189                 if (sb.length() > 0) {
190                     sb.append("@@");    //$NON-NLS-1$  @@ inserts a break before the types
191                 }
192                 sb.append("[");         //$NON-NLS-1$
193                 boolean isFirst = true;
194                 for (Format f : formats_list) {
195                     if (isFirst) {
196                         isFirst = false;
197                     } else {
198                         sb.append(", ");
199                     }
200                     sb.append(f.toString().toLowerCase(Locale.US));
201                 }
202                 // The extra space at the end makes the tooltip more readable on Windows.
203                 sb.append("]"); //$NON-NLS-1$
204 
205                 if (mRequired) {
206                     // Note: this string is split in 2 to make it translatable.
207                     sb.append(".@@");          //$NON-NLS-1$ @@ inserts a break and is not translatable
208                     sb.append("* Required.");
209                 }
210 
211                 // The extra space at the end makes the tooltip more readable on Windows.
212                 sb.append(" "); //$NON-NLS-1$
213 
214                 rawTooltip = sb.toString();
215                 tooltip = DescriptorsUtils.formatTooltip(rawTooltip);
216             }
217 
218             if (tooltip == null) {
219                 tooltip = DescriptorsUtils.formatTooltip(rawTooltip);
220             }
221             mTooltip = tooltip;
222         }
223 
224         return mTooltip.isEmpty() ? null : mTooltip;
225     }
226 
227     /**
228      * @return A new {@link UiTextAttributeNode} linked to this descriptor.
229      */
230     @Override
createUiNode(UiElementNode uiParent)231     public UiAttributeNode createUiNode(UiElementNode uiParent) {
232         return new UiTextAttributeNode(this, uiParent);
233     }
234 
235     // ------- IPropertyDescriptor Methods
236 
237     @Override
createPropertyEditor(Composite parent)238     public CellEditor createPropertyEditor(Composite parent) {
239         return new TextValueCellEditor(parent);
240     }
241 
242     @Override
getCategory()243     public String getCategory() {
244         if (isDeprecated()) {
245             return DEPRECATED_CATEGORY;
246         }
247 
248         ElementDescriptor parent = getParent();
249         if (parent != null) {
250             return parent.getUiName();
251         }
252 
253         return null;
254     }
255 
256     @Override
getDescription()257     public String getDescription() {
258         return getTooltip();
259     }
260 
261     @Override
getDisplayName()262     public String getDisplayName() {
263         return getUiName();
264     }
265 
266     @Override
getFilterFlags()267     public String[] getFilterFlags() {
268         return null;
269     }
270 
271     @Override
getHelpContextIds()272     public Object getHelpContextIds() {
273         return null;
274     }
275 
276     @Override
getId()277     public Object getId() {
278         return this;
279     }
280 
281     @Override
getLabelProvider()282     public ILabelProvider getLabelProvider() {
283         return AttributeDescriptorLabelProvider.getProvider();
284     }
285 
286     @Override
isCompatibleWith(IPropertyDescriptor anotherProperty)287     public boolean isCompatibleWith(IPropertyDescriptor anotherProperty) {
288         return anotherProperty == this;
289     }
290 }
291