| /* |
| * 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; |
| } |
| } |