blob: a1b7952029d0bbbd6738d0390fd3662e30a8ecd7 [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2002, 2005 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.gmf.runtime.common.ui.services.properties.extended;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.jface.preference.PreferenceManager;
import org.eclipse.jface.preference.PreferenceNode;
import org.eclipse.jface.viewers.DialogCellEditor;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.dialogs.PropertyDialogAction;
import org.eclipse.ui.dialogs.PropertyPage;
import org.eclipse.ui.views.properties.IPropertyDescriptor;
import org.eclipse.ui.views.properties.IPropertySource;
import org.eclipse.gmf.runtime.common.core.util.StringStatics;
import org.eclipse.gmf.runtime.common.ui.dialogs.PropertiesDialog;
import org.eclipse.gmf.runtime.common.ui.services.properties.PropertiesService;
/**
* Cell editor for properties that can be modified via a property page.
* This cell editor is composed of an elipsis button for editing via
* a property page, and a text widget for editing directly.
*
* @author ldamus
*/
public class PropertyPageCellEditor extends DialogCellEditor {
/**
* The text widget
*/
private Text text;
/**
* My modify listener for modifications to the text
*/
private ModifyListener modifyListener;
/**
* Flag which is <code>true</code> if there is a selection in the text
* widget, <code>false</code> otherwise. Used to notify that the
* copy/paste menu item enablement has changed
*/
private boolean isSelection = false;
/**
* Flag which is <code>true</code> if the text is deletable,
* <code>false</code> otherwise. Used to notify that the
* delete menu item enablement has changed
*/
private boolean isDeleteable = false;
/**
* Flag which is <code>true</code> if the text is selectable,
* <code>false</code> otherwise. Used to notify that the
* select all menu item enablement has changed
*/
private boolean isSelectable = false;
/**
* My selection provider which provides a selection to the
* {@link PropertyDialogAction}
*/
ISelectionProvider selectionProvider;
/**
* My property descriptor
*/
private final PropertyPagePropertyDescriptor propertyDescriptor;
/**
* The value of this cell editor; initially <code>null</code>.
*/
private Object value = null;
/**
* Creates a new property page cell editor parented under the given control.
* The cell editor value is <code>null</code> initially, and has no
* validator.
*
* @param parent The parent control
* @param descriptor The property descriptor for this cell
*/
public PropertyPageCellEditor(
Composite parent,
PropertyPagePropertyDescriptor descriptor) {
this(parent, descriptor, SWT.NONE);
}
/**
* Creates a new property page cell editor parented under the given control.
* The cell editor value is <code>null</code> initially, and has no
* validator.
*
* @param parent The parent control
* @param descriptor The property descriptor for this cell
* @param style the style bits
*/
public PropertyPageCellEditor(
Composite parent,
PropertyPagePropertyDescriptor descriptor,
int style) {
super(parent, style);
propertyDescriptor = descriptor;
}
/**
* Gets the property descriptor for this cell editor.
*
* @return the property descriptor
*/
private PropertyPagePropertyDescriptor getPropertyDescriptor() {
return propertyDescriptor;
}
/**
* Creates a text widget in the cell editor
*
* @see org.eclipse.jface.viewers.DialogCellEditor#createContents(Composite)
*/
protected Control createContents(Composite cell) {
setText(new Text(cell, getStyle()));
// Add a key listener to the text widget
text.addKeyListener(new KeyAdapter() {
// On key pressed, check the menu item enablement
public void keyPressed(KeyEvent e) {
keyReleaseOccured(e);
if ((getControl() == null) || getControl().isDisposed())
return;
checkSelection();
checkDeleteable();
checkSelectable();
}
});
// Add a traverse listener to the text widget
text.addTraverseListener(new TraverseListener() {
// On key traversed, disable the escape and return operations
public void keyTraversed(TraverseEvent e) {
if (e.detail == SWT.TRAVERSE_ESCAPE
|| e.detail == SWT.TRAVERSE_RETURN) {
e.doit = false;
}
}
});
// Add a mouse listener to the text widget
text.addMouseListener(new MouseAdapter() {
// On mouse up, check the menu item enablement
public void mouseUp(MouseEvent e) {
checkSelection();
checkDeleteable();
checkSelectable();
}
});
text.setFont(cell.getFont());
text.setBackground(cell.getBackground());
text.setText(StringStatics.BLANK);
text.addModifyListener(getModifyListener());
return getText();
}
/**
* Updates the contents of the text field with <code>aValue</code>.
*
* @see org.eclipse.jface.viewers.DialogCellEditor#updateContents(Object)
*/
protected void updateContents(Object aValue) {
if (getText() == null) {
return;
}
String aText = StringStatics.BLANK;
if (aValue != null) {
aText = aValue.toString();
}
getText().setText(aText);
}
/**
* Opens the {@link org.eclipse.gmf.runtime.common.ui.dialogs.PropertiesDialog}. Always
* returns null. The UI is updated by the model event when the property
* is modified by the property dialog.
*
* @see org.eclipse.jface.viewers.DialogCellEditor#openDialogBox(org.eclipse.swt.widgets.Control)
*/
protected Object openDialogBox(Control cellEditorWindow) {
// Invoke the property dialog
PropertiesDialog dialog =
new PropertiesDialog(
getControl().getShell(),
new PreferenceManager());
// handle invokation of cell editor from collection editor
PropertyPagePropertyDescriptor realDescriptor = null;
if (getValue() instanceof ElementValue) {
Object element = ((ElementValue) getValue()).getElement();
if (element instanceof PropertyPagePropertyDescriptor) {
realDescriptor = (PropertyPagePropertyDescriptor) element;
}
}
List pages = null;
if (realDescriptor != null) {
pages = realDescriptor.createPropertyPages();
} else {
pages = getPropertyDescriptor().createPropertyPages();
}
for (Iterator i = pages.iterator(); i.hasNext();) {
PropertyPage page = (PropertyPage) i.next();
// handle invokation of cell editor from collection editor
if (realDescriptor != null) {
final IPropertySource source =
realDescriptor.getPropertySource();
page.setElement(new IAdaptable() {
public Object getAdapter(Class adapter) {
if (adapter.equals(IPropertySource.class)) {
return source;
}
return null;
}
});
}
dialog.getPreferenceManager().addToRoot(
new PreferenceNode(StringStatics.BLANK, page));
}
dialog.create();
dialog.open();
// refresh property for collection editor
for (Iterator i = pages.iterator(); i.hasNext();) {
PropertyPage page = (PropertyPage) i.next();
IAdaptable adaptable = page.getElement();
if (adaptable != null) {
IPropertySource source =
(IPropertySource) adaptable.getAdapter(
IPropertySource.class);
if (source instanceof IExtendedPropertySource) {
Object element =
((IExtendedPropertySource) source).getElement();
IPropertySource propertySource =
PropertiesService.getInstance().getPropertySource(
element);
assert null != propertySource;
for (Iterator j =
Arrays
.asList(propertySource.getPropertyDescriptors())
.iterator();
j.hasNext();
) {
IPropertyDescriptor descriptor =
(IPropertyDescriptor) j.next();
if (descriptor
.getId()
.equals(getPropertyDescriptor().getId())) {
// apply new value in cell editor
setValue(
new ElementValue(
source,
propertySource.getPropertyValue(
descriptor.getId())));
fireApplyEditorValue();
break;
}
}
}
}
}
return null;
}
/**
* Returns the text widget
* @return the text widget
*/
protected Text getText() {
return text;
}
/**
* Sets the text widget
* @param text The text widget to set
*/
private void setText(Text text) {
this.text = text;
}
/**
* Notifies that this cell editor has focus. Put focus on my text widget
* and calculate the the menu item enablement.
*/
protected void doSetFocus() {
if (getText() != null) {
getText().selectAll();
getText().setFocus();
checkSelection();
checkDeleteable();
checkSelectable();
}
}
/**
* Gets the text value in my text widget
*
* @return The text in my text widget
*/
protected Object doGetValue() {
String aText = getText().getText();
// handle value from collection editor dialog
if (value instanceof ElementValue) {
((ElementValue) value).setValue(aText);
return value;
}
return aText;
}
/**
* Sets the text value in my text widget. <code>value</code> must be
* a <code>String</code>.
*
* @param aValue a text string (type <code>String</code>)
*/
protected void doSetValue(Object aValue) {
this.value = aValue;
assert null != getText();
getText().removeModifyListener(getModifyListener());
getText().setText(aValue.toString());
getText().addModifyListener(getModifyListener());
}
/**
* Returns my modify listener.
*
* @return my modify listener
*/
private ModifyListener getModifyListener() {
if (modifyListener == null) {
modifyListener = new ModifyListener() {
public void modifyText(ModifyEvent e) {
editOccured(e);
}
};
}
return modifyListener;
}
/**
* Processes a modify event that occurred in my text widget.
* Performs validation and sets the error message
* accordingly, and then reports a change using <code>fireEditorValueChanged</code>.
*
* @param e The modify event
*/
protected void editOccured(ModifyEvent e) {
String aValue = text.getText();
if (aValue == null) {
aValue = StringStatics.BLANK;
}
Object typedValue = aValue;
boolean oldValidState = isValueValid();
boolean newValidState = isCorrect(typedValue);
if (typedValue == null && newValidState) {
assert (false) : "Validator isn't limiting the cell editor's type range"; //$NON-NLS-1$
}
if (!newValidState) {
// try to insert the current value into the error message.
setErrorMessage(
MessageFormat.format(
getErrorMessage(),
new Object[] { aValue }));
}
valueChanged(oldValidState, newValidState);
}
/**
* Checks to see if the "deleteable" state (can delete/
* nothing to delete) has changed and if so fire an
* enablement changed notification.
*/
private void checkDeleteable() {
boolean oldIsDeleteable = isDeleteable;
isDeleteable = isDeleteEnabled();
if (oldIsDeleteable != isDeleteable) {
fireEnablementChanged(DELETE);
}
}
/**
* Checks to see if the "selectable" state (can select)
* has changed and if so fire an enablement changed notification.
*/
private void checkSelectable() {
boolean oldIsSelectable = isSelectable;
isSelectable = isSelectAllEnabled();
if (oldIsSelectable != isSelectable) {
fireEnablementChanged(SELECT_ALL);
}
}
/**
* Checks to see if the selection state (selection /
* no selection) has changed and if so fire an
* enablement changed notification.
*/
private void checkSelection() {
boolean oldIsSelection = isSelection;
isSelection = text.getSelectionCount() > 0;
if (oldIsSelection != isSelection) {
fireEnablementChanged(COPY);
fireEnablementChanged(CUT);
}
}
/**
* Determines if there is text to copy.
*
* @return <code>true</code> if the text selection is not empty,
* <code>false</code>otherwise
*/
public boolean isCopyEnabled() {
if (text == null || text.isDisposed())
return false;
return text.getSelectionCount() > 0;
}
/**
* Determines if there is text to cut
*
* @return <code>true</code> if the text selection is not empty,
* <code>false</code>otherwise
*/
public boolean isCutEnabled() {
if (text == null || text.isDisposed())
return false;
return text.getSelectionCount() > 0;
}
/**
* Determines if there is text to delete
*
* @return <code>true</code> if the text selection is not empty,
* <code>false</code>otherwise
*/
public boolean isDeleteEnabled() {
if (text == null || text.isDisposed())
return false;
return text.getSelectionCount() > 0
|| text.getCaretPosition() < text.getCharCount();
}
/**
* Determines if there is a text widget on which text can be pasted
*
* @return <code>true</code> if the text selection is not empty,
* <code>false</code>otherwise
*/
public boolean isPasteEnabled() {
if (text == null || text.isDisposed())
return false;
return true;
}
/**
* Determines if there is a text widget in which text can be saved
*
* @return <code>true</code> if the text widget is not disposed,
* <code>false</code>otherwise
*/
public boolean isSaveAllEnabled() {
if (text == null || text.isDisposed())
return false;
return true;
}
/**
* Determines if there is text to be selected.
*
* @return <code>true</code> if select all is possible,
* <code>false</code> otherwise
*/
public boolean isSelectAllEnabled() {
if (text == null || text.isDisposed())
return false;
return text.getCharCount() > 0;
}
/**
* Copies the selected text
*/
public void performCopy() {
text.copy();
}
/**
* Cuts the selected text to the clipboard.
*/
public void performCut() {
text.cut();
checkSelection();
checkDeleteable();
checkSelectable();
}
/**
* Deletes the selected text or, if there is no selection,
* the character next character from the current position.
*/
public void performDelete() {
if (text.getSelectionCount() > 0)
text.insert(StringStatics.BLANK);
else {
// remove the next character
int pos = text.getCaretPosition();
if (pos < text.getCharCount()) {
text.setSelection(pos, pos + 1);
text.insert(StringStatics.BLANK);
}
}
checkSelection();
checkDeleteable();
checkSelectable();
}
/**
* Pastes the the clipboard contents over the selected text.
*/
public void performPaste() {
text.paste();
checkSelection();
checkDeleteable();
checkSelectable();
}
/**
* Selects all of the text
*/
public void performSelectAll() {
text.selectAll();
checkSelection();
checkDeleteable();
}
/**
* Getter method for value
* @return the value of this cell editor
*/
protected Object getCellObjectValue() {
return value;
}
}