blob: 3833585c10159fdc6ffce118b12f2eb0f376600b [file] [log] [blame]
/**
* <copyright>
*
* Copyright (c) 2008-2013 Continental, See4sys, itemis and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
*
* Contributors:
* Continental - Initial API and implementation
* See4sys - Enhance name feature handling, JavaDoc adds
* itemis - [408536] BasicRenameAction not working for non-String attributes
*
* </copyright>
*/
package org.eclipse.sphinx.emf.ui.actions;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EFactory;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.edit.command.CommandParameter;
import org.eclipse.emf.edit.command.SetCommand;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.emf.edit.provider.IWrapperItemProvider;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.transaction.util.TransactionUtil;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.window.Window;
import org.eclipse.sphinx.emf.ui.internal.messages.Messages;
import org.eclipse.sphinx.emf.ui.util.RetrieveNameAttributeHelper;
import org.eclipse.sphinx.platform.ui.util.ExtendedPlatformUI;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TreeEditor;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.actions.BaseSelectionListenerAction;
/**
* Basic implementation of action responsible for renaming a selected model element.
*/
public class BasicRenameAction extends BaseSelectionListenerAction {
private RetrieveNameAttributeHelper helper = new RetrieveNameAttributeHelper();
private TreeViewer viewer;
private Composite textEditorParent;
private Text textEditor;
private TreeEditor treeEditor;
private boolean saving;
public BasicRenameAction() {
super(Messages.action_rename_label);
}
public BasicRenameAction(String text) {
super(text);
}
public BasicRenameAction(TreeViewer viewer) {
this(Messages.action_rename_label);
this.viewer = viewer;
}
public BasicRenameAction(String text, TreeViewer viewer) {
this(text);
this.viewer = viewer;
}
@Override
public void run() {
IStructuredSelection selection = getStructuredSelection();
if (selection.size() == 1) {
Object object = AdapterFactoryEditingDomain.unwrap(selection.getFirstElement());
if (object instanceof EObject) {
EObject target = (EObject) object;
if (viewer == null) {
// use external dialog to perform the renaming
String oldName = getOldName(target);
if (oldName == null) {
oldName = ""; //$NON-NLS-1$
}
String newName = oldName;
newName = changeNameDialog(ExtendedPlatformUI.getActiveShell(), oldName);
if (!oldName.equals(newName)) {
execRename(target, newName);
}
} else {
inlineEditor(target);
}
}
}
}
@Override
public boolean updateSelection(IStructuredSelection selection) {
// Enable only for single selection, which are instance of EObject or IWrapperItemProvider wrapping an EObject
if (selection.size() == 1) {
Object selected = selection.getFirstElement();
if (selected instanceof EObject && helper.hasNameAttribute((EObject) selected)) {
return true;
} else if (selected instanceof IWrapperItemProvider) {
Object unwrap = AdapterFactoryEditingDomain.unwrap(selected);
return updateSelection(new StructuredSelection(unwrap));
}
}
return false;
}
protected String getOldName(EObject object) {
if (helper.hasNameAttribute(object)) {
Object nameAttributeValue = object.eGet(helper.getNameAttribute(object));
return nameAttributeValue.toString();
}
return ""; //$NON-NLS-1$
}
protected void execRename(EObject objectToRename, String newName) {
TransactionalEditingDomain editingDomain = TransactionUtil.getEditingDomain(objectToRename);
EAttribute attribute = helper.getNameAttribute(objectToRename);
EFactory attributeValueFactory = attribute.getEType().getEPackage().getEFactoryInstance();
Object attributeValue = attributeValueFactory.createFromString((EDataType) attribute.getEType(), newName);
Command command = editingDomain.createCommand(SetCommand.class, new CommandParameter(objectToRename, attribute, attributeValue));
if (command.canExecute()) {
editingDomain.getCommandStack().execute(command);
}
}
/**
* @param shell
* @param oldName
* @return
*/
protected String changeNameDialog(Shell shell, String oldName) {
InputDialog dialog = new InputDialog(shell, Messages.dialog_rename_title, Messages.dialog_rename_message, oldName, null);
dialog.setBlockOnOpen(true);
int result = dialog.open();
if (result == Window.OK) {
return dialog.getValue();
} else {
return oldName;
}
}
protected void inlineEditor(final EObject object) {
// Make sure text editor is created only once. Simply reset text
// editor when action is executed more than once. Fixes bug 22269.
if (textEditorParent == null) {
createTextEditor(object);
}
String oldName = getOldName(object);
if (oldName != null) {
textEditor.setText(oldName);
}
// Open text editor with initial size.
textEditorParent.setVisible(true);
Point textSize = textEditor.computeSize(SWT.DEFAULT, SWT.DEFAULT);
textSize.x += textSize.y; // Add extra space for new characters.
Point parentSize = textEditorParent.getSize();
int inset = 1;
textEditor.setBounds(2, inset, Math.min(textSize.x, parentSize.x - 4), parentSize.y - 2 * inset);
textEditorParent.redraw();
textEditor.selectAll();
textEditor.setFocus();
}
/**
* Create the text editor widget.
*
* @param objectToRename
* the resource to rename
*/
protected void createTextEditor(final EObject objectToRename) {
// Create text editor parent. This draws a nice bounding rectangle.
textEditorParent = createParent();
textEditorParent.setVisible(false);
final int inset = 1;
if (inset > 0) {
textEditorParent.addListener(SWT.Paint, new Listener() {
@Override
public void handleEvent(Event e) {
Point textSize = textEditor.getSize();
Point parentSize = textEditorParent.getSize();
e.gc.drawRectangle(0, 0, Math.min(textSize.x + 4, parentSize.x - 1), parentSize.y - 1);
}
});
}
// Create inner text editor.
textEditor = new Text(textEditorParent, SWT.NONE);
textEditor.setFont(viewer.getTree().getFont());
textEditorParent.setBackground(textEditor.getBackground());
textEditor.addListener(SWT.Modify, new Listener() {
@Override
public void handleEvent(Event e) {
Point textSize = textEditor.computeSize(SWT.DEFAULT, SWT.DEFAULT);
textSize.x += textSize.y; // Add extra space for new
// characters.
Point parentSize = textEditorParent.getSize();
textEditor.setBounds(2, inset, Math.min(textSize.x, parentSize.x - 4), parentSize.y - 2 * inset);
textEditorParent.redraw();
}
});
textEditor.addListener(SWT.Traverse, new Listener() {
@Override
public void handleEvent(Event event) {
// Workaround for Bug 20214 due to extra
// traverse events
switch (event.detail) {
case SWT.TRAVERSE_ESCAPE:
// Do nothing in this case
disposeTextWidget();
event.doit = true;
event.detail = SWT.TRAVERSE_NONE;
break;
case SWT.TRAVERSE_RETURN:
saveChangesAndDispose(objectToRename);
event.doit = true;
event.detail = SWT.TRAVERSE_NONE;
break;
}
}
});
textEditor.addFocusListener(new FocusAdapter() {
@Override
public void focusLost(FocusEvent fe) {
saveChangesAndDispose(objectToRename);
}
});
}
/**
* Close the text widget and reset the editorText field.
*/
protected void disposeTextWidget() {
if (textEditorParent != null) {
textEditorParent.dispose();
textEditorParent = null;
textEditor = null;
if (treeEditor != null) {
treeEditor.dispose();
treeEditor = null;
}
}
}
protected void saveChangesAndDispose(EObject object) {
if (saving == true) {
return;
}
saving = true;
// Cache the resource to avoid selection loss since a selection of
// another item can trigger this method
final EObject inlinedObject = object;
final String newName = textEditor.getText();
// Run this in an async to make sure that the operation that triggered
// this action is completed. Otherwise this leads to problems when the
// icon of the item being renamed is clicked (i.e., which causes the
// rename text widget to lose focus and trigger this method).
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
String oldName = getOldName(inlinedObject);
if (oldName == null) {
oldName = ""; //$NON-NLS-1$
}
if (!oldName.equals(newName)) {
execRename(inlinedObject, newName);
if (viewer != null) {
viewer.refresh(inlinedObject, true);
}
}
// Dispose the text widget regardless
disposeTextWidget();
// Ensure the viewer tree has focus, which it may not if the
// text widget previously had focus.
if (viewer != null) {
viewer.refresh(inlinedObject, true);
}
} finally {
saving = false;
}
}
};
ExtendedPlatformUI.getDisplay().asyncExec(runnable);
}
protected Composite createParent() {
Tree tree = viewer.getTree();
Composite result = new Composite(tree, SWT.NONE);
TreeItem[] selectedItems = tree.getSelection();
treeEditor = new TreeEditor(tree);
treeEditor.horizontalAlignment = SWT.LEFT;
treeEditor.grabHorizontal = true;
treeEditor.setEditor(result, selectedItems[0]);
return result;
}
}