blob: b6551c7ae96b916178c762f49ac427a94b7f7750 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 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.ui.navigator.internal;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
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.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.navigator.CommonViewer;
import org.eclipse.ui.navigator.internal.extensions.INavigatorSiteEditor;
/**
* A NavigatorSiteEditor is used to edit (i.e., rename) elements in a Navigator view. It displays a
* text editor box overlay on the Navigator tree widget.
*
*
* <p>
* <strong>EXPERIMENTAL</strong>. This class or interface has been added as part of a work in
* progress. There is a guarantee neither that this API will work nor that it will remain the same.
* Please do not use this API without consulting with the Platform/UI team.
* </p>
*
* @since 3.2
*/
public class NavigatorSiteEditor implements INavigatorSiteEditor {
private Tree navigatorTree;
private TreeEditor treeEditor;
private Text textEditor;
private Composite textEditorParent;
private TextActionHandler textActionHandler;
private String text; // the text being edited
private CommonViewer commonViewer;
/**
* Creates an instance of a NavigatorSiteEditor.
*
* @param site
* the navigator site this editor applies to
* @param navigatorTree
* the tree that is being edited
*/
public NavigatorSiteEditor(CommonViewer aCommonViewer, Tree navigatorTree) {
commonViewer = aCommonViewer;
this.navigatorTree = navigatorTree;
treeEditor = new TreeEditor(navigatorTree);
}
/**
* Creates the parent composite for the editor overlay.
*
* @return the parent composite for the editor overlay
*/
Composite createParent() {
Composite result = new Composite(navigatorTree, SWT.NONE);
TreeItem[] selectedItems = navigatorTree.getSelection();
treeEditor.horizontalAlignment = SWT.LEFT;
treeEditor.grabHorizontal = true;
treeEditor.setEditor(result, selectedItems[0]);
return result;
}
/**
* Creates the text editor widget.
*
* @param runnable
* the Runnable to execute when editing ends by the user pressing enter or clicking
* outside the text editor box.
*/
void createTextEditor(final Runnable runnable) {
// Create text editor parent. This draws a nice bounding rect.
textEditorParent = createParent();
textEditorParent.setVisible(false);
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);
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, 1, Math.min(textSize.x, parentSize.x - 4), parentSize.y - 2);
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(runnable);
event.doit = true;
event.detail = SWT.TRAVERSE_NONE;
break;
}
}
});
textEditor.addFocusListener(new FocusAdapter() {
public void focusLost(FocusEvent fe) {
saveChangesAndDispose(runnable);
}
});
if (textActionHandler != null) {
textActionHandler.addText(textEditor);
}
}
/**
* Closes the text editor widget.
*/
void disposeTextWidget() {
if (textActionHandler != null) {
textActionHandler.removeText(textEditor);
}
if (textEditorParent != null) {
textEditorParent.dispose();
textEditorParent = null;
textEditor = null;
treeEditor.setEditor(null, null);
}
}
/**
* Displays a text editor overlay on the tree widget.
*
* @param runnable
* Runnable to execute when editing ends either by the user pressing enter or
* clicking outside the editor box.
*/
public void edit(Runnable runnable) {
IStructuredSelection selection = (IStructuredSelection) commonViewer.getSelection();
if (selection.size() != 1) {
return;
}
text = getLabel(selection.getFirstElement());
if (text == null) {
return;
}
// 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(runnable);
}
textEditor.setText(text);
// 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();
textEditor.setBounds(2, 1, Math.min(textSize.x, parentSize.x - 4), parentSize.y - 2);
textEditorParent.redraw();
textEditor.selectAll();
textEditor.setFocus();
}
/**
* Returns the displayed label of the given element.
*
* @param element
* the element that is displayed in the navigator
* @return the displayed label of the given element.
*/
String getLabel(Object element) {
return ((ILabelProvider) commonViewer.getLabelProvider()).getText(element);
}
public String getText() {
return text;
}
/**
* Saves the changes and disposes of the text widget.
*
* @param runnable
* Runnable to execute
*/
void saveChangesAndDispose(final Runnable runnable) {
final String newText = 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 editRunnable = new Runnable() {
public void run() {
disposeTextWidget();
if (newText.length() > 0 && newText.equals(text) == false) {
text = newText;
runnable.run();
}
text = null;
}
};
navigatorTree.getShell().getDisplay().asyncExec(editRunnable);
}
public void setTextActionHandler(TextActionHandler actionHandler) {
textActionHandler = actionHandler;
}
}