/******************************************************************************* * Copyright (c) 2006-2010 eBay Inc. All Rights Reserved. * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 *******************************************************************************/ package org.ebayopensource.turmeric.eclipse.ui; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.ebayopensource.turmeric.eclipse.core.logging.SOALogger; import org.ebayopensource.turmeric.eclipse.core.resources.constants.SOAProjectConstants; import org.ebayopensource.turmeric.eclipse.repositorysystem.core.GlobalRepositorySystem; import org.ebayopensource.turmeric.eclipse.repositorysystem.core.ISOAHelpProvider; import org.ebayopensource.turmeric.eclipse.repositorysystem.core.ISOAOrganizationProvider; import org.ebayopensource.turmeric.eclipse.ui.components.SOACComboControlAdapter; import org.ebayopensource.turmeric.eclipse.ui.resources.SOAConstants; import org.ebayopensource.turmeric.eclipse.ui.resources.SOAMessages; import org.ebayopensource.turmeric.eclipse.utils.ui.UIUtil; import org.ebayopensource.turmeric.eclipse.utils.ui.UIUtil.ISOAControlDecorator; import org.ebayopensource.turmeric.eclipse.validator.utils.ValidateUtil; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.jface.dialogs.IMessageProvider; import org.eclipse.jface.fieldassist.AutoCompleteField; import org.eclipse.jface.fieldassist.ComboContentAdapter; import org.eclipse.jface.fieldassist.ControlDecoration; import org.eclipse.jface.fieldassist.FieldDecoration; import org.eclipse.jface.fieldassist.FieldDecorationRegistry; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CCombo; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.forms.events.ExpansionAdapter; import org.eclipse.ui.forms.events.ExpansionEvent; import org.eclipse.ui.forms.events.IExpansionListener; import org.eclipse.ui.forms.widgets.ExpandableComposite; import org.osgi.service.prefs.BackingStoreException; /** * This is the base class for all SOA Wizard pages extending the standard * eclipse wizard page. Contains the Common code for all SOA Wizard pages. * Mainly contains some work space related functionality and some UI component * common creation logic. But it can contain anything common to the SOA Wizard * pages. Common error UI is another key functionality of this class. * * @author smathew */ public abstract class SOABasePage extends WizardPage implements ISOAControlDecorator { private final Map<Control, ControlDecoration> errorDecorations = new ConcurrentHashMap<Control, ControlDecoration>(); private final Map<Control, ControlDecoration> controlDecorations = new ConcurrentHashMap<Control, ControlDecoration>(); private ISOAOrganizationProvider organizationProvider = null; /** The Constant DEFAULT_TEXT_VALUE. */ public static final String DEFAULT_TEXT_VALUE = SOAProjectConstants.EMPTY_STRING; /* (non-Javadoc) * @see org.eclipse.jface.dialogs.DialogPage#dispose() */ @Override public void dispose() { super.dispose(); for (ControlDecoration dec : errorDecorations.values()) { dec.dispose(); } errorDecorations.clear(); for (ControlDecoration dec : controlDecorations.values()) { dec.dispose(); } controlDecorations.clear(); } /** * Gets the error decorations. * * @return the error decorations */ public Map<Control, ControlDecoration> getErrorDecorations() { return errorDecorations; } /** * Gets the control decorations. * * @return the control decorations */ public Map<Control, ControlDecoration> getControlDecorations() { return controlDecorations; } /** * Saves the provided work space root to the preference store. Once user * provides the work space root, SOA remembers it and will show it as the * default value next time user opens the wizard. * * @param workspaceRoot the workspace root */ public static void saveWorkspaceRoot(final String workspaceRoot) { final IEclipsePreferences preferences = new InstanceScope() .getNode(UIActivator.PLUGIN_ID); preferences.put(SOAConstants.WORKSPACE_ROOT, workspaceRoot); try { preferences.flush(); } catch (final BackingStoreException e) { } } /** * Constructor with no extra logic, Just calls the super. * * @param pageName the page name * @wbp.parser.constructor */ protected SOABasePage(String pageName) { super(pageName); } /** * Instantiates a new sOA base page. * * @param pageName - * Name of the page. Shown in the UI * @param title - * Title, Again shown in the UI under the name typically. * @param description the description */ protected SOABasePage(String pageName, String title, String description) { this(pageName); setTitle(title); setDescription(description); } /** * Returns the work space root stored in the preference store. * * @return the workspace root */ public static String getWorkspaceRoot() { final IEclipsePreferences preferences = new InstanceScope() .getNode(UIActivator.PLUGIN_ID); return preferences .get(SOAConstants.WORKSPACE_ROOT, SOAProjectConstants.EMPTY_STRING); } /** * Update page status. * * @param control the control * @param status the status */ public void updatePageStatus(final Control control, final IStatus status) { updatePageStatus(status, control); } /** * Update the message of the wizard page along with the appropriate icon. If * the status is not OK, then the page will be marked as not completed. * * @param status the status * @param controls the controls */ public void updatePageStatus(final IStatus status, Control... controls) { String message = null; int messageType = WizardPage.NONE; if (status != null) { switch (status.getSeverity()) { case IStatus.WARNING: messageType = IMessageProvider.WARNING; break; case IStatus.INFO: messageType = IMessageProvider.INFORMATION; break; case IStatus.ERROR: messageType = IMessageProvider.ERROR; break; } if (status != null) { message = ValidateUtil.getBasicFormattedUIErrorMessage(status); } } if (messageType == IMessageProvider.ERROR) { setErrorMessage(message); updateStatus(message, controls); } else { updateStatus(null); setMessage(message, messageType); } setPageComplete(status == null || status.getSeverity() != IStatus.ERROR); } /** * Update the status of the wizard page. Sets the message, error message and * decides the page complete status based on the message passed. * * @param message * Non-blank message messages error state, or null indicates OK. */ public void updateStatus(final String message) { updateStatus(message, (Control)null); } /** * Update status. * * @param control the control * @param message the message */ public void updateStatus(final Control control, final String message) { updateStatus(message, control); } /** * Update status. * * @param message the message * @param controls the controls */ public void updateStatus(final String message, final Control... controls) { for (ControlDecoration decoration : this.errorDecorations.values()) { decoration.hide(); decoration.setDescriptionText(null); } for (ControlDecoration decoration : this.controlDecorations.values()) { decoration.show(); } if (controls != null) { for (Control control : controls) { if (control != null) { ControlDecoration controlDecoration = this.errorDecorations.get(control); if (controlDecoration == null) { controlDecoration = new ControlDecoration(control, SWT.LEFT | SWT.TOP); FieldDecoration fieldDecoration = FieldDecorationRegistry .getDefault().getFieldDecoration( FieldDecorationRegistry.DEC_ERROR); controlDecoration.setImage(fieldDecoration.getImage()); } else { controlDecoration.show(); } controlDecoration.setDescriptionText(message); this.errorDecorations.put(control, controlDecoration); if (controlDecorations.containsKey(control)) { controlDecorations.get(control).hide(); } } } } setMessage(message); setErrorMessage(message); setPageComplete(message == null); } /** * Creates the parent container. Additionally sets the help context id also. * * @param parent the parent * @param columnCount the column count * @return the composite */ protected Composite createParentControl(Composite parent, int columnCount) { final Composite container = new Composite(parent, SWT.NONE); if (columnCount < 1) { columnCount = 1; } GridLayout layout = new GridLayout(columnCount, false); layout.verticalSpacing = 8; layout.marginLeft = 5; container.setLayout(layout); setControl(container); UIUtil.getHelpSystem().setHelp(container, getHelpContextID()); return container; } /** * Creates the advanced settings panel. * * @param parent the parent * @return the composite */ protected Composite createAdvancedSettingsPanel(final Composite parent, IExpansionListener listener) { ExpandableComposite eComposite = new ExpandableComposite(parent, ExpandableComposite.COMPACT | ExpandableComposite.TWISTIE | ExpandableComposite.EXPANDED); GridData data = new GridData(GridData.FILL_BOTH); data.verticalIndent = 7; data.horizontalSpan = 4; eComposite.setLayoutData(data); eComposite.setText("Advanced"); eComposite.addExpansionListener(new ExpansionAdapter() { @Override public void expansionStateChanged(ExpansionEvent e) { Shell shell = parent.getShell(); Point minSize = shell.getMinimumSize(); shell.setMinimumSize(shell.getSize().x, minSize.y); shell.pack(); parent.layout(); shell.setMinimumSize(minSize); } }); if (listener != null) { eComposite.addExpansionListener(listener); } Composite composite = createParentControl(eComposite, 4); eComposite.setClient(composite); return composite; } /** * Create the options specification widgets. * * @param parent org.eclipse.swt.widgets.Composite * @param tooltip the tooltip */ protected void createOptionsGroup(Composite parent, String tooltip) { Composite panel = new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(); layout.marginHeight = 1; layout.marginWidth = 1; layout.numColumns = 1; panel.setLayout(layout); panel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 4, 1)); Group optionsGroup = new Group(panel, SWT.NONE); layout = new GridLayout(); layout.numColumns = 1; optionsGroup.setLayout(layout); optionsGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); optionsGroup.setText(SOAMessages.OPTIONS); optionsGroup.setFont(parent.getFont()); UIUtil.decorateControl(this, optionsGroup, tooltip); } /** * Create an empty label widget. * * @param composite the composite * @param columnCount the column count * @return the label */ protected Label createEmptyLabel(Composite composite, int columnCount) { Label label = new Label(composite, SWT.NONE); GridData gridData = new GridData(SWT.BEGINNING); gridData.horizontalAlignment = columnCount; label.setLayoutData(gridData); return label; } /** * Creates the label text field. * * @param composite the composite * @param labelText the label text * @param defaultText the default text * @param modifyListener the modify listener * @param tooltip the tooltip * @return the text */ protected Text createLabelTextField(final Composite composite, final String labelText, final String defaultText, final ModifyListener modifyListener, final String tooltip) { return createLabelTextField(composite, labelText, defaultText, modifyListener, true, true, tooltip); } /** * Creates the label text field. * * @param composite the composite * @param labelText the label text * @param defaultText the default text * @param modifyListener the modify listener * @param textEditable the text editable * @param tooltip the tooltip * @return the text */ protected Text createLabelTextField(final Composite composite, final String labelText, final String defaultText, final ModifyListener modifyListener, final boolean textEditable, final String tooltip) { return createLabelTextField(composite, labelText, defaultText, modifyListener, true, textEditable, -1, tooltip); } /** * Creates the label text field. * * @param composite the composite * @param labelText the label text * @param defaultText the default text * @param modifyListener the modify listener * @param needEmptyLabel the need empty label * @param textEditable the text editable * @param tooltip the tooltip * @return the text */ protected Text createLabelTextField(final Composite composite, final String labelText, final String defaultText, final ModifyListener modifyListener, final boolean needEmptyLabel, final boolean textEditable, final String tooltip) { return createLabelTextField(composite, labelText, defaultText, modifyListener, needEmptyLabel, textEditable, -1, tooltip); } /** * Creates the label text field. * * @param composite the composite * @param labelText the label text * @param defaultText the default text * @param modifyListener the modify listener * @param needEmptyLabel the need empty label * @param textEditable the text editable * @param textStyle the text style * @param tooltip the tooltip * @return the text */ protected Text createLabelTextField(final Composite composite, final String labelText, final String defaultText, final ModifyListener modifyListener, final boolean needEmptyLabel, final boolean textEditable, final int textStyle, final String tooltip) { final Label label = new Label(composite, SWT.LEFT); label.setText(labelText); final Text textField = new Text(composite, textStyle != -1 ? textStyle : SWT.BORDER | SWT.SINGLE); textField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1)); textField.setEditable(textEditable); if (modifyListener != null) textField.addModifyListener(modifyListener); if (defaultText != null) textField.setText(defaultText); UIUtil.decorateControl(this, textField, tooltip); if (needEmptyLabel) createEmptyLabel(composite, 1); return textField; } /** * Create an Override button for the given Text field. * * @param parent the parent * @param label the label * @param tooltip the tooltip * @return the button */ protected Button createButton(final Composite parent, String label, String tooltip) { final Button button = new Button(parent, SWT.CHECK); button.setAlignment(SWT.LEFT); button.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 4, 1)); button.setText(label); button.setSelection(true); UIUtil.decorateControl(this, button, tooltip); return button; } /** * Create an Override button for the given Text field. * * @param parent the parent * @param relatedText the related text * @param listener the listener * @return the button */ protected Button createOverrideButton(final Composite parent, final Text relatedText, final SelectionListener listener) { final Button overrideButton = new Button(parent, SWT.CHECK); overrideButton.setAlignment(SWT.LEFT); overrideButton.setText(SOAMessages.OVERRIDE); overrideButton.setSelection(false); if (listener == null) { final SelectionListener overrideInterfaceListener = new SelectionListener() { @Override public void widgetDefaultSelected(final SelectionEvent e) { widgetSelected(e); } @Override public void widgetSelected(final SelectionEvent e) { if (overrideButton.getSelection()) { relatedText.setEnabled(true); relatedText.setEditable(true); } else { relatedText.setEditable(false); relatedText.setText(getDefaultValue(relatedText)); dialogChanged(); } } }; overrideButton.addSelectionListener(overrideInterfaceListener); } else { overrideButton.addSelectionListener(listener); } UIUtil.decorateControl(this, overrideButton, SOAMessages.OVERRIDE); return overrideButton; } /** * {@inheritDoc} */ @Override public void addControlDecoration(Control control, ControlDecoration controlDecoration) { if (control != null && controlDecoration != null && controlDecoration.getControl() == control) { controlDecorations.put(control, controlDecoration); } } /** * Create a combo box widget in standard SOA dimension and style. * * @param composite the composite * @param labelText the label text * @param editable the editable * @param items the items * @param tooltip the tooltip * @return the c combo */ public CCombo createCCombo(final Composite composite, final String labelText, final boolean editable, final String[] items, final String tooltip) { final Label label = new Label(composite, SWT.LEFT); label.setText(labelText); final int defaultStyle = SWT.BORDER | SWT.DROP_DOWN; final int style = editable ? defaultStyle : SWT.READ_ONLY | defaultStyle; final CCombo combo = new CCombo(composite, style); if (editable == false) { // we still want it look like modifiable although it is ready only. combo.setBackground(UIUtil.display() .getSystemColor(SWT.COLOR_LIST_BACKGROUND)); } else { combo.setTextLimit(100); } combo.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1)); if (items != null && items.length > 0) { combo.setItems(items); combo.select(0); if (editable == true) new AutoCompleteField(combo, new SOACComboControlAdapter(), items); } UIUtil.decorateControl(this, combo, tooltip); return combo; } /** * Creates the combo. * * @param composite the composite * @param labelText the label text * @param editable the editable * @param items the items * @param tooltip the tooltip * @return the combo */ public Combo createCombo(final Composite composite, final String labelText, final boolean editable, final String[] items, final String tooltip) { final Label label = new Label(composite, SWT.LEFT); label.setText(labelText); final int defaultStyle = SWT.BORDER | SWT.DROP_DOWN; final int style = editable ? defaultStyle : SWT.READ_ONLY | defaultStyle; final Combo combo = new Combo(composite, style); if (editable == false) { // we still want it look like modifiable although it is ready only. combo.setBackground(UIUtil.display() .getSystemColor(SWT.COLOR_LIST_BACKGROUND)); } else { combo.setTextLimit(100); } combo.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1)); if (items != null && items.length > 0) { combo.setItems(items); combo.select(0); if (editable == true) new AutoCompleteField(combo, new ComboContentAdapter(), items); } UIUtil.decorateControl(this, combo, tooltip); return combo; } /** * Validate the state of the current wizard page. * * @return true is passed validation of false otherwise */ protected boolean dialogChanged() { updateStatus(null); return true; } /** * This is a poorly named method. It is not just checking the validation * result, but it is displaying the status object. It checks if severity is * error and if it is then it will display it in the standard message area * of the wizard or ignore it otherwise. * * @param validationModel the validation model * @param controls the controls * @return true, if successful */ protected boolean checkValidationResult(IStatus validationModel, Control... controls) { if (validationModel != null && validationModel.getSeverity() == IStatus.ERROR) { updateStatus(ValidateUtil .getBasicFormattedUIErrorMessage(validationModel), controls); return false; } return true; } /** * Check validation result. * * @param control the control * @param validationModel the validation model * @return true, if successful */ protected boolean checkValidationResult(Control control, IStatus validationModel) { return checkValidationResult(validationModel, control); } /** * Standard way of processing SOA exception occured in a wizard page. Simple - * show it to the user in the standard message area of the wizard page and * log the exception. * * @param exception the exception * @return true, if successful */ protected boolean processException(Exception exception) { if (exception != null) { updateStatus(exception.getMessage()); SOALogger.getLogger().error(exception); return false; } return true; } /** The modify listener. */ protected final ModifyListener modifyListener = new ModifyListener() { @Override public void modifyText(final ModifyEvent e) { if (e != null && e.getSource() instanceof Control) { // we only do validation if the current control has user focus Control control = (Control) e.getSource(); if (control.isEnabled() && control.isFocusControl()) { if (control instanceof Text && ((Text) control).getEditable() == false) {// this // text control is not editable return; } dialogChanged(); } } } }; /** * Gets the text value of the given control. This is a convenience method to * reduce the code redundancy in finding the text value of any widget.It can * handle Text, Label, Button, Combo box * * @param control * Currently only support Text, CCombo, Label and Button * @return The value of the given control. */ protected String getTextValue(final Control control) { String value = DEFAULT_TEXT_VALUE; if (control instanceof Text) value = ((Text) control).getText(); else if (control instanceof CCombo) value = ((CCombo) control).getText(); else if (control instanceof Label) value = ((Label) control).getText(); else if (control instanceof Button) value = ((Button) control).getText(); else if (control instanceof Combo) value = ((Combo) control).getText(); return value.trim(); } /** * This id associates the widget with the tiny question mark button on the * left. * * @return The help context ID */ public String getHelpContextID() { return GlobalRepositorySystem.instanceOf().getActiveRepositorySystem() .getHelpProvider().getHelpContextID( ISOAHelpProvider.SOA_TUTORIAL); } /** * Gets the organization provider. * * @return the organization provider */ public ISOAOrganizationProvider getOrganizationProvider() { if (this.organizationProvider == null) { this.organizationProvider = GlobalRepositorySystem.instanceOf() .getActiveRepositorySystem().getActiveOrganizationProvider(); } return organizationProvider; } /** * This method is used for ensuring that the default value could be * retrieved for a particular Text widget, when user un-select the Override * button. * * @param text the text * @return the default value */ public abstract String getDefaultValue(Text text); }