blob: 0e178ecf1291f78100fff691f8860c6bf7fb0fca [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2015 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
* Tom Eicher (Avaloq Evolution AG) - block selection mode
*******************************************************************************/
package org.eclipse.ui.texteditor;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IContributionManager;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.part.EditorActionBarContributor;
/**
* Manages the installation and removal of global actions for
* the same type of editors.
* <p>
* If instantiated and used as-is, this contributor connects to all of the workbench defined
* global editor actions the corresponding actions of the current editor. It also adds addition
* actions for searching and navigation (go to line) as well as a set of status fields.</p>
* <p>
* Subclasses may override the following methods:
* <ul>
* <li><code>contributeToMenu</code> - extend to contribute to menu</li>
* <li><code>contributeToToolBar</code> - reimplement to contribute to tool bar</li>
* <li><code>contributeToStatusLine</code> - reimplement to contribute to status line</li>
* <li><code>setActiveEditor</code> - extend to react to editor changes</li>
* </ul>
* </p>
* @see org.eclipse.ui.texteditor.ITextEditorActionConstants
*/
public class BasicTextEditorActionContributor extends EditorActionBarContributor {
/** The global actions to be connected with editor actions */
private final static String[] ACTIONS= {
ITextEditorActionConstants.UNDO,
ITextEditorActionConstants.REDO,
ITextEditorActionConstants.CUT,
ITextEditorActionConstants.COPY,
ITextEditorActionConstants.PASTE,
ITextEditorActionConstants.DELETE,
ITextEditorActionConstants.SELECT_ALL,
ITextEditorActionConstants.FIND,
ITextEditorActionConstants.PRINT,
ITextEditorActionConstants.PROPERTIES,
ITextEditorActionConstants.REVERT
};
/**
* Status field definition.
* @since 3.0
*/
private static class StatusFieldDef {
private String category;
private String actionId;
private boolean visible;
private int widthInChars;
private StatusFieldDef(String category, String actionId, boolean visible, int widthInChars) {
Assert.isNotNull(category);
this.category= category;
this.actionId= actionId;
this.visible= visible;
this.widthInChars= widthInChars;
}
}
/**
* The status fields to be set to the editor
* @since 3.0
*/
private final static StatusFieldDef[] STATUS_FIELD_DEFS= {
new StatusFieldDef(ITextEditorActionConstants.STATUS_CATEGORY_FIND_FIELD, null, false, EditorMessages.Editor_FindIncremental_reverse_name.length() + 15),
new StatusFieldDef(ITextEditorActionConstants.STATUS_CATEGORY_ELEMENT_STATE, null, true, StatusLineContributionItem.DEFAULT_WIDTH_IN_CHARS + 1),
new StatusFieldDef(ITextEditorActionConstants.STATUS_CATEGORY_INPUT_MODE, ITextEditorActionDefinitionIds.TOGGLE_OVERWRITE, true, StatusLineContributionItem.DEFAULT_WIDTH_IN_CHARS),
new StatusFieldDef(ITextEditorActionConstants.STATUS_CATEGORY_INPUT_POSITION, ITextEditorActionConstants.GOTO_LINE, true, StatusLineContributionItem.DEFAULT_WIDTH_IN_CHARS)
};
/**
* The active editor part.
*/
private IEditorPart fActiveEditorPart;
/**
* The find next action.
* @since 2.0
*/
private RetargetTextEditorAction fFindNext;
/**
* The find previous action.
* @since 2.0
*/
private RetargetTextEditorAction fFindPrevious;
/**
* The incremental find action.
* @since 2.0
*/
private RetargetTextEditorAction fIncrementalFind;
/**
* The reverse incremental find action.
* @since 2.1
*/
private RetargetTextEditorAction fIncrementalFindReverse;
/**
* The go to line action.
*/
private RetargetTextEditorAction fGotoLine;
/**
* The word completion action.
* @since 3.1
*/
private RetargetTextEditorAction fHippieCompletion;
/**
* The map of status fields.
* @since 2.0
*/
private Map<StatusFieldDef, StatusLineContributionItem> fStatusFields;
/**
* Creates an empty editor action bar contributor. The action bars are
* furnished later via the <code>init</code> method.
*
* @see org.eclipse.ui.IEditorActionBarContributor#init(org.eclipse.ui.IActionBars, org.eclipse.ui.IWorkbenchPage)
*/
public BasicTextEditorActionContributor() {
fFindNext= new RetargetTextEditorAction(EditorMessages.getBundleForConstructedKeys(), "Editor.FindNext."); //$NON-NLS-1$
fFindNext.setActionDefinitionId(IWorkbenchActionDefinitionIds.FIND_NEXT);
fFindPrevious= new RetargetTextEditorAction(EditorMessages.getBundleForConstructedKeys(), "Editor.FindPrevious."); //$NON-NLS-1$
fFindPrevious.setActionDefinitionId(IWorkbenchActionDefinitionIds.FIND_PREVIOUS);
fIncrementalFind= new RetargetTextEditorAction(EditorMessages.getBundleForConstructedKeys(), "Editor.FindIncremental."); //$NON-NLS-1$
fIncrementalFind.setActionDefinitionId(IWorkbenchActionDefinitionIds.FIND_INCREMENTAL);
fIncrementalFindReverse= new RetargetTextEditorAction(EditorMessages.getBundleForConstructedKeys(), "Editor.FindIncrementalReverse."); //$NON-NLS-1$
fIncrementalFindReverse.setActionDefinitionId(IWorkbenchActionDefinitionIds.FIND_INCREMENTAL_REVERSE);
fGotoLine= new RetargetTextEditorAction(EditorMessages.getBundleForConstructedKeys(), "Editor.GotoLine."); //$NON-NLS-1$
fGotoLine.setActionDefinitionId(ITextEditorActionDefinitionIds.LINE_GOTO);
fHippieCompletion= new RetargetTextEditorAction(EditorMessages.getBundleForConstructedKeys(), "Editor.HippieCompletion."); //$NON-NLS-1$
fHippieCompletion.setActionDefinitionId(ITextEditorActionDefinitionIds.HIPPIE_COMPLETION);
fStatusFields= new HashMap<>(3);
for (int i= 0; i < STATUS_FIELD_DEFS.length; i++) {
StatusFieldDef fieldDef= STATUS_FIELD_DEFS[i];
fStatusFields.put(fieldDef, new StatusLineContributionItem(fieldDef.category, fieldDef.visible, fieldDef.widthInChars));
}
}
/**
* Returns the active editor part.
*
* @return the active editor part
*/
protected final IEditorPart getActiveEditorPart() {
return fActiveEditorPart;
}
/**
* Returns the action registered with the given text editor.
*
* @param editor the editor, or <code>null</code>
* @param actionId the action id
* @return the action, or <code>null</code> if none
*/
protected final IAction getAction(ITextEditor editor, String actionId) {
return (editor == null || actionId == null ? null : editor.getAction(actionId));
}
/**
* The method installs the global action handlers for the given text editor.
* <p>
* This method cannot be overridden by subclasses.</p>
*
* @param part the active editor part
* @since 2.0
*/
private void doSetActiveEditor(IEditorPart part) {
if (fActiveEditorPart == part)
return;
if (fActiveEditorPart instanceof ITextEditorExtension) {
ITextEditorExtension extension= (ITextEditorExtension) fActiveEditorPart;
for (int i= 0; i < STATUS_FIELD_DEFS.length; i++)
extension.setStatusField(null, STATUS_FIELD_DEFS[i].category);
}
fActiveEditorPart= part;
ITextEditor editor= (part instanceof ITextEditor) ? (ITextEditor) part : null;
IActionBars actionBars= getActionBars();
for (int i= 0; i < ACTIONS.length; i++)
actionBars.setGlobalActionHandler(ACTIONS[i], getAction(editor, ACTIONS[i]));
actionBars.setGlobalActionHandler(ITextEditorActionDefinitionIds.SHOW_WHITESPACE_CHARACTERS, getAction(editor, ITextEditorActionConstants.SHOW_WHITESPACE_CHARACTERS));
actionBars.setGlobalActionHandler(ITextEditorActionDefinitionIds.BLOCK_SELECTION_MODE, getAction(editor, ITextEditorActionConstants.BLOCK_SELECTION_MODE));
if (editor instanceof AbstractTextEditor && ((AbstractTextEditor)editor).isWordWrapSupported())
actionBars.setGlobalActionHandler(ITextEditorActionDefinitionIds.WORD_WRAP, getAction(editor, ITextEditorActionConstants.WORD_WRAP));
fFindNext.setAction(getAction(editor, ITextEditorActionConstants.FIND_NEXT));
fFindPrevious.setAction(getAction(editor, ITextEditorActionConstants.FIND_PREVIOUS));
fIncrementalFind.setAction(getAction(editor, ITextEditorActionConstants.FIND_INCREMENTAL));
fIncrementalFindReverse.setAction(getAction(editor, ITextEditorActionConstants.FIND_INCREMENTAL_REVERSE));
fGotoLine.setAction(getAction(editor, ITextEditorActionConstants.GOTO_LINE));
fHippieCompletion.setAction(getAction(editor, ITextEditorActionConstants.HIPPIE_COMPLETION));
for (int i= 0; i < STATUS_FIELD_DEFS.length; i++) {
if (fActiveEditorPart instanceof ITextEditorExtension) {
StatusLineContributionItem statusField= fStatusFields.get(STATUS_FIELD_DEFS[i]);
statusField.setActionHandler(getAction(editor, STATUS_FIELD_DEFS[i].actionId));
ITextEditorExtension extension= (ITextEditorExtension) fActiveEditorPart;
extension.setStatusField(statusField, STATUS_FIELD_DEFS[i].category);
}
}
}
/**
* The <code>BasicTextEditorActionContributor</code> implementation of this
* <code>IEditorActionBarContributor</code> method installs the global
* action handler for the given text editor by calling a private helper
* method.
* <p>
* Subclasses may extend.</p>
*
* @param part {@inheritDoc}
*/
@Override
public void setActiveEditor(IEditorPart part) {
doSetActiveEditor(part);
}
@Override
public void contributeToMenu(IMenuManager menu) {
IMenuManager editMenu= menu.findMenuUsingPath(IWorkbenchActionConstants.M_EDIT);
if (editMenu != null) {
editMenu.prependToGroup(IWorkbenchActionConstants.FIND_EXT, fIncrementalFindReverse);
editMenu.prependToGroup(IWorkbenchActionConstants.FIND_EXT, fIncrementalFind);
editMenu.prependToGroup(IWorkbenchActionConstants.FIND_EXT, fFindPrevious);
editMenu.prependToGroup(IWorkbenchActionConstants.FIND_EXT, fFindNext);
addOrInsert(editMenu, new Separator(ITextEditorActionConstants.GROUP_OPEN));
addOrInsert(editMenu, new Separator(ITextEditorActionConstants.GROUP_INFORMATION));
addOrInsert(editMenu, new Separator(ITextEditorActionConstants.GROUP_ASSIST));
addOrInsert(editMenu, new Separator(ITextEditorActionConstants.GROUP_GENERATE));
addOrInsert(editMenu, new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
editMenu.appendToGroup(ITextEditorActionConstants.GROUP_ASSIST, fHippieCompletion);
}
IMenuManager navigateMenu= menu.findMenuUsingPath(IWorkbenchActionConstants.M_NAVIGATE);
if (navigateMenu != null) {
navigateMenu.appendToGroup(IWorkbenchActionConstants.MB_ADDITIONS, fGotoLine);
}
}
/**
* The <code>item</code> is {@link IContributionManager#add(IContributionItem) added} to
* <code>menu</code> if no item with the same id currently exists. If there already is an
* contribution item with the same id, the new item gets
* {@link IContributionManager#insertAfter(String, IContributionItem) inserted after} it.
*
* @param menu the contribution manager
* @param item the contribution item
* @since 3.2
*/
private void addOrInsert(IContributionManager menu, IContributionItem item) {
String id= item.getId();
if (menu.find(id) == null)
menu.add(item);
else
menu.insertAfter(id, item);
}
@Override
public void contributeToStatusLine(IStatusLineManager statusLineManager) {
super.contributeToStatusLine(statusLineManager);
for (int i= 0; i < STATUS_FIELD_DEFS.length; i++)
statusLineManager.add(fStatusFields.get(STATUS_FIELD_DEFS[i]));
}
@Override
public void dispose() {
doSetActiveEditor(null);
super.dispose();
}
}