• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.ui;
18 
19 import com.android.ide.eclipse.adt.AdtPlugin;
20 import com.android.ide.eclipse.adt.internal.editors.AndroidEditor;
21 
22 import org.eclipse.jface.text.DefaultInformationControl;
23 import org.eclipse.swt.events.MouseEvent;
24 import org.eclipse.swt.events.MouseTrackListener;
25 import org.eclipse.swt.graphics.Point;
26 import org.eclipse.swt.layout.GridLayout;
27 import org.eclipse.swt.widgets.Button;
28 import org.eclipse.swt.widgets.Composite;
29 import org.eclipse.swt.widgets.Control;
30 import org.eclipse.swt.widgets.Label;
31 import org.eclipse.swt.widgets.Text;
32 import org.eclipse.ui.forms.SectionPart;
33 import org.eclipse.ui.forms.widgets.FormText;
34 import org.eclipse.ui.forms.widgets.FormToolkit;
35 import org.eclipse.ui.forms.widgets.Section;
36 import org.eclipse.ui.forms.widgets.TableWrapData;
37 import org.eclipse.ui.forms.widgets.TableWrapLayout;
38 
39 import java.lang.reflect.Method;
40 
41 /**
42  * Helper for the AndroidManifest form editor.
43  *
44  * Helps create a new SectionPart with sensible default parameters,
45  * create default layout or add typical widgets.
46  *
47  * IMPORTANT: This is NOT a generic class. It makes a lot of assumptions on the
48  * UI as used by the form editor for the AndroidManifest.
49  *
50  * TODO: Consider moving to a common package.
51  */
52 public final class SectionHelper {
53 
54     /**
55      * Utility class that derives from SectionPart, constructs the Section with
56      * sensible defaults (with a title and a description) and provide some shorthand
57      * methods for creating typically UI (label and text, form text.)
58      */
59     static public class ManifestSectionPart extends SectionPart {
60 
61         /**
62          * Construct a SectionPart that uses a title bar and a description.
63          * It's up to the caller to call setText() and setDescription().
64          * <p/>
65          * The section style includes a description and a title bar by default.
66          *
67          * @param body The parent (e.g. FormPage body)
68          * @param toolkit Form Toolkit
69          */
ManifestSectionPart(Composite body, FormToolkit toolkit)70         public ManifestSectionPart(Composite body, FormToolkit toolkit) {
71             this(body, toolkit, 0, false);
72         }
73 
74         /**
75          * Construct a SectionPart that uses a title bar and a description.
76          * It's up to the caller to call setText() and setDescription().
77          * <p/>
78          * The section style includes a description and a title bar by default.
79          * You can add extra styles, like Section.TWISTIE.
80          *
81          * @param body The parent (e.g. FormPage body).
82          * @param toolkit Form Toolkit.
83          * @param extra_style Extra styles (on top of description and title bar).
84          * @param use_description True if the Section.DESCRIPTION style should be added.
85          */
ManifestSectionPart(Composite body, FormToolkit toolkit, int extra_style, boolean use_description)86         public ManifestSectionPart(Composite body, FormToolkit toolkit,
87                 int extra_style, boolean use_description) {
88             super(body, toolkit, extra_style |
89                     Section.TITLE_BAR |
90                     (use_description ? Section.DESCRIPTION : 0));
91         }
92 
93         // Create non-static methods of helpers just for convenience
94 
95         /**
96          * Creates a new composite with a TableWrapLayout set with a given number of columns.
97          *
98          * If the parent composite is a Section, the new composite is set as a client.
99          *
100          * @param toolkit Form Toolkit
101          * @param numColumns Desired number of columns.
102          * @return The new composite.
103          */
createTableLayout(FormToolkit toolkit, int numColumns)104         public Composite createTableLayout(FormToolkit toolkit, int numColumns) {
105             return SectionHelper.createTableLayout(getSection(), toolkit, numColumns);
106         }
107 
108         /**
109          * Creates a label widget.
110          * If the parent layout if a TableWrapLayout, maximize it to span over all columns.
111          *
112          * @param parent The parent (e.g. composite from CreateTableLayout())
113          * @param toolkit Form Toolkit
114          * @param label The string for the label.
115          * @param tooltip An optional tooltip for the label and text. Can be null.
116          * @return The new created label
117          */
createLabel(Composite parent, FormToolkit toolkit, String label, String tooltip)118         public Label createLabel(Composite parent, FormToolkit toolkit, String label,
119                 String tooltip) {
120             return SectionHelper.createLabel(parent, toolkit, label, tooltip);
121         }
122 
123         /**
124          * Creates two widgets: a label and a text field.
125          *
126          * This expects the parent composite to have a TableWrapLayout with 2 columns.
127          *
128          * @param parent The parent (e.g. composite from CreateTableLayout())
129          * @param toolkit Form Toolkit
130          * @param label The string for the label.
131          * @param value The initial value of the text field. Can be null.
132          * @param tooltip An optional tooltip for the label and text. Can be null.
133          * @return The new created Text field (the label is not returned)
134          */
createLabelAndText(Composite parent, FormToolkit toolkit, String label, String value, String tooltip)135         public Text createLabelAndText(Composite parent, FormToolkit toolkit, String label,
136                 String value, String tooltip) {
137             return SectionHelper.createLabelAndText(parent, toolkit, label, value, tooltip);
138         }
139 
140         /**
141          * Creates a FormText widget.
142          *
143          * This expects the parent composite to have a TableWrapLayout with 2 columns.
144          *
145          * @param parent The parent (e.g. composite from CreateTableLayout())
146          * @param toolkit Form Toolkit
147          * @param isHtml True if the form text will contain HTML that must be interpreted as
148          *               rich text (i.e. parse tags & expand URLs).
149          * @param label The string for the label.
150          * @param setupLayoutData indicates whether the created form text receives a TableWrapData
151          * through the setLayoutData method. In some case, creating it will make the table parent
152          * huge, which we don't want.
153          * @return The new created FormText.
154          */
createFormText(Composite parent, FormToolkit toolkit, boolean isHtml, String label, boolean setupLayoutData)155         public FormText createFormText(Composite parent, FormToolkit toolkit, boolean isHtml,
156                 String label, boolean setupLayoutData) {
157             return SectionHelper.createFormText(parent, toolkit, isHtml, label, setupLayoutData);
158         }
159 
160         /**
161          * Forces the section to recompute its layout and redraw.
162          * This is needed after the content of the section has been changed at runtime.
163          */
layoutChanged()164         public void layoutChanged() {
165             Section section = getSection();
166 
167             // Calls getSection().reflow(), which is the same that Section calls
168             // when the expandable state is changed and the height changes.
169             // Since this is protected, some reflection is needed to invoke it.
170             try {
171                 Method reflow;
172                 reflow = section.getClass().getDeclaredMethod("reflow", (Class<?>[])null);
173                 reflow.setAccessible(true);
174                 reflow.invoke(section);
175             } catch (Exception e) {
176                 AdtPlugin.log(e, "Error when invoking Section.reflow");
177             }
178 
179             section.layout(true /* changed */, true /* all */);
180         }
181     }
182 
183     /**
184      * Creates a new composite with a TableWrapLayout set with a given number of columns.
185      *
186      * If the parent composite is a Section, the new composite is set as a client.
187      *
188      * @param composite The parent (e.g. a Section or SectionPart)
189      * @param toolkit Form Toolkit
190      * @param numColumns Desired number of columns.
191      * @return The new composite.
192      */
createTableLayout(Composite composite, FormToolkit toolkit, int numColumns)193     static public Composite createTableLayout(Composite composite, FormToolkit toolkit,
194             int numColumns) {
195         Composite table = toolkit.createComposite(composite);
196         TableWrapLayout layout = new TableWrapLayout();
197         layout.numColumns = numColumns;
198         table.setLayout(layout);
199         toolkit.paintBordersFor(table);
200         if (composite instanceof Section) {
201             ((Section) composite).setClient(table);
202         }
203         return table;
204     }
205 
206     /**
207      * Creates a new composite with a GridLayout set with a given number of columns.
208      *
209      * If the parent composite is a Section, the new composite is set as a client.
210      *
211      * @param composite The parent (e.g. a Section or SectionPart)
212      * @param toolkit Form Toolkit
213      * @param numColumns Desired number of columns.
214      * @return The new composite.
215      */
createGridLayout(Composite composite, FormToolkit toolkit, int numColumns)216     static public Composite createGridLayout(Composite composite, FormToolkit toolkit,
217             int numColumns) {
218         Composite grid = toolkit.createComposite(composite);
219         GridLayout layout = new GridLayout();
220         layout.numColumns = numColumns;
221         grid.setLayout(layout);
222         toolkit.paintBordersFor(grid);
223         if (composite instanceof Section) {
224             ((Section) composite).setClient(grid);
225         }
226         return grid;
227     }
228 
229     /**
230      * Creates two widgets: a label and a text field.
231      *
232      * This expects the parent composite to have a TableWrapLayout with 2 columns.
233      *
234      * @param parent The parent (e.g. composite from CreateTableLayout())
235      * @param toolkit Form Toolkit
236      * @param label_text The string for the label.
237      * @param value The initial value of the text field. Can be null.
238      * @param tooltip An optional tooltip for the label and text. Can be null.
239      * @return The new created Text field (the label is not returned)
240      */
createLabelAndText(Composite parent, FormToolkit toolkit, String label_text, String value, String tooltip)241     static public Text createLabelAndText(Composite parent, FormToolkit toolkit, String label_text,
242             String value, String tooltip) {
243         Label label = toolkit.createLabel(parent, label_text);
244         label.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE));
245         Text text = toolkit.createText(parent, value);
246         text.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.MIDDLE));
247 
248         addControlTooltip(label, tooltip);
249         return text;
250     }
251 
252     /**
253      * Creates a label widget.
254      * If the parent layout if a TableWrapLayout, maximize it to span over all columns.
255      *
256      * @param parent The parent (e.g. composite from CreateTableLayout())
257      * @param toolkit Form Toolkit
258      * @param label_text The string for the label.
259      * @param tooltip An optional tooltip for the label and text. Can be null.
260      * @return The new created label
261      */
createLabel(Composite parent, FormToolkit toolkit, String label_text, String tooltip)262     static public Label createLabel(Composite parent, FormToolkit toolkit, String label_text,
263             String tooltip) {
264         Label label = toolkit.createLabel(parent, label_text);
265 
266         TableWrapData twd = new TableWrapData(TableWrapData.FILL_GRAB);
267         if (parent.getLayout() instanceof TableWrapLayout) {
268             twd.colspan = ((TableWrapLayout) parent.getLayout()).numColumns;
269         }
270         label.setLayoutData(twd);
271 
272         addControlTooltip(label, tooltip);
273         return label;
274     }
275 
276     /**
277      * Associates a tooltip with a control.
278      *
279      * This mirrors the behavior from org.eclipse.pde.internal.ui.editor.text.PDETextHover
280      *
281      * @param control The control to which associate the tooltip.
282      * @param tooltip The tooltip string. Can use \n for multi-lines. Will not display if null.
283      */
addControlTooltip(final Control control, String tooltip)284     static public void addControlTooltip(final Control control, String tooltip) {
285         if (control == null || tooltip == null || tooltip.length() == 0) {
286             return;
287         }
288 
289         // Some kinds of controls already properly implement tooltip display.
290         if (control instanceof Button) {
291             control.setToolTipText(tooltip);
292             return;
293         }
294 
295         control.setToolTipText(null);
296 
297         final DefaultInformationControl ic = new DefaultInformationControl(control.getShell());
298         ic.setInformation(tooltip);
299         Point sz = ic.computeSizeHint();
300         ic.setSize(sz.x, sz.y);
301         ic.setVisible(false); // initially hidden
302 
303         control.addMouseTrackListener(new MouseTrackListener() {
304             public void mouseEnter(MouseEvent e) {
305             }
306 
307             public void mouseExit(MouseEvent e) {
308                 ic.setVisible(false);
309             }
310 
311             public void mouseHover(MouseEvent e) {
312                 ic.setLocation(control.toDisplay(10, 25));  // same offset as in PDETextHover
313                 ic.setVisible(true);
314             }
315         });
316     }
317 
318     /**
319      * Creates a FormText widget.
320      *
321      * This expects the parent composite to have a TableWrapLayout with 2 columns.
322      *
323      * @param parent The parent (e.g. composite from CreateTableLayout())
324      * @param toolkit Form Toolkit
325      * @param isHtml True if the form text will contain HTML that must be interpreted as
326      *               rich text (i.e. parse tags & expand URLs).
327      * @param label The string for the label.
328      * @param setupLayoutData indicates whether the created form text receives a TableWrapData
329      * through the setLayoutData method. In some case, creating it will make the table parent
330      * huge, which we don't want.
331      * @return The new created FormText.
332      */
createFormText(Composite parent, FormToolkit toolkit, boolean isHtml, String label, boolean setupLayoutData)333     static public FormText createFormText(Composite parent, FormToolkit toolkit,
334             boolean isHtml, String label, boolean setupLayoutData) {
335         FormText text = toolkit.createFormText(parent, true /* track focus */);
336         if (setupLayoutData) {
337             TableWrapData twd = new TableWrapData(TableWrapData.FILL_GRAB);
338             twd.maxWidth = AndroidEditor.TEXT_WIDTH_HINT;
339             if (parent.getLayout() instanceof TableWrapLayout) {
340                 twd.colspan = ((TableWrapLayout) parent.getLayout()).numColumns;
341             }
342             text.setLayoutData(twd);
343         }
344         text.setWhitespaceNormalized(true);
345         text.setText(label, isHtml /* parseTags */, isHtml /* expandURLs */);
346         return text;
347     }
348 }
349