blob: 1fd8de5ef16352a9556fdf099e2845d3e16a2141 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007 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.wst.server.ui.internal.view.servers;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
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.Control;
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.TextActionHandler;
import org.eclipse.ui.texteditor.IWorkbenchActionDefinitionIds;
import org.eclipse.wst.server.core.IServer;
import org.eclipse.wst.server.core.IServerWorkingCopy;
import org.eclipse.wst.server.core.internal.ServerPlugin;
import org.eclipse.wst.server.ui.internal.Messages;
/**
* Action to rename a server.
*/
public class RenameAction extends AbstractServerAction {
/*
* The tree editing widgets. If treeEditor is null then edit using the
* dialog. We keep the editorText around so that we can close it if a new
* selection is made.
*/
protected TreeEditor treeEditor;
protected Tree tree;
protected Text textEditor;
protected Composite textEditorParent;
private TextActionHandler textActionHandler;
// The server being edited if this is being done inline
protected IServer editedServer;
protected boolean saving = false;
public RenameAction(Shell shell, TreeViewer viewer, ISelectionProvider selectionProvider) {
super(shell, selectionProvider, Messages.actionRename);
setActionDefinitionId(IWorkbenchActionDefinitionIds.RENAME);
this.tree = viewer.getTree();
this.treeEditor = new TreeEditor(tree);
try {
selectionChanged((IStructuredSelection) selectionProvider.getSelection());
} catch (Exception e) {
// ignore
}
}
public void perform(IServer server) {
runWithInlineEditor(server);
}
/*
* Run the receiver using an inline editor from the supplied navigator. The
* navigator will tell the action when the path is ready to run.
*/
private void runWithInlineEditor(IServer server) {
queryNewServerNameInline(server);
}
/**
* On Mac the text widget already provides a border when it has focus, so
* there is no need to draw another one. The value of returned by this
* method is usd to control the inset we apply to the text field bound's in
* order to get space for drawing a border. A value of 1 means a one-pixel
* wide border around the text field. A negative value supresses the border.
* However, in M9 the system property
* "org.eclipse.swt.internal.carbon.noFocusRing" has been introduced as a
* temporary workaround for bug #28842. The existence of the property turns
* the native focus ring off if the widget is contained in a main window
* (not dialog). The check for the property should be removed after a final
* fix for #28842 has been provided.
*/
private static int getCellEditorInset(Control c) {
// special case for MacOS X
if ("carbon".equals(SWT.getPlatform())) { //$NON-NLS-1$
if (System
.getProperty("org.eclipse.swt.internal.carbon.noFocusRing") == null || c.getShell().getParent() != null) { //$NON-NLS-1$
return -2; // native border
}
}
return 1; // one pixel wide black border
}
/**
* Get the Tree being edited.
*
* @returnTree
*/
private Tree getTree() {
return tree;
}
private Composite createParent() {
Tree tree2 = getTree();
Composite result = new Composite(tree2, SWT.NONE);
TreeItem[] selectedItems = tree2.getSelection();
treeEditor.horizontalAlignment = SWT.LEFT;
treeEditor.grabHorizontal = true;
treeEditor.setEditor(result, selectedItems[0]);
return result;
}
/**
* Return the new name to be given to the target resource or
* <code>null<code>
* if the query was canceled. Rename the currently selected server using the table editor.
* Continue the action when the user is done.
*
* @param server the server to rename
*/
private void queryNewServerNameInline(final IServer server) {
// 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(server);
}
textEditor.setText(server.getName());
// 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 = getCellEditorInset(textEditorParent);
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 server the server to rename
*/
private void createTextEditor(final IServer server) {
// Create text editor parent. This draws a nice bounding rect
textEditorParent = createParent();
textEditorParent.setVisible(false);
final int inset = getCellEditorInset(textEditorParent);
if (inset > 0) {
textEditorParent.addListener(SWT.Paint, new Listener() {
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(tree.getFont());
textEditorParent.setBackground(textEditor.getBackground());
textEditor.addListener(SWT.Modify, new Listener() {
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() {
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(server);
event.doit = true;
event.detail = SWT.TRAVERSE_NONE;
break;
}
}
});
textEditor.addFocusListener(new FocusAdapter() {
public void focusLost(FocusEvent fe) {
saveChangesAndDispose(server);
}
});
if (textActionHandler != null) {
textActionHandler.addText(textEditor);
}
}
/**
* Close the text widget and reset the editorText field.
*/
protected void disposeTextWidget() {
if (textActionHandler != null)
textActionHandler.removeText(textEditor);
if (textEditorParent != null) {
textEditorParent.dispose();
textEditorParent = null;
textEditor = null;
treeEditor.setEditor(null, null);
}
}
/**
* Save the changes and dispose of the text widget.
*
* @param server the server to rename
*/
protected void saveChangesAndDispose(IServer server) {
if (saving == true)
return;
saving = true;
// Cache the resource to avoid selection loss since a selection of
// another item can trigger this method
editedServer = server;
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)
getTree().getShell().getDisplay().asyncExec(new Runnable() {
public void run() {
try {
if (!newName.equals(editedServer.getName())) {
if (ServerPlugin.isNameInUse(editedServer, newName)) {
MessageDialog.openError(shell, Messages.defaultDialogTitle, Messages.errorDuplicateName);
} else {
try {
IServerWorkingCopy wc = editedServer.createWorkingCopy();
wc.setName(newName);
wc.save(false, null);
} catch (CoreException ce) {
// ignore for now
}
}
}
editedServer = null;
// Dispose the text widget regardless
disposeTextWidget();
// Ensure the Navigator tree has focus, which it may not if
// the text widget previously had focus
if (tree != null && !tree.isDisposed()) {
tree.setFocus();
}
} finally {
saving = false;
}
}
});
}
}