/***************************************************************************** * Copyright (c) 2010 CEA LIST. * * 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: * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation *****************************************************************************/ package org.eclipse.papyrus.infra.widgets.editors; import java.util.Collection; import java.util.Collections; import java.util.List; import org.eclipse.core.databinding.observable.value.IObservableValue; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.window.Window; import org.eclipse.papyrus.infra.widgets.Activator; import org.eclipse.papyrus.infra.widgets.creation.ReferenceValueFactory; import org.eclipse.papyrus.infra.widgets.databinding.CLabelObservableValue; import org.eclipse.papyrus.infra.widgets.databinding.ReferenceDialogObservableValue; import org.eclipse.papyrus.infra.widgets.messages.Messages; import org.eclipse.papyrus.infra.widgets.providers.EncapsulatedContentProvider; import org.eclipse.papyrus.infra.widgets.providers.IAdaptableContentProvider; import org.eclipse.papyrus.infra.widgets.providers.IStaticContentProvider; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CLabel; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Widget; /** * An editor representing a single reference as a Label A filtered selection * dialog is used to edit the value. Also offers support for unsetting the * value. This Editor needs a ContentProvider, and may use an optional * LabelProvider, describing the objects that can be referred by this property * * @author Camille Letavernier * */ public class ReferenceDialog extends AbstractValueEditor implements SelectionListener { /** * The CLabel displaying the current value */ protected final CLabel currentValueLabel; /** * The Button used to browse the available values */ protected Button browseValuesButton; /** * The Button used to create a new instance */ protected Button createInstanceButton; /** * The Button used to edit the current object */ protected Button editInstanceButton; /** * The Button used to unset the current value */ protected Button unsetButton; /** * The label provider used to display the values in both the label and the * selection dialog */ protected ILabelProvider labelProvider; /** * The content provider, providing the different possible values for the * input object */ protected IStaticContentProvider contentProvider; /** * The dialog used to select the value */ protected final ITreeSelectorDialog dialog; /** * The current value for this editor */ protected Object value; /** * The factory used to create or edit objects directly from this editor */ protected ReferenceValueFactory valueFactory; /** * Indicates whether the widget is read-only or not */ protected boolean readOnly; private boolean directCreation; /** * * Constructs a new ReferenceDialog in the given parent Composite. The style * will be applied to the CLabel displaying the current value. * * @param parent * @param style */ public ReferenceDialog(Composite parent, int style) { super(parent, style); currentValueLabel = factory.createCLabel(this, null, factory.getBorderStyle() | style); currentValueLabel.setLayoutData(getDefaultLayoutData()); currentValueLabel.addMouseListener(new MouseListener() { public void mouseDoubleClick(MouseEvent e) { editAction(); // TODO : Try to determine whether the double // click should call the edit, create or browse // action // e.g. if the value is null, try to browse. If we cannot // browse, try to create an instance. } public void mouseDown(MouseEvent e) { // Nothing } public void mouseUp(MouseEvent e) { // Nothing } }); dialog = createDialog(parent.getShell()); createButtons(); updateControls(); } protected ITreeSelectorDialog createDialog(Shell shell) { return new TreeSelectorDialog(shell); } protected void createButtons() { ((GridLayout)getLayout()).numColumns += 4; browseValuesButton = factory.createButton(this, null, SWT.PUSH); browseValuesButton.setImage(Activator.getDefault().getImage("/icons/browse_12x12.gif")); //$NON-NLS-1$ browseValuesButton.setToolTipText(Messages.ReferenceDialog_EditValue); browseValuesButton.addSelectionListener(this); createInstanceButton = factory.createButton(this, null, SWT.PUSH); createInstanceButton.setImage(Activator.getDefault().getImage("/icons/Add_12x12.gif")); //$NON-NLS-1$ createInstanceButton.setToolTipText(Messages.ReferenceDialog_CreateANewObject); createInstanceButton.addSelectionListener(this); editInstanceButton = factory.createButton(this, null, SWT.PUSH); editInstanceButton.setImage(Activator.getDefault().getImage("/icons/Edit_12x12.gif")); //$NON-NLS-1$ editInstanceButton.setToolTipText(Messages.ReferenceDialog_EditTheCurrentValue); editInstanceButton.addSelectionListener(this); unsetButton = factory.createButton(this, null, SWT.PUSH); unsetButton.setImage(Activator.getDefault().getImage("/icons/Delete_12x12.gif")); //$NON-NLS-1$ unsetButton.setToolTipText(Messages.ReferenceDialog_UnsetValue); unsetButton.addSelectionListener(this); } /** * The action executed when the "browse" button is selected * Choose a value from a selection of already created objects */ protected void browseAction() { setInitialSelection(Collections.singletonList(getValue())); int result = dialog.open(); if(result == Window.OK) { Object[] newValue = dialog.getResult(); if(newValue.length == 0) { setValue(null); } else { Object value = newValue[0]; if(contentProvider instanceof IAdaptableContentProvider) { value = ((IAdaptableContentProvider)contentProvider).getAdaptedValue(value); } setValue(value); } } } /** * The action executed when the "create" button is selected Create a new * instance and assign it to this reference */ protected void createAction() { if(valueFactory != null && valueFactory.canCreateObject()) { Object value = valueFactory.createObject(createInstanceButton); if(value == null) { return; } Collection<Object> validatedObjects = valueFactory.validateObjects(Collections.singleton(value)); if(!validatedObjects.isEmpty()) { setValue(validatedObjects.iterator().next()); } } } /** * The action executed when the "edit" button is selected Edits the object * that is currently selected */ protected void editAction() { Object currentValue = getValue(); if(currentValue != null && valueFactory != null && valueFactory.canEdit()) { Object newValue = valueFactory.edit(editInstanceButton, getValue()); if(newValue != currentValue) { setValue(newValue); } updateLabel(); } } /** * The action executed when the "unset" button is selected Sets the current * reference to null */ protected void unsetAction() { setValue(null); } /** * Updates the displayed label for the current value */ protected void updateLabel() { if(binding != null) { binding.updateModelToTarget(); } else { currentValueLabel.setImage(labelProvider.getImage(getValue())); currentValueLabel.setText(labelProvider.getText(getValue())); } } /** * Sets the Content provider for this editor * * @param provider * The content provider used to retrieve the possible values for * this Reference */ public void setContentProvider(IStaticContentProvider provider) { dialog.setContentProvider(new EncapsulatedContentProvider(provider)); if(getValue() != null) { setInitialSelection(Collections.singletonList(getValue())); } this.contentProvider = provider; } /** * Sets the Label provider for this editor If the label provider is null, a * default one will be used. The same label provider is used for both the * editor's label and the selection dialog. * * @param provider * The label provider */ public void setLabelProvider(ILabelProvider provider) { if(provider == null) { setLabelProvider(new LabelProvider()); return; } dialog.setLabelProvider(provider); this.labelProvider = provider; if(widgetObservable != null) { ((CLabelObservableValue)widgetObservable).setLabelProvider(labelProvider); } updateLabel(); } /** * {@inheritDoc} */ @Override public void setLabel(String label) { super.setLabel(label); dialog.setTitle(label); } /** * {@inheritDoc} */ @Override public Object getValue() { if(modelProperty != null) { return modelProperty.getValue(); } return value; } /** * {@inheritDoc} */ @Override public Object getEditableType() { return Object.class; } /** * {@inheritDoc} */ @Override public void setReadOnly(boolean readOnly) { this.readOnly = readOnly; updateControls(); } /** * {@inheritDoc} */ @Override public boolean isReadOnly() { return !currentValueLabel.isEnabled(); } /** * {@inheritDoc} */ @Override protected void doBinding() { super.doBinding(); } protected void setInitialSelection(List<?> initialValues) { dialog.setInitialElementSelections(initialValues); } public void widgetDisposed(DisposeEvent e) { dispose(); } @Override public void setModelObservable(IObservableValue modelProperty) { setWidgetObservable(new ReferenceDialogObservableValue(this, this.currentValueLabel, modelProperty, labelProvider)); super.setModelObservable(modelProperty); updateControls(); } @Override public void setToolTipText(String text) { super.setLabelToolTipText(text); currentValueLabel.setToolTipText(text); } public void setValueFactory(ReferenceValueFactory factory) { valueFactory = factory; updateControls(); } public void widgetSelected(SelectionEvent e) { Widget widget = e.widget; if(widget == browseValuesButton) { browseAction(); } else if(widget == createInstanceButton) { createAction(); } else if(widget == editInstanceButton) { editAction(); } else if(widget == unsetButton) { unsetAction(); } } public void widgetDefaultSelected(SelectionEvent e) { // Nothing } /** * Updates the buttons' status */ protected void updateControls() { // Check if the edit & create buttons should be displayed boolean exclude = valueFactory == null || !valueFactory.canCreateObject(); setExclusion(editInstanceButton, exclude); setExclusion(createInstanceButton, exclude); setExclusion(browseValuesButton, directCreation); browseValuesButton.setEnabled(!readOnly); // If they are displayed, check if they should be enabled if(!exclude) { editInstanceButton.setEnabled(valueFactory != null && valueFactory.canEdit() && getValue() != null); createInstanceButton.setEnabled(valueFactory != null && valueFactory.canCreateObject() && !readOnly); } boolean enabled = !readOnly; enabled = enabled && getValue() != null; unsetButton.setEnabled(enabled); } @Override public void update() { super.update(); updateControls(); } public void setDirectCreation(boolean directCreation) { this.directCreation = directCreation; updateControls(); } public void setValue(Object value) { this.value = value; if(modelProperty != null) { modelProperty.setValue(value); } updateControls(); updateLabel(); commit(); } /** * @see org.eclipse.jface.viewers.StructuredViewer#setInput(Object) * @param input */ public void setInput(Object input) { this.dialog.setInput(input); } }