/******************************************************************************* * Copyright (c) 2005, 2012 IBM Corporation and others. * 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: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.bpel.ui.expressions; import org.eclipse.bpel.common.ui.details.IDetailsAreaConstants; import org.eclipse.bpel.fnmeta.model.Function; import org.eclipse.bpel.model.util.BPELConstants; import org.eclipse.bpel.model.util.BPELUtils; import org.eclipse.bpel.ui.BPELUIPlugin; import org.eclipse.bpel.ui.IBPELUIConstants; import org.eclipse.bpel.ui.IHelpContextIds; import org.eclipse.bpel.ui.Messages; import org.eclipse.bpel.ui.commands.CompoundCommand; import org.eclipse.bpel.ui.commands.SetNamespaceMappingCommand; import org.eclipse.bpel.ui.editors.TextEditorInput; import org.eclipse.bpel.ui.editors.xpath.XPathTextEditor; import org.eclipse.bpel.ui.properties.BPELPropertySection; import org.eclipse.bpel.ui.properties.DateTimeSelector; import org.eclipse.bpel.ui.properties.DurationSelector; import org.eclipse.bpel.ui.util.BPELDateTimeHelpers; import org.eclipse.bpel.ui.util.BPELUtil; import org.eclipse.core.resources.IMarker; import org.eclipse.emf.ecore.EObject; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StackLayout; import org.eclipse.swt.events.FocusAdapter; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.FormAttachment; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.layout.FormLayout; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Layout; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IPropertyListener; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.forms.widgets.FormToolkit; /** * Expression language editor for XPath. */ @SuppressWarnings("nls") public class XPathExpressionEditor extends AbstractExpressionEditor { static final String BOOLEAN_EXPR_DEFAULT = "true()"; //$NON-NLS-1$ static final String UNSIGNED_INT_EXPR_DEFAULT = "1"; //$NON-NLS-1$ static final String TEXT_STRING = Messages.XPathExpressionEditor_Text_0, LITERAL_STRING = Messages.XPathExpressionEditor_Literal_1; static final int TEXT = 0, LITERAL = 1; protected static final String DEFAULT_DURATION_VALUE = "\'P0D\'"; //$NON-NLS-1$ protected Combo combo; // Expression type values protected Label comboLabel; // Expression type protected Composite mainComposite; // high level composite control protected XPathTextEditor textEditor; // expression text /** The date/time selector, alternative to just plain text */ protected DateTimeSelector dateTimeSelector; /** The duration selector, alternative to just plain text */ protected DurationSelector durationSelector; protected IPropertyListener propertyListener; /** This composite holds a stack of editors, only the top one is shown */ protected Composite editorComposite; /** The text editor composite, a child control of the editorComposite */ protected Composite textEditorComposite; /** The duration editor composite, a child control of the editorComposiste */ protected Composite durationEditorComposite; /** The date time editor composite, a child control of the editorComposiste */ protected Composite dateTimeEditorComposite; // private int comboValue = -1; /** The input to the text editor. */ protected TextEditorInput textEditorInput; private FocusListener focusListener; /** * Create a brand new shiny XPathExpressionEditor ... */ public XPathExpressionEditor() { super(); } /** * Create controls .. */ @Override public void createControls(Composite parent, FormToolkit toolkit) { super.createControls(parent, toolkit); createEditor(parent); } protected void createEditor(Composite parent) { this.mainComposite = wf.createComposite( parent ); FormLayout layout = new FormLayout(); layout.marginWidth = layout.marginHeight = 0; mainComposite.setLayout(layout); mainComposite.setBackground(BPELUIPlugin.INSTANCE.getColorRegistry() .get(IBPELUIConstants.COLOR_WHITE)); comboLabel = wf.createLabel(mainComposite, Messages.XPathExpressionEditor_Expression_Type_2); combo = new Combo(mainComposite, SWT.BORDER | SWT.READ_ONLY | SWT.FLAT); combo.add(TEXT_STRING); combo.add(LITERAL_STRING); combo.addSelectionListener(new SelectionListener() { public void widgetSelected(SelectionEvent e) { updateEditorToType(combo.getSelectionIndex()); } public void widgetDefaultSelected(SelectionEvent e) { } }); FormData data = new FormData(); data.top = new FormAttachment(combo, 0, SWT.CENTER); data.left = new FormAttachment(0, 0); data.right = new FormAttachment(combo, -IDetailsAreaConstants.HSPACE); comboLabel.setLayoutData(data); data = new FormData(); data.top = new FormAttachment(0, IDetailsAreaConstants.VSPACE ); data.left = new FormAttachment(0, BPELUtil.calculateLabelWidth( comboLabel, BPELPropertySection.STANDARD_LABEL_WIDTH_LRG)); data.right = new FormAttachment(100, 0); combo.setLayoutData(data); // Create the editor composite // The editor composite will contain one of N editors. // We use stack layout, because only one editor is visible at a time. editorComposite = wf.createComposite(mainComposite); editorComposite.setLayout(new StackLayout()); data = new FormData(); data.top = new FormAttachment(combo,2 * IDetailsAreaConstants.VSPACE); data.left = new FormAttachment(0, 5); data.right = new FormAttachment(100, 0); data.bottom = new FormAttachment(100, 0); editorComposite.setLayoutData(data); } protected void rearrangeComboAndEditorComposite() { boolean comboVisible = isLiteralType(); combo.setVisible(comboVisible); comboLabel.setVisible(comboVisible); if (editorComposite != null) { FormData data = (FormData) editorComposite.getLayoutData(); if (comboVisible) { data.top = new FormAttachment(combo, 2 * IDetailsAreaConstants.VSPACE); } else { data.top = new FormAttachment(0, 2 * IDetailsAreaConstants.VSPACE); } } } /** * Gets the text editor composite, creates it if necessary and makes it * visible by default. * * @return the composite for the text editor ... */ Composite getTextEditorComposite() { if (textEditorComposite != null) { return textEditorComposite; } textEditorComposite = wf.createComposite(editorComposite,SWT.BORDER); textEditorComposite.setLayout(new FillLayout()); textEditor = (XPathTextEditor) createEditor( XPathTextEditor.XPATH_EDITOR_ID, this.textEditorInput, textEditorComposite); textEditor.addPropertyListener(getPropertyListener()); textEditor.addFocusListener(getFocusListener()); textEditor.setDecoration(true); return textEditorComposite; } protected FocusListener getFocusListener() { if (focusListener == null){ focusListener = new FocusAdapter(){ public void focusLost(FocusEvent e) { notifyFocusOut(); } };} return focusListener; } Composite getDateTimeEditor() { if (dateTimeEditorComposite != null) { return dateTimeEditorComposite; } dateTimeEditorComposite = wf.createComposite(editorComposite, SWT.NONE); FormLayout layout = new FormLayout(); layout.marginWidth = layout.marginHeight = 0; dateTimeEditorComposite.setLayout(layout); Label label = wf.createLabel(dateTimeEditorComposite, Messages.XPathExpressionEditor_Date_Time_UTC_3); dateTimeSelector = new DateTimeSelector(wf, dateTimeEditorComposite, SWT.NONE, BPELDateTimeHelpers.yearMin, BPELDateTimeHelpers.yearMax); String body = (String) textEditorInput.getAdapter(String.class); int[] dateTime = BPELDateTimeHelpers.parseXPathDateTime(body, false); dateTimeSelector.setValues(dateTime); FormData data = new FormData(); data.top = new FormAttachment(0, 10); data.left = new FormAttachment(0, 0); data.right = new FormAttachment(dateTimeSelector, -IDetailsAreaConstants.HSPACE); label.setLayoutData(data); data = new FormData(); data.top = new FormAttachment(0, 10); data.left = new FormAttachment(0, BPELUtil.calculateLabelWidth( label, BPELPropertySection.STANDARD_LABEL_WIDTH_LRG)); // data.right = new FormAttachment(100, 0); dateTimeSelector.setLayoutData(data); dateTimeSelector.addSelectionListener( new SelectionListener() { public void widgetSelected(SelectionEvent e) { // Push new values to the text editor document so that // it is reflected next time we shift // to the text editor. if (textEditorInput != null) { int[] values = dateTimeSelector.getValues(); textEditorInput.setEditorContent ( BPELDateTimeHelpers.createXPathDateTime(values, false) , getModelObject() ); } notifyChanged(); } public void widgetDefaultSelected(SelectionEvent e) { } }); PlatformUI.getWorkbench().getHelpSystem().setHelp( dateTimeEditorComposite, IHelpContextIds.XPATH_DATE); return dateTimeEditorComposite; } /** * Get or create the duration editor. * * @return */ Composite getDurationEditor() { if (durationEditorComposite != null) { return durationEditorComposite; } durationEditorComposite = wf.createComposite(editorComposite, SWT.NONE); FormLayout layout = new FormLayout(); layout.marginWidth = layout.marginHeight = 0; durationEditorComposite.setLayout(layout); Label label = wf.createLabel(durationEditorComposite, Messages.XPathExpressionEditor_Duration_4); durationSelector = new DurationSelector(wf, durationEditorComposite, SWT.NONE); FormData data = new FormData(); data.top = new FormAttachment(0, 10); data.left = new FormAttachment(0, 0); data.right = new FormAttachment(durationSelector, -IDetailsAreaConstants.HSPACE); label.setLayoutData(data); data = new FormData(); data.top = new FormAttachment(0, 10); data.left = new FormAttachment(0, BPELUtil.calculateLabelWidth(label, BPELPropertySection.STANDARD_LABEL_WIDTH_LRG)); // data.right = new FormAttachment(100, 0); durationSelector.setLayoutData(data); durationSelector.addSelectionListener( new SelectionListener() { public void widgetSelected(SelectionEvent e) { // Push new values to the text editor document so that // it is reflected next time we shift // to the text editor. if (textEditorInput != null) { int[] duration = durationSelector.getValues(); textEditorInput.setEditorContent( BPELDateTimeHelpers.createXPathDuration(duration) , getModelObject() ); } } public void widgetDefaultSelected(SelectionEvent e) { } }); PlatformUI.getWorkbench().getHelpSystem().setHelp( durationEditorComposite, IHelpContextIds.XPATH_DURATION); return durationEditorComposite; } /** * (non-Javadoc) * * @see org.eclipse.bpel.ui.expressions.IExpressionEditor#dispose() */ public void dispose() { if (textEditor != null) { getEditorManager().disposeEditor(textEditor); textEditor = null; } // This is the main composite of all the editors. if (editorComposite != null && !editorComposite.isDisposed()) { editorComposite.dispose(); editorComposite = null; } } /** * This is called from a number of places and we have to be smart to not * create and re-create the editors every time refresh is called. * */ @Override public void refresh() { int editorType = combo.getSelectionIndex(); if (editorType < 0) { String body = (String) textEditorInput.getAdapter(String.class); // TODO: try literal widgets! editorType = TEXT; if (BPELDateTimeHelpers.parseXPathDuration(body) != null) { editorType = LITERAL; } else if (BPELDateTimeHelpers.parseXPathDateTime(body, false) != null) { editorType = LITERAL; } // update the editor type combo.select(editorType); } updateEditorToType(editorType); } /** * Update the editor to the right type. * * @param editorType */ void updateEditorToType(int editorType) { String body = (String) textEditorInput.getAdapter(String.class); switch (editorType) { case TEXT: restackEditorComposite(getTextEditorComposite()); break; case LITERAL: if (IEditorConstants.ET_DURATION.equals(getExprType())) { restackEditorComposite(getDurationEditor()); int[] duration = BPELDateTimeHelpers.parseXPathDuration(body); if (duration != null) { durationSelector.setValues(duration); } } else { restackEditorComposite(getDateTimeEditor()); int[] dateTime = BPELDateTimeHelpers.parseXPathDateTime(body, false); if (dateTime != null) { dateTimeSelector.setValues(dateTime); } } break; } } /** * We re-stack the editors and have stack layout only show the top child * control. * * @param c * the editor composite for one of our editors. */ void restackEditorComposite(Composite c) { Layout layout = c.getParent().getLayout(); if (layout instanceof StackLayout) { StackLayout stackLayout = (StackLayout) layout; if (c != stackLayout.topControl) { stackLayout.topControl = c; rearrangeComboAndEditorComposite(); c.getParent().layout(true); } } } /** * About to be hidden. */ public void aboutToBeHidden() { } /** * The editor is about to be shown. * * @see org.eclipse.bpel.ui.expressions.IExpressionEditor#aboutToBeShown() */ public void aboutToBeShown() { refresh(); } /** * If the editor is dirty it registers an ongoing change. */ protected IPropertyListener getPropertyListener() { if (propertyListener == null) { propertyListener = new IPropertyListener() { public void propertyChanged(Object source, int propId) { if (propId == IEditorPart.PROP_DIRTY) { boolean isEditorDirty = false; if (textEditor != null) { isEditorDirty = textEditor.isDirty(); } if (isEditorDirty) { notifyChanged(); } } } }; } return propertyListener; } /** * @see org.eclipse.bpel.ui.expressions.IExpressionEditor#getUserContext() */ public Object getUserContext() { return null; } /** * @see org.eclipse.bpel.ui.expressions.IExpressionEditor#restoreUserContext(java.lang.Object) */ public void restoreUserContext(Object userContext) { // TODO! this is bogus if (textEditor != null) { textEditor.setFocus(); } } /** * Return the body of the editor. * * @see org.eclipse.bpel.ui.expressions.AbstractExpressionEditor#getEditorContent() */ @Override public String getEditorContent() { int editorType = combo.getSelectionIndex(); if (editorType == LITERAL) { if (IEditorConstants.ET_DURATION.equals(getExprType())) { int[] duration = durationSelector.getValues(); return BPELDateTimeHelpers.createXPathDuration(duration); } int[] dateTime = dateTimeSelector.getValues(); return BPELDateTimeHelpers.createXPathDateTime(dateTime, false); } return textEditor.getContents(); } /** * @see org.eclipse.bpel.ui.expressions.AbstractExpressionEditor#setEditorContent(java.lang.String) */ @Override public void setEditorContent (String body) { this.textEditorInput = new TextEditorInput(body, getModelObject(), getExprType() ); // Refresh the text editor input, if not set if (textEditor != null) { textEditor.setInput(this.textEditorInput); } } /** * Answer if the editor edits literal type expressions. These have their own * editor UI to deal with that. * * @return */ boolean isLiteralType() { return IEditorConstants.ET_DURATION.equals(getExprType()) || IEditorConstants.ET_DATETIME.equals(getExprType()); } /** * Return the default body for the given edit UI type. * * @return the default body to throw into the editor. */ public String getDefaultContent() { if (isLiteralType()) { return getDefaultBody(LITERAL); } return getDefaultBody(TEXT); } protected String getDefaultBody(int comboValue) { String exprType = getExprType(); switch (comboValue) { case TEXT: { if (exprType.indexOf(IEditorConstants.ET_BOOLEAN) >= 0) { return BOOLEAN_EXPR_DEFAULT; } else if (exprType.indexOf(IEditorConstants.ET_UNSIGNED_INT) >= 0) { return UNSIGNED_INT_EXPR_DEFAULT; } return ""; //$NON-NLS-1$ } case LITERAL: { if (exprType.indexOf(IEditorConstants.ET_DURATION) >= 0) { return DEFAULT_DURATION_VALUE; } int[] dateTime = BPELDateTimeHelpers.getCurrentLocalDateTime(); BPELDateTimeHelpers.convertLocalToGMT(dateTime); return BPELDateTimeHelpers.createXPathDateTime(dateTime, false); } } return ""; //$NON-NLS-1$ } /** * @see org.eclipse.bpel.ui.expressions.IExpressionEditor#gotoTextMarker(org.eclipse.core.resources.IMarker, java.lang.String, java.lang.Object) */ public void gotoTextMarker(IMarker marker, String codeType, Object modelObject) { // TODO } /** * @see org.eclipse.bpel.ui.expressions.IExpressionEditor#supportsExpressionType(java.lang.String) */ public boolean supportsExpressionType ( String exprType ) { return true; } /** * * @see org.eclipse.bpel.ui.expressions.IExpressionEditor#markAsClean() */ public void markAsClean() { if (textEditor != null) { textEditor.markAsClean(); } } /** * This is probably not the best place to do this, but we do need to do this someplace ... * * @see org.eclipse.bpel.ui.expressions.AbstractExpressionEditor#addExtraStoreCommands(org.eclipse.gef.commands.CompoundCommand) */ @Override public void addExtraStoreCommands (CompoundCommand compoundCommand) { EObject eObj = (EObject) getModelObject(); for(Function fn : Functions.getInstance(BPELConstants.XMLNS_XPATH_EXPRESSION_LANGUAGE_2007).getFunctions().values()) { if (BPELUtils.isEmptyOrWhitespace(fn.getNamespace()) || BPELConstants.XMLNS_XPATH_EXPRESSION_LANGUAGE.equals(fn.getNamespace())) { continue; } String pfx = BPELUtils.getNamespacePrefix( eObj, fn.getNamespace()); if (pfx == null) { compoundCommand.add(new SetNamespaceMappingCommand(eObj, fn.getNamespace(), fn.getPrefix() )) ; } } } }