001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.texteditor;
011:
012: import java.util.HashMap;
013: import java.util.Map;
014:
015: import org.eclipse.core.runtime.Assert;
016:
017: import org.eclipse.jface.action.IAction;
018: import org.eclipse.jface.action.IContributionItem;
019: import org.eclipse.jface.action.IContributionManager;
020: import org.eclipse.jface.action.IMenuManager;
021: import org.eclipse.jface.action.IStatusLineManager;
022: import org.eclipse.jface.action.Separator;
023: import org.eclipse.ui.IActionBars;
024: import org.eclipse.ui.IEditorPart;
025: import org.eclipse.ui.IWorkbenchActionConstants;
026: import org.eclipse.ui.part.EditorActionBarContributor;
027:
028: /**
029: * Manages the installation and removal of global actions for
030: * the same type of editors.
031: * <p>
032: * If instantiated and used as-is, this contributor connects to all of the workbench defined
033: * global editor actions the corresponding actions of the current editor. It also adds addition
034: * actions for searching and navigation (go to line) as well as a set of status fields.</p>
035: * <p>
036: * Subclasses may override the following methods:
037: * <ul>
038: * <li><code>contributeToMenu</code> - extend to contribute to menu</li>
039: * <li><code>contributeToToolBar</code> - reimplement to contribute to tool bar</li>
040: * <li><code>contributeToStatusLine</code> - reimplement to contribute to status line</li>
041: * <li><code>setActiveEditor</code> - extend to react to editor changes</li>
042: * </ul>
043: * </p>
044: * @see org.eclipse.ui.texteditor.ITextEditorActionConstants
045: */
046: public class BasicTextEditorActionContributor extends
047: EditorActionBarContributor {
048:
049: /** The global actions to be connected with editor actions */
050: private final static String[] ACTIONS = {
051: ITextEditorActionConstants.UNDO,
052: ITextEditorActionConstants.REDO,
053: ITextEditorActionConstants.CUT,
054: ITextEditorActionConstants.COPY,
055: ITextEditorActionConstants.PASTE,
056: ITextEditorActionConstants.DELETE,
057: ITextEditorActionConstants.SELECT_ALL,
058: ITextEditorActionConstants.FIND,
059: ITextEditorActionConstants.PRINT,
060: ITextEditorActionConstants.PROPERTIES,
061: ITextEditorActionConstants.REVERT };
062:
063: /**
064: * Status field definition.
065: * @since 3.0
066: */
067: private static class StatusFieldDef {
068:
069: private String category;
070: private String actionId;
071: private boolean visible;
072: private int widthInChars;
073:
074: private StatusFieldDef(String category, String actionId,
075: boolean visible, int widthInChars) {
076: Assert.isNotNull(category);
077: this .category = category;
078: this .actionId = actionId;
079: this .visible = visible;
080: this .widthInChars = widthInChars;
081: }
082: }
083:
084: /**
085: * The status fields to be set to the editor
086: * @since 3.0
087: */
088: private final static StatusFieldDef[] STATUS_FIELD_DEFS = {
089: new StatusFieldDef(
090: ITextEditorActionConstants.STATUS_CATEGORY_FIND_FIELD,
091: null, false,
092: EditorMessages.Editor_FindIncremental_reverse_name
093: .length() + 15),
094: new StatusFieldDef(
095: ITextEditorActionConstants.STATUS_CATEGORY_ELEMENT_STATE,
096: null,
097: true,
098: StatusLineContributionItem.DEFAULT_WIDTH_IN_CHARS + 1),
099: new StatusFieldDef(
100: ITextEditorActionConstants.STATUS_CATEGORY_INPUT_MODE,
101: ITextEditorActionDefinitionIds.TOGGLE_OVERWRITE,
102: true,
103: StatusLineContributionItem.DEFAULT_WIDTH_IN_CHARS),
104: new StatusFieldDef(
105: ITextEditorActionConstants.STATUS_CATEGORY_INPUT_POSITION,
106: ITextEditorActionConstants.GOTO_LINE, true,
107: StatusLineContributionItem.DEFAULT_WIDTH_IN_CHARS) };
108:
109: /**
110: * The active editor part.
111: */
112: private IEditorPart fActiveEditorPart;
113: /**
114: * The find next action.
115: * @since 2.0
116: */
117: private RetargetTextEditorAction fFindNext;
118: /**
119: * The find previous action.
120: * @since 2.0
121: */
122: private RetargetTextEditorAction fFindPrevious;
123: /**
124: * The incremental find action.
125: * @since 2.0
126: */
127: private RetargetTextEditorAction fIncrementalFind;
128: /**
129: * The reverse incremental find action.
130: * @since 2.1
131: */
132: private RetargetTextEditorAction fIncrementalFindReverse;
133: /**
134: * The go to line action.
135: */
136: private RetargetTextEditorAction fGotoLine;
137: /**
138: * The word completion action.
139: * @since 3.1
140: */
141: private RetargetTextEditorAction fHippieCompletion;
142: /**
143: * The map of status fields.
144: * @since 2.0
145: */
146: private Map fStatusFields;
147:
148: /**
149: * Creates an empty editor action bar contributor. The action bars are
150: * furnished later via the <code>init</code> method.
151: *
152: * @see org.eclipse.ui.IEditorActionBarContributor#init(org.eclipse.ui.IActionBars, org.eclipse.ui.IWorkbenchPage)
153: */
154: public BasicTextEditorActionContributor() {
155:
156: fFindNext = new RetargetTextEditorAction(EditorMessages
157: .getBundleForConstructedKeys(), "Editor.FindNext."); //$NON-NLS-1$
158: fFindNext
159: .setActionDefinitionId(IWorkbenchActionDefinitionIds.FIND_NEXT);
160: fFindPrevious = new RetargetTextEditorAction(EditorMessages
161: .getBundleForConstructedKeys(), "Editor.FindPrevious."); //$NON-NLS-1$
162: fFindPrevious
163: .setActionDefinitionId(IWorkbenchActionDefinitionIds.FIND_PREVIOUS);
164: fIncrementalFind = new RetargetTextEditorAction(EditorMessages
165: .getBundleForConstructedKeys(),
166: "Editor.FindIncremental."); //$NON-NLS-1$
167: fIncrementalFind
168: .setActionDefinitionId(IWorkbenchActionDefinitionIds.FIND_INCREMENTAL);
169: fIncrementalFindReverse = new RetargetTextEditorAction(
170: EditorMessages.getBundleForConstructedKeys(),
171: "Editor.FindIncrementalReverse."); //$NON-NLS-1$
172: fIncrementalFindReverse
173: .setActionDefinitionId(IWorkbenchActionDefinitionIds.FIND_INCREMENTAL_REVERSE);
174: fGotoLine = new RetargetTextEditorAction(EditorMessages
175: .getBundleForConstructedKeys(), "Editor.GotoLine."); //$NON-NLS-1$
176: fGotoLine
177: .setActionDefinitionId(ITextEditorActionDefinitionIds.LINE_GOTO);
178: fHippieCompletion = new RetargetTextEditorAction(EditorMessages
179: .getBundleForConstructedKeys(),
180: "Editor.HippieCompletion."); //$NON-NLS-1$
181: fHippieCompletion
182: .setActionDefinitionId(ITextEditorActionDefinitionIds.HIPPIE_COMPLETION);
183:
184: fStatusFields = new HashMap(3);
185: for (int i = 0; i < STATUS_FIELD_DEFS.length; i++) {
186: StatusFieldDef fieldDef = STATUS_FIELD_DEFS[i];
187: fStatusFields.put(fieldDef, new StatusLineContributionItem(
188: fieldDef.category, fieldDef.visible,
189: fieldDef.widthInChars));
190: }
191: }
192:
193: /**
194: * Returns the active editor part.
195: *
196: * @return the active editor part
197: */
198: protected final IEditorPart getActiveEditorPart() {
199: return fActiveEditorPart;
200: }
201:
202: /**
203: * Returns the action registered with the given text editor.
204: *
205: * @param editor the editor, or <code>null</code>
206: * @param actionId the action id
207: * @return the action, or <code>null</code> if none
208: */
209: protected final IAction getAction(ITextEditor editor,
210: String actionId) {
211: return (editor == null || actionId == null ? null : editor
212: .getAction(actionId));
213: }
214:
215: /**
216: * The method installs the global action handlers for the given text editor.
217: * <p>
218: * This method cannot be overridden by subclasses.</p>
219: *
220: * @param part the active editor part
221: * @since 2.0
222: */
223: private void doSetActiveEditor(IEditorPart part) {
224:
225: if (fActiveEditorPart == part)
226: return;
227:
228: if (fActiveEditorPart instanceof ITextEditorExtension) {
229: ITextEditorExtension extension = (ITextEditorExtension) fActiveEditorPart;
230: for (int i = 0; i < STATUS_FIELD_DEFS.length; i++)
231: extension.setStatusField(null,
232: STATUS_FIELD_DEFS[i].category);
233: }
234:
235: fActiveEditorPart = part;
236: ITextEditor editor = (part instanceof ITextEditor) ? (ITextEditor) part
237: : null;
238:
239: IActionBars actionBars = getActionBars();
240: for (int i = 0; i < ACTIONS.length; i++)
241: actionBars.setGlobalActionHandler(ACTIONS[i], getAction(
242: editor, ACTIONS[i]));
243: actionBars
244: .setGlobalActionHandler(
245: ITextEditorActionDefinitionIds.SHOW_WHITESPACE_CHARACTERS,
246: getAction(
247: editor,
248: ITextEditorActionConstants.SHOW_WHITESPACE_CHARACTERS));
249:
250: fFindNext.setAction(getAction(editor,
251: ITextEditorActionConstants.FIND_NEXT));
252: fFindPrevious.setAction(getAction(editor,
253: ITextEditorActionConstants.FIND_PREVIOUS));
254: fIncrementalFind.setAction(getAction(editor,
255: ITextEditorActionConstants.FIND_INCREMENTAL));
256: fIncrementalFindReverse.setAction(getAction(editor,
257: ITextEditorActionConstants.FIND_INCREMENTAL_REVERSE));
258: fGotoLine.setAction(getAction(editor,
259: ITextEditorActionConstants.GOTO_LINE));
260: fHippieCompletion.setAction(getAction(editor,
261: ITextEditorActionConstants.HIPPIE_COMPLETION));
262:
263: for (int i = 0; i < STATUS_FIELD_DEFS.length; i++) {
264: if (fActiveEditorPart instanceof ITextEditorExtension) {
265: StatusLineContributionItem statusField = (StatusLineContributionItem) fStatusFields
266: .get(STATUS_FIELD_DEFS[i]);
267: statusField.setActionHandler(getAction(editor,
268: STATUS_FIELD_DEFS[i].actionId));
269: ITextEditorExtension extension = (ITextEditorExtension) fActiveEditorPart;
270: extension.setStatusField(statusField,
271: STATUS_FIELD_DEFS[i].category);
272: }
273: }
274: }
275:
276: /**
277: * The <code>BasicTextEditorActionContributor</code> implementation of this
278: * <code>IEditorActionBarContributor</code> method installs the global
279: * action handler for the given text editor by calling a private helper
280: * method.
281: * <p>
282: * Subclasses may extend.</p>
283: *
284: * @param part {@inheritDoc}
285: */
286: public void setActiveEditor(IEditorPart part) {
287: doSetActiveEditor(part);
288: }
289:
290: /*
291: * @see EditorActionBarContributor#contributeToMenu(IMenuManager)
292: */
293: public void contributeToMenu(IMenuManager menu) {
294:
295: IMenuManager editMenu = menu
296: .findMenuUsingPath(IWorkbenchActionConstants.M_EDIT);
297: if (editMenu != null) {
298: editMenu.prependToGroup(IWorkbenchActionConstants.FIND_EXT,
299: fIncrementalFindReverse);
300: editMenu.prependToGroup(IWorkbenchActionConstants.FIND_EXT,
301: fIncrementalFind);
302: editMenu.prependToGroup(IWorkbenchActionConstants.FIND_EXT,
303: fFindPrevious);
304: editMenu.prependToGroup(IWorkbenchActionConstants.FIND_EXT,
305: fFindNext);
306:
307: addOrInsert(editMenu, new Separator(
308: ITextEditorActionConstants.GROUP_OPEN));
309: addOrInsert(editMenu, new Separator(
310: ITextEditorActionConstants.GROUP_INFORMATION));
311: addOrInsert(editMenu, new Separator(
312: ITextEditorActionConstants.GROUP_ASSIST));
313: addOrInsert(editMenu, new Separator(
314: ITextEditorActionConstants.GROUP_GENERATE));
315: addOrInsert(editMenu, new Separator(
316: IWorkbenchActionConstants.MB_ADDITIONS));
317:
318: editMenu.appendToGroup(
319: ITextEditorActionConstants.GROUP_ASSIST,
320: fHippieCompletion);
321: }
322:
323: IMenuManager navigateMenu = menu
324: .findMenuUsingPath(IWorkbenchActionConstants.M_NAVIGATE);
325: if (navigateMenu != null) {
326: navigateMenu.appendToGroup(
327: IWorkbenchActionConstants.MB_ADDITIONS, fGotoLine);
328: }
329: }
330:
331: /**
332: * The <code>item</code> is {@link IContributionManager#add(IContributionItem) added} to
333: * <code>menu</code> if no item with the same id currently exists. If there already is an
334: * contribution item with the same id, the new item gets
335: * {@link IContributionManager#insertAfter(String, IContributionItem) inserted after} it.
336: *
337: * @param menu the contribution manager
338: * @param item the contribution item
339: * @since 3.2
340: */
341: private void addOrInsert(IContributionManager menu,
342: IContributionItem item) {
343: String id = item.getId();
344: if (menu.find(id) == null)
345: menu.add(item);
346: else
347: menu.insertAfter(id, item);
348: }
349:
350: /*
351: * @see EditorActionBarContributor#contributeToStatusLine(org.eclipse.jface.action.IStatusLineManager)
352: * @since 2.0
353: */
354: public void contributeToStatusLine(
355: IStatusLineManager statusLineManager) {
356: super .contributeToStatusLine(statusLineManager);
357: for (int i = 0; i < STATUS_FIELD_DEFS.length; i++)
358: statusLineManager.add((IContributionItem) fStatusFields
359: .get(STATUS_FIELD_DEFS[i]));
360: }
361:
362: /*
363: * @see org.eclipse.ui.IEditorActionBarContributor#dispose()
364: * @since 2.0
365: */
366: public void dispose() {
367: doSetActiveEditor(null);
368: super.dispose();
369: }
370: }
|