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