blob: f4826472d65f7ac65abf4f7ee2ad0b6a26a01c6d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2015 THALES GLOBAL SERVICES.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Thales - initial API and implementation
*******************************************************************************/
package org.eclipse.amalgam.explorer.activity.api.editor.pages.helper;
import java.util.List;
import org.eclipse.amalgam.explorer.activity.internal.Couple;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
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.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.ui.forms.IFormColors;
import org.eclipse.ui.forms.IManagedForm;
import org.eclipse.ui.forms.events.ExpansionAdapter;
import org.eclipse.ui.forms.events.ExpansionEvent;
import org.eclipse.ui.forms.events.IHyperlinkListener;
import org.eclipse.ui.forms.widgets.ExpandableComposite;
import org.eclipse.ui.forms.widgets.FormText;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.ImageHyperlink;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.forms.widgets.TableWrapData;
import org.eclipse.ui.forms.widgets.TableWrapLayout;
/**
* UI Forms helper.<br>
* Allows creation of Composites, Layouts and Forms widgets.
*
*/
public class FormHelper {
/**
* Layout usable types.
*
*/
public static enum LayoutType {
GRID_LAYOUT, TABLEWRAP_LAYOUT
}
/**
* Create a new composite and set the layout using
* {@link #updateCompositeLayoutWithLayoutType(Composite, org.eclipse.amalgam.explorer.activity.api.editor.pages.helper.mdsofa.common.ui.helper.FormHelper.LayoutType, int)}
* method.
*
* @param toolkit_p
* @param parent_p
* @param numColumns_p
* @return
*/
public static Composite createCompositeWithLayoutType(FormToolkit toolkit_p, Composite parent_p,
LayoutType layoutType_p, int numColumns_p, boolean equalWidth_p) {
Composite result = toolkit_p.createComposite(parent_p);
updateCompositeLayoutWithLayoutType(result, layoutType_p, numColumns_p, equalWidth_p);
return result;
}
/**
* Create a user text widget with preceding label.<br>
* Requires at least a two columns layout so that both the label and the
* text are displayed on the same line.
*
* @param toolkit_p
* @param parent_p
* @param labelMessage_p
* @param initialText_p
* @param editable_p
* @return
*/
public static Couple<Label, Text> createLabelAndText(FormToolkit toolkit_p, Composite parent_p,
String labelMessage_p, String initialText_p, boolean editable_p) {
// Create label.
Label label = toolkit_p.createLabel(parent_p, labelMessage_p, SWT.WRAP);
label.setForeground(toolkit_p.getColors().getColor(IFormColors.TITLE));
// Create text.
Text text = new Text(parent_p, SWT.BORDER);
text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
// Set existing value.
if (null != initialText_p) {
text.setText(initialText_p);
}
// Set editable state.
text.setEditable(editable_p);
return new Couple<Label, Text>(label, text);
}
/**
* Create a user text widget with preceding label and following button.<br>
* Requires at least a three columns layout so that the label, the text and
* the button are displayed on the same line.
*
* @param toolkit_p
* @param parent_p
* @param labelMessage_p
* @param buttonLabel_p
* @param listener_p
* @return
*/
public static Couple<Text, Button> createLabelTextAndButton(FormToolkit toolkit_p, Composite parent_p,
String labelMessage_p, String buttonLabel_p, SelectionListener listener_p) {
// Create label and text.
Couple<Label, Text> labelAndText = createLabelAndText(toolkit_p, parent_p, labelMessage_p, null, true);
// Create button.
Button button = toolkit_p.createButton(parent_p, buttonLabel_p, SWT.PUSH);
// Add button listener.
if (null != listener_p) {
button.addSelectionListener(listener_p);
}
return new Couple<Text, Button>(labelAndText.getValue(), button);
}
/**
* Create a link with a label description.<br>
* Requires a two columns layout so that both the link and the label are
* displayed on the same line.
*
* @param toolkit_p
* @param parent_p
* @param icon_p
* @param linkText_p
* @param linkRef_p
* @param linkDescription_p
* can be <code>null</code>, if not necessary. Description is
* rendered as a tooltip.
* @param listener_p
*/
public static ImageHyperlink createLinkWithDescription(FormToolkit toolkit_p, Composite parent_p, Image icon_p,
String linkText_p, Object linkRef_p, String linkDescription_p, IHyperlinkListener listener_p) {
ImageHyperlink specificationLink = toolkit_p.createImageHyperlink(parent_p, SWT.WRAP);
specificationLink.setText(linkText_p);
if (null != linkDescription_p) {
specificationLink.setToolTipText(linkDescription_p);
}
if (icon_p != null)
specificationLink.setImage(icon_p);
if (linkRef_p != null)
specificationLink.setHref(linkRef_p);
if (listener_p != null)
specificationLink.addHyperlinkListener(listener_p);
return specificationLink;
}
/**
* Create a rich {@link FormText} with specified parameters.
*
* @param toolkit_p
* @param parent_p
* @param content_p
* @param listener_p
*/
public static FormText createRichText(FormToolkit toolkit_p, Composite parent_p, String content_p,
IHyperlinkListener listener_p) {
// Create the form text.
FormText text = toolkit_p.createFormText(parent_p, false);
if (null != content_p) {
try {
// Set its pseudo HTML content.
text.setText(content_p, true, false);
} catch (SWTException e) {
text.setText(e.getMessage(), false, false);
}
}
if (null != listener_p) {
text.addHyperlinkListener(listener_p);
}
return text;
}
/**
* Create a section with a composite child using given child layout type.<br>
* Created section layouts in filling and grabbing in both directions.
*
* @param toolkit_p
* @param parent_p
* @param sectionStyle_p
* @param layoutType_p
* @param childNumColumns_p
* @param equalWidth_p
* @return
*/
public static Couple<Section, Composite> createSectionWithChildComposite(FormToolkit toolkit_p, Composite parent_p,
int sectionStyle_p, LayoutType layoutType_p, int childNumColumns_p, boolean equalWidth_p) {
Section resultingSection = toolkit_p.createSection(parent_p, sectionStyle_p);
updateControlLayoutDataWithLayoutTypeData(resultingSection, layoutType_p);
Composite childComposite = createCompositeWithLayoutType(toolkit_p, resultingSection, layoutType_p,
childNumColumns_p, equalWidth_p);
resultingSection.setClient(childComposite);
return new Couple<Section, Composite>(resultingSection, childComposite);
}
/**
* Create a section with specified title and description.<br>
* The created section layouts its content according to the
* {@link TableWrapLayout}.
*
* @param toolkit_p
* @param parent_p
* @param title_p
* @param description_p
* can be <code>null</code>
* @return a {@link Couple} containing the child composite and the created
* section.
*/
public static Couple<Section, Composite> createSectionWithDescription(FormToolkit toolkit_p, Composite parent_p,
String title_p, String description_p) {
// Create the section style.
int sectionStyle = ExpandableComposite.TITLE_BAR;
if (null != description_p) {
// Add description style.
sectionStyle |= Section.DESCRIPTION;
}
// Create the section.
Couple<Section, Composite> createdSectionWithChildComposite = createSectionWithChildComposite(toolkit_p,
parent_p, sectionStyle, LayoutType.GRID_LAYOUT, 1, true);
// Get created section.
Section section = createdSectionWithChildComposite.getKey();
// Set it its title.
section.setText(title_p);
// Set it its description if necessary.
if (null != description_p) {
section.setDescription(description_p);
}
return createdSectionWithChildComposite;
}
/**
* Create a section with specified title and description.<br>
* The created section layouts its content according to the
* {@link TableWrapLayout}.
*
* @param managedForm_p
* @param parent_p
* @param title_p
* @param description_p
* can be <code>null</code>
* @return a {@link Couple} containing the child composite and the created
* section.
*/
public static Couple<Section, Composite> createTwistieSectionWithDescription(final IManagedForm managedForm_p,
Composite parent_p, String title_p, String description_p) {
// Create the section style.
int sectionStyle = ExpandableComposite.TWISTIE | ExpandableComposite.TITLE_BAR;
if (null != description_p) {
// Add description style.
sectionStyle |= Section.DESCRIPTION;
}
// Create the section.
Couple<Section, Composite> createdSectionWithChildComposite = createSectionWithChildComposite(
managedForm_p.getToolkit(), parent_p, sectionStyle, LayoutType.TABLEWRAP_LAYOUT, 1, true);
// Get created section.
Section section = createdSectionWithChildComposite.getKey();
section.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB));
// Set it its title.
section.setText(title_p);
// Set it its description if necessary.
if (null != description_p) {
section.setDescription(description_p);
}
// Handle expansion.
section.addExpansionListener(new ExpansionAdapter() {
@Override
public void expansionStateChanged(ExpansionEvent e) {
managedForm_p.reflow(false);
}
});
return createdSectionWithChildComposite;
}
/**
* Create a twistie section with a title, a description and a toolbar.
*
* @param sectionContainer_p
* @param managedForm_p
* @param title_p
* @param description_p
* can be <code>null</code>
* @param isExpanded_p
* Is the section expanded at startup.
* @param toolbarActions_p
* can be <code>null</code>
* @return
*/
public static Couple<Section, Composite> createTwistieSectionWithToolbar(Composite sectionContainer_p,
IManagedForm managedForm_p, String title_p, String description_p, boolean isExpanded_p,
List<? extends IAction> toolbarActions_p) {
// Create the section.
Couple<Section, Composite> createdSection = FormHelper.createTwistieSectionWithDescription(managedForm_p,
sectionContainer_p, title_p, description_p);
// Make this section expanded at construction time.
Section section = createdSection.getKey();
section.setExpanded(isExpanded_p);
// Create the toolbar for the section.
if (null != toolbarActions_p) {
createSectionToolbar(section, toolbarActions_p);
}
return createdSection;
}
/**
* Force control size.
*
* @param control_p
* @param widthInChars_p
* The expected width, in number of chars to display.
* @param heightInChars_p
* The expected height, in number of chars to display.
*/
public static void forceControlSize(Control control_p, int widthInChars_p, int heightInChars_p) {
// Preconditions.
if ((null == control_p) || (0 >= widthInChars_p) || (0 >= heightInChars_p)) {
return;
}
// Get font metrics.
GC gc = new GC(control_p);
FontMetrics fontMetrics = gc.getFontMetrics();
gc.dispose();
// Get layout data.
Object layoutData = control_p.getLayoutData();
if (layoutData instanceof GridData) {
GridData data = (GridData) layoutData;
data.widthHint = Dialog.convertWidthInCharsToPixels(fontMetrics, widthInChars_p);
data.heightHint = Dialog.convertHeightInCharsToPixels(fontMetrics, heightInChars_p);
} else if (layoutData instanceof TableWrapData) {
TableWrapData data = (TableWrapData) layoutData;
data.heightHint = Dialog.convertHeightInCharsToPixels(fontMetrics, heightInChars_p);
}
}
/**
* Update given composite with given layout type and given number of columns
* (if it makes any sense).<br>
* Also set the layout data to
* {@link #updateControlLayoutDataWithLayoutTypeData(Composite, org.eclipse.amalgam.explorer.activity.api.editor.pages.helper.mdsofa.common.ui.helper.FormHelper.LayoutType)}
* .
*
* @param composite_p
* @param layoutType_p
* @param numColumns_p
*/
public static Object updateCompositeLayoutWithLayoutType(Composite composite_p, LayoutType layoutType_p,
int numColumns_p, boolean equalWidth_p) {
Layout selectedLayout = null;
if (LayoutType.GRID_LAYOUT.equals(layoutType_p)) {
GridLayout layout = new GridLayout();
layout.numColumns = numColumns_p;
layout.makeColumnsEqualWidth = equalWidth_p;
selectedLayout = layout;
} else if (LayoutType.TABLEWRAP_LAYOUT.equals(layoutType_p)) {
TableWrapLayout layout = new TableWrapLayout();
layout.numColumns = numColumns_p;
layout.makeColumnsEqualWidth = equalWidth_p;
selectedLayout = layout;
}
// Do not set neither layout if layout could not be created.
if (null != selectedLayout) {
composite_p.setLayout(selectedLayout);
}
return selectedLayout;
}
/**
* Update given control layout data depending on given layout type.<br>
* Replace layout data is set to fill/grab in both directions, if it makes
* any sense.
*
* @param control_p
*/
public static Object updateControlLayoutDataWithLayoutTypeData(Control control_p, LayoutType layoutType_p) {
Object layoutData = null;
if (LayoutType.GRID_LAYOUT.equals(layoutType_p)) {
layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
} else if (LayoutType.TABLEWRAP_LAYOUT.equals(layoutType_p)) {
layoutData = new TableWrapData(TableWrapData.FILL_GRAB);
}
// Do not set layout data if it could not be created.
if (null != layoutData) {
control_p.setLayoutData(layoutData);
}
return layoutData;
}
/**
* Create a section toolbar in given section filled in with provided
* actions.
*
* @param section_p
* @param actions_p
*/
public static void createSectionToolbar(Section section_p, List<? extends IAction> actions_p) {
// Preconditions.
if ((null == actions_p) || actions_p.isEmpty() || (null == section_p)) {
return;
}
// Create a toolbar manager.
ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
// Create the widget against the section widget.
ToolBar toolbar = toolBarManager.createControl(section_p);
// Create cursor to provide the end-user with an UI feedback.
final Cursor handCursor = new Cursor(Display.getCurrent(), SWT.CURSOR_HAND);
toolbar.setCursor(handCursor);
// Cursor needs to be explicitly disposed
toolbar.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
if ((null != handCursor) && !handCursor.isDisposed()) {
handCursor.dispose();
}
}
});
// Loop over provided actions.
for (IAction action : actions_p) {
toolBarManager.add(action);
}
toolBarManager.update(true);
section_p.setTextClient(toolbar);
}
/**
* Adapt specified composite to {@link FormToolkit} recursively.
*
* @param toolkit_p
* @param composite_p
*/
public static void adaptRecursively(FormToolkit toolkit_p, Composite composite_p) {
// Preconditions.
if ((null == composite_p) || (null == toolkit_p)) {
return;
}
toolkit_p.adapt(composite_p, true, true);
Control[] children = composite_p.getChildren();
for (Control control : children) {
if (null != control) {
toolkit_p.adapt(control, true, true);
if (control instanceof Composite) {
adaptRecursively(toolkit_p, (Composite) control);
}
}
}
}
/**
* Adapt background color of specified composite and its children.
*
* @param composite_p
* @param color_p
* @param ignoreEditableTextField_p
* <code>true</code> means editable text field won't be modified.
*/
public static void adaptBackgroundColor(Composite composite_p, Color color_p, boolean ignoreEditableTextField_p) {
// Preconditions.
if ((null == composite_p) || (null == color_p)) {
return;
}
composite_p.setBackground(color_p);
Control[] children = composite_p.getChildren();
for (Control control : children) {
if (null != control) {
boolean applyColor = true;
if ((control instanceof Text) && !ignoreEditableTextField_p && ((Text) control).getEditable()) {
applyColor = false;
}
if (applyColor) {
control.setBackground(color_p);
}
if (control instanceof Composite) {
adaptBackgroundColor((Composite) control, color_p, ignoreEditableTextField_p);
}
}
}
}
}