OSDN Git Service

android-2.1_r1 snapshot
[android-x86/sdk.git] / eclipse / plugins / com.android.ide.eclipse.adt / src / com / android / ide / eclipse / adt / internal / editors / uimodel / UiFlagAttributeNode.java
1 /*
2  * Copyright (C) 2008 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.AndroidEditor;
20 import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils;
21 import com.android.ide.eclipse.adt.internal.editors.descriptors.FlagAttributeDescriptor;
22 import com.android.ide.eclipse.adt.internal.editors.descriptors.TextAttributeDescriptor;
23 import com.android.ide.eclipse.adt.internal.editors.ui.SectionHelper;
24 import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
25
26 import org.eclipse.jface.dialogs.Dialog;
27 import org.eclipse.jface.resource.FontDescriptor;
28 import org.eclipse.jface.resource.JFaceResources;
29 import org.eclipse.swt.SWT;
30 import org.eclipse.swt.events.ControlAdapter;
31 import org.eclipse.swt.events.ControlEvent;
32 import org.eclipse.swt.events.SelectionAdapter;
33 import org.eclipse.swt.events.SelectionEvent;
34 import org.eclipse.swt.graphics.Font;
35 import org.eclipse.swt.graphics.Rectangle;
36 import org.eclipse.swt.layout.GridData;
37 import org.eclipse.swt.layout.GridLayout;
38 import org.eclipse.swt.widgets.Button;
39 import org.eclipse.swt.widgets.Composite;
40 import org.eclipse.swt.widgets.Control;
41 import org.eclipse.swt.widgets.Label;
42 import org.eclipse.swt.widgets.Shell;
43 import org.eclipse.swt.widgets.Table;
44 import org.eclipse.swt.widgets.TableColumn;
45 import org.eclipse.swt.widgets.TableItem;
46 import org.eclipse.swt.widgets.Text;
47 import org.eclipse.ui.dialogs.SelectionStatusDialog;
48 import org.eclipse.ui.forms.IManagedForm;
49 import org.eclipse.ui.forms.widgets.FormToolkit;
50 import org.eclipse.ui.forms.widgets.TableWrapData;
51
52 import java.util.ArrayList;
53 import java.util.HashSet;
54 import java.util.Set;
55
56 /**
57  * Represents an XML attribute that is defined by a set of flag values,
58  * i.e. enum names separated by pipe (|) characters.
59  * 
60  * Note: in Android resources, a "flag" is a list of fixed values where one or
61  * more values can be selected using an "or", e.g. "align='left|top'".
62  * By contrast, an "enum" is a list of fixed values of which only one can be
63  * selected at a given time, e.g. "gravity='right'".
64  * <p/>
65  * This class handles the "flag" case.
66  * The "enum" case is done using {@link UiListAttributeNode}.
67  */
68 public class UiFlagAttributeNode extends UiTextAttributeNode {
69
70     public UiFlagAttributeNode(FlagAttributeDescriptor attributeDescriptor,
71             UiElementNode uiParent) {
72         super(attributeDescriptor, uiParent);
73     }
74
75     /* (non-java doc)
76      * Creates a label widget and an associated text field.
77      * <p/>
78      * As most other parts of the android manifest editor, this assumes the
79      * parent uses a table layout with 2 columns.
80      */
81     @Override
82     public void createUiControl(Composite parent, IManagedForm managedForm) {
83         setManagedForm(managedForm);
84         FormToolkit toolkit = managedForm.getToolkit();
85         TextAttributeDescriptor desc = (TextAttributeDescriptor) getDescriptor();
86
87         Label label = toolkit.createLabel(parent, desc.getUiName());
88         label.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE));
89         SectionHelper.addControlTooltip(label, DescriptorsUtils.formatTooltip(desc.getTooltip()));
90
91         Composite composite = toolkit.createComposite(parent);
92         composite.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.MIDDLE));
93         GridLayout gl = new GridLayout(2, false);
94         gl.marginHeight = gl.marginWidth = 0;
95         composite.setLayout(gl);
96         // Fixes missing text borders under GTK... also requires adding a 1-pixel margin
97         // for the text field below
98         toolkit.paintBordersFor(composite);
99         
100         final Text text = toolkit.createText(composite, getCurrentValue());
101         GridData gd = new GridData(GridData.FILL_HORIZONTAL);
102         gd.horizontalIndent = 1;  // Needed by the fixed composite borders under GTK
103         text.setLayoutData(gd);
104         final Button selectButton = toolkit.createButton(composite, "Select...", SWT.PUSH);
105         
106         setTextWidget(text);
107         
108         selectButton.addSelectionListener(new SelectionAdapter() {
109             @Override
110             public void widgetSelected(SelectionEvent e) {
111                 super.widgetSelected(e);
112
113                 String currentText = getTextWidgetValue();
114                 
115                 String result = showDialog(selectButton.getShell(), currentText);
116                 
117                 if (result != null) {
118                     setTextWidgetValue(result);
119                 }
120             }
121         });
122     }
123
124     /**
125      * Get the flag names, either from the initial names set in the attribute
126      * or by querying the framework resource parser.
127      * 
128      * {@inheritDoc}
129      */
130     @Override
131     public String[] getPossibleValues(String prefix) {
132         String attr_name = getDescriptor().getXmlLocalName();
133         String element_name = getUiParent().getDescriptor().getXmlName();
134         
135         String[] values = null;
136         
137         if (getDescriptor() instanceof FlagAttributeDescriptor &&
138                 ((FlagAttributeDescriptor) getDescriptor()).getNames() != null) {
139             // Get enum values from the descriptor
140             values = ((FlagAttributeDescriptor) getDescriptor()).getNames();
141         }
142
143         if (values == null) {
144             // or from the AndroidTargetData
145             UiElementNode uiNode = getUiParent();
146             AndroidEditor editor = uiNode.getEditor();
147             AndroidTargetData data = editor.getTargetData();
148             if (data != null) {
149                 values = data.getAttributeValues(element_name, attr_name);
150             }
151         }
152         
153         return values;
154     }
155     
156     /**
157      * Shows a dialog letting the user choose a set of enum, and returns a string
158      * containing the result.
159      */
160     public String showDialog(Shell shell, String currentValue) {
161         FlagSelectionDialog dlg = new FlagSelectionDialog(
162                 shell, currentValue.trim().split("\\s*\\|\\s*")); //$NON-NLS-1$
163         dlg.open();
164         Object[] result = dlg.getResult();
165         if (result != null) {
166             StringBuilder buf = new StringBuilder();
167             for (Object name : result) {
168                 if (name instanceof String) {
169                     if (buf.length() > 0) {
170                         buf.append("|"); //$NON-NLS-1$
171                     }
172                     buf.append(name);
173                 }
174             }
175             
176             return buf.toString();
177         }
178         
179         return null;
180
181     }
182     
183     /**
184      * Displays a list of flag names with checkboxes.
185      */
186     private class FlagSelectionDialog extends SelectionStatusDialog {
187
188         private Set<String> mCurrentSet;
189         private Table mTable;
190
191         public FlagSelectionDialog(Shell parentShell, String[] currentNames) {
192             super(parentShell);
193             
194             mCurrentSet = new HashSet<String>();
195             for (String name : currentNames) {
196                 if (name.length() > 0) {
197                     mCurrentSet.add(name);
198                 }
199             }
200
201             int shellStyle = getShellStyle();
202             setShellStyle(shellStyle | SWT.MAX | SWT.RESIZE);
203         }
204
205         @Override
206         protected void computeResult() {
207             if (mTable != null) {
208                 ArrayList<String> results = new ArrayList<String>();
209                 
210                 for (TableItem item : mTable.getItems()) {
211                     if (item.getChecked()) {
212                         results.add((String)item.getData());
213                     }
214                 }
215                 
216                 setResult(results);
217             }
218         }
219
220         @Override
221         protected Control createDialogArea(Composite parent) {
222             Composite composite= new Composite(parent, SWT.NONE);
223             composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
224             composite.setLayout(new GridLayout(1, true));
225             composite.setFont(parent.getFont());
226             
227             Label label = new Label(composite, SWT.NONE);
228             label.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
229             label.setText(String.format("Select the flag values for attribute %1$s:",
230                     ((FlagAttributeDescriptor) getDescriptor()).getUiName()));
231  
232             mTable = new Table(composite, SWT.CHECK | SWT.BORDER);
233             GridData data = new GridData();
234             // The 60,18 hints are the ones used by AbstractElementListSelectionDialog
235             data.widthHint = convertWidthInCharsToPixels(60);
236             data.heightHint = convertHeightInCharsToPixels(18);
237             data.grabExcessVerticalSpace = true;
238             data.grabExcessHorizontalSpace = true;
239             data.horizontalAlignment = GridData.FILL;
240             data.verticalAlignment = GridData.FILL;
241             mTable.setLayoutData(data);
242
243             mTable.setHeaderVisible(false);
244             final TableColumn column = new TableColumn(mTable, SWT.NONE);
245
246             // List all the expected flag names and check those which are currently used
247             String[] names = getPossibleValues(null);
248             if (names != null) {
249                 for (String name : names) {
250                     TableItem item = new TableItem(mTable, SWT.NONE);
251                     item.setText(name);
252                     item.setData(name);
253                     
254                     boolean hasName = mCurrentSet.contains(name);
255                     item.setChecked(hasName);
256                     if (hasName) {
257                         mCurrentSet.remove(name);
258                     }
259                 }
260             }
261
262             // If there are unknown flag names currently used, display them at the end if the
263             // table already checked.
264             if (!mCurrentSet.isEmpty()) {
265                 FontDescriptor fontDesc = JFaceResources.getDialogFontDescriptor();
266                 fontDesc = fontDesc.withStyle(SWT.ITALIC);
267                 Font font = fontDesc.createFont(JFaceResources.getDialogFont().getDevice());
268
269                 for (String name : mCurrentSet) {
270                     TableItem item = new TableItem(mTable, SWT.NONE);
271                     item.setText(String.format("%1$s (unknown flag)", name));
272                     item.setData(name);
273                     item.setChecked(true);
274                     item.setFont(font);
275                 }
276             }
277             
278             // Add a listener that will resize the column to the full width of the table
279             // so that only one column appears in the table even if the dialog is resized.
280             ControlAdapter listener = new ControlAdapter() {
281                 @Override
282                 public void controlResized(ControlEvent e) {
283                     Rectangle r = mTable.getClientArea();
284                     column.setWidth(r.width);
285                 }
286             };
287             
288             mTable.addControlListener(listener);
289             listener.controlResized(null /* event not used */);
290
291             // Add a selection listener that will check/uncheck items when they are double-clicked
292             mTable.addSelectionListener(new SelectionAdapter() {
293                 /** Default selection means double-click on "most" platforms */
294                 @Override
295                 public void widgetDefaultSelected(SelectionEvent e) {
296                     if (e.item instanceof TableItem) {
297                         TableItem i = (TableItem) e.item;
298                         i.setChecked(!i.getChecked());
299                     }
300                     super.widgetDefaultSelected(e);
301                 } 
302             });
303             
304             Dialog.applyDialogFont(composite);            
305             setHelpAvailable(false);
306             
307             return composite;
308         }
309     }
310 }