diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/ui/SectionHelper.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/ui/SectionHelper.java | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/ui/SectionHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/ui/SectionHelper.java new file mode 100644 index 000000000..fdb5d8292 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/ui/SectionHelper.java @@ -0,0 +1,364 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ide.eclipse.adt.internal.editors.ui; + +import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor; + +import org.eclipse.jface.text.DefaultInformationControl; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseTrackListener; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.forms.SectionPart; +import org.eclipse.ui.forms.widgets.FormText; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.Section; +import org.eclipse.ui.forms.widgets.TableWrapData; +import org.eclipse.ui.forms.widgets.TableWrapLayout; + +import java.lang.reflect.Method; + +/** + * Helper for the AndroidManifest form editor. + * + * Helps create a new SectionPart with sensible default parameters, + * create default layout or add typical widgets. + * + * IMPORTANT: This is NOT a generic class. It makes a lot of assumptions on the + * UI as used by the form editor for the AndroidManifest. + * + * TODO: Consider moving to a common package. + */ +public final class SectionHelper { + + /** + * Utility class that derives from SectionPart, constructs the Section with + * sensible defaults (with a title and a description) and provide some shorthand + * methods for creating typically UI (label and text, form text.) + */ + static public class ManifestSectionPart extends SectionPart { + + /** + * Construct a SectionPart that uses a title bar and a description. + * It's up to the caller to call setText() and setDescription(). + * <p/> + * The section style includes a description and a title bar by default. + * + * @param body The parent (e.g. FormPage body) + * @param toolkit Form Toolkit + */ + public ManifestSectionPart(Composite body, FormToolkit toolkit) { + this(body, toolkit, 0, false); + } + + /** + * Construct a SectionPart that uses a title bar and a description. + * It's up to the caller to call setText() and setDescription(). + * <p/> + * The section style includes a description and a title bar by default. + * You can add extra styles, like Section.TWISTIE. + * + * @param body The parent (e.g. FormPage body). + * @param toolkit Form Toolkit. + * @param extra_style Extra styles (on top of description and title bar). + * @param use_description True if the Section.DESCRIPTION style should be added. + */ + public ManifestSectionPart(Composite body, FormToolkit toolkit, + int extra_style, boolean use_description) { + super(body, toolkit, extra_style | + Section.TITLE_BAR | + (use_description ? Section.DESCRIPTION : 0)); + } + + // Create non-static methods of helpers just for convenience + + /** + * Creates a new composite with a TableWrapLayout set with a given number of columns. + * + * If the parent composite is a Section, the new composite is set as a client. + * + * @param toolkit Form Toolkit + * @param numColumns Desired number of columns. + * @return The new composite. + */ + public Composite createTableLayout(FormToolkit toolkit, int numColumns) { + return SectionHelper.createTableLayout(getSection(), toolkit, numColumns); + } + + /** + * Creates a label widget. + * If the parent layout if a TableWrapLayout, maximize it to span over all columns. + * + * @param parent The parent (e.g. composite from CreateTableLayout()) + * @param toolkit Form Toolkit + * @param label The string for the label. + * @param tooltip An optional tooltip for the label and text. Can be null. + * @return The new created label + */ + public Label createLabel(Composite parent, FormToolkit toolkit, String label, + String tooltip) { + return SectionHelper.createLabel(parent, toolkit, label, tooltip); + } + + /** + * Creates two widgets: a label and a text field. + * + * This expects the parent composite to have a TableWrapLayout with 2 columns. + * + * @param parent The parent (e.g. composite from CreateTableLayout()) + * @param toolkit Form Toolkit + * @param label The string for the label. + * @param value The initial value of the text field. Can be null. + * @param tooltip An optional tooltip for the label and text. Can be null. + * @return The new created Text field (the label is not returned) + */ + public Text createLabelAndText(Composite parent, FormToolkit toolkit, String label, + String value, String tooltip) { + return SectionHelper.createLabelAndText(parent, toolkit, label, value, tooltip); + } + + /** + * Creates a FormText widget. + * + * This expects the parent composite to have a TableWrapLayout with 2 columns. + * + * @param parent The parent (e.g. composite from CreateTableLayout()) + * @param toolkit Form Toolkit + * @param isHtml True if the form text will contain HTML that must be interpreted as + * rich text (i.e. parse tags & expand URLs). + * @param label The string for the label. + * @param setupLayoutData indicates whether the created form text receives a TableWrapData + * through the setLayoutData method. In some case, creating it will make the table parent + * huge, which we don't want. + * @return The new created FormText. + */ + public FormText createFormText(Composite parent, FormToolkit toolkit, boolean isHtml, + String label, boolean setupLayoutData) { + return SectionHelper.createFormText(parent, toolkit, isHtml, label, setupLayoutData); + } + + /** + * Forces the section to recompute its layout and redraw. + * This is needed after the content of the section has been changed at runtime. + */ + public void layoutChanged() { + Section section = getSection(); + + // Calls getSection().reflow(), which is the same that Section calls + // when the expandable state is changed and the height changes. + // Since this is protected, some reflection is needed to invoke it. + try { + Method reflow; + reflow = section.getClass().getDeclaredMethod("reflow", (Class<?>[])null); + reflow.setAccessible(true); + reflow.invoke(section); + } catch (Exception e) { + AdtPlugin.log(e, "Error when invoking Section.reflow"); + } + + section.layout(true /* changed */, true /* all */); + } + } + + /** + * Creates a new composite with a TableWrapLayout set with a given number of columns. + * + * If the parent composite is a Section, the new composite is set as a client. + * + * @param composite The parent (e.g. a Section or SectionPart) + * @param toolkit Form Toolkit + * @param numColumns Desired number of columns. + * @return The new composite. + */ + static public Composite createTableLayout(Composite composite, FormToolkit toolkit, + int numColumns) { + Composite table = toolkit.createComposite(composite); + TableWrapLayout layout = new TableWrapLayout(); + layout.numColumns = numColumns; + table.setLayout(layout); + toolkit.paintBordersFor(table); + if (composite instanceof Section) { + ((Section) composite).setClient(table); + } + return table; + } + + /** + * Creates a new composite with a GridLayout set with a given number of columns. + * + * If the parent composite is a Section, the new composite is set as a client. + * + * @param composite The parent (e.g. a Section or SectionPart) + * @param toolkit Form Toolkit + * @param numColumns Desired number of columns. + * @return The new composite. + */ + static public Composite createGridLayout(Composite composite, FormToolkit toolkit, + int numColumns) { + Composite grid = toolkit.createComposite(composite); + GridLayout layout = new GridLayout(); + layout.numColumns = numColumns; + grid.setLayout(layout); + toolkit.paintBordersFor(grid); + if (composite instanceof Section) { + ((Section) composite).setClient(grid); + } + return grid; + } + + /** + * Creates two widgets: a label and a text field. + * + * This expects the parent composite to have a TableWrapLayout with 2 columns. + * + * @param parent The parent (e.g. composite from CreateTableLayout()) + * @param toolkit Form Toolkit + * @param label_text The string for the label. + * @param value The initial value of the text field. Can be null. + * @param tooltip An optional tooltip for the label and text. Can be null. + * @return The new created Text field (the label is not returned) + */ + static public Text createLabelAndText(Composite parent, FormToolkit toolkit, String label_text, + String value, String tooltip) { + Label label = toolkit.createLabel(parent, label_text); + label.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE)); + Text text = toolkit.createText(parent, value); + text.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.MIDDLE)); + + addControlTooltip(label, tooltip); + return text; + } + + /** + * Creates a label widget. + * If the parent layout if a TableWrapLayout, maximize it to span over all columns. + * + * @param parent The parent (e.g. composite from CreateTableLayout()) + * @param toolkit Form Toolkit + * @param label_text The string for the label. + * @param tooltip An optional tooltip for the label and text. Can be null. + * @return The new created label + */ + static public Label createLabel(Composite parent, FormToolkit toolkit, String label_text, + String tooltip) { + Label label = toolkit.createLabel(parent, label_text); + + TableWrapData twd = new TableWrapData(TableWrapData.FILL_GRAB); + if (parent.getLayout() instanceof TableWrapLayout) { + twd.colspan = ((TableWrapLayout) parent.getLayout()).numColumns; + } + label.setLayoutData(twd); + + addControlTooltip(label, tooltip); + return label; + } + + /** + * Associates a tooltip with a control. + * + * This mirrors the behavior from org.eclipse.pde.internal.ui.editor.text.PDETextHover + * + * @param control The control to which associate the tooltip. + * @param tooltip The tooltip string. Can use \n for multi-lines. Will not display if null. + */ + static public void addControlTooltip(final Control control, String tooltip) { + if (control == null || tooltip == null || tooltip.length() == 0) { + return; + } + + // Some kinds of controls already properly implement tooltip display. + if (control instanceof Button) { + control.setToolTipText(tooltip); + return; + } + + control.setToolTipText(null); + + final DefaultInformationControl ic = new DefaultInformationControl(control.getShell()); + ic.setInformation(tooltip); + Point sz = ic.computeSizeHint(); + ic.setSize(sz.x, sz.y); + ic.setVisible(false); // initially hidden + + control.addMouseTrackListener(new MouseTrackListener() { + @Override + public void mouseEnter(MouseEvent e) { + } + + @Override + public void mouseExit(MouseEvent e) { + ic.setVisible(false); + } + + @Override + public void mouseHover(MouseEvent e) { + ic.setLocation(control.toDisplay(10, 25)); // same offset as in PDETextHover + ic.setVisible(true); + } + }); + control.addDisposeListener(new DisposeListener() { + @Override + public void widgetDisposed(DisposeEvent e) { + ic.dispose(); + } + }); + } + + /** + * Creates a FormText widget. + * + * This expects the parent composite to have a TableWrapLayout with 2 columns. + * + * @param parent The parent (e.g. composite from CreateTableLayout()) + * @param toolkit Form Toolkit + * @param isHtml True if the form text will contain HTML that must be interpreted as + * rich text (i.e. parse tags & expand URLs). + * @param label The string for the label. + * @param setupLayoutData indicates whether the created form text receives a TableWrapData + * through the setLayoutData method. In some case, creating it will make the table parent + * huge, which we don't want. + * @return The new created FormText. + */ + static public FormText createFormText(Composite parent, FormToolkit toolkit, + boolean isHtml, String label, boolean setupLayoutData) { + FormText text = toolkit.createFormText(parent, true /* track focus */); + if (setupLayoutData) { + TableWrapData twd = new TableWrapData(TableWrapData.FILL_GRAB); + twd.maxWidth = AndroidXmlEditor.TEXT_WIDTH_HINT; + if (parent.getLayout() instanceof TableWrapLayout) { + twd.colspan = ((TableWrapLayout) parent.getLayout()).numColumns; + } + text.setLayoutData(twd); + } + text.setWhitespaceNormalized(true); + if (isHtml && !label.startsWith("<form>")) { //$NON-NLS-1$ + // This assertion is violated, for example by the Class attribute for an activity + //assert label.startsWith("<form>") : "HTML for FormText must be wrapped in <form>...</form>"; //$NON-NLS-1$ + label = "<form>" + label + "</form>"; //$NON-NLS-1$ //$NON-NLS-2$ + } + text.setText(label, isHtml /* parseTags */, isHtml /* expandURLs */); + return text; + } +} |