blob: 9594b08a4c98ea5e77a72a3a635d3258a5630ce0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2014 Xored Software Inc 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:
* Xored Software Inc - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.rcptt.ui.editors;
import java.util.ResourceBundle;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.operations.IOperationHistory;
import org.eclipse.core.commands.operations.IOperationHistoryListener;
import org.eclipse.core.commands.operations.IUndoContext;
import org.eclipse.core.commands.operations.OperationHistoryEvent;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.observable.ChangeEvent;
import org.eclipse.core.databinding.observable.IChangeListener;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.jface.bindings.keys.ParseException;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.text.ITextOperationTarget;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.ITextViewerExtension6;
import org.eclipse.jface.text.IUndoManagerExtension;
import org.eclipse.jface.text.TextViewer;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchCommandConstants;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.operations.RedoActionHandler;
import org.eclipse.ui.operations.UndoActionHandler;
import org.eclipse.ui.texteditor.FindReplaceAction;
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
import org.eclipse.ui.texteditor.ResourceAction;
import org.eclipse.rcptt.internal.ui.Messages;
import org.eclipse.rcptt.internal.ui.Q7UIPlugin;
import org.eclipse.rcptt.ui.actions.GotoScriptLineAction;
public class TextViewerActionsSupport implements FocusListener, DisposeListener {
private final TextViewer textViewer;
private final IWorkbenchPartSite partSite;
private final Shell shell;
private final IObservableValue editable;
@SuppressWarnings("unused")
private final DataBindingContext dbc = new DataBindingContext();
private final static String CutLabel = Messages.TextViewerActionsSupport_CutLabel;
private final static String CopyLabel = Messages.TextViewerActionsSupport_CopyLabel;
private final static String PasteLabel = Messages.TextViewerActionsSupport_PasteLabel;
private final static String DeleteLabel = Messages.TextViewerActionsSupport_DeleteLabel;
private final static String SelectAllLabel = Messages.TextViewerActionsSupport_SelectAllLabel;
final static String BUNDLE_FOR_CONSTRUCTED_KEYS = "org.eclipse.ui.texteditor.ConstructedEditorMessages";//$NON-NLS-1$
private Action undoAction;
private Action redoAction;
private Action cutAction;
private Action copyAction;
private Action pasteAction;
private Action deleteAction;
private Action selectAllAction;
private ResourceAction findAction;
private Action contentAssistAction;
private Action gotoLineAction;
public TextViewerActionsSupport(TextViewer textViewer,
IWorkbenchPartSite partSite, IObservableValue editable) {
this.textViewer = textViewer;
this.partSite = partSite;
this.shell = partSite.getShell();
this.editable = editable;
init();
}
public TextViewerActionsSupport(TextViewer textViewer, Shell shell,
IObservableValue editable) {
this.textViewer = textViewer;
this.partSite = null;
this.shell = shell;
this.editable = editable;
init();
}
private void init() {
addListeners();
createActions();
if (partSite == null) {
setAcceleratorLabel();
} else if (getTextWidget() != null && getTextWidget().isFocusControl()) {
activateActions();
}
updateEditActionsEnablement();
editable.addChangeListener(new IChangeListener() {
public void handleChange(ChangeEvent event) {
updateEditActionsEnablement();
}
});
createPopupMenu();
}
public Action getUndoAction() {
return undoAction;
}
public Action getRedoAction() {
return redoAction;
}
public Action getCutAction() {
return cutAction;
}
public Action getCopyAction() {
return copyAction;
}
public Action getPasteAction() {
return pasteAction;
}
public Action getDeleteAction() {
return deleteAction;
}
public Action getSelectAllAction() {
return selectAllAction;
}
public ResourceAction getFindAction() {
return findAction;
}
public Action getContentAssistAction() {
return contentAssistAction;
}
public Action getGotoLineAction() {
return gotoLineAction;
}
private void addListeners() {
if (getTextWidget() != null) {
if (partSite != null) {
getTextWidget().addFocusListener(this);
getTextWidget().addDisposeListener(this);
} else {
getTextWidget().addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent event) {
try {
processKeyDown(event);
} catch (ParseException e) {
Q7UIPlugin.log(e);
}
}
});
}
}
this.textViewer
.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
updateEditActionsEnablement();
}
});
}
private void processKeyDown(KeyEvent e) throws ParseException {
KeyStroke pressed = KeyStroke.getInstance(e.stateMask,
Character.toUpperCase(e.keyCode));
if (pressed.equals(KeyStroke.getInstance("M1+Z"))) { //$NON-NLS-1$
undoAction.run();
} else if (pressed.equals(KeyStroke.getInstance("M1+Y"))) { //$NON-NLS-1$
redoAction.run();
} else if (pressed.equals(KeyStroke.getInstance("M1+A"))) { //$NON-NLS-1$
selectAllAction.run();
} else if (pressed.equals(KeyStroke.getInstance("M1+F"))) { //$NON-NLS-1$
findAction.run();
} else if (pressed.equals(KeyStroke.getInstance("Ctrl+Space"))) { //$NON-NLS-1$
contentAssistAction.run();
} else if (gotoLineAction != null
&& pressed.equals(KeyStroke.getInstance("M1+L"))) { //$NON-NLS-1$
gotoLineAction.run();
}
}
private void createPopupMenu() {
if (getTextWidget() != null) {
MenuManager popupMenuManager = new MenuManager();
IMenuListener listener = new IMenuListener() {
public void menuAboutToShow(IMenuManager mng) {
fillContextMenu(mng);
}
};
popupMenuManager.addMenuListener(listener);
popupMenuManager.setRemoveAllWhenShown(true);
Menu menu = popupMenuManager.createContextMenu(textViewer
.getControl());
getTextWidget().setMenu(menu);
}
}
private void fillContextMenu(IMenuManager menuManager) {
if (undoAction != null)
menuManager.add(undoAction);
if (redoAction != null)
menuManager.add(redoAction);
if (undoAction != null || redoAction != null)
menuManager.add(new Separator());
menuManager.add(cutAction);
menuManager.add(copyAction);
menuManager.add(pasteAction);
menuManager.add(new Separator());
menuManager.add(deleteAction);
menuManager.add(selectAllAction);
}
private void updateEditActionsEnablement() {
ITextSelection selection = (ITextSelection) textViewer.getSelection();
boolean hasSelectedText = !selection.isEmpty()
&& selection.getLength() > 0;
boolean isEditable = (Boolean) editable.getValue();
cutAction.setEnabled(isEditable && hasSelectedText);
copyAction.setEnabled(hasSelectedText);
pasteAction.setEnabled(isEditable);
deleteAction.setEnabled(isEditable && hasSelectedText);
if (findAction != null) {
findAction.setEnabled(true);
}
}
private void createActions() {
createUndoRedoActions();
createCommonTextAction();
createAdditionalAction();
}
private void createUndoRedoActions() {
if (textViewer instanceof ITextViewerExtension6
&& textViewer.getUndoManager() instanceof IUndoManagerExtension) {
final IUndoContext undoContext = ((IUndoManagerExtension) textViewer
.getUndoManager()).getUndoContext();
if (undoContext != null) {
if (partSite != null) {
undoAction = new UndoActionHandler(partSite, undoContext);
redoAction = new RedoActionHandler(partSite, undoContext);
} else {
undoAction = new CustomUndoAction(undoContext);
redoAction = new CustomRedoAction(undoContext);
}
undoAction
.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_UNDO);
redoAction
.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_REDO);
textViewer.getUndoManager().reset();
}
}
}
private void createCommonTextAction() {
cutAction = new Action(CutLabel) {
public void run() {
if (textViewer.canDoOperation(ITextOperationTarget.CUT))
textViewer.doOperation(ITextOperationTarget.CUT);
};
};
cutAction.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_CUT);
cutAction
.setImageDescriptor(getImageDescriptor(ISharedImages.IMG_TOOL_CUT));
cutAction
.setDisabledImageDescriptor(getImageDescriptor(ISharedImages.IMG_TOOL_CUT_DISABLED));
copyAction = new Action(CopyLabel) {
public void run() {
if (textViewer.canDoOperation(ITextOperationTarget.COPY))
textViewer.doOperation(ITextOperationTarget.COPY);
};
};
copyAction.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_COPY);
copyAction
.setImageDescriptor(getImageDescriptor(ISharedImages.IMG_TOOL_COPY));
copyAction
.setDisabledImageDescriptor(getImageDescriptor(ISharedImages.IMG_TOOL_COPY_DISABLED));
pasteAction = new Action(PasteLabel) {
public void run() {
if (textViewer.canDoOperation(ITextOperationTarget.PASTE))
textViewer.doOperation(ITextOperationTarget.PASTE);
};
};
pasteAction
.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_PASTE);
pasteAction
.setImageDescriptor(getImageDescriptor(ISharedImages.IMG_TOOL_PASTE));
pasteAction
.setDisabledImageDescriptor(getImageDescriptor(ISharedImages.IMG_TOOL_PASTE_DISABLED));
deleteAction = new Action(DeleteLabel) {
public void run() {
if (textViewer.canDoOperation(ITextOperationTarget.DELETE))
textViewer.doOperation(ITextOperationTarget.DELETE);
};
};
deleteAction
.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_DELETE);
deleteAction
.setImageDescriptor(getImageDescriptor(ISharedImages.IMG_TOOL_DELETE));
deleteAction
.setDisabledImageDescriptor(getImageDescriptor(ISharedImages.IMG_TOOL_DELETE_DISABLED));
selectAllAction = new Action(SelectAllLabel) {
public void run() {
if (textViewer.canDoOperation(ITextOperationTarget.SELECT_ALL))
textViewer.doOperation(ITextOperationTarget.SELECT_ALL);
};
};
selectAllAction
.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_SELECT_ALL);
}
private void createAdditionalAction() {
if (shell != null) {
ResourceBundle fgBundleForConstructedKeys = ResourceBundle
.getBundle(BUNDLE_FOR_CONSTRUCTED_KEYS);
findAction = new FindReplaceAction(
fgBundleForConstructedKeys, "Editor.FindReplace.", shell, textViewer.getFindReplaceTarget()); //$NON-NLS-1$
findAction
.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_FIND_AND_REPLACE);
}
contentAssistAction = new Action() {
@Override
public void run() {
if (textViewer.isEditable()
&& textViewer.getTextWidget().isFocusControl()) {
Display display = Display.getCurrent();
BusyIndicator.showWhile(display, new Runnable() {
public void run() {
textViewer
.doOperation(ISourceViewer.CONTENTASSIST_PROPOSALS);
}
});
}
}
};
contentAssistAction
.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_CONTENT_ASSIST);
// create gotoLine action only if textViewer not in editPart
if (partSite == null && textViewer.getDocument() != null) {
gotoLineAction = new GotoScriptLineAction(textViewer);
gotoLineAction
.setActionDefinitionId(ITextEditorActionDefinitionIds.LINE_GOTO);
}
}
private void setAcceleratorLabel() {
if (undoAction != null) {
undoAction.setAccelerator(KeyCodeAcceleratorFormat("M1+Z")); //$NON-NLS-1$
}
if (redoAction != null) {
redoAction.setAccelerator(KeyCodeAcceleratorFormat("M1+Y")); //$NON-NLS-1$
}
cutAction.setAccelerator(KeyCodeAcceleratorFormat("M1+X")); //$NON-NLS-1$
copyAction.setAccelerator(KeyCodeAcceleratorFormat("M1+C")); //$NON-NLS-1$
pasteAction.setAccelerator(KeyCodeAcceleratorFormat("M1+V")); //$NON-NLS-1$
deleteAction.setAccelerator(KeyCodeAcceleratorFormat("DELETE")); //$NON-NLS-1$
selectAllAction.setAccelerator(KeyCodeAcceleratorFormat("M1+A")); //$NON-NLS-1$
if (gotoLineAction != null) {
gotoLineAction.setAccelerator(KeyCodeAcceleratorFormat("M1+L")); //$NON-NLS-1$
}
}
private int KeyCodeAcceleratorFormat(String shortcut) {
try {
return KeyStroke.getInstance(shortcut).getModifierKeys()
| KeyStroke.getInstance(shortcut).getNaturalKey();
} catch (ParseException e) {
return 0;
}
}
private void activateActions() {
IActionBars actionBars = getActionBars();
if (actionBars != null) {
actionBars.setGlobalActionHandler(ITextEditorActionConstants.UNDO,
undoAction);
actionBars.setGlobalActionHandler(ITextEditorActionConstants.REDO,
redoAction);
actionBars.setGlobalActionHandler(ITextEditorActionConstants.CUT,
cutAction);
actionBars.setGlobalActionHandler(ITextEditorActionConstants.COPY,
copyAction);
actionBars.setGlobalActionHandler(ITextEditorActionConstants.PASTE,
pasteAction);
actionBars.setGlobalActionHandler(
ITextEditorActionConstants.DELETE, deleteAction);
actionBars.setGlobalActionHandler(
ITextEditorActionConstants.SELECT_ALL, selectAllAction);
actionBars.setGlobalActionHandler(ITextEditorActionConstants.FIND,
findAction);
actionBars.setGlobalActionHandler(
ITextEditorActionConstants.CONTENT_ASSIST,
contentAssistAction);
actionBars.updateActionBars();
}
}
private void deactivateActions() {
IActionBars actionBars = getActionBars();
if (actionBars != null) {
actionBars.setGlobalActionHandler(ITextEditorActionConstants.UNDO,
null);
actionBars.setGlobalActionHandler(ITextEditorActionConstants.REDO,
null);
actionBars.setGlobalActionHandler(ITextEditorActionConstants.CUT,
null);
actionBars.setGlobalActionHandler(ITextEditorActionConstants.COPY,
null);
actionBars.setGlobalActionHandler(ITextEditorActionConstants.PASTE,
null);
actionBars.setGlobalActionHandler(
ITextEditorActionConstants.DELETE, null);
actionBars.setGlobalActionHandler(
ITextEditorActionConstants.SELECT_ALL, null);
actionBars.setGlobalActionHandler(ITextEditorActionConstants.FIND,
null);
actionBars.setGlobalActionHandler(
ITextEditorActionConstants.CONTENT_ASSIST, null);
actionBars.updateActionBars();
}
}
public void widgetDisposed(DisposeEvent e) {
deactivateActions();
}
public void focusGained(FocusEvent e) {
activateActions();
}
public void focusLost(FocusEvent e) {
deactivateActions();
}
private ImageDescriptor getImageDescriptor(String imageId) {
return PlatformUI.getWorkbench().getSharedImages()
.getImageDescriptor(imageId);
}
private StyledText getTextWidget() {
return textViewer.getTextWidget();
}
private IActionBars getActionBars() {
if (partSite instanceof IEditorSite)
return ((IEditorSite) partSite).getActionBars();
if (partSite instanceof IViewSite)
return ((IViewSite) partSite).getActionBars();
return null;
}
private abstract class CustomOperationAction extends Action {
private IUndoContext undoContext = null;
CustomOperationAction(IUndoContext context) {
super(""); //$NON-NLS-1$
undoContext = context;
AddHistoryListener();
updateEnablement();
}
private void AddHistoryListener() {
getHistory().addOperationHistoryListener(
new IOperationHistoryListener() {
public void historyNotification(
OperationHistoryEvent event) {
if (event.getOperation().hasContext(undoContext)) {
updateEnablement();
}
}
});
}
protected abstract void updateEnablement();
IOperationHistory getHistory() {
return PlatformUI.getWorkbench().getOperationSupport()
.getOperationHistory();
}
final IUndoContext getUndoContext() {
return undoContext;
}
}
private class CustomUndoAction extends CustomOperationAction {
CustomUndoAction(IUndoContext context) {
super(context);
setText(Messages.TextViewerActionsSupport_UndoLabel);
setImageDescriptor(PlatformUI.getWorkbench().getSharedImages()
.getImageDescriptor(ISharedImages.IMG_TOOL_UNDO));
setDisabledImageDescriptor(PlatformUI.getWorkbench()
.getSharedImages()
.getImageDescriptor(ISharedImages.IMG_TOOL_UNDO_DISABLED));
}
public final void run() {
if (isEnabled()) {
try {
getHistory().undo(getUndoContext(), null, null);
} catch (ExecutionException e) {
Q7UIPlugin.log(e);
}
}
}
protected void updateEnablement() {
setEnabled(getHistory().canUndo(getUndoContext()));
}
}
private class CustomRedoAction extends CustomOperationAction {
CustomRedoAction(IUndoContext context) {
super(context);
setText(Messages.TextViewerActionsSupport_RedoLabel);
setImageDescriptor(PlatformUI.getWorkbench().getSharedImages()
.getImageDescriptor(ISharedImages.IMG_TOOL_REDO));
setDisabledImageDescriptor(PlatformUI.getWorkbench()
.getSharedImages()
.getImageDescriptor(ISharedImages.IMG_TOOL_REDO_DISABLED));
}
public final void run() {
if (isEnabled()) {
try {
getHistory().redo(getUndoContext(), null, null);
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
protected void updateEnablement() {
setEnabled(getHistory().canRedo(getUndoContext()));
}
}
}