KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > texteditor > AbstractTextEditor


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  * Chris.Dennis@invidi.com - http://bugs.eclipse.org/bugs/show_bug.cgi?id=29027
11  * Michel Ishizuka (cqw10305@nifty.com) - http://bugs.eclipse.org/bugs/show_bug.cgi?id=68963
12  * Genady Beryozkin, me@genady.org - https://bugs.eclipse.org/bugs/show_bug.cgi?id=11668
13  * Benjamin Muskalla <b.muskalla@gmx.net> - https://bugs.eclipse.org/bugs/show_bug.cgi?id=41573
14  *******************************************************************************/

15 package org.eclipse.ui.texteditor;
16
17
18 import java.lang.reflect.InvocationTargetException JavaDoc;
19 import java.util.ArrayList JavaDoc;
20 import java.util.HashMap JavaDoc;
21 import java.util.Iterator JavaDoc;
22 import java.util.List JavaDoc;
23 import java.util.Map JavaDoc;
24 import java.util.ResourceBundle JavaDoc;
25
26 import org.osgi.framework.Bundle;
27
28 import org.eclipse.swt.SWT;
29 import org.eclipse.swt.custom.BusyIndicator;
30 import org.eclipse.swt.custom.ST;
31 import org.eclipse.swt.custom.StyledText;
32 import org.eclipse.swt.custom.VerifyKeyListener;
33 import org.eclipse.swt.dnd.DND;
34 import org.eclipse.swt.dnd.DragSource;
35 import org.eclipse.swt.dnd.DragSourceAdapter;
36 import org.eclipse.swt.dnd.DragSourceEvent;
37 import org.eclipse.swt.dnd.DropTargetAdapter;
38 import org.eclipse.swt.dnd.DropTargetEvent;
39 import org.eclipse.swt.dnd.DropTargetListener;
40 import org.eclipse.swt.dnd.TextTransfer;
41 import org.eclipse.swt.dnd.Transfer;
42 import org.eclipse.swt.events.KeyEvent;
43 import org.eclipse.swt.events.KeyListener;
44 import org.eclipse.swt.events.MouseEvent;
45 import org.eclipse.swt.events.MouseListener;
46 import org.eclipse.swt.events.VerifyEvent;
47 import org.eclipse.swt.events.VerifyListener;
48 import org.eclipse.swt.graphics.Color;
49 import org.eclipse.swt.graphics.Font;
50 import org.eclipse.swt.graphics.FontData;
51 import org.eclipse.swt.graphics.GC;
52 import org.eclipse.swt.graphics.Image;
53 import org.eclipse.swt.graphics.ImageData;
54 import org.eclipse.swt.graphics.PaletteData;
55 import org.eclipse.swt.graphics.Point;
56 import org.eclipse.swt.graphics.RGB;
57 import org.eclipse.swt.widgets.Caret;
58 import org.eclipse.swt.widgets.Composite;
59 import org.eclipse.swt.widgets.Control;
60 import org.eclipse.swt.widgets.Display;
61 import org.eclipse.swt.widgets.Menu;
62 import org.eclipse.swt.widgets.Shell;
63
64 import org.eclipse.core.commands.operations.IOperationApprover;
65 import org.eclipse.core.commands.operations.IOperationHistory;
66 import org.eclipse.core.commands.operations.IUndoContext;
67 import org.eclipse.core.commands.operations.OperationHistoryFactory;
68
69 import org.eclipse.core.runtime.Assert;
70 import org.eclipse.core.runtime.CoreException;
71 import org.eclipse.core.runtime.IConfigurationElement;
72 import org.eclipse.core.runtime.ILog;
73 import org.eclipse.core.runtime.IProgressMonitor;
74 import org.eclipse.core.runtime.IStatus;
75 import org.eclipse.core.runtime.NullProgressMonitor;
76 import org.eclipse.core.runtime.Platform;
77 import org.eclipse.core.runtime.SafeRunner;
78 import org.eclipse.core.runtime.Status;
79
80 import org.eclipse.text.undo.DocumentUndoManagerRegistry;
81 import org.eclipse.text.undo.IDocumentUndoManager;
82
83 import org.eclipse.jface.action.Action;
84 import org.eclipse.jface.action.GroupMarker;
85 import org.eclipse.jface.action.IAction;
86 import org.eclipse.jface.action.IMenuListener;
87 import org.eclipse.jface.action.IMenuManager;
88 import org.eclipse.jface.action.IStatusLineManager;
89 import org.eclipse.jface.action.MenuManager;
90 import org.eclipse.jface.action.Separator;
91 import org.eclipse.jface.dialogs.ErrorDialog;
92 import org.eclipse.jface.dialogs.MessageDialog;
93 import org.eclipse.jface.internal.text.html.HTMLTextPresenter;
94 import org.eclipse.jface.operation.IRunnableWithProgress;
95 import org.eclipse.jface.preference.IPreferenceStore;
96 import org.eclipse.jface.preference.PreferenceConverter;
97 import org.eclipse.jface.resource.ImageDescriptor;
98 import org.eclipse.jface.resource.JFaceResources;
99 import org.eclipse.jface.util.IPropertyChangeListener;
100 import org.eclipse.jface.util.PropertyChangeEvent;
101 import org.eclipse.jface.util.SafeRunnable;
102 import org.eclipse.jface.viewers.IPostSelectionProvider;
103 import org.eclipse.jface.viewers.ISelection;
104 import org.eclipse.jface.viewers.ISelectionChangedListener;
105 import org.eclipse.jface.viewers.ISelectionProvider;
106 import org.eclipse.jface.viewers.SelectionChangedEvent;
107 import org.eclipse.jface.viewers.StructuredSelection;
108 import org.eclipse.jface.window.IShellProvider;
109
110 import org.eclipse.jface.text.AbstractInformationControlManager;
111 import org.eclipse.jface.text.BadLocationException;
112 import org.eclipse.jface.text.DefaultInformationControl;
113 import org.eclipse.jface.text.DefaultLineTracker;
114 import org.eclipse.jface.text.DocumentEvent;
115 import org.eclipse.jface.text.IDocument;
116 import org.eclipse.jface.text.IDocumentListener;
117 import org.eclipse.jface.text.IFindReplaceTarget;
118 import org.eclipse.jface.text.IFindReplaceTargetExtension;
119 import org.eclipse.jface.text.IInformationControl;
120 import org.eclipse.jface.text.IInformationControlCreator;
121 import org.eclipse.jface.text.IMarkRegionTarget;
122 import org.eclipse.jface.text.IRegion;
123 import org.eclipse.jface.text.IRewriteTarget;
124 import org.eclipse.jface.text.ISelectionValidator;
125 import org.eclipse.jface.text.ITextHover;
126 import org.eclipse.jface.text.ITextInputListener;
127 import org.eclipse.jface.text.ITextListener;
128 import org.eclipse.jface.text.ITextOperationTarget;
129 import org.eclipse.jface.text.ITextSelection;
130 import org.eclipse.jface.text.ITextViewer;
131 import org.eclipse.jface.text.ITextViewerExtension;
132 import org.eclipse.jface.text.ITextViewerExtension2;
133 import org.eclipse.jface.text.ITextViewerExtension4;
134 import org.eclipse.jface.text.ITextViewerExtension5;
135 import org.eclipse.jface.text.ITextViewerExtension6;
136 import org.eclipse.jface.text.ITextViewerExtension7;
137 import org.eclipse.jface.text.IUndoManager;
138 import org.eclipse.jface.text.IUndoManagerExtension;
139 import org.eclipse.jface.text.Position;
140 import org.eclipse.jface.text.Region;
141 import org.eclipse.jface.text.TabsToSpacesConverter;
142 import org.eclipse.jface.text.TextEvent;
143 import org.eclipse.jface.text.TextSelection;
144 import org.eclipse.jface.text.TextUtilities;
145 import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
146 import org.eclipse.jface.text.information.IInformationProvider;
147 import org.eclipse.jface.text.information.IInformationProviderExtension;
148 import org.eclipse.jface.text.information.IInformationProviderExtension2;
149 import org.eclipse.jface.text.information.InformationPresenter;
150 import org.eclipse.jface.text.link.LinkedModeModel;
151 import org.eclipse.jface.text.link.LinkedPosition;
152 import org.eclipse.jface.text.revisions.RevisionInformation;
153 import org.eclipse.jface.text.source.Annotation;
154 import org.eclipse.jface.text.source.CompositeRuler;
155 import org.eclipse.jface.text.source.IAnnotationHover;
156 import org.eclipse.jface.text.source.IAnnotationHoverExtension;
157 import org.eclipse.jface.text.source.IAnnotationModel;
158 import org.eclipse.jface.text.source.ILineRange;
159 import org.eclipse.jface.text.source.ISourceViewer;
160 import org.eclipse.jface.text.source.ISourceViewerExtension3;
161 import org.eclipse.jface.text.source.IVerticalRuler;
162 import org.eclipse.jface.text.source.IVerticalRulerColumn;
163 import org.eclipse.jface.text.source.IVerticalRulerExtension;
164 import org.eclipse.jface.text.source.IVerticalRulerInfo;
165 import org.eclipse.jface.text.source.SourceViewer;
166 import org.eclipse.jface.text.source.SourceViewerConfiguration;
167 import org.eclipse.jface.text.source.VerticalRuler;
168
169 import org.eclipse.ui.IActionBars;
170 import org.eclipse.ui.IEditorDescriptor;
171 import org.eclipse.ui.IEditorInput;
172 import org.eclipse.ui.IEditorPart;
173 import org.eclipse.ui.IEditorRegistry;
174 import org.eclipse.ui.IEditorSite;
175 import org.eclipse.ui.IKeyBindingService;
176 import org.eclipse.ui.IMemento;
177 import org.eclipse.ui.INavigationLocation;
178 import org.eclipse.ui.INavigationLocationProvider;
179 import org.eclipse.ui.IPartListener;
180 import org.eclipse.ui.IPartService;
181 import org.eclipse.ui.IPersistableEditor;
182 import org.eclipse.ui.IReusableEditor;
183 import org.eclipse.ui.ISaveablesLifecycleListener;
184 import org.eclipse.ui.ISaveablesSource;
185 import org.eclipse.ui.IWindowListener;
186 import org.eclipse.ui.IWorkbenchActionConstants;
187 import org.eclipse.ui.IWorkbenchPart;
188 import org.eclipse.ui.IWorkbenchWindow;
189 import org.eclipse.ui.PartInitException;
190 import org.eclipse.ui.PlatformUI;
191 import org.eclipse.ui.Saveable;
192 import org.eclipse.ui.SaveablesLifecycleEvent;
193 import org.eclipse.ui.actions.CommandNotMappedException;
194 import org.eclipse.ui.actions.ContributedAction;
195 import org.eclipse.ui.dialogs.PropertyDialogAction;
196 import org.eclipse.ui.dnd.IDragAndDropService;
197 import org.eclipse.ui.internal.texteditor.EditPosition;
198 import org.eclipse.ui.internal.texteditor.NLSUtility;
199 import org.eclipse.ui.internal.texteditor.TextEditorPlugin;
200 import org.eclipse.ui.internal.texteditor.rulers.StringSetSerializer;
201 import org.eclipse.ui.operations.LinearUndoViolationUserApprover;
202 import org.eclipse.ui.operations.NonLocalUndoUserApprover;
203 import org.eclipse.ui.operations.OperationHistoryActionHandler;
204 import org.eclipse.ui.operations.RedoActionHandler;
205 import org.eclipse.ui.operations.UndoActionHandler;
206 import org.eclipse.ui.part.EditorPart;
207 import org.eclipse.ui.texteditor.rulers.IColumnSupport;
208 import org.eclipse.ui.texteditor.rulers.IContributedRulerColumn;
209 import org.eclipse.ui.texteditor.rulers.RulerColumnDescriptor;
210 import org.eclipse.ui.texteditor.rulers.RulerColumnPreferenceAdapter;
211 import org.eclipse.ui.texteditor.rulers.RulerColumnRegistry;
212
213
214 /**
215  * Abstract base implementation of a text editor.
216  * <p>
217  * Subclasses are responsible for configuring the editor appropriately.
218  * The standard text editor, <code>TextEditor</code>, is one such example.</p>
219  * <p>
220  * If a subclass calls {@linkplain #setEditorContextMenuId(String) setEditorContextMenuId} the argument is
221  * used as the id under which the editor's context menu is registered for extensions.
222  * If no id is set, the context menu is registered under <b>[editor_id].EditorContext</b>
223  * whereby [editor_id] is replaced with the editor's part id. If the editor is instructed to
224  * run in version 1.0 context menu registration compatibility mode, the latter form of the
225  * registration even happens if a context menu id has been set via {@linkplain #setEditorContextMenuId(String) setEditorContextMenuId}.
226  * If no id is set while in compatibility mode, the menu is registered under
227  * {@link #DEFAULT_EDITOR_CONTEXT_MENU_ID}.</p>
228  * <p>
229  * If a subclass calls {@linkplain #setRulerContextMenuId(String) setRulerContextMenuId} the argument is
230  * used as the id under which the ruler's context menu is registered for extensions.
231  * If no id is set, the context menu is registered under <b>[editor_id].RulerContext</b>
232  * whereby [editor_id] is replaced with the editor's part id. If the editor is instructed to
233  * run in version 1.0 context menu registration compatibility mode, the latter form of the
234  * registration even happens if a context menu id has been set via {@linkplain #setRulerContextMenuId(String) setRulerContextMenuId}.
235  * If no id is set while in compatibility mode, the menu is registered under
236  * {@link #DEFAULT_RULER_CONTEXT_MENU_ID}.</p>
237  */

238 public abstract class AbstractTextEditor extends EditorPart implements ITextEditor, IReusableEditor, ITextEditorExtension, ITextEditorExtension2, ITextEditorExtension3, ITextEditorExtension4, INavigationLocationProvider, ISaveablesSource, IPersistableEditor {
239
240     /**
241      * Tag used in xml configuration files to specify editor action contributions.
242      * Current value: <code>editorContribution</code>
243      * @since 2.0
244      */

245     private static final String JavaDoc TAG_CONTRIBUTION_TYPE= "editorContribution"; //$NON-NLS-1$
246

247     /**
248      * Tags used in the {@link IMemento} when saving and
249      * restoring editor state.
250      *
251      * @see #saveState(IMemento)
252      * @see #restoreState(IMemento)
253      * @since 3.3
254      */

255     protected static final String JavaDoc TAG_SELECTION_OFFSET= "selectionOffset"; //$NON-NLS-1$
256
protected static final String JavaDoc TAG_SELECTION_LENGTH= "selectionLength"; //$NON-NLS-1$
257
// XXX: workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=168524
258
private static final String JavaDoc TAG_SELECTION_HPIXEL= "selectionHPixel"; //$NON-NLS-1$
259

260
261     /**
262      * The caret width for the wide (double) caret.
263      * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=21715.
264      * Value: {@value}
265      * @since 3.0
266      */

267     private static final int WIDE_CARET_WIDTH= 2;
268
269     /**
270      * The caret width for the narrow (single) caret.
271      * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=21715.
272      * Value: {@value}
273      * @since 3.0
274      */

275     private static final int SINGLE_CARET_WIDTH= 1;
276
277     /**
278      * The text input listener.
279      *
280      * @see ITextInputListener
281      * @since 2.1
282      */

283     private static class TextInputListener implements ITextInputListener {
284         /** Indicates whether the editor input changed during the process of state validation. */
285         public boolean inputChanged;
286
287         /* Detectors for editor input changes during the process of state validation. */
288         public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) {}
289         public void inputDocumentChanged(IDocument oldInput, IDocument newInput) { inputChanged= true; }
290     }
291
292     /**
293      * Internal element state listener.
294      */

295     class ElementStateListener implements IElementStateListener, IElementStateListenerExtension {
296
297             /**
298              * Internal <code>VerifyListener</code> for performing the state validation of the
299              * editor input in case of the first attempted manipulation via typing on the keyboard.
300              * @since 2.0
301              */

302             class Validator implements VerifyListener {
303                 /*
304                  * @see VerifyListener#verifyText(org.eclipse.swt.events.VerifyEvent)
305                  */

306                 public void verifyText(VerifyEvent e) {
307                     IDocument document= getDocumentProvider().getDocument(getEditorInput());
308                     final boolean[] documentChanged= new boolean[1];
309                     IDocumentListener listener= new IDocumentListener() {
310                         public void documentAboutToBeChanged(DocumentEvent event) {
311                         }
312                         public void documentChanged(DocumentEvent event) {
313                             documentChanged[0]= true;
314                         }
315                     };
316                     try {
317                         if (document != null)
318                             document.addDocumentListener(listener);
319                         if (! validateEditorInputState() || documentChanged[0])
320                             e.doit= false;
321                     } finally {
322                         if (document != null)
323                             document.removeDocumentListener(listener);
324                     }
325                 }
326             }
327
328         /**
329          * The listener's validator.
330          * @since 2.0
331          */

332         private Validator fValidator;
333         /**
334          * The display used for posting runnable into the UI thread.
335          * @since 3.0
336          */

337         private Display fDisplay;
338
339         /*
340          * @see IElementStateListenerExtension#elementStateValidationChanged(Object, boolean)
341          * @since 2.0
342          */

343         public void elementStateValidationChanged(final Object JavaDoc element, final boolean isStateValidated) {
344             if (element != null && element.equals(getEditorInput())) {
345                 Runnable JavaDoc r= new Runnable JavaDoc() {
346                     public void run() {
347                         enableSanityChecking(true);
348                         if (isStateValidated && fValidator != null) {
349                             ISourceViewer viewer= fSourceViewer;
350                             if (viewer != null) {
351                                 StyledText textWidget= viewer.getTextWidget();
352                                 if (textWidget != null && !textWidget.isDisposed())
353                                     textWidget.removeVerifyListener(fValidator);
354                                 fValidator= null;
355                                 enableStateValidation(false);
356                             }
357                         } else if (!isStateValidated && fValidator == null) {
358                             ISourceViewer viewer= fSourceViewer;
359                             if (viewer != null) {
360                                 StyledText textWidget= viewer.getTextWidget();
361                                 if (textWidget != null && !textWidget.isDisposed()) {
362                                     fValidator= new Validator();
363                                     enableStateValidation(true);
364                                     textWidget.addVerifyListener(fValidator);
365                                 }
366                             }
367                         }
368                     }
369                 };
370                 execute(r, false);
371             }
372         }
373
374
375         /*
376          * @see IElementStateListener#elementDirtyStateChanged(Object, boolean)
377          */

378         public void elementDirtyStateChanged(Object JavaDoc element, boolean isDirty) {
379             if (element != null && element.equals(getEditorInput())) {
380                 Runnable JavaDoc r= new Runnable JavaDoc() {
381                     public void run() {
382                         enableSanityChecking(true);
383                         firePropertyChange(PROP_DIRTY);
384                     }
385                 };
386                 execute(r, false);
387             }
388         }
389
390         /*
391          * @see IElementStateListener#elementContentAboutToBeReplaced(Object)
392          */

393         public void elementContentAboutToBeReplaced(Object JavaDoc element) {
394             if (element != null && element.equals(getEditorInput())) {
395                 Runnable JavaDoc r= new Runnable JavaDoc() {
396                     public void run() {
397                         enableSanityChecking(true);
398                         rememberSelection();
399                         resetHighlightRange();
400                     }
401                 };
402                 execute(r, false);
403             }
404         }
405
406         /*
407          * @see IElementStateListener#elementContentReplaced(Object)
408          */

409         public void elementContentReplaced(Object JavaDoc element) {
410             if (element != null && element.equals(getEditorInput())) {
411                 Runnable JavaDoc r= new Runnable JavaDoc() {
412                     public void run() {
413                         enableSanityChecking(true);
414                         firePropertyChange(PROP_DIRTY);
415                         restoreSelection();
416                         handleElementContentReplaced();
417                     }
418                 };
419                 execute(r, false);
420             }
421         }
422
423         /*
424          * @see IElementStateListener#elementDeleted(Object)
425          */

426         public void elementDeleted(Object JavaDoc deletedElement) {
427             if (deletedElement != null && deletedElement.equals(getEditorInput())) {
428                 Runnable JavaDoc r= new Runnable JavaDoc() {
429                     public void run() {
430                         enableSanityChecking(true);
431                         close(false);
432                     }
433                 };
434                 execute(r, false);
435             }
436         }
437
438         /*
439          * @see IElementStateListener#elementMoved(Object, Object)
440          */

441         public void elementMoved(final Object JavaDoc originalElement, final Object JavaDoc movedElement) {
442             if (originalElement != null && originalElement.equals(getEditorInput())) {
443                 final boolean doValidationAsync= Display.getCurrent() != null;
444                 Runnable JavaDoc r= new Runnable JavaDoc() {
445                     public void run() {
446                         enableSanityChecking(true);
447
448                         if (fSourceViewer == null)
449                             return;
450
451                         if (!canHandleMove((IEditorInput) originalElement, (IEditorInput) movedElement)) {
452                             close(true);
453                             return;
454                         }
455
456                         if (movedElement == null || movedElement instanceof IEditorInput) {
457                             rememberSelection();
458
459                             final IDocumentProvider d= getDocumentProvider();
460                             final String JavaDoc previousContent;
461                             IDocumentUndoManager previousUndoManager=null;
462                             IDocument changed= null;
463                             boolean wasDirty= isDirty();
464                             changed= d.getDocument(getEditorInput());
465                             if (changed != null) {
466                                 if (wasDirty)
467                                     previousContent= changed.get();
468                                 else
469                                     previousContent= null;
470                                 
471                                 previousUndoManager= DocumentUndoManagerRegistry.getDocumentUndoManager(changed);
472                                 if (previousUndoManager != null)
473                                     previousUndoManager.connect(this);
474                             }
475                             else
476                                 previousContent= null;
477                             
478                             setInput((IEditorInput) movedElement);
479                             
480                             // The undo manager needs to be replaced with one for the new document.
481
// Transfer the undo history and then disconnect from the old undo manager.
482
if (previousUndoManager != null) {
483                                 IDocument newDocument= getDocumentProvider().getDocument(movedElement);
484                                 if (newDocument != null) {
485                                     IDocumentUndoManager newUndoManager= DocumentUndoManagerRegistry.getDocumentUndoManager(newDocument);
486                                     if (newUndoManager != null)
487                                         newUndoManager.transferUndoHistory(previousUndoManager);
488                                 }
489                                 previousUndoManager.disconnect(this);
490                             }
491
492                             if (wasDirty && changed != null) {
493                                 Runnable JavaDoc r2= new Runnable JavaDoc() {
494                                     public void run() {
495                                         validateState(getEditorInput());
496                                         d.getDocument(getEditorInput()).set(previousContent);
497                                         updateStatusField(ITextEditorActionConstants.STATUS_CATEGORY_ELEMENT_STATE);
498                                         restoreSelection();
499                                     }
500                                 };
501                                 execute(r2, doValidationAsync);
502                             } else
503                                 restoreSelection();
504
505                         }
506                     }
507                 };
508                 execute(r, false);
509             }
510         }
511
512         /*
513          * @see IElementStateListenerExtension#elementStateChanging(Object)
514          * @since 2.0
515          */

516         public void elementStateChanging(Object JavaDoc element) {
517             if (element != null && element.equals(getEditorInput()))
518                 enableSanityChecking(false);
519         }
520
521         /*
522          * @see IElementStateListenerExtension#elementStateChangeFailed(Object)
523          * @since 2.0
524          */

525         public void elementStateChangeFailed(Object JavaDoc element) {
526             if (element != null && element.equals(getEditorInput()))
527                 enableSanityChecking(true);
528         }
529
530         /**
531          * Executes the given runnable in the UI thread.
532          * <p>
533          * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=76765 for details
534          * about why the parameter <code>postAsync</code> has been
535          * introduced in the course of 3.1.
536          *
537          * @param runnable runnable to be executed
538          * @param postAsync <code>true</code> if the runnable must be posted asynchronous, <code>false</code> otherwise
539          * @since 3.0
540          */

541         private void execute(Runnable JavaDoc runnable, boolean postAsync) {
542             if (postAsync || Display.getCurrent() == null) {
543                 if (fDisplay == null)
544                     fDisplay= getSite().getShell().getDisplay();
545                 fDisplay.asyncExec(runnable);
546             } else
547                 runnable.run();
548         }
549     }
550
551     /**
552      * Internal text listener for updating all content dependent
553      * actions. The updating is done asynchronously.
554      */

555     class TextListener implements ITextListener, ITextInputListener {
556
557         /** The posted updater code. */
558         private Runnable JavaDoc fRunnable= new Runnable JavaDoc() {
559             public void run() {
560                 fIsRunnablePosted= false;
561
562                 if (fSourceViewer != null) {
563                     updateContentDependentActions();
564
565                     // remember the last edit position
566
if (isDirty() && fUpdateLastEditPosition) {
567                         fUpdateLastEditPosition= false;
568                         ISelection sel= getSelectionProvider().getSelection();
569                         IEditorInput input= getEditorInput();
570                         IDocument document= getDocumentProvider().getDocument(input);
571
572                         if (fLocalLastEditPosition != null) {
573                             document.removePosition(fLocalLastEditPosition);
574                             fLocalLastEditPosition= null;
575                         }
576
577                         if (sel instanceof ITextSelection && !sel.isEmpty()) {
578                             ITextSelection s= (ITextSelection) sel;
579                             fLocalLastEditPosition= new Position(s.getOffset(), s.getLength());
580                             try {
581                                 document.addPosition(fLocalLastEditPosition);
582                             } catch (BadLocationException ex) {
583                                 fLocalLastEditPosition= null;
584                             }
585                         }
586                         TextEditorPlugin.getDefault().setLastEditPosition(new EditPosition(input, getEditorSite().getId(), fLocalLastEditPosition));
587                     }
588                 }
589             }
590         };
591
592         /** Display used for posting the updater code. */
593         private Display fDisplay;
594         /**
595          * The editor's last edit position
596          * @since 3.0
597          */

598         private Position fLocalLastEditPosition;
599         /**
600          * Has the runnable been posted?
601          * @since 3.0
602          */

603         private boolean fIsRunnablePosted= false;
604         /**
605          * Should the last edit position be updated?
606          * @since 3.0
607          */

608         private boolean fUpdateLastEditPosition= false;
609
610         /*
611          * @see ITextListener#textChanged(TextEvent)
612          */

613         public void textChanged(TextEvent event) {
614
615             /*
616              * Also works for text events which do not base on a DocumentEvent.
617              * This way, if the visible document of the viewer changes, all content
618              * dependent actions are updated as well.
619              */

620
621             if (fDisplay == null)
622                 fDisplay= getSite().getShell().getDisplay();
623
624             if (event.getDocumentEvent() != null)
625                 fUpdateLastEditPosition= true;
626
627             if (!fIsRunnablePosted) {
628                 fIsRunnablePosted= true;
629                 fDisplay.asyncExec(fRunnable);
630             }
631         }
632
633         /*
634          * @see org.eclipse.jface.text.ITextInputListener#inputDocumentAboutToBeChanged(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument)
635          */

636         public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) {
637             if (oldInput != null && fLocalLastEditPosition != null) {
638                 oldInput.removePosition(fLocalLastEditPosition);
639                 fLocalLastEditPosition= null;
640             }
641         }
642
643         /*
644          * @see org.eclipse.jface.text.ITextInputListener#inputDocumentChanged(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument)
645          */

646         public void inputDocumentChanged(IDocument oldInput, IDocument newInput) {
647         }
648     }
649
650     /**
651      * Internal property change listener for handling changes in the editor's preferences.
652      */

653     class PropertyChangeListener implements IPropertyChangeListener {
654         /*
655          * @see IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
656          */

657         public void propertyChange(PropertyChangeEvent event) {
658             handlePreferenceStoreChanged(event);
659         }
660     }
661
662     /**
663      * Internal property change listener for handling workbench font changes.
664      * @since 2.1
665      */

666     class FontPropertyChangeListener implements IPropertyChangeListener {
667         /*
668          * @see IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
669          */

670         public void propertyChange(PropertyChangeEvent event) {
671             if (fSourceViewer == null)
672                 return;
673
674             String JavaDoc property= event.getProperty();
675
676             if (getFontPropertyPreferenceKey().equals(property)) {
677                 initializeViewerFont(fSourceViewer);
678                 updateCaret();
679             }
680         }
681     }
682
683     /**
684      * Internal key verify listener for triggering action activation codes.
685      */

686     class ActivationCodeTrigger implements VerifyKeyListener {
687
688         /** Indicates whether this trigger has been installed. */
689         private boolean fIsInstalled= false;
690         /**
691          * The key binding service to use.
692          * @since 2.0
693          */

694         private IKeyBindingService fKeyBindingService;
695
696         /*
697          * @see VerifyKeyListener#verifyKey(org.eclipse.swt.events.VerifyEvent)
698          */

699         public void verifyKey(VerifyEvent event) {
700
701             ActionActivationCode code= null;
702             int size= fActivationCodes.size();
703             for (int i= 0; i < size; i++) {
704                 code= (ActionActivationCode) fActivationCodes.get(i);
705                 if (code.matches(event)) {
706                     IAction action= getAction(code.fActionId);
707                     if (action != null) {
708
709                         if (action instanceof IUpdate)
710                             ((IUpdate) action).update();
711
712                         if (!action.isEnabled() && action instanceof IReadOnlyDependent) {
713                             IReadOnlyDependent dependent= (IReadOnlyDependent) action;
714                             boolean writable= dependent.isEnabled(true);
715                             if (writable) {
716                                 event.doit= false;
717                                 return;
718                             }
719                         } else if (action.isEnabled()) {
720                             event.doit= false;
721                             action.run();
722                             return;
723                         }
724                     }
725                 }
726             }
727         }
728
729         /**
730          * Installs this trigger on the editor's text widget.
731          * @since 2.0
732          */

733         public void install() {
734             if (!fIsInstalled) {
735
736                 if (fSourceViewer instanceof ITextViewerExtension) {
737                     ITextViewerExtension e= (ITextViewerExtension) fSourceViewer;
738                     e.prependVerifyKeyListener(this);
739                 } else {
740                     StyledText text= fSourceViewer.getTextWidget();
741                     text.addVerifyKeyListener(this);
742                 }
743
744                 fKeyBindingService= getEditorSite().getKeyBindingService();
745                 fIsInstalled= true;
746             }
747         }
748
749         /**
750          * Uninstalls this trigger from the editor's text widget.
751          * @since 2.0
752          */

753         public void uninstall() {
754             if (fIsInstalled) {
755
756                 if (fSourceViewer instanceof ITextViewerExtension) {
757                     ITextViewerExtension e= (ITextViewerExtension) fSourceViewer;
758                     e.removeVerifyKeyListener(this);
759                 } else if (fSourceViewer != null) {
760                     StyledText text= fSourceViewer.getTextWidget();
761                     if (text != null && !text.isDisposed())
762                         text.removeVerifyKeyListener(fActivationCodeTrigger);
763                 }
764
765                 fIsInstalled= false;
766                 fKeyBindingService= null;
767             }
768         }
769
770         /**
771          * Registers the given action for key activation.
772          * @param action the action to be registered
773          * @since 2.0
774          */

775         public void registerActionForKeyActivation(IAction action) {
776             if (action.getActionDefinitionId() != null)
777                 fKeyBindingService.registerAction(action);
778         }
779
780         /**
781          * The given action is no longer available for key activation
782          * @param action the action to be unregistered
783          * @since 2.0
784          */

785         public void unregisterActionFromKeyActivation(IAction action) {
786             if (action.getActionDefinitionId() != null)
787                 fKeyBindingService.unregisterAction(action);
788         }
789
790         /**
791          * Sets the key binding scopes for this editor.
792          * @param keyBindingScopes the key binding scopes
793          * @since 2.1
794          */

795         public void setScopes(String JavaDoc[] keyBindingScopes) {
796             if (keyBindingScopes != null && keyBindingScopes.length > 0)
797                 fKeyBindingService.setScopes(keyBindingScopes);
798         }
799     }
800
801     /**
802      * Representation of action activation codes.
803      */

804     static class ActionActivationCode {
805
806         /** The action id. */
807         public String JavaDoc fActionId;
808         /** The character. */
809         public char fCharacter;
810         /** The key code. */
811         public int fKeyCode= -1;
812         /** The state mask. */
813         public int fStateMask= SWT.DEFAULT;
814
815         /**
816          * Creates a new action activation code for the given action id.
817          * @param actionId the action id
818          */

819         public ActionActivationCode(String JavaDoc actionId) {
820             fActionId= actionId;
821         }
822
823         /**
824          * Returns <code>true</code> if this activation code matches the given verify event.
825          * @param event the event to test for matching
826          * @return whether this activation code matches <code>event</code>
827          */

828         public boolean matches(VerifyEvent event) {
829             return (event.character == fCharacter &&
830                         (fKeyCode == -1 || event.keyCode == fKeyCode) &&
831                         (fStateMask == SWT.DEFAULT || event.stateMask == fStateMask));
832         }
833     }
834
835     /**
836      * Internal part and shell activation listener for triggering state validation.
837      * @since 2.0
838      */

839     class ActivationListener implements IPartListener, IWindowListener {
840
841         /** Cache of the active workbench part. */
842         private IWorkbenchPart fActivePart;
843         /** Indicates whether activation handling is currently be done. */
844         private boolean fIsHandlingActivation= false;
845         /**
846          * The part service.
847          * @since 3.1
848          */

849         private IPartService fPartService;
850
851         /**
852          * Creates this activation listener.
853          *
854          * @param partService the part service on which to add the part listener
855          * @since 3.1
856          */

857         public ActivationListener(IPartService partService) {
858             fPartService= partService;
859             fPartService.addPartListener(this);
860             PlatformUI.getWorkbench().addWindowListener(this);
861         }
862
863         /**
864          * Disposes this activation listener.
865          *
866          * @since 3.1
867          */

868         public void dispose() {
869             fPartService.removePartListener(this);
870             PlatformUI.getWorkbench().removeWindowListener(this);
871             fPartService= null;
872         }
873
874         /*
875          * @see IPartListener#partActivated(org.eclipse.ui.IWorkbenchPart)
876          */

877         public void partActivated(IWorkbenchPart part) {
878             fActivePart= part;
879             handleActivation();
880         }
881
882         /*
883          * @see IPartListener#partBroughtToTop(org.eclipse.ui.IWorkbenchPart)
884          */

885         public void partBroughtToTop(IWorkbenchPart part) {
886         }
887
888         /*
889          * @see IPartListener#partClosed(org.eclipse.ui.IWorkbenchPart)
890          */

891         public void partClosed(IWorkbenchPart part) {
892         }
893
894         /*
895          * @see IPartListener#partDeactivated(org.eclipse.ui.IWorkbenchPart)
896          */

897         public void partDeactivated(IWorkbenchPart part) {
898             fActivePart= null;
899         }
900
901         /*
902          * @see IPartListener#partOpened(org.eclipse.ui.IWorkbenchPart)
903          */

904         public void partOpened(IWorkbenchPart part) {
905             // Restore the saved state if any
906
if (part == AbstractTextEditor.this && fMementoToRestore != null && containsSavedState(fMementoToRestore))
907                 doRestoreState(fMementoToRestore);
908             fMementoToRestore= null;
909         }
910
911         /**
912          * Handles the activation triggering a element state check in the editor.
913          */

914         private void handleActivation() {
915             if (fIsHandlingActivation)
916                 return;
917
918             if (fActivePart == AbstractTextEditor.this) {
919                 fIsHandlingActivation= true;
920                 try {
921                     safelySanityCheckState(getEditorInput());
922                 } finally {
923                     fIsHandlingActivation= false;
924                 }
925             }
926         }
927
928         /*
929          * @see org.eclipse.ui.IWindowListener#windowActivated(org.eclipse.ui.IWorkbenchWindow)
930          * @since 3.1
931          */

932         public void windowActivated(IWorkbenchWindow window) {
933             if (window == getEditorSite().getWorkbenchWindow()) {
934                 /*
935                  * Workaround for problem described in
936                  * http://dev.eclipse.org/bugs/show_bug.cgi?id=11731
937                  * Will be removed when SWT has solved the problem.
938                  */

939                 window.getShell().getDisplay().asyncExec(new Runnable JavaDoc() {
940                     public void run() {
941                         handleActivation();
942                     }
943                 });
944             }
945         }
946
947         /*
948          * @see org.eclipse.ui.IWindowListener#windowDeactivated(org.eclipse.ui.IWorkbenchWindow)
949          * @since 3.1
950          */

951         public void windowDeactivated(IWorkbenchWindow window) {
952         }
953
954         /*
955          * @see org.eclipse.ui.IWindowListener#windowClosed(org.eclipse.ui.IWorkbenchWindow)
956          * @since 3.1
957          */

958         public void windowClosed(IWorkbenchWindow window) {
959         }
960
961         /*
962          * @see org.eclipse.ui.IWindowListener#windowOpened(org.eclipse.ui.IWorkbenchWindow)
963          * @since 3.1
964          */

965         public void windowOpened(IWorkbenchWindow window) {
966         }
967     }
968
969     /**
970      * Internal interface for a cursor listener. I.e. aggregation
971      * of mouse and key listener.
972      * @since 2.0
973      */

974     interface ICursorListener extends MouseListener, KeyListener {
975     }
976
977     /**
978      * Maps an action definition id to an StyledText action.
979      * @since 2.0
980      */

981     protected static final class IdMapEntry {
982
983         /** The action id. */
984         private String JavaDoc fActionId;
985         /** The StyledText action. */
986         private int fAction;
987
988         /**
989          * Creates a new mapping.
990          * @param actionId the action id
991          * @param action the StyledText action
992          */

993         public IdMapEntry(String JavaDoc actionId, int action) {
994             fActionId= actionId;
995             fAction= action;
996         }
997
998         /**
999          * Returns the action id.
1000         * @return the action id
1001         */

1002        public String JavaDoc getActionId() {
1003            return fActionId;
1004        }
1005
1006        /**
1007         * Returns the action.
1008         * @return the action
1009         */

1010        public int getAction() {
1011            return fAction;
1012        }
1013    }
1014
1015    /**
1016     * Internal action to scroll the editor's viewer by a specified number of lines.
1017     * @since 2.0
1018     */

1019    class ScrollLinesAction extends Action {
1020
1021        /** Number of lines to scroll. */
1022        private int fScrollIncrement;
1023
1024        /**
1025         * Creates a new scroll action that scroll the given number of lines. If the
1026         * increment is &lt; 0, it's scrolling up, if &gt; 0 it's scrolling down.
1027         * @param scrollIncrement the number of lines to scroll
1028         */

1029        public ScrollLinesAction(int scrollIncrement) {
1030            fScrollIncrement= scrollIncrement;
1031        }
1032
1033        /*
1034         * @see IAction#run()
1035         */

1036        public void run() {
1037            if (fSourceViewer instanceof ITextViewerExtension5) {
1038                ITextViewerExtension5 extension= (ITextViewerExtension5) fSourceViewer;
1039                StyledText textWidget= fSourceViewer.getTextWidget();
1040                int topIndex= textWidget.getTopIndex();
1041                int newTopIndex= Math.max(0, topIndex + fScrollIncrement);
1042                fSourceViewer.setTopIndex(extension.widgetLine2ModelLine(newTopIndex));
1043            } else {
1044                int topIndex= fSourceViewer.getTopIndex();
1045                int newTopIndex= Math.max(0, topIndex + fScrollIncrement);
1046                fSourceViewer.setTopIndex(newTopIndex);
1047            }
1048        }
1049    }
1050
1051    /**
1052     * Action to toggle the insert mode. The action is checked if smart mode is
1053     * turned on.
1054     *
1055     * @since 2.1
1056     */

1057    class ToggleInsertModeAction extends ResourceAction {
1058
1059        public ToggleInsertModeAction(ResourceBundle JavaDoc bundle, String JavaDoc prefix) {
1060            super(bundle, prefix, IAction.AS_CHECK_BOX);
1061        }
1062
1063        /*
1064         * @see org.eclipse.jface.action.IAction#run()
1065         */

1066        public void run() {
1067            switchToNextInsertMode();
1068        }
1069
1070        /*
1071         * @see org.eclipse.jface.action.IAction#isChecked()
1072         * @since 3.0
1073         */

1074        public boolean isChecked() {
1075            return fInsertMode == SMART_INSERT;
1076        }
1077    }
1078
1079    /**
1080     * Action to toggle the overwrite mode.
1081     *
1082     * @since 3.0
1083     */

1084    class ToggleOverwriteModeAction extends ResourceAction {
1085
1086        public ToggleOverwriteModeAction(ResourceBundle JavaDoc bundle, String JavaDoc prefix) {
1087            super(bundle, prefix);
1088        }
1089
1090        /*
1091         * @see org.eclipse.jface.action.IAction#run()
1092         */

1093        public void run() {
1094            toggleOverwriteMode();
1095        }
1096    }
1097
1098    /**
1099     * This action implements smart end.
1100     * Instead of going to the end of a line it does the following:
1101     * - if smart home/end is enabled and the caret is before the line's last non-whitespace and then the caret is moved directly after it
1102     * - if the caret is after last non-whitespace the caret is moved at the end of the line
1103     * - if the caret is at the end of the line the caret is moved directly after the line's last non-whitespace character
1104     * @since 2.1 (in 3.3 the access modifier changed from package visibility to protected)
1105     */

1106    protected class LineEndAction extends TextNavigationAction {
1107
1108        /** boolean flag which tells if the text up to the line end should be selected. */
1109        private boolean fDoSelect;
1110
1111        /**
1112         * Create a new line end action.
1113         *
1114         * @param textWidget the styled text widget
1115         * @param doSelect a boolean flag which tells if the text up to the line end should be selected
1116         */

1117        public LineEndAction(StyledText textWidget, boolean doSelect) {
1118            super(textWidget, ST.LINE_END);
1119            fDoSelect= doSelect;
1120        }
1121
1122        /**
1123         * Computes the offset of the line end position.
1124         * <p>
1125         * XXX: will become protected in 3.4.
1126         * </p>
1127         *
1128         * @param document the document where to compute the line end position
1129         * @param line the line to determine the end position of
1130         * @param length the length of the line
1131         * @param offset the caret position in the document
1132         * @return the offset of the line end
1133         * @since 3.3
1134         */

1135        int getLineEndPosition(final IDocument document, final String JavaDoc line, final int length, final int offset) {
1136            int index= length - 1;
1137            while (index > -1 && Character.isWhitespace(line.charAt(index)))
1138                index--;
1139            index++;
1140            
1141            LinkedModeModel model= LinkedModeModel.getModel(document, offset);
1142            if (model != null) {
1143                LinkedPosition linkedPosition= model.findPosition(new LinkedPosition(document, offset, 0));
1144                if (linkedPosition != null) {
1145                    int linkedPositionEnd= linkedPosition.getOffset() + linkedPosition.getLength();
1146                    int lineOffset;
1147                    try {
1148                        lineOffset= document.getLineInformationOfOffset(offset).getOffset();
1149                        if (offset != linkedPositionEnd && linkedPositionEnd - lineOffset < index)
1150                            index= linkedPositionEnd - lineOffset;
1151                    } catch (BadLocationException e) {
1152                        //should not happen
1153
}
1154                }
1155            }
1156            return index;
1157        }
1158        
1159        /*
1160         * @see org.eclipse.jface.action.IAction#run()
1161         */

1162        public void run() {
1163            boolean isSmartHomeEndEnabled= false;
1164            IPreferenceStore store= getPreferenceStore();
1165            if (store != null)
1166                isSmartHomeEndEnabled= store.getBoolean(AbstractTextEditor.PREFERENCE_NAVIGATION_SMART_HOME_END);
1167
1168            StyledText st= fSourceViewer.getTextWidget();
1169            if (st == null || st.isDisposed())
1170                return;
1171            int caretOffset= st.getCaretOffset();
1172            int lineNumber= st.getLineAtOffset(caretOffset);
1173            int lineOffset= st.getOffsetAtLine(lineNumber);
1174
1175            int lineLength;
1176            int caretOffsetInDocument;
1177            final IDocument document= fSourceViewer.getDocument();
1178
1179            try {
1180                caretOffsetInDocument= widgetOffset2ModelOffset(fSourceViewer, caretOffset);
1181                lineLength= document.getLineInformationOfOffset(caretOffsetInDocument).getLength();
1182            } catch (BadLocationException ex) {
1183                return;
1184            }
1185            int lineEndOffset= lineOffset + lineLength;
1186
1187            int delta= lineEndOffset - st.getCharCount();
1188            if (delta > 0) {
1189                lineEndOffset -= delta;
1190                lineLength -= delta;
1191            }
1192
1193            String JavaDoc line= ""; //$NON-NLS-1$
1194
if (lineLength > 0)
1195                line= st.getText(lineOffset, lineEndOffset - 1);
1196
1197            // Remember current selection
1198
Point oldSelection= st.getSelection();
1199
1200            // The new caret position
1201
int newCaretOffset= -1;
1202
1203            if (isSmartHomeEndEnabled) {
1204                // Compute the line end offset
1205
int i= getLineEndPosition(document, line, lineLength, caretOffsetInDocument);
1206
1207                if (caretOffset - lineOffset == i)
1208                    // to end of line
1209
newCaretOffset= lineEndOffset;
1210                else
1211                    // to end of text
1212
newCaretOffset= lineOffset + i;
1213
1214            } else {
1215
1216                if (caretOffset < lineEndOffset)
1217                    // to end of line
1218
newCaretOffset= lineEndOffset;
1219
1220            }
1221
1222            if (newCaretOffset == -1)
1223                newCaretOffset= caretOffset;
1224            else
1225                st.setCaretOffset(newCaretOffset);
1226
1227            st.setCaretOffset(newCaretOffset);
1228            if (fDoSelect) {
1229                if (caretOffset < oldSelection.y)
1230                    st.setSelection(oldSelection.y, newCaretOffset);
1231                else
1232                    st.setSelection(oldSelection.x, newCaretOffset);
1233            } else
1234                st.setSelection(newCaretOffset);
1235
1236            fireSelectionChanged(oldSelection);
1237        }
1238    }
1239
1240    /**
1241     * This action implements smart home.
1242     * Instead of going to the start of a line it does the following:
1243     * - if smart home/end is enabled and the caret is after the line's first non-whitespace then the caret is moved directly before it
1244     * - if the caret is before the line's first non-whitespace the caret is moved to the beginning of the line
1245     * - if the caret is at the beginning of the line the caret is moved directly before the line's first non-whitespace character
1246     * @since 2.1
1247     */

1248    protected class LineStartAction extends TextNavigationAction {
1249
1250        /** boolean flag which tells if the text up to the beginning of the line should be selected. */
1251        private final boolean fDoSelect;
1252
1253        /**
1254         * Creates a new line start action.
1255         *
1256         * @param textWidget the styled text widget
1257         * @param doSelect a boolean flag which tells if the text up to the beginning of the line should be selected
1258         */

1259        public LineStartAction(final StyledText textWidget, final boolean doSelect) {
1260            super(textWidget, ST.LINE_START);
1261            fDoSelect= doSelect;
1262        }
1263
1264        /**
1265         * Computes the offset of the line start position.
1266         *
1267         * @param document the document where to compute the line start position
1268         * @param line the line to determine the start position of
1269         * @param length the length of the line
1270         * @param offset the caret position in the document
1271         * @return the offset of the line start
1272         * @since 3.0
1273         */

1274        protected int getLineStartPosition(final IDocument document, final String JavaDoc line, final int length, final int offset) {
1275            int index= 0;
1276            while (index < length && Character.isWhitespace(line.charAt(index)))
1277                index++;
1278            
1279            LinkedModeModel model= LinkedModeModel.getModel(document, offset);
1280            if (model != null) {
1281                LinkedPosition linkedPosition= model.findPosition(new LinkedPosition(document, offset, 0));
1282                if (linkedPosition != null) {
1283                    int linkedPositionOffset= linkedPosition.getOffset();
1284                    int lineOffset;
1285                    try {
1286                        lineOffset= document.getLineInformationOfOffset(offset).getOffset();
1287                        if (offset != linkedPositionOffset && index < linkedPositionOffset - lineOffset)
1288                            index= linkedPositionOffset - lineOffset;
1289                    } catch (BadLocationException e) {
1290                        //should not happen
1291
}
1292                }
1293            }
1294            return index;
1295        }
1296
1297        /*
1298         * @see org.eclipse.jface.action.IAction#run()
1299         */

1300        public void run() {
1301            boolean isSmartHomeEndEnabled= false;
1302            IPreferenceStore store= getPreferenceStore();
1303            if (store != null)
1304                isSmartHomeEndEnabled= store.getBoolean(AbstractTextEditor.PREFERENCE_NAVIGATION_SMART_HOME_END);
1305
1306            StyledText st= fSourceViewer.getTextWidget();
1307            if (st == null || st.isDisposed())
1308                return;
1309
1310            int caretOffset= st.getCaretOffset();
1311            int lineNumber= st.getLineAtOffset(caretOffset);
1312            int lineOffset= st.getOffsetAtLine(lineNumber);
1313
1314            int lineLength;
1315            int caretOffsetInDocument;
1316            final IDocument document= fSourceViewer.getDocument();
1317
1318            try {
1319                caretOffsetInDocument= widgetOffset2ModelOffset(fSourceViewer, caretOffset);
1320                lineLength= document.getLineInformationOfOffset(caretOffsetInDocument).getLength();
1321            } catch (BadLocationException ex) {
1322                return;
1323            }
1324
1325            String JavaDoc line= ""; //$NON-NLS-1$
1326
if (lineLength > 0) {
1327                int end= lineOffset + lineLength - 1;
1328                end= Math.min(end, st.getCharCount() -1);
1329                line= st.getText(lineOffset, end);
1330            }
1331
1332            // Remember current selection
1333
Point oldSelection= st.getSelection();
1334
1335            // The new caret position
1336
int newCaretOffset= -1;
1337            
1338            if (isSmartHomeEndEnabled) {
1339                
1340                // Compute the line start offset
1341
int index= getLineStartPosition(document, line, lineLength, caretOffsetInDocument);
1342
1343                if (caretOffset - lineOffset == index)
1344                    // to beginning of line
1345
newCaretOffset= lineOffset;
1346                else
1347                    // to beginning of text
1348
newCaretOffset= lineOffset + index;
1349
1350            } else {
1351
1352                if (caretOffset > lineOffset)
1353                    // to beginning of line
1354
newCaretOffset= lineOffset;
1355            }
1356
1357            if (newCaretOffset == -1)
1358                newCaretOffset= caretOffset;
1359            else
1360                st.setCaretOffset(newCaretOffset);
1361
1362            if (fDoSelect) {
1363                if (caretOffset < oldSelection.y)
1364                    st.setSelection(oldSelection.y, newCaretOffset);
1365                else
1366                    st.setSelection(oldSelection.x, newCaretOffset);
1367            } else
1368                st.setSelection(newCaretOffset);
1369
1370            fireSelectionChanged(oldSelection);
1371        }
1372
1373    }
1374
1375    /**
1376     * Internal action to show the editor's ruler context menu (accessibility).
1377     * @since 2.0
1378     */

1379    class ShowRulerContextMenuAction extends Action {
1380        /*
1381         * @see IAction#run()
1382         */

1383        public void run() {
1384            if (fSourceViewer == null)
1385                return;
1386
1387            StyledText text= fSourceViewer.getTextWidget();
1388            if (text == null || text.isDisposed())
1389                return;
1390
1391            Point location= text.getLocationAtOffset(text.getCaretOffset());
1392            location.x= 0;
1393
1394            if (fVerticalRuler instanceof IVerticalRulerExtension)
1395                ((IVerticalRulerExtension) fVerticalRuler).setLocationOfLastMouseButtonActivity(location.x, location.y);
1396
1397            location= text.toDisplay(location);
1398            fRulerContextMenu.setLocation(location.x, location.y);
1399            fRulerContextMenu.setVisible(true);
1400        }
1401    }
1402
1403
1404    /**
1405     * Editor specific selection provider which wraps the source viewer's selection provider.
1406     * @since 2.1
1407     */

1408    class SelectionProvider implements IPostSelectionProvider, ISelectionValidator {
1409
1410        /*
1411         * @see org.eclipse.jface.viewers.ISelectionProvider#addSelectionChangedListener(ISelectionChangedListener)
1412         */

1413        public void addSelectionChangedListener(ISelectionChangedListener listener) {
1414            if (fSourceViewer != null)
1415                fSourceViewer.getSelectionProvider().addSelectionChangedListener(listener);
1416        }
1417
1418        /*
1419         * @see org.eclipse.jface.viewers.ISelectionProvider#getSelection()
1420         */

1421        public ISelection getSelection() {
1422            return doGetSelection();
1423        }
1424
1425        /*
1426         * @see org.eclipse.jface.viewers.ISelectionProvider#removeSelectionChangedListener(ISelectionChangedListener)
1427         */

1428        public void removeSelectionChangedListener(ISelectionChangedListener listener) {
1429            if (fSourceViewer != null)
1430                fSourceViewer.getSelectionProvider().removeSelectionChangedListener(listener);
1431        }
1432
1433        /*
1434         * @see org.eclipse.jface.viewers.ISelectionProvider#setSelection(ISelection)
1435         */

1436        public void setSelection(ISelection selection) {
1437            doSetSelection(selection);
1438        }
1439
1440        /*
1441         * @see org.eclipse.jface.text.IPostSelectionProvider#addPostSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener)
1442         * @since 3.0
1443         */

1444        public void addPostSelectionChangedListener(ISelectionChangedListener listener) {
1445            if (fSourceViewer != null) {
1446                if (fSourceViewer.getSelectionProvider() instanceof IPostSelectionProvider) {
1447                    IPostSelectionProvider provider= (IPostSelectionProvider) fSourceViewer.getSelectionProvider();
1448                    provider.addPostSelectionChangedListener(listener);
1449                }
1450            }
1451        }
1452
1453        /*
1454         * @see org.eclipse.jface.text.IPostSelectionProvider#removePostSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener)
1455         * @since 3.0
1456         */

1457        public void removePostSelectionChangedListener(ISelectionChangedListener listener) {
1458            if (fSourceViewer != null) {
1459                if (fSourceViewer.getSelectionProvider() instanceof IPostSelectionProvider) {
1460                    IPostSelectionProvider provider= (IPostSelectionProvider) fSourceViewer.getSelectionProvider();
1461                    provider.removePostSelectionChangedListener(listener);
1462                }
1463            }
1464        }
1465
1466        /*
1467         * @see org.eclipse.jface.text.IPostSelectionValidator#isValid()
1468         * @since 3.0
1469         */

1470        public boolean isValid(ISelection postSelection) {
1471            return fSelectionListener != null && fSelectionListener.isValid(postSelection);
1472    }
1473    }
1474
1475    /**
1476     * Internal implementation class for a change listener.
1477     * @since 3.0
1478     */

1479    protected abstract class AbstractSelectionChangedListener implements ISelectionChangedListener {
1480
1481        /**
1482         * Installs this selection changed listener with the given selection provider. If
1483         * the selection provider is a post selection provider, post selection changed
1484         * events are the preferred choice, otherwise normal selection changed events
1485         * are requested.
1486         *
1487         * @param selectionProvider
1488         */

1489        public void install(ISelectionProvider selectionProvider) {
1490            if (selectionProvider == null)
1491                return;
1492
1493            if (selectionProvider instanceof IPostSelectionProvider) {
1494                IPostSelectionProvider provider= (IPostSelectionProvider) selectionProvider;
1495                provider.addPostSelectionChangedListener(this);
1496            } else {
1497                selectionProvider.addSelectionChangedListener(this);
1498            }
1499        }
1500
1501        /**
1502         * Removes this selection changed listener from the given selection provider.
1503         *
1504         * @param selectionProvider the selection provider
1505         */

1506        public void uninstall(ISelectionProvider selectionProvider) {
1507            if (selectionProvider == null)
1508                return;
1509
1510            if (selectionProvider instanceof IPostSelectionProvider) {
1511                IPostSelectionProvider provider= (IPostSelectionProvider) selectionProvider;
1512                provider.removePostSelectionChangedListener(this);
1513            } else {
1514                selectionProvider.removeSelectionChangedListener(this);
1515            }
1516        }
1517    }
1518
1519    /**
1520     * This selection listener allows the SelectionProvider to implement {@link ISelectionValidator}.
1521     *
1522     * @since 3.0
1523     */

1524    private class SelectionListener extends AbstractSelectionChangedListener implements IDocumentListener {
1525
1526        private IDocument fDocument;
1527        private final Object JavaDoc INVALID_SELECTION= new Object JavaDoc();
1528        private Object JavaDoc fPostSelection= INVALID_SELECTION;
1529
1530        /*
1531         * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
1532         */

1533        public synchronized void selectionChanged(SelectionChangedEvent event) {
1534            fPostSelection= event.getSelection();
1535        }
1536
1537        /*
1538         * @see org.eclipse.jface.text.IDocumentListener#documentAboutToBeChanged(org.eclipse.jface.text.DocumentEvent)
1539         * @since 3.0
1540         */

1541        public synchronized void documentAboutToBeChanged(DocumentEvent event) {
1542            fPostSelection= INVALID_SELECTION;
1543        }
1544
1545        /*
1546         * @see org.eclipse.jface.text.IDocumentListener#documentChanged(org.eclipse.jface.text.DocumentEvent)
1547         * @since 3.0
1548         */

1549        public void documentChanged(DocumentEvent event) {
1550        }
1551
1552        public synchronized boolean isValid(ISelection selection) {
1553            return fPostSelection != INVALID_SELECTION && fPostSelection == selection;
1554        }
1555
1556        public void setDocument(IDocument document) {
1557            if (fDocument != null)
1558                fDocument.removeDocumentListener(this);
1559
1560            fDocument= document;
1561            if (fDocument != null)
1562                fDocument.addDocumentListener(this);
1563        }
1564
1565        /*
1566         * @see org.eclipse.ui.texteditor.AbstractTextEditor.AbstractSelectionChangedListener#install(org.eclipse.jface.viewers.ISelectionProvider)
1567         * @since 3.0
1568         */

1569        public void install(ISelectionProvider selectionProvider) {
1570            super.install(selectionProvider);
1571
1572            if (selectionProvider != null)
1573                selectionProvider.addSelectionChangedListener(this);
1574        }
1575
1576        /*
1577         * @see org.eclipse.ui.texteditor.AbstractTextEditor.AbstractSelectionChangedListener#uninstall(org.eclipse.jface.viewers.ISelectionProvider)
1578         * @since 3.0
1579         */

1580        public void uninstall(ISelectionProvider selectionProvider) {
1581            if (selectionProvider != null)
1582                selectionProvider.removeSelectionChangedListener(this);
1583
1584            if (fDocument != null) {
1585                fDocument.removeDocumentListener(this);
1586                fDocument= null;
1587            }
1588            super.uninstall(selectionProvider);
1589        }
1590    }
1591    
1592    
1593    /**
1594     * Implements the ruler column support of for the given editor.
1595     * <p>
1596     * This is currently only used to support vertical ruler columns.
1597     * </p>
1598     *
1599     * @since 3.3
1600     */

1601    protected static class ColumnSupport implements IColumnSupport {
1602        private final AbstractTextEditor fEditor;
1603        private final RulerColumnRegistry fRegistry;
1604        private final List JavaDoc fColumns;
1605
1606        /**
1607         * Creates a new column support for the given editor. Only the editor itself should normally
1608         * create such an instance.
1609         *
1610         * @param editor the editor
1611         * @param registry the contribution registry to refer to
1612         */

1613        public ColumnSupport(AbstractTextEditor editor, RulerColumnRegistry registry) {
1614            Assert.isLegal(editor != null);
1615            Assert.isLegal(registry != null);
1616            fEditor= editor;
1617            fRegistry= registry;
1618            fColumns= new ArrayList JavaDoc();
1619        }
1620
1621        /*
1622         * @see org.eclipse.ui.texteditor.IColumnSupport#setColumnVisible(java.lang.String, boolean)
1623         */

1624        public final void setColumnVisible(RulerColumnDescriptor descriptor, boolean visible) {
1625            Assert.isLegal(descriptor != null);
1626
1627            final CompositeRuler ruler= getRuler();
1628            if (ruler == null)
1629                return;
1630
1631            if (!isColumnSupported(descriptor))
1632                visible= false;
1633
1634            if (isColumnVisible(descriptor)) {
1635                if (!visible)
1636                    removeColumn(ruler, descriptor);
1637            } else {
1638                if (visible)
1639                    addColumn(ruler, descriptor);
1640            }
1641        }
1642        
1643        private void addColumn(final CompositeRuler ruler, final RulerColumnDescriptor descriptor) {
1644            
1645            final int idx= computeIndex(ruler, descriptor);
1646            
1647            SafeRunnable runnable= new SafeRunnable() {
1648                public void run() throws Exception JavaDoc {
1649                    IContributedRulerColumn column= descriptor.createColumn(fEditor);
1650                    fColumns.add(column);
1651                    initializeColumn(column);
1652                    ruler.addDecorator(idx, column);
1653                }
1654            };
1655            SafeRunner.run(runnable);
1656        }
1657
1658        /**
1659         * Hook to let subclasses initialize a newly created column.
1660         * <p>
1661         * Subclasses may extend this method.</p>
1662         *
1663         * @param column the created column
1664         */

1665        protected void initializeColumn(IContributedRulerColumn column) {
1666        }
1667
1668        private void removeColumn(final CompositeRuler ruler, final RulerColumnDescriptor descriptor) {
1669            removeColumn(ruler, getVisibleColumn(ruler, descriptor));
1670        }
1671        
1672        private void removeColumn(final CompositeRuler ruler, final IContributedRulerColumn rulerColumn) {
1673            if (rulerColumn != null) {
1674                SafeRunnable runnable= new SafeRunnable() {
1675                    public void run() throws Exception JavaDoc {
1676                        if (ruler != null)
1677                            ruler.removeDecorator(rulerColumn);
1678                        rulerColumn.columnRemoved();
1679                    }
1680                };
1681                SafeRunner.run(runnable);
1682            }
1683        }
1684
1685        /**
1686         * Returns the currently visible column matching <code>id</code>, <code>null</code> if
1687         * none.
1688         *
1689         * @param ruler the composite ruler to scan
1690         * @param descriptor the descriptor of the column of interest
1691         * @return the matching column or <code>null</code>
1692         */

1693        private IContributedRulerColumn getVisibleColumn(CompositeRuler ruler, RulerColumnDescriptor descriptor) {
1694            for (Iterator JavaDoc it= ruler.getDecoratorIterator(); it.hasNext();) {
1695                IVerticalRulerColumn column= (IVerticalRulerColumn)it.next();
1696                if (column instanceof IContributedRulerColumn) {
1697                    IContributedRulerColumn rulerColumn= (IContributedRulerColumn)column;
1698                    RulerColumnDescriptor rcd= rulerColumn.getDescriptor();
1699                    if (descriptor.equals(rcd))
1700                        return rulerColumn;
1701                }
1702            }
1703            return null;
1704        }
1705
1706        /**
1707         * Computes the insertion index for a column contribution into the currently visible columns.
1708         *
1709         * @param ruler the composite ruler into which to insert the column
1710         * @param descriptor the descriptor to compute the index for
1711         * @return the insertion index for a new column
1712         */

1713        private int computeIndex(CompositeRuler ruler, RulerColumnDescriptor descriptor) {
1714            int index= 0;
1715            List JavaDoc all= fRegistry.getColumnDescriptors();
1716            int newPos= all.indexOf(descriptor);
1717            for (Iterator JavaDoc it= ruler.getDecoratorIterator(); it.hasNext();) {
1718                IVerticalRulerColumn column= (IVerticalRulerColumn) it.next();
1719                if (column instanceof IContributedRulerColumn) {
1720                    RulerColumnDescriptor rcd= ((IContributedRulerColumn)column).getDescriptor();
1721                    if (rcd != null && all.indexOf(rcd) > newPos)
1722                        break;
1723                } else if ("org.eclipse.jface.text.source.projection.ProjectionRulerColumn".equals(column.getClass().getName())) { //$NON-NLS-1$
1724
// projection column is always the rightmost column
1725
break;
1726                }
1727                index++;
1728            }
1729            return index;
1730        }
1731
1732        /*
1733         * @see org.eclipse.ui.texteditor.IColumnSupport#isColumnVisible(java.lang.String)
1734         */

1735        public final boolean isColumnVisible(RulerColumnDescriptor descriptor) {
1736            Assert.isLegal(descriptor != null);
1737            CompositeRuler ruler= getRuler();
1738            return ruler != null && getVisibleColumn(ruler, descriptor) != null;
1739        }
1740        
1741        /*
1742         * @see org.eclipse.ui.texteditor.IColumnSupport#isColumnSupported(java.lang.String)
1743         */

1744        public final boolean isColumnSupported(RulerColumnDescriptor descriptor) {
1745            Assert.isLegal(descriptor != null);
1746            if (getRuler() == null)
1747                return false;
1748            
1749            if (descriptor == null)
1750                return false;
1751            
1752            return descriptor.matchesEditor(fEditor);
1753        }
1754        
1755        /**
1756         * Returns the editor's vertical ruler, if it is a {@link CompositeRuler}, <code>null</code>
1757         * otherwise.
1758         *
1759         * @return the editor's {@link CompositeRuler} or <code>null</code>
1760         */

1761        private CompositeRuler getRuler() {
1762            Object JavaDoc ruler= fEditor.getAdapter(IVerticalRulerInfo.class);
1763            if (ruler instanceof CompositeRuler)
1764                return (CompositeRuler) ruler;
1765            return null;
1766        }
1767
1768        /**
1769         * {@inheritDoc}
1770         * <p>
1771         * Subclasses may extend this method.</p>
1772         *
1773         */

1774        public void dispose() {
1775            for (Iterator JavaDoc iter= new ArrayList JavaDoc(fColumns).iterator(); iter.hasNext();)
1776                removeColumn(getRuler(), (IContributedRulerColumn)iter.next());
1777            fColumns.clear();
1778        }
1779    }
1780
1781
1782
1783    /**
1784     * Information provider used to present focusable information shells.
1785     *
1786     * @since 3.3
1787     */

1788    private static final class InformationProvider implements IInformationProvider, IInformationProviderExtension, IInformationProviderExtension2 {
1789        
1790        private IRegion fHoverRegion;
1791        private Object JavaDoc fHoverInfo;
1792        private IInformationControlCreator fControlCreator;
1793        
1794        InformationProvider(IRegion hoverRegion, Object JavaDoc hoverInfo, IInformationControlCreator controlCreator) {
1795            fHoverRegion= hoverRegion;
1796            fHoverInfo= hoverInfo;
1797            fControlCreator= controlCreator;
1798        }
1799        /*
1800         * @see org.eclipse.jface.text.information.IInformationProvider#getSubject(org.eclipse.jface.text.ITextViewer, int)
1801         */

1802        public IRegion getSubject(ITextViewer textViewer, int invocationOffset) {
1803            return fHoverRegion;
1804        }
1805        /*
1806         * @see org.eclipse.jface.text.information.IInformationProvider#getInformation(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion)
1807         */

1808        public String JavaDoc getInformation(ITextViewer textViewer, IRegion subject) {
1809            return fHoverInfo.toString();
1810        }
1811        /*
1812         * @see org.eclipse.jface.text.information.IInformationProviderExtension#getInformation2(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion)
1813         * @since 3.2
1814         */

1815        public Object JavaDoc getInformation2(ITextViewer textViewer, IRegion subject) {
1816            return fHoverInfo;
1817        }
1818        /*
1819         * @see org.eclipse.jface.text.information.IInformationProviderExtension2#getInformationPresenterControlCreator()
1820         */

1821        public IInformationControlCreator getInformationPresenterControlCreator() {
1822            return fControlCreator;
1823        }
1824    }
1825    
1826    /**
1827     * This action behaves in two different ways: If there is no current text
1828     * hover, the javadoc is displayed using information presenter. If there is
1829     * a current text hover, it is converted into a information presenter in
1830     * order to make it sticky.
1831     *
1832     * @since 3.3
1833     */

1834    private final class InformationDispatchAction extends TextEditorAction {
1835
1836        /** The wrapped text operation action. */
1837        private final TextOperationAction fTextOperationAction;
1838
1839        /**
1840         * Creates a dispatch action.
1841         *
1842         * @param resourceBundle the resource bundle
1843         * @param prefix the prefix
1844         * @param textOperationAction the text operation action
1845         */

1846        public InformationDispatchAction(ResourceBundle JavaDoc resourceBundle, String JavaDoc prefix, final TextOperationAction textOperationAction) {
1847            super(resourceBundle, prefix, AbstractTextEditor.this);
1848            if (textOperationAction == null)
1849                throw new IllegalArgumentException JavaDoc();
1850            fTextOperationAction= textOperationAction;
1851        }
1852
1853        /*
1854         * @see org.eclipse.jface.action.IAction#run()
1855         */

1856        public void run() {
1857
1858            ISourceViewer sourceViewer= getSourceViewer();
1859            if (sourceViewer == null) {
1860                if (fTextOperationAction.isEnabled())
1861                    fTextOperationAction.run();
1862                return;
1863            }
1864
1865            if (sourceViewer instanceof ITextViewerExtension4) {
1866                ITextViewerExtension4 extension4= (ITextViewerExtension4) sourceViewer;
1867                if (extension4.moveFocusToWidgetToken())
1868                    return;
1869            }
1870
1871            if (sourceViewer instanceof ITextViewerExtension2) {
1872                // does a text hover exist?
1873
ITextHover textHover= ((ITextViewerExtension2) sourceViewer).getCurrentTextHover();
1874                if (textHover != null && makeTextHoverFocusable(sourceViewer, textHover))
1875                    return;
1876            }
1877
1878            if (sourceViewer instanceof ISourceViewerExtension3) {
1879                // does an annotation hover exist?
1880
IAnnotationHover annotationHover= ((ISourceViewerExtension3) sourceViewer).getCurrentAnnotationHover();
1881                if (annotationHover != null && makeAnnotationHoverFocusable(sourceViewer, annotationHover))
1882                    return;
1883            }
1884            
1885            // otherwise, just run the action
1886
if (fTextOperationAction.isEnabled())
1887                fTextOperationAction.run();
1888        }
1889
1890        /**
1891         * Tries to make a text hover focusable (or "sticky").
1892         *
1893         * @param sourceViewer the source viewer to display the hover over
1894         * @param textHover the hover to make focusable
1895         * @return <code>true</code> if successful, <code>false</code> otherwise
1896         */

1897        private boolean makeTextHoverFocusable(ISourceViewer sourceViewer, ITextHover textHover) {
1898            Point hoverEventLocation= ((ITextViewerExtension2) sourceViewer).getHoverEventLocation();
1899            int offset= computeOffsetAtLocation(sourceViewer, hoverEventLocation.x, hoverEventLocation.y);
1900            if (offset == -1)
1901                return false;
1902            
1903            try {
1904                IRegion hoverRegion= textHover.getHoverRegion(sourceViewer, offset);
1905                if (hoverRegion == null)
1906                    return false;
1907
1908                String JavaDoc hoverInfo= textHover.getHoverInfo(sourceViewer, hoverRegion);
1909
1910                IInformationControlCreator controlCreator= null;
1911                if (textHover instanceof IInformationProviderExtension2)
1912                    controlCreator= ((IInformationProviderExtension2)textHover).getInformationPresenterControlCreator();
1913
1914                IInformationProvider informationProvider= new InformationProvider(hoverRegion, hoverInfo, controlCreator);
1915
1916                fInformationPresenter.setOffset(offset);
1917                fInformationPresenter.setAnchor(AbstractInformationControlManager.ANCHOR_BOTTOM);
1918                fInformationPresenter.setMargins(6, 6); // default values from AbstractInformationControlManager
1919
String JavaDoc contentType= TextUtilities.getContentType(sourceViewer.getDocument(), getSourceViewerConfiguration().getConfiguredDocumentPartitioning(getSourceViewer()), offset, true);
1920                fInformationPresenter.setInformationProvider(informationProvider, contentType);
1921                fInformationPresenter.showInformation();
1922
1923                return true;
1924
1925            } catch (BadLocationException e) {
1926                return false;
1927            }
1928        }
1929
1930        /**
1931         * Tries to make an annotation hover focusable (or "sticky").
1932         *
1933         * @param sourceViewer the source viewer to display the hover over
1934         * @param annotationHover the hover to make focusable
1935         * @return <code>true</code> if successful, <code>false</code> otherwise
1936         */

1937        private boolean makeAnnotationHoverFocusable(ISourceViewer sourceViewer, IAnnotationHover annotationHover) {
1938            IVerticalRulerInfo info= getVerticalRuler();
1939            int line= info.getLineOfLastMouseButtonActivity();
1940            if (line == -1)
1941                return false;
1942
1943            try {
1944
1945                // compute the hover information
1946
Object JavaDoc hoverInfo;
1947                if (annotationHover instanceof IAnnotationHoverExtension) {
1948                    IAnnotationHoverExtension extension= (IAnnotationHoverExtension) annotationHover;
1949                    ILineRange hoverLineRange= extension.getHoverLineRange(sourceViewer, line);
1950                    if (hoverLineRange == null)
1951                        return false;
1952                    final int maxVisibleLines= Integer.MAX_VALUE; // allow any number of lines being displayed, as we support scrolling
1953
hoverInfo= extension.getHoverInfo(sourceViewer, hoverLineRange, maxVisibleLines);
1954                } else {
1955                    hoverInfo= annotationHover.getHoverInfo(sourceViewer, line);
1956                }
1957                
1958                // hover region: the beginning of the concerned line to place the control right over the line
1959
IDocument document= sourceViewer.getDocument();
1960                int offset= document.getLineOffset(line);
1961                String JavaDoc contentType= TextUtilities.getContentType(document, getSourceViewerConfiguration().getConfiguredDocumentPartitioning(getSourceViewer()), offset, true);
1962
1963                IInformationControlCreator controlCreator= null;
1964                if (annotationHover instanceof IInformationProviderExtension2)
1965                    controlCreator= ((IInformationProviderExtension2) annotationHover).getInformationPresenterControlCreator();
1966                else if (annotationHover instanceof IAnnotationHoverExtension)
1967                    controlCreator= ((IAnnotationHoverExtension) annotationHover).getHoverControlCreator();
1968                
1969                IInformationProvider informationProvider= new InformationProvider(new Region(offset, 0), hoverInfo, controlCreator);
1970
1971                fInformationPresenter.setOffset(offset);
1972                fInformationPresenter.setAnchor(AbstractInformationControlManager.ANCHOR_RIGHT);
1973                fInformationPresenter.setMargins(4, 0); // AnnotationBarHoverManager sets (5,0), minus SourceViewer.GAP_SIZE_1
1974
fInformationPresenter.setInformationProvider(informationProvider, contentType);
1975                fInformationPresenter.showInformation();
1976
1977                return true;
1978
1979            } catch (BadLocationException e) {
1980                return false;
1981            }
1982        }
1983
1984        // modified version from TextViewer
1985
private int computeOffsetAtLocation(ITextViewer textViewer, int x, int y) {
1986
1987            StyledText styledText= textViewer.getTextWidget();
1988            IDocument document= textViewer.getDocument();
1989
1990            if (document == null)
1991                return -1;
1992
1993            try {
1994                int widgetOffset= styledText.getOffsetAtLocation(new Point(x, y));
1995                Point p= styledText.getLocationAtOffset(widgetOffset);
1996                if (p.x > x)
1997                    widgetOffset--;
1998                
1999                if (textViewer instanceof ITextViewerExtension5) {
2000                    ITextViewerExtension5 extension= (ITextViewerExtension5) textViewer;
2001                    return extension.widgetOffset2ModelOffset(widgetOffset);
2002                }
2003                IRegion visibleRegion= textViewer.getVisibleRegion();
2004                return widgetOffset + visibleRegion.getOffset();
2005            } catch (IllegalArgumentException JavaDoc e) {
2006                return -1;
2007            }
2008
2009        }
2010    }
2011    
2012    
2013    /**
2014     * Key used to look up font preference.
2015     * Value: <code>"org.eclipse.jface.textfont"</code>
2016     *
2017     * @deprecated As of 2.1, replaced by {@link JFaceResources#TEXT_FONT}
2018     */

2019    public final static String JavaDoc PREFERENCE_FONT= JFaceResources.TEXT_FONT;
2020    /**
2021     * Key used to look up foreground color preference.
2022     * Value: <code>AbstractTextEditor.Color.Foreground</code>
2023     * @since 2.0
2024     */

2025    public final static String JavaDoc PREFERENCE_COLOR_FOREGROUND= "AbstractTextEditor.Color.Foreground"; //$NON-NLS-1$
2026
/**
2027     * Key used to look up background color preference.
2028     * Value: <code>AbstractTextEditor.Color.Background</code>
2029     * @since 2.0
2030     */

2031    public final static String JavaDoc PREFERENCE_COLOR_BACKGROUND= "AbstractTextEditor.Color.Background"; //$NON-NLS-1$
2032
/**
2033     * Key used to look up foreground color system default preference.
2034     * Value: <code>AbstractTextEditor.Color.Foreground.SystemDefault</code>
2035     * @since 2.0
2036     */

2037    public final static String JavaDoc PREFERENCE_COLOR_FOREGROUND_SYSTEM_DEFAULT= "AbstractTextEditor.Color.Foreground.SystemDefault"; //$NON-NLS-1$
2038
/**
2039     * Key used to look up background color system default preference.
2040     * Value: <code>AbstractTextEditor.Color.Background.SystemDefault</code>
2041     * @since 2.0
2042     */

2043    public final static String JavaDoc PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT= "AbstractTextEditor.Color.Background.SystemDefault"; //$NON-NLS-1$
2044
/**
2045     * Key used to look up selection foreground color preference.
2046     * Value: <code>AbstractTextEditor.Color.SelectionForeground</code>
2047     * @since 3.0
2048     */

2049    public final static String JavaDoc PREFERENCE_COLOR_SELECTION_FOREGROUND= "AbstractTextEditor.Color.SelectionForeground"; //$NON-NLS-1$
2050
/**
2051     * Key used to look up selection background color preference.
2052     * Value: <code>AbstractTextEditor.Color.SelectionBackground</code>
2053     * @since 3.0
2054     */

2055    public final static String JavaDoc PREFERENCE_COLOR_SELECTION_BACKGROUND= "AbstractTextEditor.Color.SelectionBackground"; //$NON-NLS-1$
2056
/**
2057     * Key used to look up selection foreground color system default preference.
2058     * Value: <code>AbstractTextEditor.Color.SelectionForeground.SystemDefault</code>
2059     * @since 3.0
2060     */

2061    public final static String JavaDoc PREFERENCE_COLOR_SELECTION_FOREGROUND_SYSTEM_DEFAULT= "AbstractTextEditor.Color.SelectionForeground.SystemDefault"; //$NON-NLS-1$
2062
/**
2063     * Key used to look up selection background color system default preference.
2064     * Value: <code>AbstractTextEditor.Color.SelectionBackground.SystemDefault</code>
2065     * @since 3.0
2066     */

2067    public final static String JavaDoc PREFERENCE_COLOR_SELECTION_BACKGROUND_SYSTEM_DEFAULT= "AbstractTextEditor.Color.SelectionBackground.SystemDefault"; //$NON-NLS-1$
2068
/**
2069     * Key used to look up find scope background color preference.
2070     * Value: <code>AbstractTextEditor.Color.FindScope</code>
2071     * @since 2.0
2072     */

2073    public final static String JavaDoc PREFERENCE_COLOR_FIND_SCOPE= "AbstractTextEditor.Color.FindScope"; //$NON-NLS-1$
2074
/**
2075     * Key used to look up smart home/end preference.
2076     * Value: <code>AbstractTextEditor.Navigation.SmartHomeEnd</code>
2077     * @since 2.1
2078     */

2079    public final static String JavaDoc PREFERENCE_NAVIGATION_SMART_HOME_END= "AbstractTextEditor.Navigation.SmartHomeEnd"; //$NON-NLS-1$
2080
/**
2081     * Key used to look up the custom caret preference.
2082     * Value: {@value}
2083     * @since 3.0
2084     */

2085    public final static String JavaDoc PREFERENCE_USE_CUSTOM_CARETS= "AbstractTextEditor.Accessibility.UseCustomCarets"; //$NON-NLS-1$
2086
/**
2087     * Key used to look up the caret width preference.
2088     * Value: {@value}
2089     * @since 3.0
2090     */

2091    public final static String JavaDoc PREFERENCE_WIDE_CARET= "AbstractTextEditor.Accessibility.WideCaret"; //$NON-NLS-1$
2092
/**
2093     * A named preference that controls if hyperlinks are turned on or off.
2094     * <p>
2095     * Value is of type <code>Boolean</code>.
2096     * </p>
2097     *
2098     * @since 3.1
2099     */

2100    public static final String JavaDoc PREFERENCE_HYPERLINKS_ENABLED= "hyperlinksEnabled"; //$NON-NLS-1$
2101

2102    /**
2103     * A named preference that controls the key modifier for hyperlinks.
2104     * <p>
2105     * Value is of type <code>String</code>.
2106     * </p>
2107     *
2108     * @since 3.1
2109     */

2110    public static final String JavaDoc PREFERENCE_HYPERLINK_KEY_MODIFIER= "hyperlinkKeyModifier"; //$NON-NLS-1$
2111
/**
2112     * A named preference that controls the key modifier mask for hyperlinks.
2113     * The value is only used if the value of <code>PREFERENCE_HYPERLINK_KEY_MODIFIER</code>
2114     * cannot be resolved to valid SWT modifier bits.
2115     * <p>
2116     * Value is of type <code>String</code>.
2117     * </p>
2118     *
2119     * @see #PREFERENCE_HYPERLINK_KEY_MODIFIER
2120     * @since 3.1
2121     */

2122    public static final String JavaDoc PREFERENCE_HYPERLINK_KEY_MODIFIER_MASK= "hyperlinkKeyModifierMask"; //$NON-NLS-1$
2123
/**
2124     * A named preference that controls the visible ruler column contributions.
2125     * <p>
2126     * Value is of type <code>String</code> and should be read using a {@link RulerColumnPreferenceAdapter}.
2127     * </p>
2128     *
2129     * @since 3.3
2130     */

2131    public static final String JavaDoc PREFERENCE_RULER_CONTRIBUTIONS= "rulerContributions"; //$NON-NLS-1$
2132
/**
2133     * A named preference that controls the display of whitespace characters.
2134     * <p>
2135     * Value is of type <code>Boolean</code>.
2136     * </p>
2137     *
2138     * @since 3.3
2139     */

2140    public static final String JavaDoc PREFERENCE_SHOW_WHITESPACE_CHARACTERS= "showWhitespaceCharacters"; //$NON-NLS-1$
2141
/**
2142     * A named preference that controls whether text drag and drop is enabled.
2143     * <p>
2144     * Value is of type <code>Boolean</code>.
2145     * </p>
2146     *
2147     * @since 3.3
2148     */

2149    public static final String JavaDoc PREFERENCE_TEXT_DRAG_AND_DROP_ENABLED= "textDragAndDropEnabled"; //$NON-NLS-1$
2150

2151
2152    /** Menu id for the editor context menu. */
2153    public final static String JavaDoc DEFAULT_EDITOR_CONTEXT_MENU_ID= "#EditorContext"; //$NON-NLS-1$
2154
/** Menu id for the ruler context menu. */
2155    public final static String JavaDoc DEFAULT_RULER_CONTEXT_MENU_ID= "#RulerContext"; //$NON-NLS-1$
2156

2157    /** The width of the vertical ruler. */
2158    protected final static int VERTICAL_RULER_WIDTH= 12;
2159
2160    /**
2161     * The complete mapping between action definition IDs used by eclipse and StyledText actions.
2162     *
2163     * @since 2.0
2164     */

2165    protected final static IdMapEntry[] ACTION_MAP= new IdMapEntry[] {
2166        // navigation
2167
new IdMapEntry(ITextEditorActionDefinitionIds.LINE_UP, ST.LINE_UP),
2168        new IdMapEntry(ITextEditorActionDefinitionIds.LINE_DOWN, ST.LINE_DOWN),
2169        new IdMapEntry(ITextEditorActionDefinitionIds.LINE_START, ST.LINE_START),
2170        new IdMapEntry(ITextEditorActionDefinitionIds.LINE_END, ST.LINE_END),
2171        new IdMapEntry(ITextEditorActionDefinitionIds.COLUMN_PREVIOUS, ST.COLUMN_PREVIOUS),
2172        new IdMapEntry(ITextEditorActionDefinitionIds.COLUMN_NEXT, ST.COLUMN_NEXT),
2173        new IdMapEntry(ITextEditorActionDefinitionIds.PAGE_UP, ST.PAGE_UP),
2174        new IdMapEntry(ITextEditorActionDefinitionIds.PAGE_DOWN, ST.PAGE_DOWN),
2175        new IdMapEntry(ITextEditorActionDefinitionIds.WORD_PREVIOUS, ST.WORD_PREVIOUS),
2176        new IdMapEntry(ITextEditorActionDefinitionIds.WORD_NEXT, ST.WORD_NEXT),
2177        new IdMapEntry(ITextEditorActionDefinitionIds.TEXT_START, ST.TEXT_START),
2178        new IdMapEntry(ITextEditorActionDefinitionIds.TEXT_END, ST.TEXT_END),
2179        new IdMapEntry(ITextEditorActionDefinitionIds.WINDOW_START, ST.WINDOW_START),
2180        new IdMapEntry(ITextEditorActionDefinitionIds.WINDOW_END, ST.WINDOW_END),
2181        // selection
2182
new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_LINE_UP, ST.SELECT_LINE_UP),
2183        new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_LINE_DOWN, ST.SELECT_LINE_DOWN),
2184        new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_LINE_START, ST.SELECT_LINE_START),
2185        new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_LINE_END, ST.SELECT_LINE_END),
2186        new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_COLUMN_PREVIOUS, ST.SELECT_COLUMN_PREVIOUS),
2187        new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_COLUMN_NEXT, ST.SELECT_COLUMN_NEXT),
2188        new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_PAGE_UP, ST.SELECT_PAGE_UP),
2189        new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_PAGE_DOWN, ST.SELECT_PAGE_DOWN),
2190        new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_WORD_PREVIOUS, ST.SELECT_WORD_PREVIOUS),
2191        new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_WORD_NEXT, ST.SELECT_WORD_NEXT),
2192        new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_TEXT_START, ST.SELECT_TEXT_START),
2193        new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_TEXT_END, ST.SELECT_TEXT_END),
2194        new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_WINDOW_START, ST.SELECT_WINDOW_START),
2195        new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_WINDOW_END, ST.SELECT_WINDOW_END),
2196        // modification
2197
new IdMapEntry(IWorkbenchActionDefinitionIds.CUT, ST.CUT),
2198        new IdMapEntry(IWorkbenchActionDefinitionIds.COPY, ST.COPY),
2199        new IdMapEntry(IWorkbenchActionDefinitionIds.PASTE, ST.PASTE),
2200        new IdMapEntry(ITextEditorActionDefinitionIds.DELETE_PREVIOUS, ST.DELETE_PREVIOUS),
2201        new IdMapEntry(ITextEditorActionDefinitionIds.DELETE_NEXT, ST.DELETE_NEXT),
2202        new IdMapEntry(ITextEditorActionDefinitionIds.DELETE_PREVIOUS_WORD, ST.DELETE_WORD_PREVIOUS),
2203        new IdMapEntry(ITextEditorActionDefinitionIds.DELETE_NEXT_WORD, ST.DELETE_WORD_NEXT),
2204        // miscellaneous
2205
new IdMapEntry(ITextEditorActionDefinitionIds.TOGGLE_OVERWRITE, ST.TOGGLE_OVERWRITE)
2206    };
2207
2208    private final String JavaDoc fReadOnlyLabel= EditorMessages.Editor_statusline_state_readonly_label;
2209    private final String JavaDoc fWritableLabel= EditorMessages.Editor_statusline_state_writable_label;
2210    private final String JavaDoc fInsertModeLabel= EditorMessages.Editor_statusline_mode_insert_label;
2211    private final String JavaDoc fOverwriteModeLabel= EditorMessages.Editor_statusline_mode_overwrite_label;
2212    private final String JavaDoc fSmartInsertModeLabel= EditorMessages.Editor_statusline_mode_smartinsert_label;
2213
2214    /** The error message shown in the status line in case of failed information look up. */
2215    protected final String JavaDoc fErrorLabel= EditorMessages.Editor_statusline_error_label;
2216
2217    /**
2218     * Data structure for the position label value.
2219     */

2220    private static class PositionLabelValue {
2221
2222        public int fValue;
2223
2224        public String JavaDoc toString() {
2225            return String.valueOf(fValue);
2226        }
2227    }
2228    /** The pattern used to show the position label in the status line. */
2229    private final String JavaDoc fPositionLabelPattern= EditorMessages.Editor_statusline_position_pattern;
2230    /** The position label value of the current line. */
2231    private final PositionLabelValue fLineLabel= new PositionLabelValue();
2232    /** The position label value of the current column. */
2233    private final PositionLabelValue fColumnLabel= new PositionLabelValue();
2234    /** The arguments for the position label pattern. */
2235    private final Object JavaDoc[] fPositionLabelPatternArguments= new Object JavaDoc[] { fLineLabel, fColumnLabel };
2236    /**
2237     * The column support of this editor.
2238     * @since 3.3
2239     */

2240    private IColumnSupport fColumnSupport;
2241
2242    /** The editor's explicit document provider. */
2243    private IDocumentProvider fExplicitDocumentProvider;
2244    /** The editor's preference store. */
2245    private IPreferenceStore fPreferenceStore;
2246    /** The editor's range indicator. */
2247    private Annotation fRangeIndicator;
2248    /** The editor's source viewer configuration. */
2249    private SourceViewerConfiguration fConfiguration;
2250    /** The editor's source viewer. */
2251    private ISourceViewer fSourceViewer;
2252    /**
2253     * The editor's selection provider.
2254     * @since 2.1
2255     */

2256    private SelectionProvider fSelectionProvider= new SelectionProvider();
2257    /**
2258     * The editor's selection listener.
2259     * @since 3.0
2260     */

2261    private SelectionListener fSelectionListener;
2262    /** The editor's font. */
2263    private Font fFont; /**
2264     * The editor's foreground color.
2265     * @since 2.0
2266     */

2267    private Color fForegroundColor;
2268    /**
2269     * The editor's background color.
2270     * @since 2.0
2271     */

2272    private Color fBackgroundColor;
2273    /**
2274     * The editor's selection foreground color.
2275     * @since 3.0
2276     */

2277    private Color fSelectionForegroundColor;
2278    /**
2279     * The editor's selection background color.
2280     * @since 3.0
2281     */

2282    private Color fSelectionBackgroundColor;
2283    /**
2284     * The find scope's highlight color.
2285     * @since 2.0
2286     */

2287    private Color fFindScopeHighlightColor;
2288
2289    /**
2290     * The editor's status line.
2291     * @since 2.1
2292     */

2293    private IEditorStatusLine fEditorStatusLine;
2294    /** The editor's vertical ruler. */
2295    private IVerticalRuler fVerticalRuler;
2296    /** The editor's context menu id. */
2297    private String JavaDoc fEditorContextMenuId;
2298    /** The ruler's context menu id. */
2299    private String JavaDoc fRulerContextMenuId;
2300    /** The editor's help context id. */
2301    private String JavaDoc fHelpContextId;
2302    /** The editor's presentation mode. */
2303    private boolean fShowHighlightRangeOnly;
2304    /** The actions registered with the editor. */
2305    private Map JavaDoc fActions= new HashMap JavaDoc(10);
2306    /** The actions marked as selection dependent. */
2307    private List JavaDoc fSelectionActions= new ArrayList JavaDoc(5);
2308    /** The actions marked as content dependent. */
2309    private List JavaDoc fContentActions= new ArrayList JavaDoc(5);
2310    /**
2311     * The actions marked as property dependent.
2312     * @since 2.0
2313     */

2314    private List JavaDoc fPropertyActions= new ArrayList JavaDoc(5);
2315    /**
2316     * The actions marked as state dependent.
2317     * @since 2.0
2318     */

2319    private List JavaDoc fStateActions= new ArrayList JavaDoc(5);
2320    /** The editor's action activation codes. */
2321    private List JavaDoc fActivationCodes= new ArrayList JavaDoc(2);
2322    /** The verify key listener for activation code triggering. */
2323    private ActivationCodeTrigger fActivationCodeTrigger= new ActivationCodeTrigger();
2324    /** Context menu listener. */
2325    private IMenuListener fMenuListener;
2326    /** Vertical ruler mouse listener. */
2327    private MouseListener fMouseListener;
2328    /** Selection changed listener. */
2329    private ISelectionChangedListener fSelectionChangedListener;
2330    /** Title image to be disposed. */
2331    private Image fTitleImage;
2332    /** The text context menu to be disposed. */
2333    private Menu fTextContextMenu;
2334    /** The ruler context menu to be disposed. */
2335    private Menu fRulerContextMenu;
2336    /** The editor's element state listener. */
2337    private IElementStateListener fElementStateListener= new ElementStateListener();
2338    /**
2339     * The editor's text input listener.
2340     * @since 2.1
2341     */

2342    private TextInputListener fTextInputListener= new TextInputListener();
2343    /** The editor's text listener. */
2344    private TextListener fTextListener= new TextListener();
2345    /** The editor's property change listener. */
2346    private IPropertyChangeListener fPropertyChangeListener= new PropertyChangeListener();
2347    /**
2348     * The editor's font properties change listener.
2349     * @since 2.1
2350     */

2351    private IPropertyChangeListener fFontPropertyChangeListener= new FontPropertyChangeListener();
2352
2353    /**
2354     * The editor's activation listener.
2355     * @since 2.0
2356     */

2357    private ActivationListener fActivationListener;
2358    /**
2359     * The map of the editor's status fields.
2360     * @since 2.0
2361     */

2362    private Map JavaDoc fStatusFields;
2363    /**
2364     * The editor's cursor listener.
2365     * @since 2.0
2366     */

2367    private ICursorListener fCursorListener;
2368    /**
2369     * The editor's remembered text selection.
2370     * @since 2.0
2371     */

2372    private ISelection fRememberedSelection;
2373    /**
2374     * Indicates whether the editor runs in 1.0 context menu registration compatibility mode.
2375     * @since 2.0
2376     */

2377    private boolean fCompatibilityMode= true;
2378    /**
2379     * The number of re-entrances into error correction code while saving.
2380     * @since 2.0
2381     */

2382    private int fErrorCorrectionOnSave;
2383    /**
2384     * The delete line target.
2385     * @since 2.1
2386     */

2387    private DeleteLineTarget fDeleteLineTarget;
2388    /**
2389     * The incremental find target.
2390     * @since 2.0
2391     */

2392    private IncrementalFindTarget fIncrementalFindTarget;
2393    /**
2394     * The mark region target.
2395     * @since 2.0
2396     */

2397    private IMarkRegionTarget fMarkRegionTarget;
2398    /**
2399     * Cached modification stamp of the editor's input.
2400     * @since 2.0
2401     */

2402    private long fModificationStamp= -1;
2403    /**
2404     * Ruler context menu listeners.
2405     * @since 2.0
2406     */

2407    private List JavaDoc fRulerContextMenuListeners= new ArrayList JavaDoc();
2408    /**
2409     * Indicates whether sanity checking in enabled.
2410     * @since 2.0
2411     */

2412    private boolean fIsSanityCheckEnabled= true;
2413    /**
2414     * The find replace target.
2415     * @since 2.1
2416     */

2417    private FindReplaceTarget fFindReplaceTarget;
2418    /**
2419     * Indicates whether state validation is enabled.
2420     * @since 2.1
2421     */

2422    private boolean fIsStateValidationEnabled= true;
2423    /**
2424     * The key binding scopes of this editor.
2425     * @since 2.1
2426     */

2427    private String JavaDoc[] fKeyBindingScopes;
2428    /**
2429     * Whether the overwrite mode can be turned on.
2430     * @since 3.0
2431     */

2432    private boolean fIsOverwriteModeEnabled= true;
2433    /**
2434     * Whether the overwrite mode is currently on.
2435     * @since 3.0
2436     */

2437    private boolean fIsOverwriting= false;
2438    /**
2439     * The editor's insert mode.
2440     * @since 3.0
2441     */

2442    private InsertMode fInsertMode= SMART_INSERT;
2443    /**
2444     * The sequence of legal editor insert modes.
2445     * @since 3.0
2446     */

2447    private List JavaDoc fLegalInsertModes= null;
2448    /**
2449     * The non-default caret.
2450     * @since 3.0
2451     */

2452    private Caret fNonDefaultCaret;
2453    /**
2454     * The image used in non-default caret.
2455     * @since 3.0
2456     */

2457    private Image fNonDefaultCaretImage;
2458    /**
2459     * The styled text's initial caret.
2460     * @since 3.0
2461     */

2462    private Caret fInitialCaret;
2463    /**
2464     * The operation approver used to warn on undoing of non-local operations.
2465     * @since 3.1
2466     */

2467    private IOperationApprover fNonLocalOperationApprover;
2468    /**
2469     * The operation approver used to warn of linear undo violations.
2470     * @since 3.1
2471     */

2472    private IOperationApprover fLinearUndoViolationApprover;
2473    /**
2474     * This editor's memento holding data for restoring it after restart.
2475     * @since 3.3
2476     */

2477    private IMemento fMementoToRestore;
2478    /**
2479     * This editor's savable.
2480     * @since 3.3
2481     */

2482    private TextEditorSavable fSavable;
2483    /**
2484     * Tells whether text drag and drop is enabled.
2485     * @since 3.3
2486     */

2487    private boolean fIsTextDragAndDropEnabled= false;
2488    /**
2489     * Tells whether text drag and drop has been installed on the control.
2490     * @since 3.3
2491     */

2492    private boolean fIsTextDragAndDropInstalled= false;
2493    /**
2494     * Helper token to decide whether drag and
2495     * drop happens inside the same editor.
2496     * @since 3.3
2497     */

2498    private Object JavaDoc fTextDragAndDropToken;
2499    /**
2500     * The information presenter.
2501     * @since 3.3
2502     */

2503    private InformationPresenter fInformationPresenter;
2504
2505
2506    /**
2507     * Creates a new text editor. If not explicitly set, this editor uses
2508     * a <code>SourceViewerConfiguration</code> to configure its
2509     * source viewer. This viewer does not have a range indicator installed,
2510     * nor any menu id set. By default, the created editor runs in 1.0 context
2511     * menu registration compatibility mode.
2512     */

2513    protected AbstractTextEditor() {
2514        super();
2515        fEditorContextMenuId= null;
2516        fRulerContextMenuId= null;
2517        fHelpContextId= null;
2518    }
2519
2520    /*
2521     * @see ITextEditor#getDocumentProvider()
2522     */

2523    public IDocumentProvider getDocumentProvider() {
2524        return fExplicitDocumentProvider;
2525    }
2526
2527    /**
2528     * Returns the editor's range indicator. May return <code>null</code> if no
2529     * range indicator is installed.
2530     *
2531     * @return the editor's range indicator which may be <code>null</code>
2532     */

2533    protected final Annotation getRangeIndicator() {
2534        return fRangeIndicator;
2535    }
2536
2537    /**
2538     * Returns the editor's source viewer configuration. May return <code>null</code>
2539     * before the editor's part has been created and after disposal.
2540     *
2541     * @return the editor's source viewer configuration which may be <code>null</code>
2542     */

2543    protected final SourceViewerConfiguration getSourceViewerConfiguration() {
2544        return fConfiguration;
2545    }
2546
2547    /**
2548     * Returns the editor's source viewer. May return <code>null</code> before
2549     * the editor's part has been created and after disposal.
2550     *
2551     * @return the editor's source viewer which may be <code>null</code>
2552     */

2553    protected final ISourceViewer getSourceViewer() {
2554        return fSourceViewer;
2555    }
2556
2557    /**
2558     * Returns the editor's vertical ruler. May return <code>null</code> before
2559     * the editor's part has been created and after disposal.
2560     *
2561     * @return the editor's vertical ruler which may be <code>null</code>
2562     */

2563    protected final IVerticalRuler getVerticalRuler() {
2564        return fVerticalRuler;
2565    }
2566
2567    /**
2568     * Returns the editor's context menu id. May return <code>null</code> before
2569     * the editor's part has been created.
2570     *
2571     * @return the editor's context menu id which may be <code>null</code>
2572     */

2573    protected final String JavaDoc getEditorContextMenuId() {
2574        return fEditorContextMenuId;
2575    }
2576
2577    /**
2578     * Returns the ruler's context menu id. May return <code>null</code> before
2579     * the editor's part has been created.
2580     *
2581     * @return the ruler's context menu id which may be <code>null</code>
2582     */

2583    protected final String JavaDoc getRulerContextMenuId() {
2584        return fRulerContextMenuId;
2585    }
2586
2587    /**
2588     * Returns the editor's help context id or <code>null</code> if none has
2589     * been set.
2590     *
2591     * @return the editor's help context id which may be <code>null</code>
2592     */

2593    protected final String JavaDoc getHelpContextId() {
2594        return fHelpContextId;
2595    }
2596
2597    /**
2598     * Returns this editor's preference store or <code>null</code> if none has
2599     * been set.
2600     *
2601     * @return this editor's preference store which may be <code>null</code>
2602     */

2603    protected final IPreferenceStore getPreferenceStore() {
2604        return fPreferenceStore;
2605    }
2606
2607    /**
2608     * Sets this editor's document provider. This method must be
2609     * called before the editor's control is created.
2610     *
2611     * @param provider the document provider
2612     */

2613    protected void setDocumentProvider(IDocumentProvider provider) {
2614        fExplicitDocumentProvider= provider;
2615    }
2616
2617    /**
2618     * Sets this editor's source viewer configuration used to configure its
2619     * internal source viewer. This method must be called before the editor's
2620     * control is created. If not, this editor uses a <code>SourceViewerConfiguration</code>.
2621     *
2622     * @param configuration the source viewer configuration object
2623     */

2624    protected void setSourceViewerConfiguration(SourceViewerConfiguration configuration) {
2625        Assert.isNotNull(configuration);
2626        fConfiguration= configuration;
2627    }
2628
2629    /**
2630     * Sets the annotation which this editor uses to represent the highlight
2631     * range if the editor is configured to show the entire document. If the
2632     * range indicator is not set, this editor will not show a range indication.
2633     *
2634     * @param rangeIndicator the annotation
2635     */

2636    protected void setRangeIndicator(Annotation rangeIndicator) {
2637        Assert.isNotNull(rangeIndicator);
2638        fRangeIndicator= rangeIndicator;
2639    }
2640
2641    /**
2642     * Sets this editor's context menu id.
2643     *
2644     * @param contextMenuId the context menu id
2645     */

2646    protected void setEditorContextMenuId(String JavaDoc contextMenuId) {
2647        Assert.isNotNull(contextMenuId);
2648        fEditorContextMenuId= contextMenuId;
2649    }
2650
2651    /**
2652     * Sets the ruler's context menu id.
2653     *
2654     * @param contextMenuId the context menu id
2655     */

2656    protected void setRulerContextMenuId(String JavaDoc contextMenuId) {
2657        Assert.isNotNull(contextMenuId);
2658        fRulerContextMenuId= contextMenuId;
2659    }
2660
2661    /**
2662     * Sets the context menu registration 1.0 compatibility mode. (See class
2663     * description for more details.)
2664     *
2665     * @param compatible <code>true</code> if compatibility mode is enabled
2666     * @since 2.0
2667     */

2668    protected final void setCompatibilityMode(boolean compatible) {
2669        fCompatibilityMode= compatible;
2670    }
2671
2672    /**
2673     * Sets the editor's help context id.
2674     *
2675     * @param helpContextId the help context id
2676     */

2677    protected void setHelpContextId(String JavaDoc helpContextId) {
2678        Assert.isNotNull(helpContextId);
2679        fHelpContextId= helpContextId;
2680    }
2681
2682    /**
2683     * Sets the key binding scopes for this editor.
2684     *
2685     * @param scopes a non-empty array of key binding scope identifiers
2686     * @since 2.1
2687     */

2688    protected void setKeyBindingScopes(String JavaDoc[] scopes) {
2689        Assert.isTrue(scopes != null && scopes.length > 0);
2690        fKeyBindingScopes= scopes;
2691    }
2692
2693    /**
2694     * Sets this editor's preference store. This method must be
2695     * called before the editor's control is created.
2696     *
2697     * @param store the preference store or <code>null</code> to remove the
2698     * preference store
2699     */

2700    protected void setPreferenceStore(IPreferenceStore store) {
2701        if (fPreferenceStore != null)
2702            fPreferenceStore.removePropertyChangeListener(fPropertyChangeListener);
2703
2704        fPreferenceStore= store;
2705
2706        if (fPreferenceStore != null)
2707            fPreferenceStore.addPropertyChangeListener(fPropertyChangeListener);
2708    }
2709
2710    /*
2711     * @see ITextEditor#isEditable()
2712     */

2713    public boolean isEditable() {
2714        IDocumentProvider provider= getDocumentProvider();
2715        if (provider instanceof IDocumentProviderExtension) {
2716            IDocumentProviderExtension extension= (IDocumentProviderExtension) provider;
2717            return extension.isModifiable(getEditorInput());
2718        }
2719        return false;
2720    }
2721
2722    /**
2723     * {@inheritDoc}
2724     * <p>
2725     * Returns <code>null</code> after disposal.
2726     * </p>
2727     *
2728     * @return the selection provider or <code>null</code> if the editor has
2729     * been disposed
2730     */

2731    public ISelectionProvider getSelectionProvider() {
2732        return fSelectionProvider;
2733    }
2734
2735    /**
2736     * Remembers the current selection of this editor. This method is called when, e.g.,
2737     * the content of the editor is about to be reverted to the saved state. This method
2738     * remembers the selection in a semantic format, i.e., in a format which allows to
2739     * restore the selection even if the originally selected text is no longer part of the
2740     * editor's content.
2741     * <p>
2742     * Subclasses should implement this method including all necessary state. This
2743     * default implementation remembers the textual range only and is thus purely
2744     * syntactic.</p>
2745     *
2746     * @see #restoreSelection()
2747     * @since 2.0
2748     */

2749    protected void rememberSelection() {
2750        fRememberedSelection= doGetSelection();
2751    }
2752
2753    /**
2754     * Returns the current selection.
2755     * @return ISelection
2756     * @since 2.1
2757     */

2758    protected ISelection doGetSelection() {
2759        ISelectionProvider sp= null;
2760        if (fSourceViewer != null)
2761            sp= fSourceViewer.getSelectionProvider();
2762        return (sp == null ? null : sp.getSelection());
2763    }
2764
2765    /**
2766     * Restores a selection previously remembered by <code>rememberSelection</code>.
2767     * Subclasses may reimplement this method and thereby semantically adapt the
2768     * remembered selection. This default implementation just selects the
2769     * remembered textual range.
2770     *
2771     * @see #rememberSelection()
2772     * @since 2.0
2773     */

2774    protected void restoreSelection() {
2775        if (fRememberedSelection instanceof ITextSelection) {
2776            ITextSelection textSelection= (ITextSelection)fRememberedSelection;
2777            if (isValidSelection(textSelection.getOffset(), textSelection.getLength()))
2778                doSetSelection(fRememberedSelection);
2779        }
2780        fRememberedSelection= null;
2781    }
2782
2783    /**
2784     * Tells whether the given selection is valid.
2785     *
2786     * @param offset the offset of the selection
2787     * @param length the length of the selection
2788     * @return <code>true</code> if the selection is valid
2789     * @since 2.1
2790     */

2791    private boolean isValidSelection(int offset, int length) {
2792        IDocumentProvider provider= getDocumentProvider();
2793        if (provider != null) {
2794            IDocument document= provider.getDocument(getEditorInput());
2795            if (document != null) {
2796                int end= offset + length;
2797                int documentLength= document.getLength();
2798                return 0 <= offset && offset <= documentLength && 0 <= end && end <= documentLength && length >= 0;
2799            }
2800        }
2801        return false;
2802    }
2803
2804    /**
2805     * Sets the given selection.
2806     * @param selection
2807     * @since 2.1
2808     */

2809    protected void doSetSelection(ISelection selection) {
2810        if (selection instanceof ITextSelection) {
2811            ITextSelection textSelection= (ITextSelection) selection;
2812            selectAndReveal(textSelection.getOffset(), textSelection.getLength());
2813        }
2814    }
2815
2816    /**
2817     * Creates and returns the listener on this editor's context menus.
2818     *
2819     * @return the menu listener
2820     */

2821    protected final IMenuListener getContextMenuListener() {
2822        if (fMenuListener == null) {
2823            fMenuListener= new IMenuListener() {
2824
2825                public void menuAboutToShow(IMenuManager menu) {
2826                    String JavaDoc id= menu.getId();
2827                    if (getRulerContextMenuId().equals(id)) {
2828                        setFocus();
2829                        rulerContextMenuAboutToShow(menu);
2830                    } else if (getEditorContextMenuId().equals(id)) {
2831                        setFocus();
2832                        editorContextMenuAboutToShow(menu);
2833                    }
2834                }
2835            };
2836        }
2837        return fMenuListener;
2838    }
2839
2840    /**
2841     * Creates and returns the listener on this editor's vertical ruler.
2842     *
2843     * @return the mouse listener
2844     */

2845    protected final MouseListener getRulerMouseListener() {
2846        if (fMouseListener == null) {
2847            fMouseListener= new MouseListener() {
2848
2849                private boolean fDoubleClicked= false;
2850                private final int fDoubleClickTime= Display.getDefault().getDoubleClickTime();
2851                private long fMouseUpDelta= 0;
2852
2853                private void triggerAction(String JavaDoc actionID) {
2854                    IAction action= getAction(actionID);
2855                    if (action != null) {
2856                        if (action instanceof IUpdate)
2857                            ((IUpdate) action).update();
2858                        if (action.isEnabled())
2859                            action.run();
2860                    }
2861                }
2862
2863                public void mouseUp(final MouseEvent e) {
2864                    setFocus();
2865                    final int delay= fDoubleClickTime - (int)(System.currentTimeMillis() - fMouseUpDelta);
2866                    if (1 != e.button)
2867                        return;
2868                    
2869                    Runnable JavaDoc runnable= new Runnable JavaDoc() {
2870                        public void run() {
2871                            if (!fDoubleClicked)
2872                                triggerAction(ITextEditorActionConstants.RULER_CLICK);
2873                        }
2874                    };
2875                    if (delay <= 0)
2876                        runnable.run();
2877                    else
2878                        Display.getDefault().timerExec(delay, runnable);
2879                }
2880
2881                public void mouseDoubleClick(MouseEvent e) {
2882                    if (1 == e.button) {
2883                        fDoubleClicked= true;
2884                        triggerAction(ITextEditorActionConstants.RULER_DOUBLE_CLICK);
2885                    }
2886                }
2887
2888                public void mouseDown(MouseEvent e) {
2889                    fMouseUpDelta= System.currentTimeMillis();
2890                    fDoubleClicked= false;
2891                    StyledText text= fSourceViewer.getTextWidget();
2892                    if (text != null && !text.isDisposed()) {
2893                            Display display= text.getDisplay();
2894                            Point location= display.getCursorLocation();
2895                            fRulerContextMenu.setLocation(location.x, location.y);
2896                    }
2897                }
2898            };
2899        }
2900        return fMouseListener;
2901    }
2902
2903    /**
2904     * Returns this editor's selection changed listener to be installed
2905     * on the editor's source viewer.
2906     *
2907     * @return the listener
2908     */

2909    protected final ISelectionChangedListener getSelectionChangedListener() {
2910        if (fSelectionChangedListener == null) {
2911            fSelectionChangedListener= new ISelectionChangedListener() {
2912
2913                private Runnable JavaDoc fRunnable= new Runnable JavaDoc() {
2914                    public void run() {
2915                        // check whether editor has not been disposed yet
2916
if (fSourceViewer != null && fSourceViewer.getDocument() != null) {
2917                            updateSelectionDependentActions();
2918                        }
2919                    }
2920                };
2921
2922                private Display fDisplay;
2923
2924                public void selectionChanged(SelectionChangedEvent event) {
2925                    if (fDisplay == null)
2926                        fDisplay= getSite().getShell().getDisplay();
2927                    fDisplay.asyncExec(fRunnable);
2928                    handleCursorPositionChanged();
2929                }
2930            };
2931        }
2932
2933        return fSelectionChangedListener;
2934    }
2935
2936    /**
2937     * Returns this editor's "cursor" listener to be installed on the editor's
2938     * source viewer. This listener is listening to key and mouse button events.
2939     * It triggers the updating of the status line by calling
2940     * <code>handleCursorPositionChanged()</code>.
2941     *
2942     * @return the listener
2943     * @since 2.0
2944     */

2945    protected final ICursorListener getCursorListener() {
2946        if (fCursorListener == null) {
2947            fCursorListener= new ICursorListener() {
2948
2949                public void keyPressed(KeyEvent e) {
2950                    handleCursorPositionChanged();
2951                }
2952
2953                public void keyReleased(KeyEvent e) {
2954                }
2955
2956                public void mouseDoubleClick(MouseEvent e) {
2957                }
2958
2959                public void mouseDown(MouseEvent e) {
2960                }
2961
2962                public void mouseUp(MouseEvent e) {
2963                    handleCursorPositionChanged();
2964                }
2965            };
2966        }
2967        return fCursorListener;
2968    }
2969
2970    /**
2971     * Implements the <code>init</code> method of <code>IEditorPart</code>.
2972     * Subclasses replacing <code>init</code> may choose to call this method in
2973     * their implementation.
2974     *
2975     * @param window the workbench window
2976     * @param site the editor's site
2977     * @param input the editor input for the editor being created
2978     * @throws PartInitException if {@link #doSetInput(IEditorInput)} fails or gets canceled
2979     *
2980     * @see org.eclipse.ui.IEditorPart#init(org.eclipse.ui.IEditorSite, org.eclipse.ui.IEditorInput)
2981     * @since 2.1
2982     */

2983    protected final void internalInit(IWorkbenchWindow window, final IEditorSite site, final IEditorInput input) throws PartInitException {
2984
2985        IRunnableWithProgress runnable= new IRunnableWithProgress() {
2986            public void run(IProgressMonitor monitor) throws InvocationTargetException JavaDoc, InterruptedException JavaDoc {
2987                try {
2988
2989                    if (getDocumentProvider() instanceof IDocumentProviderExtension2) {
2990                        IDocumentProviderExtension2 extension= (IDocumentProviderExtension2) getDocumentProvider();
2991                        extension.setProgressMonitor(monitor);
2992                    }
2993
2994                    doSetInput(input);
2995
2996                } catch (CoreException x) {
2997                    throw new InvocationTargetException JavaDoc(x);
2998                } finally {
2999                    if (getDocumentProvider() instanceof IDocumentProviderExtension2) {
3000                        IDocumentProviderExtension2 extension= (IDocumentProviderExtension2) getDocumentProvider();
3001                        extension.setProgressMonitor(null);
3002                    }
3003                }
3004            }
3005        };
3006
3007        try {
3008// When using the progress service always a modal dialog pops up. The site should be asked for a runnable context
3009
// which could be the workbench window or the progress service, depending on what the site represents.
3010
// getSite().getWorkbenchWindow().getWorkbench().getProgressService().run(false, true, runnable);
3011

3012            getSite().getWorkbenchWindow().run(false, true, runnable);
3013
3014        } catch (InterruptedException JavaDoc x) {
3015        } catch (InvocationTargetException JavaDoc x) {
3016            Throwable JavaDoc t= x.getTargetException();
3017            if (t instanceof CoreException) {
3018                /*
3019                /* XXX: Remove unpacking of CoreException once the following bug is
3020                 * fixed: https://bugs.eclipse.org/bugs/show_bug.cgi?id=81640
3021                 */

3022                CoreException e= (CoreException)t;
3023                IStatus status= e.getStatus();
3024                if (status.getException() != null)
3025                    throw new PartInitException(status);
3026                throw new PartInitException(new Status(status.getSeverity(), status.getPlugin(), status.getCode(), status.getMessage(), t));
3027            }
3028            throw new PartInitException(new Status(IStatus.ERROR, TextEditorPlugin.PLUGIN_ID, IStatus.OK, EditorMessages.Editor_error_init, t));
3029        }
3030    }
3031
3032    /*
3033     * @see IEditorPart#init(org.eclipse.ui.IEditorSite, org.eclipse.ui.IEditorInput)
3034     */

3035    public void init(final IEditorSite site, final IEditorInput input) throws PartInitException {
3036
3037        setSite(site);
3038
3039        internalInit(site.getWorkbenchWindow(), site, input);
3040        fActivationListener= new ActivationListener(site.getWorkbenchWindow().getPartService());
3041    }
3042
3043    /**
3044     * Creates the vertical ruler to be used by this editor.
3045     * Subclasses may re-implement this method.
3046     *
3047     * @return the vertical ruler
3048     */

3049    protected IVerticalRuler createVerticalRuler() {
3050        return new VerticalRuler(VERTICAL_RULER_WIDTH);
3051    }
3052    
3053    /**
3054     * Adds enabled ruler contributions to the vertical ruler.
3055     * <p>
3056     * Clients may extend or replace.</p>
3057     *
3058     * @param ruler the composite ruler to add contributions to
3059     * @since 3.3
3060     */

3061    protected void updateContributedRulerColumns(CompositeRuler ruler) {
3062        IColumnSupport support= (IColumnSupport)getAdapter(IColumnSupport.class);
3063        if (support == null)
3064            return;
3065        
3066        RulerColumnPreferenceAdapter adapter= null;
3067        if (fPreferenceStore != null)
3068            adapter= new RulerColumnPreferenceAdapter(getPreferenceStore(), PREFERENCE_RULER_CONTRIBUTIONS);
3069        
3070        RulerColumnRegistry registry= RulerColumnRegistry.getDefault();
3071        List JavaDoc descriptors= registry.getColumnDescriptors();
3072        for (Iterator JavaDoc it= descriptors.iterator(); it.hasNext();) {
3073            final RulerColumnDescriptor descriptor= (RulerColumnDescriptor) it.next();
3074            support.setColumnVisible(descriptor, adapter == null || adapter.isEnabled(descriptor));
3075        }
3076    }
3077
3078    /**
3079     * Creates the column support to be used by this editor to manage the
3080     * contributed ruler columns.
3081     * Subclasses may re-implement this method using the {@link ColumnSupport},
3082     * e.g. by returning <code>new ColumnSupport(this, RulerColumnRegistry.getDefault());</code>.
3083     * <p>
3084     * <strong>Note:</strong> If you override this method to provide column support you will
3085     * also need to override {@link #createVerticalRuler()} to return a {@link CompositeRuler}.</p>
3086     * <p>
3087     * Out of the box this class does not install this support and hence this
3088     * implementation always returns <code>null</code>.</p>
3089     *
3090     * @return the column support or <code>null</code> if none
3091     * @since 3.3
3092     */

3093    protected IColumnSupport createColumnSupport() {
3094        return null;
3095    }
3096
3097    /**
3098     * Creates the source viewer to be used by this editor.
3099     * Subclasses may re-implement this method.
3100     *
3101     * @param parent the parent control
3102     * @param ruler the vertical ruler
3103     * @param styles style bits, <code>SWT.WRAP</code> is currently not supported
3104     * @return the source viewer
3105     */

3106    protected ISourceViewer createSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
3107        return new SourceViewer(parent, ruler, styles);
3108    }
3109
3110    /**
3111     * Initializes the drag and drop support for the given viewer based on
3112     * provided editor adapter for drop target listeners.
3113     *
3114     * @param viewer the viewer
3115     * @since 3.0
3116     */

3117    protected void initializeDragAndDrop(ISourceViewer viewer) {
3118        IDragAndDropService dndService= (IDragAndDropService)getSite().getService(IDragAndDropService.class);
3119        if (dndService == null)
3120            return;
3121        
3122        ITextEditorDropTargetListener listener= (ITextEditorDropTargetListener) getAdapter(ITextEditorDropTargetListener.class);
3123
3124        if (listener == null) {
3125            Object JavaDoc object= Platform.getAdapterManager().loadAdapter(this, "org.eclipse.ui.texteditor.ITextEditorDropTargetListener"); //$NON-NLS-1$
3126
if (object instanceof ITextEditorDropTargetListener)
3127                listener= (ITextEditorDropTargetListener)object;
3128        }
3129
3130        if (listener != null)
3131            dndService.addMergedDropTarget(viewer.getTextWidget(), DND.DROP_MOVE | DND.DROP_COPY, listener.getTransfers(), listener);
3132
3133        IPreferenceStore store= getPreferenceStore();
3134        if (store != null && store.getBoolean(PREFERENCE_TEXT_DRAG_AND_DROP_ENABLED))
3135            installTextDragAndDrop(viewer);
3136
3137    }
3138
3139    /**
3140     * The <code>AbstractTextEditor</code> implementation of this
3141     * <code>IWorkbenchPart</code> method creates the vertical ruler and
3142     * source viewer.
3143     * <p>
3144     * Subclasses may extend this method. Besides extending this method, the
3145     * behavior of <code>createPartControl</code> may be customized by
3146     * calling, extending or replacing the following methods: <br>
3147     * Subclasses may supply customized implementations for some members using
3148     * the following methods before <code>createPartControl</code> is invoked:
3149     * <ul>
3150     * <li>
3151     * {@linkplain #setSourceViewerConfiguration(SourceViewerConfiguration) setSourceViewerConfiguration}
3152     * to supply a custom source viewer configuration,</li>
3153     * <li>{@linkplain #setRangeIndicator(Annotation) setRangeIndicator} to
3154     * provide a range indicator,</li>
3155     * <li>{@linkplain #setHelpContextId(String) setHelpContextId} to provide a
3156     * help context id,</li>
3157     * <li>{@linkplain #setEditorContextMenuId(String) setEditorContextMenuId}
3158     * to set a custom context menu id,</li>
3159     * <li>{@linkplain #setRulerContextMenuId(String) setRulerContextMenuId} to
3160     * set a custom ruler context menu id.</li>
3161     * </ul>
3162     * <br>
3163     * Subclasses may replace the following methods called from within
3164     * <code>createPartControl</code>:
3165     * <ul>
3166     * <li>{@linkplain #createVerticalRuler() createVerticalRuler} to supply a
3167     * custom vertical ruler,</li>
3168     * <li>{@linkplain #createSourceViewer(Composite, IVerticalRuler, int) createSourceViewer}
3169     * to supply a custom source viewer,</li>
3170     * <li>{@linkplain #getSelectionProvider() getSelectionProvider} to supply
3171     * a custom selection provider.</li>
3172     * </ul>
3173     * <br>
3174     * Subclasses may extend the following methods called from within
3175     * <code>createPartControl</code>:
3176     * <ul>
3177     * <li>
3178     * {@linkplain #initializeViewerColors(ISourceViewer) initializeViewerColors}
3179     * to customize the viewer color scheme (may also be replaced),</li>
3180     * <li>
3181     * {@linkplain #initializeDragAndDrop(ISourceViewer) initializeDragAndDrop}
3182     * to customize drag and drop (may also be replaced),</li>
3183     * <li>{@linkplain #createNavigationActions() createNavigationActions} to
3184     * add navigation actions,</li>
3185     * <li>{@linkplain #createActions() createActions} to add text editor
3186     * actions.</li>
3187     * </ul>
3188     * </p>
3189     *
3190     * @param parent the parent composite
3191     */

3192    public void createPartControl(Composite parent) {
3193
3194        fVerticalRuler= createVerticalRuler();
3195
3196        int styles= SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION;
3197        fSourceViewer= createSourceViewer(parent, fVerticalRuler, styles);
3198
3199        if (fConfiguration == null)
3200            fConfiguration= new SourceViewerConfiguration();
3201        fSourceViewer.configure(fConfiguration);
3202
3203        if (fRangeIndicator != null)
3204            fSourceViewer.setRangeIndicator(fRangeIndicator);
3205
3206        fSourceViewer.addTextListener(fTextListener);
3207        fSourceViewer.addTextInputListener(fTextListener);
3208        getSelectionProvider().addSelectionChangedListener(getSelectionChangedListener());
3209
3210        initializeViewerFont(fSourceViewer);
3211        initializeViewerColors(fSourceViewer);
3212        initializeFindScopeColor(fSourceViewer);
3213        initializeDragAndDrop(fSourceViewer);
3214
3215        StyledText styledText= fSourceViewer.getTextWidget();
3216
3217        /* gestures commented out until proper solution (i.e. preference page) can be found
3218         * for bug # 28417:
3219         *
3220        final Map gestureMap= new HashMap();
3221
3222        gestureMap.put("E", "org.eclipse.ui.navigate.forwardHistory");
3223        gestureMap.put("N", "org.eclipse.ui.file.save");
3224        gestureMap.put("NW", "org.eclipse.ui.file.saveAll");
3225        gestureMap.put("S", "org.eclipse.ui.file.close");
3226        gestureMap.put("SW", "org.eclipse.ui.file.closeAll");
3227        gestureMap.put("W", "org.eclipse.ui.navigate.backwardHistory");
3228        gestureMap.put("EN", "org.eclipse.ui.edit.copy");
3229        gestureMap.put("ES", "org.eclipse.ui.edit.paste");
3230        gestureMap.put("EW", "org.eclipse.ui.edit.cut");
3231
3232        Capture capture= Capture.create();
3233        capture.setControl(styledText);
3234
3235        capture.addCaptureListener(new CaptureListener() {
3236            public void gesture(Gesture gesture) {
3237                if (gesture.getPen() == 3) {
3238                    String actionId= (String) gestureMap.get(Util.recognize(gesture.getPoints(), 20));
3239
3240                    if (actionId != null) {
3241                        IKeyBindingService keyBindingService= getEditorSite().getKeyBindingService();
3242
3243                        if (keyBindingService instanceof KeyBindingService) {
3244                            IAction action= ((KeyBindingService) keyBindingService).getAction(actionId);
3245
3246                            if (action != null) {
3247                                if (action instanceof IUpdate)
3248                                    ((IUpdate) action).update();
3249
3250                                if (action.isEnabled())
3251                                    action.run();
3252                            }
3253                        }
3254
3255                        return;
3256                    }
3257
3258                    fTextContextMenu.setVisible(true);
3259                }
3260            };
3261        });
3262        */

3263
3264        styledText.addMouseListener(getCursorListener());
3265        styledText.addKeyListener(getCursorListener());
3266
3267        if (getHelpContextId() != null)
3268            PlatformUI.getWorkbench().getHelpSystem().setHelp(styledText, getHelpContextId());
3269
3270
3271        String JavaDoc id= fEditorContextMenuId != null ? fEditorContextMenuId : DEFAULT_EDITOR_CONTEXT_MENU_ID;
3272
3273        MenuManager manager= new MenuManager(id, id);
3274        manager.setRemoveAllWhenShown(true);
3275        manager.addMenuListener(getContextMenuListener());
3276        fTextContextMenu= manager.createContextMenu(styledText);
3277
3278        // comment this line if using gestures, above.
3279
styledText.setMenu(fTextContextMenu);
3280
3281        if (fEditorContextMenuId != null)
3282            getEditorSite().registerContextMenu(fEditorContextMenuId, manager, getSelectionProvider(), isEditorInputIncludedInContextMenu());
3283        else if (fCompatibilityMode)
3284            getEditorSite().registerContextMenu(DEFAULT_EDITOR_CONTEXT_MENU_ID, manager, getSelectionProvider(), isEditorInputIncludedInContextMenu());
3285
3286        if ((fEditorContextMenuId != null && fCompatibilityMode) || fEditorContextMenuId == null) {
3287            String JavaDoc partId= getEditorSite().getId();
3288            if (partId != null)
3289                getEditorSite().registerContextMenu(partId + ".EditorContext", manager, getSelectionProvider(), isEditorInputIncludedInContextMenu()); //$NON-NLS-1$
3290
}
3291
3292        if (fEditorContextMenuId == null)
3293            fEditorContextMenuId= DEFAULT_EDITOR_CONTEXT_MENU_ID;
3294
3295
3296        id= fRulerContextMenuId != null ? fRulerContextMenuId : DEFAULT_RULER_CONTEXT_MENU_ID;
3297        manager= new MenuManager(id, id);
3298        manager.setRemoveAllWhenShown(true);
3299        manager.addMenuListener(getContextMenuListener());
3300
3301        Control rulerControl= fVerticalRuler.getControl();
3302        fRulerContextMenu= manager.createContextMenu(rulerControl);
3303        rulerControl.setMenu(fRulerContextMenu);
3304        rulerControl.addMouseListener(getRulerMouseListener());
3305
3306        if (fRulerContextMenuId != null)
3307            getEditorSite().registerContextMenu(fRulerContextMenuId, manager, getSelectionProvider(), false);
3308        else if (fCompatibilityMode)
3309            getEditorSite().registerContextMenu(DEFAULT_RULER_CONTEXT_MENU_ID, manager, getSelectionProvider(), false);
3310
3311        if ((fRulerContextMenuId != null && fCompatibilityMode) || fRulerContextMenuId == null) {
3312            String JavaDoc partId= getSite().getId();
3313            if (partId != null)
3314                getEditorSite().registerContextMenu(partId + ".RulerContext", manager, getSelectionProvider(), false); //$NON-NLS-1$
3315
}
3316
3317        if (fRulerContextMenuId == null)
3318            fRulerContextMenuId= DEFAULT_RULER_CONTEXT_MENU_ID;
3319
3320        getSite().setSelectionProvider(getSelectionProvider());
3321
3322        fSelectionListener= new SelectionListener();
3323        fSelectionListener.install(getSelectionProvider());
3324        fSelectionListener.setDocument(getDocumentProvider().getDocument(getEditorInput()));
3325
3326        initializeActivationCodeTrigger();
3327
3328        createNavigationActions();
3329        createAccessibilityActions();
3330        createActions();
3331
3332        initializeSourceViewer(getEditorInput());
3333        
3334        /* since 3.2 - undo redo actions should be created after
3335         * the source viewer is initialized, so that the undo manager
3336         * can obtain its undo context from its document.
3337         */

3338        createUndoRedoActions();
3339
3340        JFaceResources.getFontRegistry().addListener(fFontPropertyChangeListener);
3341        
3342        IVerticalRuler ruler= getVerticalRuler();
3343        if (ruler instanceof CompositeRuler)
3344            updateContributedRulerColumns((CompositeRuler) ruler);
3345        
3346        IInformationControlCreator informationControlCreator= new IInformationControlCreator() {
3347            public IInformationControl createInformationControl(Shell shell) {
3348                boolean cutDown= false;
3349                int style= cutDown ? SWT.NONE : (SWT.V_SCROLL | SWT.H_SCROLL);
3350                return new DefaultInformationControl(shell, SWT.RESIZE | SWT.TOOL, style, new HTMLTextPresenter(cutDown));
3351            }
3352        };
3353        
3354        fInformationPresenter= new InformationPresenter(informationControlCreator);
3355        fInformationPresenter.setSizeConstraints(60, 10, true, true);
3356        fInformationPresenter.install(getSourceViewer());
3357        fInformationPresenter.setDocumentPartitioning(getSourceViewerConfiguration().getConfiguredDocumentPartitioning(getSourceViewer()));
3358        
3359    }
3360    
3361    /**
3362     * Installs text drag and drop on the given source viewer.
3363     *
3364     * @param viewer the viewer
3365     * @since 3.3
3366     */

3367    protected void installTextDragAndDrop(final ISourceViewer viewer) {
3368        if (fIsTextDragAndDropEnabled || viewer == null)
3369            return;
3370        
3371        if (fIsTextDragAndDropInstalled) {
3372            fIsTextDragAndDropEnabled= true;
3373            return;
3374        }
3375        
3376        final IDragAndDropService dndService= (IDragAndDropService)getSite().getService(IDragAndDropService.class);
3377        if (dndService == null)
3378            return;
3379
3380        fIsTextDragAndDropEnabled= true;
3381        
3382        final StyledText st= viewer.getTextWidget();
3383        
3384        // Install drag source
3385
final ISelectionProvider selectionProvider= viewer.getSelectionProvider();
3386        final DragSource source= new DragSource(st, DND.DROP_COPY | DND.DROP_MOVE);
3387        source.setTransfer(new Transfer[] {TextTransfer.getInstance()});
3388        source.addDragListener(new DragSourceAdapter() {
3389            String JavaDoc fSelectedText;
3390            Point fSelection;
3391            public void dragStart(DragSourceEvent event) {
3392                fTextDragAndDropToken= null;
3393                
3394                // XXX: This is only a workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=162192
3395
if (!fIsTextDragAndDropEnabled) {
3396                    event.doit= false;
3397                    event.image= null;
3398                    return;
3399                }
3400                
3401                try {
3402                    fSelection= st.getSelection();
3403                    int offset= st.getOffsetAtLocation(new Point(event.x, event.y));
3404                    Point p= st.getLocationAtOffset(offset);
3405                    if (p.x > event.x)
3406                        offset--;
3407                    event.doit= offset > fSelection.x && offset < fSelection.y;
3408
3409                    ISelection selection= selectionProvider.getSelection();
3410                    if (selection instanceof ITextSelection)
3411                        fSelectedText= ((ITextSelection)selection).getText();
3412                    else // fallback to widget
3413
fSelectedText= st.getSelectionText();
3414                } catch (IllegalArgumentException JavaDoc ex) {
3415                    event.doit= false;
3416                }
3417            }
3418            
3419            public void dragSetData(DragSourceEvent event) {
3420                event.data= fSelectedText;
3421                fTextDragAndDropToken= this; // Can be any non-null object
3422
}
3423            
3424            public void dragFinished(DragSourceEvent event) {
3425                try {
3426                    if (event.detail == DND.DROP_MOVE && validateEditorInputState()) {
3427                        Point newSelection= st.getSelection();
3428                        int length= fSelection.y - fSelection.x;
3429                        int delta= 0;
3430                        if (newSelection.x < fSelection.x)
3431                            delta= length;
3432                        st.replaceTextRange(fSelection.x + delta, length, ""); //$NON-NLS-1$
3433

3434                        if (fTextDragAndDropToken == null) {
3435                            // Move in same editor - end compound change
3436
IRewriteTarget target= (IRewriteTarget)getAdapter(IRewriteTarget.class);
3437                            if (target != null)
3438                                target.endCompoundChange();
3439                        }
3440                        
3441                    }
3442                } finally {
3443                    fTextDragAndDropToken= null;
3444                }
3445            }
3446        });
3447        
3448        // Install drag target
3449
DropTargetListener dropTargetListener= new DropTargetAdapter() {
3450            
3451            private Point fSelection;
3452            
3453            public void dragEnter(DropTargetEvent event) {
3454                fTextDragAndDropToken= null;
3455                fSelection= st.getSelection();
3456                
3457                // XXX: This is only a workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=162192
3458
if (!fIsTextDragAndDropEnabled) {
3459                    event.detail= DND.DROP_NONE;
3460                    event.feedback= DND.FEEDBACK_NONE;
3461                    return;
3462                }
3463
3464                if (event.detail == DND.DROP_DEFAULT)
3465                    event.detail= DND.DROP_MOVE;
3466            }
3467            
3468            public void dragOperationChanged(DropTargetEvent event) {
3469                if (!fIsTextDragAndDropEnabled) {
3470                    event.detail= DND.DROP_NONE;
3471                    event.feedback= DND.FEEDBACK_NONE;
3472                    return;
3473                }
3474                
3475                if (event.detail == DND.DROP_DEFAULT)
3476                    event.detail= DND.DROP_MOVE;
3477            }
3478            
3479            public void dragOver(DropTargetEvent event) {
3480                
3481                // XXX: This is only a workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=162192
3482
if (!fIsTextDragAndDropEnabled) {
3483                    event.feedback= DND.FEEDBACK_NONE;
3484                    return;
3485                }
3486                
3487                event.feedback |= DND.FEEDBACK_SCROLL;
3488            }
3489            
3490            public void drop(DropTargetEvent event) {
3491                try {
3492                    if (!fIsTextDragAndDropEnabled)
3493                        return;
3494    
3495                    if (fTextDragAndDropToken != null && event.detail == DND.DROP_MOVE) {
3496                        // Move in same editor
3497
int caretOffset= st.getCaretOffset();
3498                        if (fSelection.x <= caretOffset && caretOffset <= fSelection.y) {
3499                            event.detail= DND.DROP_NONE;
3500                            return;
3501                        }
3502                        
3503                        // Start compound change
3504
IRewriteTarget target= (IRewriteTarget)getAdapter(IRewriteTarget.class);
3505                        if (target != null)
3506                            target.beginCompoundChange();
3507                    }
3508                    
3509                    if (!validateEditorInputState()) {
3510                        event.detail= DND.DROP_NONE;
3511                        return;
3512                    }
3513                    
3514                    String JavaDoc text= (String JavaDoc)event.data;
3515                    Point newSelection= st.getSelection();
3516                    try {
3517                        int modelOffset= widgetOffset2ModelOffset(viewer, newSelection.x);
3518                        viewer.getDocument().replace(modelOffset, 0, text);
3519                    } catch (BadLocationException e) {
3520                        return;
3521                    }
3522                    st.setSelectionRange(newSelection.x, text.length());
3523                } finally {
3524                    fTextDragAndDropToken= null;
3525                }
3526            }
3527        };
3528        dndService.addMergedDropTarget(st, DND.DROP_MOVE | DND.DROP_COPY, new Transfer[] {TextTransfer.getInstance()}, dropTargetListener);
3529
3530        fIsTextDragAndDropInstalled= true;
3531        fIsTextDragAndDropEnabled= true;
3532    }
3533
3534    /**
3535     * Uninstalls text drag and drop from the given source viewer.
3536     *
3537     * @param viewer the viewer
3538     * @since 3.3
3539     */

3540    protected void uninstallTextDragAndDrop(ISourceViewer viewer) {
3541        fIsTextDragAndDropEnabled= false;
3542    }
3543    
3544    /**
3545     * Tells whether the editor input should be included when adding object
3546     * contributions to this editor's context menu.
3547     * <p>
3548     * This implementation always returns <code>true</code>.
3549     * </p>
3550     *
3551     * @return <code>true</code> if the editor input should be considered
3552     * @since 3.2
3553     */

3554    protected boolean isEditorInputIncludedInContextMenu() {
3555        return true;
3556    }
3557
3558    /**
3559     * Initializes the activation code trigger.
3560     *
3561     * @since 2.1
3562     */

3563    private void initializeActivationCodeTrigger() {
3564        fActivationCodeTrigger.install();
3565        fActivationCodeTrigger.setScopes(fKeyBindingScopes);
3566    }
3567
3568    /**
3569     * Initializes the given viewer's font.
3570     *
3571     * @param viewer the viewer
3572     * @since 2.0
3573     */

3574    private void initializeViewerFont(ISourceViewer viewer) {
3575
3576        boolean isSharedFont= true;
3577        Font font= null;
3578        String JavaDoc symbolicFontName= getSymbolicFontName();
3579
3580        if (symbolicFontName != null)
3581            font= JFaceResources.getFont(symbolicFontName);
3582        else if (fPreferenceStore != null) {
3583            // Backward compatibility
3584
if (fPreferenceStore.contains(JFaceResources.TEXT_FONT) && !fPreferenceStore.isDefault(JFaceResources.TEXT_FONT)) {
3585                FontData data= PreferenceConverter.getFontData(fPreferenceStore, JFaceResources.TEXT_FONT);
3586
3587                if (data != null) {
3588                    isSharedFont= false;
3589                    font= new Font(viewer.getTextWidget().getDisplay(), data);
3590                }
3591            }
3592        }
3593        if (font == null)
3594            font= JFaceResources.getTextFont();
3595
3596        setFont(viewer, font);
3597
3598        if (fFont != null) {
3599            fFont.dispose();
3600            fFont= null;
3601        }
3602
3603        if (!isSharedFont)
3604            fFont= font;
3605    }
3606
3607    /**
3608     * Sets the font for the given viewer sustaining selection and scroll position.
3609     *
3610     * @param sourceViewer the source viewer
3611     * @param font the font
3612     * @since 2.0
3613     */

3614    private void setFont(ISourceViewer sourceViewer, Font font) {
3615        if (sourceViewer.getDocument() != null) {
3616
3617            Point selection= sourceViewer.getSelectedRange();
3618            int topIndex= sourceViewer.getTopIndex();
3619
3620            StyledText styledText= sourceViewer.getTextWidget();
3621            Control parent= styledText;
3622            if (sourceViewer instanceof ITextViewerExtension) {
3623                ITextViewerExtension extension= (ITextViewerExtension) sourceViewer;
3624                parent= extension.getControl();
3625            }
3626
3627            parent.setRedraw(false);
3628
3629            styledText.setFont(font);
3630
3631            if (fVerticalRuler instanceof IVerticalRulerExtension) {
3632                IVerticalRulerExtension e= (IVerticalRulerExtension) fVerticalRuler;
3633                e.setFont(font);
3634            }
3635
3636            sourceViewer.setSelectedRange(selection.x , selection.y);
3637            sourceViewer.setTopIndex(topIndex);
3638
3639            if (parent instanceof Composite) {
3640                Composite composite= (Composite) parent;
3641                composite.layout(true);
3642            }
3643
3644            parent.setRedraw(true);
3645
3646
3647        } else {
3648
3649            StyledText styledText= sourceViewer.getTextWidget();
3650            styledText.setFont(font);
3651
3652            if (fVerticalRuler instanceof IVerticalRulerExtension) {
3653                IVerticalRulerExtension e= (IVerticalRulerExtension) fVerticalRuler;
3654                e.setFont(font);
3655            }
3656        }
3657    }
3658
3659    /**
3660     * Creates a color from the information stored in the given preference store.
3661     * Returns <code>null</code> if there is no such information available.
3662     *
3663     * @param store the store to read from
3664     * @param key the key used for the lookup in the preference store
3665     * @param display the display used create the color
3666     * @return the created color according to the specification in the preference store
3667     * @since 2.0
3668     */

3669    private Color createColor(IPreferenceStore store, String JavaDoc key, Display display) {
3670
3671        RGB rgb= null;
3672
3673        if (store.contains(key)) {
3674
3675            if (store.isDefault(key))
3676                rgb= PreferenceConverter.getDefaultColor(store, key);
3677            else
3678                rgb= PreferenceConverter.getColor(store, key);
3679
3680            if (rgb != null)
3681                return new Color(display, rgb);
3682        }
3683
3684        return null;
3685    }
3686
3687    /**
3688     * Initializes the fore- and background colors of the given viewer for both
3689     * normal and selected text.
3690     *
3691     * @param viewer the viewer to be initialized
3692     * @since 2.0
3693     */

3694    protected void initializeViewerColors(ISourceViewer viewer) {
3695
3696        IPreferenceStore store= getPreferenceStore();
3697        if (store != null) {
3698
3699            StyledText styledText= viewer.getTextWidget();
3700
3701            // ----------- foreground color --------------------
3702
Color color= store.getBoolean(PREFERENCE_COLOR_FOREGROUND_SYSTEM_DEFAULT)
3703                ? null
3704                : createColor(store, PREFERENCE_COLOR_FOREGROUND, styledText.getDisplay());
3705            styledText.setForeground(color);
3706
3707            if (fForegroundColor != null)
3708                fForegroundColor.dispose();
3709
3710            fForegroundColor= color;
3711
3712            // ---------- background color ----------------------
3713
color= store.getBoolean(PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT)
3714                ? null
3715                : createColor(store, PREFERENCE_COLOR_BACKGROUND, styledText.getDisplay());
3716            styledText.setBackground(color);
3717
3718            if (fBackgroundColor != null)
3719                fBackgroundColor.dispose();
3720
3721            fBackgroundColor= color;
3722
3723            // ----------- selection foreground color --------------------
3724
color= store.getBoolean(PREFERENCE_COLOR_SELECTION_FOREGROUND_SYSTEM_DEFAULT)
3725                ? null
3726                : createColor(store, PREFERENCE_COLOR_SELECTION_FOREGROUND, styledText.getDisplay());
3727            styledText.setSelectionForeground(color);
3728
3729            if (fSelectionForegroundColor != null)
3730                fSelectionForegroundColor.dispose();
3731
3732            fSelectionForegroundColor= color;
3733
3734            // ---------- selection background color ----------------------
3735
color= store.getBoolean(PREFERENCE_COLOR_SELECTION_BACKGROUND_SYSTEM_DEFAULT)
3736                ? null
3737                : createColor(store, PREFERENCE_COLOR_SELECTION_BACKGROUND, styledText.getDisplay());
3738            styledText.setSelectionBackground(color);
3739
3740            if (fSelectionBackgroundColor != null)
3741                fSelectionBackgroundColor.dispose();
3742
3743            fSelectionBackgroundColor= color;
3744        }
3745    }
3746
3747    /**
3748     * Initializes the background color used for highlighting the document ranges
3749     * defining search scopes.
3750     *
3751     * @param viewer the viewer to initialize
3752     * @since 2.0
3753     */

3754    private void initializeFindScopeColor(ISourceViewer viewer) {
3755
3756        IPreferenceStore store= getPreferenceStore();
3757        if (store != null) {
3758
3759            StyledText styledText= viewer.getTextWidget();
3760
3761            Color color= createColor(store, PREFERENCE_COLOR_FIND_SCOPE, styledText.getDisplay());
3762
3763            IFindReplaceTarget target= viewer.getFindReplaceTarget();
3764            if (target != null && target instanceof IFindReplaceTargetExtension)
3765                ((IFindReplaceTargetExtension) target).setScopeHighlightColor(color);
3766
3767            if (fFindScopeHighlightColor != null)
3768                fFindScopeHighlightColor.dispose();
3769
3770            fFindScopeHighlightColor= color;
3771        }
3772    }
3773
3774
3775    /**
3776     * Initializes the editor's source viewer based on the given editor input.
3777     *
3778     * @param input the editor input to be used to initialize the source viewer
3779     */

3780    private void initializeSourceViewer(IEditorInput input) {
3781
3782        IAnnotationModel model= getDocumentProvider().getAnnotationModel(input);
3783        IDocument document= getDocumentProvider().getDocument(input);
3784
3785        if (document != null) {
3786            fSourceViewer.setDocument(document, model);
3787            fSourceViewer.setEditable(isEditable());
3788            fSourceViewer.showAnnotations(model != null);
3789        }
3790
3791        if (fElementStateListener instanceof IElementStateListenerExtension) {
3792            IElementStateListenerExtension extension= (IElementStateListenerExtension) fElementStateListener;
3793            extension.elementStateValidationChanged(input, false);
3794        }
3795
3796        if (fInitialCaret == null)
3797            fInitialCaret= fSourceViewer.getTextWidget().getCaret();
3798
3799        if (fIsOverwriting)
3800            fSourceViewer.getTextWidget().invokeAction(ST.TOGGLE_OVERWRITE);
3801        handleInsertModeChanged();
3802        
3803        if (isTabsToSpacesConversionEnabled())
3804            installTabsToSpacesConverter();
3805        
3806    }
3807
3808    /**
3809     * Initializes the editor's title based on the given editor input.
3810     *
3811     * @param input the editor input to be used
3812     */

3813    private void initializeTitle(IEditorInput input) {
3814
3815        Image oldImage= fTitleImage;
3816        fTitleImage= null;
3817        String JavaDoc title= ""; //$NON-NLS-1$
3818

3819        if (input != null) {
3820            IEditorRegistry editorRegistry= PlatformUI.getWorkbench().getEditorRegistry();
3821            IEditorDescriptor editorDesc= editorRegistry.findEditor(getSite().getId());
3822            ImageDescriptor imageDesc= editorDesc != null ? editorDesc.getImageDescriptor() : null;
3823
3824            fTitleImage= imageDesc != null ? imageDesc.createImage() : null;
3825            title= input.getName();
3826        }
3827
3828        setTitleImage(fTitleImage);
3829        setPartName(title);
3830
3831        firePropertyChange(PROP_DIRTY);
3832
3833        if (oldImage != null && !oldImage.isDisposed())
3834            oldImage.dispose();
3835    }
3836
3837    /**
3838     * Hook method for setting the document provider for the given input.
3839     * This default implementation does nothing. Clients may
3840     * reimplement.
3841     *
3842     * @param input the input of this editor.
3843     * @since 3.0
3844     */

3845    protected void setDocumentProvider(IEditorInput input) {
3846    }
3847
3848    /**
3849     * If there is no explicit document provider set, the implicit one is
3850     * re-initialized based on the given editor input.
3851     *
3852     * @param input the editor input.
3853     */

3854    private void updateDocumentProvider(IEditorInput input) {
3855
3856        IProgressMonitor rememberedProgressMonitor= null;
3857
3858        IDocumentProvider provider= getDocumentProvider();
3859        if (provider != null) {
3860            provider.removeElementStateListener(fElementStateListener);
3861            if (provider instanceof IDocumentProviderExtension2) {
3862                IDocumentProviderExtension2 extension= (IDocumentProviderExtension2) provider;
3863                rememberedProgressMonitor= extension.getProgressMonitor();
3864                extension.setProgressMonitor(null);
3865            }
3866        }
3867
3868        setDocumentProvider(input);
3869
3870        provider= getDocumentProvider();
3871        if (provider != null) {
3872            provider.addElementStateListener(fElementStateListener);
3873            if (provider instanceof IDocumentProviderExtension2) {
3874                IDocumentProviderExtension2 extension= (IDocumentProviderExtension2) provider;
3875                extension.setProgressMonitor(rememberedProgressMonitor);
3876            }
3877        }
3878    }
3879
3880    /**
3881     * Called directly from <code>setInput</code> and from within a workspace
3882     * runnable from <code>init</code>, this method does the actual setting
3883     * of the editor input. Closes the editor if <code>input</code> is
3884     * <code>null</code>. Disconnects from any previous editor input and its
3885     * document provider and connects to the new one.
3886     * <p>
3887     * Subclasses may extend.
3888     * </p>
3889     *
3890     * @param input the input to be set
3891     * @exception CoreException if input cannot be connected to the document
3892     * provider
3893     */

3894    protected void doSetInput(IEditorInput input) throws CoreException {
3895        ISaveablesLifecycleListener listener= (ISaveablesLifecycleListener)getSite().getService(ISaveablesLifecycleListener.class);
3896        if (listener == null)
3897            fSavable= null;
3898        
3899        if (input == null) {
3900            close(isSaveOnCloseNeeded());
3901            
3902            if (fSavable != null) {
3903                listener.handleLifecycleEvent(new SaveablesLifecycleEvent(this, SaveablesLifecycleEvent.POST_CLOSE, getSaveables(), false));
3904                fSavable.disconnectEditor();
3905                fSavable= null;
3906            }
3907            
3908        } else {
3909            boolean mustSendLifeCycleEvent= false;
3910            if (fSavable != null) {
3911                listener.handleLifecycleEvent(new SaveablesLifecycleEvent(this, SaveablesLifecycleEvent.POST_CLOSE, getSaveables(), false));
3912                fSavable.disconnectEditor();
3913                fSavable= null;
3914                mustSendLifeCycleEvent= true;
3915            }
3916
3917            IEditorInput oldInput= getEditorInput();
3918            if (oldInput != null)
3919                getDocumentProvider().disconnect(oldInput);
3920
3921            super.setInput(input);
3922
3923            updateDocumentProvider(input);
3924
3925            IDocumentProvider provider= getDocumentProvider();
3926            if (provider == null) {
3927                IStatus s= new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, IStatus.OK, EditorMessages.Editor_error_no_provider, null);
3928                throw new CoreException(s);
3929            }
3930
3931            provider.connect(input);
3932
3933            initializeTitle(input);
3934
3935            if (fSourceViewer != null) {
3936                initializeSourceViewer(input);
3937
3938                // Reset the undo context for the undo and redo action handlers
3939
IAction undoAction= getAction(ITextEditorActionConstants.UNDO);
3940                IAction redoAction= getAction(ITextEditorActionConstants.REDO);
3941                boolean areOperationActionHandlersInstalled= undoAction instanceof OperationHistoryActionHandler && redoAction instanceof OperationHistoryActionHandler;
3942                IUndoContext undoContext= getUndoContext();
3943                if (undoContext != null && areOperationActionHandlersInstalled) {
3944                    ((OperationHistoryActionHandler)undoAction).setContext(undoContext);
3945                    ((OperationHistoryActionHandler)redoAction).setContext(undoContext);
3946                } else {
3947                    createUndoRedoActions();
3948                }
3949            }
3950
3951            if (fIsOverwriting)
3952                toggleOverwriteMode();
3953            setInsertMode((InsertMode) getLegalInsertModes().get(0));
3954            updateCaret();
3955
3956            updateStatusField(ITextEditorActionConstants.STATUS_CATEGORY_ELEMENT_STATE);
3957
3958            if (fSelectionListener != null)
3959                fSelectionListener.setDocument(getDocumentProvider().getDocument(input));
3960            
3961            IVerticalRuler ruler= getVerticalRuler();
3962            if (ruler instanceof CompositeRuler)
3963                updateContributedRulerColumns((CompositeRuler) ruler);
3964            
3965            // Send savable life-cycle if needed.
3966
if (mustSendLifeCycleEvent && listener != null)
3967                listener.handleLifecycleEvent(new SaveablesLifecycleEvent(this, SaveablesLifecycleEvent.POST_OPEN, getSaveables(), false));
3968            
3969        }
3970        
3971    }
3972
3973    /**
3974     * Returns this editor's viewer's undo manager undo context.
3975     *
3976     * @return the undo context or <code>null</code> if not available
3977     * @since 3.1
3978     */

3979    private IUndoContext getUndoContext() {
3980        if (fSourceViewer instanceof ITextViewerExtension6) {
3981            IUndoManager undoManager= ((ITextViewerExtension6)fSourceViewer).getUndoManager();
3982            if (undoManager instanceof IUndoManagerExtension)
3983                return ((IUndoManagerExtension)undoManager).getUndoContext();
3984        }
3985        return null;
3986    }
3987    
3988    /*
3989     * @see org.eclipse.ui.part.EditorPart#setInputWithNotify(org.eclipse.ui.IEditorInput)
3990     * @since 3.2
3991     */

3992    protected final void setInputWithNotify(IEditorInput input) {
3993        try {
3994
3995            doSetInput(input);
3996
3997            /*
3998             * The following bugs explain why we fire this property change:
3999             * https://bugs.eclipse.org/bugs/show_bug.cgi?id=90283
4000             * https://bugs.eclipse.org/bugs/show_bug.cgi?id=92049
4001             * https://bugs.eclipse.org/bugs/show_bug.cgi?id=92286
4002             */

4003            firePropertyChange(IEditorPart.PROP_INPUT);
4004
4005        } catch (CoreException x) {
4006            String JavaDoc title= EditorMessages.Editor_error_setinput_title;
4007            String JavaDoc msg= EditorMessages.Editor_error_setinput_message;
4008            Shell shell= getSite().getShell();
4009            ErrorDialog.openError(shell, title, msg, x.getStatus());
4010        }
4011    }
4012    
4013    /*
4014     * @see EditorPart#setInput(org.eclipse.ui.IEditorInput)
4015     */

4016    public final void setInput(IEditorInput input) {
4017        setInputWithNotify(input);
4018    }
4019    
4020    /*
4021     * @see ITextEditor#close
4022     */

4023    public void close(final boolean save) {
4024
4025        enableSanityChecking(false);
4026
4027        Display display= getSite().getShell().getDisplay();
4028        display.asyncExec(new Runnable JavaDoc() {
4029            public void run() {
4030                if (fSourceViewer != null)
4031                    getSite().getPage().closeEditor(AbstractTextEditor.this, save);
4032            }
4033        });
4034    }
4035
4036    /**
4037     * The <code>AbstractTextEditor</code> implementation of this
4038     * <code>IWorkbenchPart</code> method may be extended by subclasses.
4039     * Subclasses must call <code>super.dispose()</code>.
4040     * <p>
4041     * Note that many methods may return <code>null</code> after the editor is
4042     * disposed.
4043     * </p>
4044     */

4045    public void dispose() {
4046
4047        if (fActivationListener != null) {
4048            fActivationListener.dispose();
4049            fActivationListener= null;
4050        }
4051
4052        if (fTitleImage != null) {
4053            fTitleImage.dispose();
4054            fTitleImage= null;
4055        }
4056
4057        if (fFont != null) {
4058            fFont.dispose();
4059            fFont= null;
4060        }
4061
4062        disposeNonDefaultCaret();
4063        fInitialCaret= null;
4064
4065        if (fForegroundColor != null) {
4066            fForegroundColor.dispose();
4067            fForegroundColor= null;
4068        }
4069
4070        if (fBackgroundColor != null) {
4071            fBackgroundColor.dispose();
4072            fBackgroundColor= null;
4073        }
4074
4075        if (fSelectionForegroundColor != null) {
4076            fSelectionForegroundColor.dispose();
4077            fSelectionForegroundColor= null;
4078        }
4079
4080        if (fSelectionBackgroundColor != null) {
4081            fSelectionBackgroundColor.dispose();
4082            fSelectionBackgroundColor= null;
4083        }
4084
4085        if (fFindScopeHighlightColor != null) {
4086            fFindScopeHighlightColor.dispose();
4087            fFindScopeHighlightColor= null;
4088        }
4089
4090        if (fFontPropertyChangeListener != null) {
4091            JFaceResources.getFontRegistry().removeListener(fFontPropertyChangeListener);
4092            fFontPropertyChangeListener= null;
4093        }
4094
4095        if (fPropertyChangeListener != null) {
4096            if (fPreferenceStore != null) {
4097                fPreferenceStore.removePropertyChangeListener(fPropertyChangeListener);
4098                fPreferenceStore= null;
4099            }
4100            fPropertyChangeListener= null;
4101        }
4102
4103        if (fActivationCodeTrigger != null) {
4104            fActivationCodeTrigger.uninstall();
4105            fActivationCodeTrigger= null;
4106        }
4107
4108        if (fSelectionListener != null) {
4109            fSelectionListener.uninstall(getSelectionProvider());
4110            fSelectionListener= null;
4111        }
4112
4113        if (fSavable != null) {
4114            fSavable.disconnectEditor();
4115            fSavable= null;
4116        }
4117        
4118        disposeDocumentProvider();
4119
4120        if (fSourceViewer != null) {
4121
4122            if (fTextListener != null) {
4123                fSourceViewer.removeTextListener(fTextListener);
4124                fSourceViewer.removeTextInputListener(fTextListener);
4125                fTextListener= null;
4126            }
4127
4128            uninstallTabsToSpacesConverter();
4129
4130            fTextInputListener= null;
4131            fSelectionProvider= null;
4132            fSourceViewer= null;
4133        }
4134
4135        if (fTextContextMenu != null) {
4136            fTextContextMenu.dispose();
4137            fTextContextMenu= null;
4138        }
4139
4140        if (fRulerContextMenu != null) {
4141            fRulerContextMenu.dispose();
4142            fRulerContextMenu= null;
4143        }
4144
4145        if (fActions != null) {
4146            fActions.clear();
4147            fActions= null;
4148        }
4149
4150        if (fSelectionActions != null) {
4151            fSelectionActions.clear();
4152            fSelectionActions= null;
4153        }
4154
4155        if (fContentActions != null) {
4156            fContentActions.clear();
4157            fContentActions= null;
4158        }
4159
4160        if (fPropertyActions != null) {
4161            fPropertyActions.clear();
4162            fPropertyActions= null;
4163        }
4164
4165        if (fStateActions != null) {
4166            fStateActions.clear();
4167            fStateActions= null;
4168        }
4169
4170        if (fActivationCodes != null) {
4171            fActivationCodes.clear();
4172            fActivationCodes= null;
4173        }
4174
4175        if (fEditorStatusLine != null)
4176            fEditorStatusLine= null;
4177
4178        if (fConfiguration != null)
4179            fConfiguration= null;
4180
4181        if (fColumnSupport != null) {
4182            fColumnSupport.dispose();
4183            fColumnSupport= null;
4184        }
4185
4186        if (fVerticalRuler != null)
4187            fVerticalRuler= null;
4188
4189        IOperationHistory history= OperationHistoryFactory.getOperationHistory();
4190        if (history != null) {
4191            if (fNonLocalOperationApprover != null)
4192                history.removeOperationApprover(fNonLocalOperationApprover);
4193            if (fLinearUndoViolationApprover != null)
4194                history.removeOperationApprover(fLinearUndoViolationApprover);
4195        }
4196        fNonLocalOperationApprover= null;
4197        fLinearUndoViolationApprover= null;
4198        
4199        super.dispose();
4200    }
4201
4202    /**
4203     * Disposes of the connection with the document provider. Subclasses
4204     * may extend.
4205     *
4206     * @since 3.0
4207     */

4208    protected void disposeDocumentProvider() {
4209        IDocumentProvider provider= getDocumentProvider();
4210        if (provider != null) {
4211
4212            IEditorInput input= getEditorInput();
4213            if (input != null)
4214                provider.disconnect(input);
4215
4216            if (fElementStateListener != null) {
4217                provider.removeElementStateListener(fElementStateListener);
4218                fElementStateListener= null;
4219            }
4220
4221        }
4222        fExplicitDocumentProvider= null;
4223    }
4224
4225    /**
4226     * Determines whether the given preference change affects the editor's
4227     * presentation. This implementation always returns <code>false</code>.
4228     * May be reimplemented by subclasses.
4229     *
4230     * @param event the event which should be investigated
4231     * @return <code>true</code> if the event describes a preference change affecting the editor's presentation
4232     * @since 2.0
4233     */

4234    protected boolean affectsTextPresentation(PropertyChangeEvent event) {
4235        return false;
4236    }
4237
4238    /**
4239     * Returns the symbolic font name for this editor as defined in XML.
4240     *
4241     * @return a String with the symbolic font name or <code>null</code> if
4242     * none is defined
4243     * @since 2.1
4244     */

4245    private String JavaDoc getSymbolicFontName() {
4246        if (getConfigurationElement() != null)
4247            return getConfigurationElement().getAttribute("symbolicFontName"); //$NON-NLS-1$
4248
return null;
4249    }
4250
4251    /**
4252     * Returns the property preference key for the editor font. Subclasses may
4253     * replace this method.
4254     *
4255     * @return a String with the key
4256     * @since 2.1
4257     */

4258    protected final String JavaDoc getFontPropertyPreferenceKey() {
4259        String JavaDoc symbolicFontName= getSymbolicFontName();
4260        if (symbolicFontName != null)
4261            return symbolicFontName;
4262        return JFaceResources.TEXT_FONT;
4263    }
4264
4265    /**
4266     * Handles a property change event describing a change of the editor's
4267     * preference store and updates the preference related editor properties.
4268     * <p>
4269     * Subclasses may extend.
4270     * </p>
4271     *
4272     * @param event the property change event
4273     */

4274    protected void handlePreferenceStoreChanged(PropertyChangeEvent event) {
4275
4276        if (fSourceViewer == null)
4277            return;
4278
4279        String JavaDoc property= event.getProperty();
4280
4281        if (getFontPropertyPreferenceKey().equals(property))
4282            // There is a separate handler for font preference changes
4283
return;
4284
4285        if (PREFERENCE_COLOR_FOREGROUND.equals(property) || PREFERENCE_COLOR_FOREGROUND_SYSTEM_DEFAULT.equals(property) ||
4286                PREFERENCE_COLOR_BACKGROUND.equals(property) || PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT.equals(property) ||
4287                PREFERENCE_COLOR_SELECTION_FOREGROUND.equals(property) || PREFERENCE_COLOR_SELECTION_FOREGROUND_SYSTEM_DEFAULT.equals(property) ||
4288                PREFERENCE_COLOR_SELECTION_BACKGROUND.equals(property) || PREFERENCE_COLOR_SELECTION_BACKGROUND_SYSTEM_DEFAULT.equals(property))
4289        {
4290            initializeViewerColors(fSourceViewer);
4291        } else if (PREFERENCE_COLOR_FIND_SCOPE.equals(property)) {
4292            initializeFindScopeColor(fSourceViewer);
4293        } else if (PREFERENCE_USE_CUSTOM_CARETS.equals(property)) {
4294            updateCaret();
4295        } else if (PREFERENCE_WIDE_CARET.equals(property)) {
4296            updateCaret();
4297        }
4298
4299        if (affectsTextPresentation(event))
4300            fSourceViewer.invalidateTextPresentation();
4301
4302        if (PREFERENCE_HYPERLINKS_ENABLED.equals(property)) {
4303            if (fSourceViewer instanceof ITextViewerExtension6) {
4304                IHyperlinkDetector[] detectors= getSourceViewerConfiguration().getHyperlinkDetectors(fSourceViewer);
4305                int stateMask= getSourceViewerConfiguration().getHyperlinkStateMask(fSourceViewer);
4306                ITextViewerExtension6 textViewer6= (ITextViewerExtension6)fSourceViewer;
4307                textViewer6.setHyperlinkDetectors(detectors, stateMask);
4308            }
4309            return;
4310        }
4311
4312        if (PREFERENCE_HYPERLINK_KEY_MODIFIER.equals(property)) {
4313            if (fSourceViewer instanceof ITextViewerExtension6) {
4314                ITextViewerExtension6 textViewer6= (ITextViewerExtension6)fSourceViewer;
4315                IHyperlinkDetector[] detectors= getSourceViewerConfiguration().getHyperlinkDetectors(fSourceViewer);
4316                int stateMask= getSourceViewerConfiguration().getHyperlinkStateMask(fSourceViewer);
4317                textViewer6.setHyperlinkDetectors(detectors, stateMask);
4318            }
4319            return;
4320        }
4321        
4322        if (PREFERENCE_RULER_CONTRIBUTIONS.equals(property)) {
4323            String JavaDoc[] difference= StringSetSerializer.getDifference((String JavaDoc) event.getOldValue(), (String JavaDoc) event.getNewValue());
4324            IColumnSupport support= (IColumnSupport) getAdapter(IColumnSupport.class);
4325            for (int i= 0; i < difference.length; i++) {
4326                RulerColumnDescriptor desc= RulerColumnRegistry.getDefault().getColumnDescriptor(difference[i]);
4327                if (desc != null && support.isColumnSupported(desc)) {
4328                    boolean newState= !support.isColumnVisible(desc);
4329                    support.setColumnVisible(desc, newState);
4330                }
4331            }
4332            return;
4333        }
4334        
4335        if (PREFERENCE_SHOW_WHITESPACE_CHARACTERS.equals(property)) {
4336            IAction action= getAction(ITextEditorActionConstants.SHOW_WHITESPACE_CHARACTERS);
4337            if (action instanceof IUpdate)
4338                ((IUpdate)action).update();
4339            return;
4340        }
4341        
4342        if (PREFERENCE_TEXT_DRAG_AND_DROP_ENABLED.equals(property)) {
4343            IPreferenceStore store= getPreferenceStore();
4344            if (store != null && store.getBoolean(PREFERENCE_TEXT_DRAG_AND_DROP_ENABLED))
4345                installTextDragAndDrop(getSourceViewer());
4346            else
4347                uninstallTextDragAndDrop(getSourceViewer());
4348            return;
4349        }
4350        
4351    }
4352
4353    /**
4354     * Returns the progress monitor related to this editor. It should not be
4355     * necessary to extend this method.
4356     *
4357     * @return the progress monitor related to this editor
4358     * @since 2.1
4359     */

4360    protected IProgressMonitor getProgressMonitor() {
4361
4362        IProgressMonitor pm= null;
4363
4364        IStatusLineManager manager= getStatusLineManager();
4365        if (manager != null)
4366            pm= manager.getProgressMonitor();
4367
4368        return pm != null ? pm : new NullProgressMonitor();
4369    }
4370
4371    /**
4372     * Handles an external change of the editor's input element. Subclasses may
4373     * extend.
4374     */

4375    protected void handleEditorInputChanged() {
4376
4377        String JavaDoc title;
4378        String JavaDoc msg;
4379        Shell shell= getSite().getShell();
4380
4381        final IDocumentProvider provider= getDocumentProvider();
4382        if (provider == null) {
4383            // fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=15066
4384
close(false);
4385            return;
4386        }
4387
4388        final IEditorInput input= getEditorInput();
4389        if (provider.isDeleted(input)) {
4390
4391            if (isSaveAsAllowed()) {
4392
4393                title= EditorMessages.Editor_error_activated_deleted_save_title;
4394                msg= EditorMessages.Editor_error_activated_deleted_save_message;
4395
4396                String JavaDoc[] buttons= {
4397                        EditorMessages.Editor_error_activated_deleted_save_button_save,
4398                        EditorMessages.Editor_error_activated_deleted_save_button_close,
4399                };
4400
4401                MessageDialog dialog= new MessageDialog(shell, title, null, msg, MessageDialog.QUESTION, buttons, 0);
4402
4403                if (dialog.open() == 0) {
4404                    IProgressMonitor pm= getProgressMonitor();
4405                    performSaveAs(pm);
4406                    if (pm.isCanceled())
4407                        handleEditorInputChanged();
4408                } else {
4409                    close(false);
4410                }
4411
4412            } else {
4413
4414                title= EditorMessages.Editor_error_activated_deleted_close_title;
4415                msg= EditorMessages.Editor_error_activated_deleted_close_message;
4416                if (MessageDialog.openConfirm(shell, title, msg))
4417                    close(false);
4418            }
4419
4420        } else {
4421
4422            title= EditorMessages.Editor_error_activated_outofsync_title;
4423            msg= EditorMessages.Editor_error_activated_outofsync_message;
4424
4425            if (MessageDialog.openQuestion(shell, title, msg)) {
4426
4427
4428                try {
4429                    if (provider instanceof IDocumentProviderExtension) {
4430                        IDocumentProviderExtension extension= (IDocumentProviderExtension) provider;
4431                        extension.synchronize(input);
4432                    } else {
4433                        doSetInput(input);
4434                    }
4435                } catch (CoreException x) {
4436                    IStatus status= x.getStatus();
4437                    if (status == null || status.getSeverity() != IStatus.CANCEL) {
4438                        title= EditorMessages.Editor_error_refresh_outofsync_title;
4439                        msg= EditorMessages.Editor_error_refresh_outofsync_message;
4440                        ErrorDialog.openError(shell, title, msg, x.getStatus());
4441                    }
4442                }
4443            }
4444        }
4445    }
4446
4447    /**
4448     * The <code>AbstractTextEditor</code> implementation of this
4449     * <code>IEditorPart</code> method calls <code>performSaveAs</code>.
4450     * Subclasses may reimplement.
4451     */

4452    public void doSaveAs() {
4453        /*
4454         * 1GEUSSR: ITPUI:ALL - User should never loose changes made in the editors.
4455         * Changed Behavior to make sure that if called inside a regular save (because
4456         * of deletion of input element) there is a way to report back to the caller.
4457         */

4458        performSaveAs(getProgressMonitor());
4459    }
4460
4461    /**
4462     * Performs a save as and reports the result state back to the
4463     * given progress monitor. This default implementation does nothing.
4464     * Subclasses may reimplement.
4465     *
4466     * @param progressMonitor the progress monitor for communicating result state or <code>null</code>
4467     */

4468    protected void performSaveAs(IProgressMonitor progressMonitor) {
4469    }
4470
4471    /**
4472     * The <code>AbstractTextEditor</code> implementation of this
4473     * <code>IEditorPart</code> method may be extended by subclasses.
4474     *
4475     * @param progressMonitor the progress monitor for communicating result state or <code>null</code>
4476     */

4477    public void doSave(IProgressMonitor progressMonitor) {
4478
4479        IDocumentProvider p= getDocumentProvider();
4480        if (p == null)
4481            return;
4482
4483        if (p.isDeleted(getEditorInput())) {
4484
4485            if (isSaveAsAllowed()) {
4486
4487                /*
4488                 * 1GEUSSR: ITPUI:ALL - User should never loose changes made in the editors.
4489                 * Changed Behavior to make sure that if called inside a regular save (because
4490                 * of deletion of input element) there is a way to report back to the caller.
4491                 */

4492                performSaveAs(progressMonitor);
4493
4494            } else {
4495
4496                Shell shell= getSite().getShell();
4497                String JavaDoc title= EditorMessages.Editor_error_save_deleted_title;
4498                String JavaDoc msg= EditorMessages.Editor_error_save_deleted_message;
4499                MessageDialog.openError(shell, title, msg);
4500            }
4501
4502        } else {
4503            updateState(getEditorInput());
4504            validateState(getEditorInput());
4505            performSave(false, progressMonitor);
4506        }
4507    }
4508
4509    /**
4510     * Enables/disables sanity checking.
4511     * @param enable <code>true</code> if sanity checking should be enabled, <code>false</code> otherwise
4512     * @since 2.0
4513     */

4514    protected void enableSanityChecking(boolean enable) {
4515        synchronized (this) {
4516            fIsSanityCheckEnabled= enable;
4517        }
4518    }
4519
4520    /**
4521     * Checks the state of the given editor input if sanity checking is enabled.
4522     * @param input the editor input whose state is to be checked
4523     * @since 2.0
4524     */

4525    protected void safelySanityCheckState(IEditorInput input) {
4526        boolean enabled= false;
4527
4528        synchronized (this) {
4529            enabled= fIsSanityCheckEnabled;
4530        }
4531
4532        if (enabled)
4533            sanityCheckState(input);
4534    }
4535
4536    /**
4537     * Checks the state of the given editor input.
4538     * @param input the editor input whose state is to be checked
4539     * @since 2.0
4540     */

4541    protected void sanityCheckState(IEditorInput input) {
4542
4543        IDocumentProvider p= getDocumentProvider();
4544        if (p == null)
4545            return;
4546
4547        if (p instanceof IDocumentProviderExtension3) {
4548
4549            IDocumentProviderExtension3 p3= (IDocumentProviderExtension3) p;
4550
4551            long stamp= p.getModificationStamp(input);
4552            if (stamp != fModificationStamp) {
4553                fModificationStamp= stamp;
4554                if (!p3.isSynchronized(input))
4555                    handleEditorInputChanged();
4556            }
4557
4558        } else {
4559
4560            if (fModificationStamp == -1)
4561                fModificationStamp= p.getSynchronizationStamp(input);
4562
4563            long stamp= p.getModificationStamp(input);
4564            if (stamp != fModificationStamp) {
4565                fModificationStamp= stamp;
4566                if (stamp != p.getSynchronizationStamp(input))
4567                    handleEditorInputChanged();
4568            }
4569        }
4570
4571        updateState(getEditorInput());
4572        updateStatusField(ITextEditorActionConstants.STATUS_CATEGORY_ELEMENT_STATE);
4573    }
4574
4575    /**
4576     * Enables/disables state validation.
4577     * @param enable <code>true</code> if state validation should be enabled, <code>false</code> otherwise
4578     * @since 2.1
4579     */

4580    protected void enableStateValidation(boolean enable) {
4581        synchronized (this) {
4582            fIsStateValidationEnabled= enable;
4583        }
4584    }
4585
4586    /**
4587     * Validates the state of the given editor input. The predominate intent
4588     * of this method is to take any action probably necessary to ensure that
4589     * the input can persistently be changed.
4590     *
4591     * @param input the input to be validated
4592     * @since 2.0
4593     */

4594    protected void validateState(IEditorInput input) {
4595
4596        IDocumentProvider provider= getDocumentProvider();
4597        if (! (provider instanceof IDocumentProviderExtension))
4598            return;
4599
4600        IDocumentProviderExtension extension= (IDocumentProviderExtension) provider;
4601
4602        try {
4603
4604            extension.validateState(input, getSite().getShell());
4605
4606        } catch (CoreException x) {
4607            IStatus status= x.getStatus();
4608            if (status == null || status.getSeverity() != IStatus.CANCEL) {
4609                Bundle JavaDoc bundle= Platform.getBundle(PlatformUI.PLUGIN_ID);
4610                ILog log= Platform.getLog(bundle);
4611                log.log(x.getStatus());
4612
4613                Shell shell= getSite().getShell();
4614                String JavaDoc title= EditorMessages.Editor_error_validateEdit_title;
4615                String JavaDoc msg= EditorMessages.Editor_error_validateEdit_message;
4616                ErrorDialog.openError(shell, title, msg, x.getStatus());
4617            }
4618            return;
4619        }
4620
4621        if (fSourceViewer != null)
4622            fSourceViewer.setEditable(isEditable());
4623
4624        updateStateDependentActions();
4625    }
4626
4627    /*
4628     * @see org.eclipse.ui.texteditor.ITextEditorExtension2#validateEditorInputState()
4629     * @since 2.1
4630     */

4631    public boolean validateEditorInputState() {
4632
4633        boolean enabled= false;
4634
4635        synchronized (this) {
4636            enabled= fIsStateValidationEnabled;
4637        }
4638
4639        if (enabled) {
4640
4641            ISourceViewer viewer= fSourceViewer;
4642            if (viewer == null)
4643                return false;
4644
4645            fTextInputListener.inputChanged= false;
4646            viewer.addTextInputListener(fTextInputListener);
4647
4648            try {
4649                final IEditorInput input= getEditorInput();
4650                BusyIndicator.showWhile(getSite().getShell().getDisplay(), new Runnable JavaDoc() {
4651                    /*
4652                     * @see java.lang.Runnable#run()
4653                     */

4654                    public void run() {
4655                        validateState(input);
4656                    }
4657                });
4658                sanityCheckState(input);
4659                return !isEditorInputReadOnly() && !fTextInputListener.inputChanged;
4660
4661            } finally {
4662                viewer.removeTextInputListener(fTextInputListener);
4663            }
4664
4665        }
4666
4667        return !isEditorInputReadOnly();
4668    }
4669
4670    /**
4671     * Updates the state of the given editor input such as read-only flag.
4672     *
4673     * @param input the input to be validated
4674     * @since 2.0
4675     */

4676    protected void updateState(IEditorInput input) {
4677        IDocumentProvider provider= getDocumentProvider();
4678        if (provider instanceof IDocumentProviderExtension) {
4679            IDocumentProviderExtension extension= (IDocumentProviderExtension) provider;
4680            try {
4681
4682                boolean wasReadOnly= isEditorInputReadOnly();
4683                extension.updateStateCache(input);
4684
4685                if (fSourceViewer != null)
4686                    fSourceViewer.setEditable(isEditable());
4687
4688                if (wasReadOnly != isEditorInputReadOnly())
4689                    updateStateDependentActions();
4690
4691            } catch (CoreException x) {
4692                Bundle JavaDoc bundle= Platform.getBundle(PlatformUI.PLUGIN_ID);
4693                ILog log= Platform.getLog(bundle);
4694                log.log(x.getStatus());
4695            }
4696        }
4697    }
4698
4699    /**
4700     * Performs the save and handles errors appropriately.
4701     *
4702     * @param overwrite indicates whether or not overwriting is allowed
4703     * @param progressMonitor the monitor in which to run the operation
4704     * @since 3.0
4705     */

4706    protected void performSave(boolean overwrite, IProgressMonitor progressMonitor) {
4707
4708        IDocumentProvider provider= getDocumentProvider();
4709        if (provider == null)
4710            return;
4711
4712        try {
4713
4714            provider.aboutToChange(getEditorInput());
4715            IEditorInput input= getEditorInput();
4716            provider.saveDocument(progressMonitor, input, getDocumentProvider().getDocument(input), overwrite);
4717            editorSaved();
4718
4719        } catch (CoreException x) {
4720            IStatus status= x.getStatus();
4721            if (status == null || status.getSeverity() != IStatus.CANCEL)
4722                handleExceptionOnSave(x, progressMonitor);
4723        } finally {
4724            provider.changed(getEditorInput());
4725        }
4726    }
4727
4728    /**
4729     * Handles the given exception. If the exception reports an out-of-sync
4730     * situation, this is reported to the user. Otherwise, the exception
4731     * is generically reported.
4732     *
4733     * @param exception the exception to handle
4734     * @param progressMonitor the progress monitor
4735     */

4736    protected void handleExceptionOnSave(CoreException exception, IProgressMonitor progressMonitor) {
4737
4738        try {
4739            ++ fErrorCorrectionOnSave;
4740
4741            boolean isSynchronized= false;
4742            IDocumentProvider p= getDocumentProvider();
4743
4744            if (p instanceof IDocumentProviderExtension3) {
4745                IDocumentProviderExtension3 p3= (IDocumentProviderExtension3) p;
4746                isSynchronized= p3.isSynchronized(getEditorInput());
4747            } else {
4748                long modifiedStamp= p.getModificationStamp(getEditorInput());
4749                long synchStamp= p.getSynchronizationStamp(getEditorInput());
4750                isSynchronized= (modifiedStamp == synchStamp);
4751            }
4752
4753            if (isNotSynchronizedException(exception) && fErrorCorrectionOnSave == 1 && !isSynchronized) {
4754                String JavaDoc title= EditorMessages.Editor_error_save_outofsync_title;
4755                String JavaDoc msg= NLSUtility.format(EditorMessages.Editor_error_save_outofsync_message, getEditorInput().getToolTipText());
4756
4757                if (MessageDialog.openQuestion(getSite().getShell(), title, msg))
4758                    performSave(true, progressMonitor);
4759                else {
4760                    /*
4761                     * 1GEUPKR: ITPJUI:ALL - Loosing work with simultaneous edits
4762                     * Set progress monitor to canceled in order to report back
4763                     * to enclosing operations.
4764                     */

4765                    if (progressMonitor != null)
4766                        progressMonitor.setCanceled(true);
4767                }
4768            } else {
4769                String JavaDoc title= EditorMessages.Editor_error_save_title;
4770                String JavaDoc msg= EditorMessages.Editor_error_save_message;
4771                openSaveErrorDialog(title, msg, exception);
4772
4773                /*
4774                 * 1GEUPKR: ITPJUI:ALL - Loosing work with simultaneous edits
4775                 * Set progress monitor to canceled in order to report back
4776                 * to enclosing operations.
4777                 */

4778                if (progressMonitor != null)
4779                    progressMonitor.setCanceled(true);
4780            }
4781        } finally {
4782            -- fErrorCorrectionOnSave;
4783        }
4784    }
4785
4786    /**
4787     * Presents an error dialog to the user when a problem
4788     * happens during save.
4789     * <p>
4790     * Subclasses can decide to override the given title and message.
4791     * </p>
4792     *
4793     * @param title the dialog title
4794     * @param message the message to display
4795     * @param exception the exception to handle
4796     * @since 3.3
4797     */

4798    protected void openSaveErrorDialog(String JavaDoc title, String JavaDoc message, CoreException exception) {
4799        ErrorDialog.openError(getSite().getShell(), title, message, exception.getStatus());
4800    }
4801
4802    /**
4803     * Tells whether the given core exception is exactly the
4804     * exception which is thrown for a non-synchronized element.
4805     *
4806     * @param ex the core exception
4807     * @return <code>true</code> iff the given core exception is exactly the
4808     * exception which is thrown for a non-synchronized element
4809     * @since 3.1
4810     */

4811    private boolean isNotSynchronizedException(CoreException ex) {
4812        IDocumentProvider provider= getDocumentProvider();
4813        if (provider instanceof IDocumentProviderExtension5)
4814            return ((IDocumentProviderExtension5)provider).isNotSynchronizedException(getEditorInput(), ex);
4815        return false;
4816    }
4817
4818    /**
4819     * The <code>AbstractTextEditor</code> implementation of this
4820     * <code>IEditorPart</code> method returns <code>false</code>.
4821     * Subclasses may override.
4822     *
4823     * @return <code>false</code>
4824     */

4825    public boolean isSaveAsAllowed() {
4826        return false;
4827    }
4828
4829    /*
4830     * @see EditorPart#isDirty()
4831     */

4832    public boolean isDirty() {
4833        IDocumentProvider p= getDocumentProvider();
4834        return p == null ? false : p.canSaveDocument(getEditorInput());
4835    }
4836
4837    /**
4838     * The <code>AbstractTextEditor</code> implementation of this
4839     * <code>ITextEditor</code> method may be extended by subclasses.
4840     */

4841    public void doRevertToSaved() {
4842        IDocumentProvider p= getDocumentProvider();
4843        if (p == null)
4844            return;
4845
4846        performRevert();
4847    }
4848
4849    /**
4850     * Performs revert and handles errors appropriately.
4851     * <p>
4852     * Subclasses may extend.
4853     * </p>
4854     *
4855     * @since 3.0
4856     */

4857    protected void performRevert() {
4858
4859        IDocumentProvider provider= getDocumentProvider();
4860        if (provider == null)
4861            return;
4862
4863        try {
4864
4865            provider.aboutToChange(getEditorInput());
4866            provider.resetDocument(getEditorInput());
4867            editorSaved();
4868
4869        } catch (CoreException x) {
4870            IStatus status= x.getStatus();
4871            if (status == null || status.getSeverity() != IStatus.CANCEL ) {
4872                Shell shell= getSite().getShell();
4873                String JavaDoc title= EditorMessages.Editor_error_revert_title;
4874                String JavaDoc msg= EditorMessages.Editor_error_revert_message;
4875                ErrorDialog.openError(shell, title, msg, x.getStatus());
4876            }
4877        } finally {
4878            provider.changed(getEditorInput());
4879        }
4880    }
4881
4882    /**
4883     * Performs any additional action necessary to perform after the input
4884     * document's content has been replaced.
4885     * <p>
4886     * Clients may extended this method.
4887     *
4888     * @since 3.0
4889     */

4890    protected void handleElementContentReplaced() {
4891    }
4892
4893    /*
4894     * @see ITextEditor#setAction(String, IAction)
4895     */

4896    public void setAction(String JavaDoc actionID, IAction action) {
4897        Assert.isNotNull(actionID);
4898        if (action == null) {
4899            action= (IAction) fActions.remove(actionID);
4900            if (action != null)
4901                fActivationCodeTrigger.unregisterActionFromKeyActivation(action);
4902        } else {
4903            fActions.put(actionID, action);
4904            fActivationCodeTrigger.registerActionForKeyActivation(action);
4905        }
4906    }
4907
4908    /*
4909     * @see ITextEditor#setActionActivationCode(String, char, int, int)
4910     */

4911    public void setActionActivationCode(String JavaDoc actionID, char activationCharacter, int activationKeyCode, int activationStateMask) {
4912
4913        Assert.isNotNull(actionID);
4914
4915        ActionActivationCode found= findActionActivationCode(actionID);
4916        if (found == null) {
4917            found= new ActionActivationCode(actionID);
4918            fActivationCodes.add(found);
4919        }
4920
4921        found.fCharacter= activationCharacter;
4922        found.fKeyCode= activationKeyCode;
4923        found.fStateMask= activationStateMask;
4924    }
4925
4926    /**
4927     * Returns the activation code registered for the specified action.
4928     *
4929     * @param actionID the action id
4930     * @return the registered activation code or <code>null</code> if no code has been installed
4931     */

4932    private ActionActivationCode findActionActivationCode(String JavaDoc actionID) {
4933        int size= fActivationCodes.size();
4934        for (int i= 0; i < size; i++) {
4935            ActionActivationCode code= (ActionActivationCode) fActivationCodes.get(i);
4936            if (actionID.equals(code.fActionId))
4937                return code;
4938        }
4939        return null;
4940    }
4941
4942    /*
4943     * @see ITextEditor#removeActionActivationCode(String)
4944     */

4945    public void removeActionActivationCode(String JavaDoc actionID) {
4946        Assert.isNotNull(actionID);
4947        ActionActivationCode code= findActionActivationCode(actionID);
4948        if (code != null)
4949            fActivationCodes.remove(code);
4950    }
4951
4952    /*
4953     * @see ITextEditor#getAction(String)
4954     */

4955    public IAction getAction(String JavaDoc actionID) {
4956        Assert.isNotNull(actionID);
4957        IAction action= (IAction) fActions.get(actionID);
4958
4959        if (action == null) {
4960            action= findContributedAction(actionID);
4961            if (action != null)
4962                setAction(actionID, action);
4963        }
4964
4965        return action;
4966    }
4967
4968    /**
4969     * Returns the action with the given action id that has been contributed via XML to this editor.
4970     * The lookup honors the dependencies of plug-ins.
4971     *
4972     * @param actionID the action id to look up
4973     * @return the action that has been contributed
4974     * @since 2.0
4975     */

4976    private IAction findContributedAction(String JavaDoc actionID) {
4977        List JavaDoc actions= new ArrayList JavaDoc();
4978        IConfigurationElement[] elements= Platform.getExtensionRegistry().getConfigurationElementsFor(PlatformUI.PLUGIN_ID, "editorActions"); //$NON-NLS-1$
4979
for (int i= 0; i < elements.length; i++) {
4980            IConfigurationElement element= elements[i];
4981            if (TAG_CONTRIBUTION_TYPE.equals(element.getName())) {
4982                if (!getSite().getId().equals(element.getAttribute("targetID"))) //$NON-NLS-1$
4983
continue;
4984
4985                IConfigurationElement[] children= element.getChildren("action"); //$NON-NLS-1$
4986
for (int j= 0; j < children.length; j++) {
4987                    IConfigurationElement child= children[j];
4988                    if (actionID.equals(child.getAttribute("actionID"))) //$NON-NLS-1$
4989
actions.add(child);
4990                }
4991            }
4992        }
4993        int actionSize= actions.size();
4994        if (actionSize > 0) {
4995            IConfigurationElement element;
4996            if (actionSize > 1) {
4997                IConfigurationElement[] actionArray= (IConfigurationElement[])actions.toArray(new IConfigurationElement[actionSize]);
4998                ConfigurationElementSorter sorter= new ConfigurationElementSorter() {
4999                    /*
5000                     * @see org.eclipse.ui.texteditor.ConfigurationElementSorter#getConfigurationElement(java.lang.Object)
5001                     */

5002                    public IConfigurationElement getConfigurationElement(Object JavaDoc object) {
5003                        return (IConfigurationElement)object;
5004                    }
5005                };
5006                sorter.sort(actionArray);
5007                element= actionArray[0];
5008            } else
5009                element= (IConfigurationElement)actions.get(0);
5010
5011            try {
5012                return new ContributedAction(getSite(), element);
5013            } catch (CommandNotMappedException e) {
5014                // out of luck, no command action mapping
5015
}
5016        }
5017
5018        return null;
5019    }
5020
5021    /**
5022     * Updates the specified action by calling <code>IUpdate.update</code>
5023     * if applicable.
5024     *
5025     * @param actionId the action id
5026     */

5027    private void updateAction(String JavaDoc actionId) {
5028        Assert.isNotNull(actionId);
5029        if (fActions != null) {
5030            IAction action= (IAction) fActions.get(actionId);
5031            if (action instanceof IUpdate)
5032                ((IUpdate) action).update();
5033        }
5034    }
5035
5036    /**
5037     * Marks or unmarks the given action to be updated on text selection changes.
5038     *
5039     * @param actionId the action id
5040     * @param mark <code>true</code> if the action is selection dependent
5041     */

5042    public void markAsSelectionDependentAction(String JavaDoc actionId, boolean mark) {
5043        Assert.isNotNull(actionId);
5044        if (mark) {
5045            if (!fSelectionActions.contains(actionId))
5046                fSelectionActions.add(actionId);
5047        } else
5048            fSelectionActions.remove(actionId);
5049    }
5050
5051    /**
5052     * Marks or unmarks the given action to be updated on content changes.
5053     *
5054     * @param actionId the action id
5055     * @param mark <code>true</code> if the action is content dependent
5056     */

5057    public void markAsContentDependentAction(String JavaDoc actionId, boolean mark) {
5058        Assert.isNotNull(actionId);
5059        if (mark) {
5060            if (!fContentActions.contains(actionId))
5061                fContentActions.add(actionId);
5062        } else
5063            fContentActions.remove(actionId);
5064    }
5065
5066    /**
5067     * Marks or unmarks the given action to be updated on property changes.
5068     *
5069     * @param actionId the action id
5070     * @param mark <code>true</code> if the action is property dependent
5071     * @since 2.0
5072     */

5073    public void markAsPropertyDependentAction(String JavaDoc actionId, boolean mark) {
5074        Assert.isNotNull(actionId);
5075        if (mark) {
5076            if (!fPropertyActions.contains(actionId))
5077                fPropertyActions.add(actionId);
5078        } else
5079            fPropertyActions.remove(actionId);
5080    }
5081
5082    /**
5083     * Marks or unmarks the given action to be updated on state changes.
5084     *
5085     * @param actionId the action id
5086     * @param mark <code>true</code> if the action is state dependent
5087     * @since 2.0
5088     */

5089    public void markAsStateDependentAction(String JavaDoc actionId, boolean mark) {
5090        Assert.isNotNull(actionId);
5091        if (mark) {
5092            if (!fStateActions.contains(actionId))
5093                fStateActions.add(actionId);
5094        } else
5095            fStateActions.remove(actionId);
5096    }
5097
5098    /**
5099     * Updates all selection dependent actions.
5100     */

5101    protected void updateSelectionDependentActions() {
5102        if (fSelectionActions != null) {
5103            Iterator JavaDoc e= fSelectionActions.iterator();
5104            while (e.hasNext())
5105                updateAction((String JavaDoc) e.next());
5106        }
5107    }
5108
5109    /**
5110     * Updates all content dependent actions.
5111     */

5112    protected void updateContentDependentActions() {
5113        if (fContentActions != null) {
5114            Iterator JavaDoc e= fContentActions.iterator();
5115            while (e.hasNext())
5116                updateAction((String JavaDoc) e.next());
5117        }
5118    }
5119
5120    /**
5121     * Updates all property dependent actions.
5122     * @since 2.0
5123     */

5124    protected void updatePropertyDependentActions() {
5125        if (fPropertyActions != null) {
5126            Iterator JavaDoc e= fPropertyActions.iterator();
5127            while (e.hasNext())
5128                updateAction((String JavaDoc) e.next());
5129        }
5130    }
5131
5132    /**
5133     * Updates all state dependent actions.
5134     * @since 2.0
5135     */

5136    protected void updateStateDependentActions() {
5137        if (fStateActions != null) {
5138            Iterator JavaDoc e= fStateActions.iterator();
5139            while (e.hasNext())
5140                updateAction((String JavaDoc) e.next());
5141        }
5142    }
5143
5144    /**
5145     * Creates action entries for all SWT StyledText actions as defined in
5146     * <code>org.eclipse.swt.custom.ST</code>. Overwrites and
5147     * extends the list of these actions afterwards.
5148     * <p>
5149     * Subclasses may extend.
5150     * </p>
5151     * @since 2.0
5152     */

5153    protected void createNavigationActions() {
5154
5155        IAction action;
5156
5157        StyledText textWidget= fSourceViewer.getTextWidget();
5158        for (int i= 0; i < ACTION_MAP.length; i++) {
5159            IdMapEntry entry= ACTION_MAP[i];
5160            action= new TextNavigationAction(textWidget, entry.getAction());
5161            action.setActionDefinitionId(entry.getActionId());
5162            setAction(entry.getActionId(), action);
5163        }
5164
5165        action= new ToggleOverwriteModeAction(EditorMessages.getBundleForConstructedKeys(), "Editor.ToggleOverwriteMode."); //$NON-NLS-1$
5166
action.setActionDefinitionId(ITextEditorActionDefinitionIds.TOGGLE_OVERWRITE);
5167        setAction(ITextEditorActionDefinitionIds.TOGGLE_OVERWRITE, action);
5168        textWidget.setKeyBinding(SWT.INSERT, SWT.NULL);
5169
5170        action= new ScrollLinesAction(-1);
5171        action.setActionDefinitionId(ITextEditorActionDefinitionIds.SCROLL_LINE_UP);
5172        setAction(ITextEditorActionDefinitionIds.SCROLL_LINE_UP, action);
5173
5174        action= new ScrollLinesAction(1);
5175        action.setActionDefinitionId(ITextEditorActionDefinitionIds.SCROLL_LINE_DOWN);
5176        setAction(ITextEditorActionDefinitionIds.SCROLL_LINE_DOWN, action);
5177
5178        action= new LineEndAction(textWidget, false);
5179        action.setActionDefinitionId(ITextEditorActionDefinitionIds.LINE_END);
5180        setAction(ITextEditorActionDefinitionIds.LINE_END, action);
5181
5182        action= new LineStartAction(textWidget, false);
5183        action.setActionDefinitionId(ITextEditorActionDefinitionIds.LINE_START);
5184        setAction(ITextEditorActionDefinitionIds.LINE_START, action);
5185
5186        action= new LineEndAction(textWidget, true);
5187        action.setActionDefinitionId(ITextEditorActionDefinitionIds.SELECT_LINE_END);
5188        setAction(ITextEditorActionDefinitionIds.SELECT_LINE_END, action);
5189
5190        action= new LineStartAction(textWidget, true);
5191        action.setActionDefinitionId(ITextEditorActionDefinitionIds.SELECT_LINE_START);
5192        setAction(ITextEditorActionDefinitionIds.SELECT_LINE_START, action);
5193
5194        // to accommodate https://bugs.eclipse.org/bugs/show_bug.cgi?id=51516
5195
// nullify handling of DELETE key by StyledText
5196
textWidget.setKeyBinding(SWT.DEL, SWT.NULL);
5197    }
5198
5199    /**
5200     * Creates this editor's accessibility actions.
5201     * @since 2.0
5202     */

5203    private void createAccessibilityActions() {
5204        IAction action= new ShowRulerContextMenuAction();
5205        action.setActionDefinitionId(ITextEditorActionDefinitionIds.SHOW_RULER_CONTEXT_MENU);
5206        setAction(ITextEditorActionDefinitionIds.SHOW_RULER_CONTEXT_MENU, action);
5207    }
5208
5209    /**
5210     * Creates this editor's undo/redo actions.
5211     * <p>
5212     * Subclasses may override or extend.</p>
5213     *
5214     * @since 3.1
5215     */

5216    protected void createUndoRedoActions() {
5217        IUndoContext undoContext= getUndoContext();
5218        if (undoContext != null) {
5219            // Use actions provided by global undo/redo
5220

5221            // Create the undo action
5222
OperationHistoryActionHandler undoAction= new UndoActionHandler(getEditorSite(), undoContext);
5223            PlatformUI.getWorkbench().getHelpSystem().setHelp(undoAction, IAbstractTextEditorHelpContextIds.UNDO_ACTION);
5224            undoAction.setActionDefinitionId(IWorkbenchActionDefinitionIds.UNDO);
5225            registerUndoRedoAction(ITextEditorActionConstants.UNDO, undoAction);
5226
5227            // Create the redo action.
5228
OperationHistoryActionHandler redoAction= new RedoActionHandler(getEditorSite(), undoContext);
5229            PlatformUI.getWorkbench().getHelpSystem().setHelp(redoAction, IAbstractTextEditorHelpContextIds.REDO_ACTION);
5230            redoAction.setActionDefinitionId(IWorkbenchActionDefinitionIds.REDO);
5231            registerUndoRedoAction(ITextEditorActionConstants.REDO, redoAction);
5232
5233            // Install operation approvers
5234
IOperationHistory history= OperationHistoryFactory.getOperationHistory();
5235
5236            // The first approver will prompt when operations affecting outside elements are to be undone or redone.
5237
if (fNonLocalOperationApprover != null)
5238                history.removeOperationApprover(fNonLocalOperationApprover);
5239            fNonLocalOperationApprover= getUndoRedoOperationApprover(undoContext);
5240            history.addOperationApprover(fNonLocalOperationApprover);
5241
5242            // The second approver will prompt from this editor when an undo is attempted on an operation
5243
// and it is not the most recent operation in the editor.
5244
if (fLinearUndoViolationApprover != null)
5245                history.removeOperationApprover(fLinearUndoViolationApprover);
5246            fLinearUndoViolationApprover= new LinearUndoViolationUserApprover(undoContext, this);
5247            history.addOperationApprover(fLinearUndoViolationApprover);
5248
5249        } else {
5250            // Use text operation actions (pre 3.1 style)
5251

5252            ResourceAction action;
5253            
5254            if (getAction(ITextEditorActionConstants.UNDO) == null) {
5255                action= new TextOperationAction(EditorMessages.getBundleForConstructedKeys(), "Editor.Undo.", this, ITextOperationTarget.UNDO); //$NON-NLS-1$
5256
action.setHelpContextId(IAbstractTextEditorHelpContextIds.UNDO_ACTION);
5257                action.setActionDefinitionId(IWorkbenchActionDefinitionIds.UNDO);
5258                setAction(ITextEditorActionConstants.UNDO, action);
5259            }
5260
5261            if (getAction(ITextEditorActionConstants.REDO) == null) {
5262                action= new TextOperationAction(EditorMessages.getBundleForConstructedKeys(), "Editor.Redo.", this, ITextOperationTarget.REDO); //$NON-NLS-1$
5263
action.setHelpContextId(IAbstractTextEditorHelpContextIds.REDO_ACTION);
5264                action.setActionDefinitionId(IWorkbenchActionDefinitionIds.REDO);
5265                setAction(ITextEditorActionConstants.REDO, action);
5266            }
5267        }
5268    }
5269    
5270    /**
5271     * Registers the given undo/redo action under the given ID and
5272     * ensures that previously installed actions get disposed. It
5273     * also takes care of re-registering the new action with the
5274     * global action handler.
5275     *
5276     * @param actionId the action id under which to register the action
5277     * @param action the action to register
5278     * @since 3.1
5279     */

5280    private void registerUndoRedoAction(String JavaDoc actionId, OperationHistoryActionHandler action) {
5281        IAction oldAction= getAction(actionId);
5282        if (oldAction instanceof OperationHistoryActionHandler)
5283            ((OperationHistoryActionHandler)oldAction).dispose();
5284
5285        setAction(actionId, action);
5286        
5287        IActionBars actionBars= getEditorSite().getActionBars();
5288        if (actionBars != null)
5289            actionBars.setGlobalActionHandler(actionId, action);
5290    }
5291
5292    /**
5293     * Return an {@link IOperationApprover} appropriate for approving the undo and
5294     * redo of operations that have the specified undo context.
5295     * <p>
5296     * Subclasses may override.
5297     * </p>
5298     * @param undoContext the IUndoContext of operations that should be examined
5299     * by the operation approver
5300     * @return the <code>IOperationApprover</code> appropriate for approving undo
5301     * and redo operations inside this editor, or <code>null</code> if no
5302     * approval is needed
5303     * @since 3.1
5304     */

5305    protected IOperationApprover getUndoRedoOperationApprover(IUndoContext undoContext) {
5306        return new NonLocalUndoUserApprover(undoContext, this, new Object JavaDoc [] { getEditorInput() }, Object JavaDoc.class);
5307    }
5308
5309    /**
5310     * Creates this editor's standard actions and connects them with the global
5311     * workbench actions.
5312     * <p>
5313     * Subclasses may extend.</p>
5314     */

5315    protected void createActions() {
5316
5317        ResourceAction action;
5318
5319        action= new TextOperationAction(EditorMessages.getBundleForConstructedKeys(), "Editor.Cut.", this, ITextOperationTarget.CUT); //$NON-NLS-1$
5320
action.setHelpContextId(IAbstractTextEditorHelpContextIds.CUT_ACTION);
5321        action.setActionDefinitionId(IWorkbenchActionDefinitionIds.CUT);
5322        setAction(ITextEditorActionConstants.CUT, action);
5323
5324        action= new TextOperationAction(EditorMessages.getBundleForConstructedKeys(), "Editor.Copy.", this, ITextOperationTarget.COPY, true); //$NON-NLS-1$
5325
action.setHelpContextId(IAbstractTextEditorHelpContextIds.COPY_ACTION);
5326        action.setActionDefinitionId(IWorkbenchActionDefinitionIds.COPY);
5327        setAction(ITextEditorActionConstants.COPY, action);
5328
5329        action= new TextOperationAction(EditorMessages.getBundleForConstructedKeys(), "Editor.Paste.", this, ITextOperationTarget.PASTE); //$NON-NLS-1$
5330
action.setHelpContextId(IAbstractTextEditorHelpContextIds.PASTE_ACTION);
5331        action.setActionDefinitionId(IWorkbenchActionDefinitionIds.PASTE);
5332        setAction(ITextEditorActionConstants.PASTE, action);
5333
5334        action= new TextOperationAction(EditorMessages.getBundleForConstructedKeys(), "Editor.Delete.", this, ITextOperationTarget.DELETE); //$NON-NLS-1$
5335
action.setHelpContextId(IAbstractTextEditorHelpContextIds.DELETE_ACTION);
5336        action.setActionDefinitionId(IWorkbenchActionDefinitionIds.DELETE);
5337        setAction(ITextEditorActionConstants.DELETE, action);
5338
5339        action= new DeleteLineAction(EditorMessages.getBundleForConstructedKeys(), "Editor.DeleteLine.", this, DeleteLineAction.WHOLE, false); //$NON-NLS-1$
5340
action.setHelpContextId(IAbstractTextEditorHelpContextIds.DELETE_LINE_ACTION);
5341        action.setActionDefinitionId(ITextEditorActionDefinitionIds.DELETE_LINE);
5342        setAction(ITextEditorActionConstants.DELETE_LINE, action);
5343
5344        action= new DeleteLineAction(EditorMessages.getBundleForConstructedKeys(), "Editor.CutLine.", this, DeleteLineAction.WHOLE, true); //$NON-NLS-1$
5345
action.setHelpContextId(IAbstractTextEditorHelpContextIds.CUT_LINE_ACTION);
5346        action.setActionDefinitionId(ITextEditorActionDefinitionIds.CUT_LINE);
5347        setAction(ITextEditorActionConstants.CUT_LINE, action);
5348
5349        action= new DeleteLineAction(EditorMessages.getBundleForConstructedKeys(), "Editor.DeleteLineToBeginning.", this, DeleteLineAction.TO_BEGINNING, false); //$NON-NLS-1$
5350
action.setHelpContextId(IAbstractTextEditorHelpContextIds.DELETE_LINE_TO_BEGINNING_ACTION);
5351        action.setActionDefinitionId(ITextEditorActionDefinitionIds.DELETE_LINE_TO_BEGINNING);
5352        setAction(ITextEditorActionConstants.DELETE_LINE_TO_BEGINNING, action);
5353
5354        action= new DeleteLineAction(EditorMessages.getBundleForConstructedKeys(), "Editor.CutLineToBeginning.", this, DeleteLineAction.TO_BEGINNING, true); //$NON-NLS-1$
5355
action.setHelpContextId(IAbstractTextEditorHelpContextIds.CUT_LINE_TO_BEGINNING_ACTION);
5356        action.setActionDefinitionId(ITextEditorActionDefinitionIds.CUT_LINE_TO_BEGINNING);
5357        setAction(ITextEditorActionConstants.CUT_LINE_TO_BEGINNING, action);
5358
5359        action= new DeleteLineAction(EditorMessages.getBundleForConstructedKeys(), "Editor.DeleteLineToEnd.", this, DeleteLineAction.TO_END, false); //$NON-NLS-1$
5360
action.setHelpContextId(IAbstractTextEditorHelpContextIds.DELETE_LINE_TO_END_ACTION);
5361        action.setActionDefinitionId(ITextEditorActionDefinitionIds.DELETE_LINE_TO_END);
5362        setAction(ITextEditorActionConstants.DELETE_LINE_TO_END, action);
5363
5364        action= new DeleteLineAction(EditorMessages.getBundleForConstructedKeys(), "Editor.CutLineToEnd.", this, DeleteLineAction.TO_END, true); //$NON-NLS-1$
5365
action.setHelpContextId(IAbstractTextEditorHelpContextIds.CUT_LINE_TO_END_ACTION);
5366        action.setActionDefinitionId(ITextEditorActionDefinitionIds.CUT_LINE_TO_END);
5367        setAction(ITextEditorActionConstants.CUT_LINE_TO_END, action);
5368
5369        action= new JoinLinesAction(EditorMessages.getBundleForConstructedKeys(), "Editor.JoinLines.", this, " "); //$NON-NLS-1$ //$NON-NLS-2$
5370
action.setHelpContextId(IAbstractTextEditorHelpContextIds.JOIN_LINES_ACTION);
5371        action.setActionDefinitionId(ITextEditorActionDefinitionIds.JOIN_LINES);
5372        setAction(ITextEditorActionConstants.JOIN_LINES, action);
5373
5374        action= new MarkAction(EditorMessages.getBundleForConstructedKeys(), "Editor.SetMark.", this, MarkAction.SET_MARK); //$NON-NLS-1$
5375
action.setHelpContextId(IAbstractTextEditorHelpContextIds.SET_MARK_ACTION);
5376        action.setActionDefinitionId(ITextEditorActionDefinitionIds.SET_MARK);
5377        setAction(ITextEditorActionConstants.SET_MARK, action);
5378
5379        action= new MarkAction(EditorMessages.getBundleForConstructedKeys(), "Editor.ClearMark.", this, MarkAction.CLEAR_MARK); //$NON-NLS-1$
5380
action.setHelpContextId(IAbstractTextEditorHelpContextIds.CLEAR_MARK_ACTION);
5381        action.setActionDefinitionId(ITextEditorActionDefinitionIds.CLEAR_MARK);
5382        setAction(ITextEditorActionConstants.CLEAR_MARK, action);
5383
5384        action= new MarkAction(EditorMessages.getBundleForConstructedKeys(), "Editor.SwapMark.", this, MarkAction.SWAP_MARK); //$NON-NLS-1$
5385
action.setHelpContextId(IAbstractTextEditorHelpContextIds.SWAP_MARK_ACTION);
5386        action.setActionDefinitionId(ITextEditorActionDefinitionIds.SWAP_MARK);
5387        setAction(ITextEditorActionConstants.SWAP_MARK, action);
5388
5389        action= new TextOperationAction(EditorMessages.getBundleForConstructedKeys(), "Editor.SelectAll.", this, ITextOperationTarget.SELECT_ALL, true); //$NON-NLS-1$
5390
action.setHelpContextId(IAbstractTextEditorHelpContextIds.SELECT_ALL_ACTION);
5391        action.setActionDefinitionId(IWorkbenchActionDefinitionIds.SELECT_ALL);
5392        setAction(ITextEditorActionConstants.SELECT_ALL, action);
5393
5394        action= new ShiftAction(EditorMessages.getBundleForConstructedKeys(), "Editor.ShiftRight.", this, ITextOperationTarget.SHIFT_RIGHT); //$NON-NLS-1$
5395
action.setHelpContextId(IAbstractTextEditorHelpContextIds.SHIFT_RIGHT_ACTION);
5396        action.setActionDefinitionId(ITextEditorActionDefinitionIds.SHIFT_RIGHT);
5397        setAction(ITextEditorActionConstants.SHIFT_RIGHT, action);
5398
5399        action= new ShiftAction(EditorMessages.getBundleForConstructedKeys(), "Editor.ShiftRight.", this, ITextOperationTarget.SHIFT_RIGHT) { //$NON-NLS-1$
5400
public void update() {
5401                updateForTab();
5402            }
5403        };
5404        setAction(ITextEditorActionConstants.SHIFT_RIGHT_TAB, action);
5405
5406        action= new ShiftAction(EditorMessages.getBundleForConstructedKeys(), "Editor.ShiftLeft.", this, ITextOperationTarget.SHIFT_LEFT); //$NON-NLS-1$
5407
action.setHelpContextId(IAbstractTextEditorHelpContextIds.SHIFT_LEFT_ACTION);
5408        action.setActionDefinitionId(ITextEditorActionDefinitionIds.SHIFT_LEFT);
5409        setAction(ITextEditorActionConstants.SHIFT_LEFT, action);
5410
5411        action= new TextOperationAction(EditorMessages.getBundleForConstructedKeys(), "Editor.Print.", this, ITextOperationTarget.PRINT, true); //$NON-NLS-1$
5412
action.setHelpContextId(IAbstractTextEditorHelpContextIds.PRINT_ACTION);
5413        action.setActionDefinitionId(IWorkbenchActionDefinitionIds.PRINT);
5414        setAction(ITextEditorActionConstants.PRINT, action);
5415
5416        action= new FindReplaceAction(EditorMessages.getBundleForConstructedKeys(), "Editor.FindReplace.", this); //$NON-NLS-1$
5417
action.setHelpContextId(IAbstractTextEditorHelpContextIds.FIND_ACTION);
5418        action.setActionDefinitionId(IWorkbenchActionDefinitionIds.FIND_REPLACE);
5419        setAction(ITextEditorActionConstants.FIND, action);
5420
5421        action= new FindNextAction(EditorMessages.getBundleForConstructedKeys(), "Editor.FindNext.", this, true); //$NON-NLS-1$
5422
action.setHelpContextId(IAbstractTextEditorHelpContextIds.FIND_NEXT_ACTION);
5423        action.setActionDefinitionId(IWorkbenchActionDefinitionIds.FIND_NEXT);
5424        setAction(ITextEditorActionConstants.FIND_NEXT, action);
5425
5426        action= new FindNextAction(EditorMessages.getBundleForConstructedKeys(), "Editor.FindPrevious.", this, false); //$NON-NLS-1$
5427
action.setHelpContextId(IAbstractTextEditorHelpContextIds.FIND_PREVIOUS_ACTION);
5428        action.setActionDefinitionId(IWorkbenchActionDefinitionIds.FIND_PREVIOUS);
5429        setAction(ITextEditorActionConstants.FIND_PREVIOUS, action);
5430
5431        action= new IncrementalFindAction(EditorMessages.getBundleForConstructedKeys(), "Editor.FindIncremental.", this, true); //$NON-NLS-1$
5432
action.setHelpContextId(IAbstractTextEditorHelpContextIds.FIND_INCREMENTAL_ACTION);
5433        action.setActionDefinitionId(IWorkbenchActionDefinitionIds.FIND_INCREMENTAL);
5434        setAction(ITextEditorActionConstants.FIND_INCREMENTAL, action);
5435
5436        action= new IncrementalFindAction(EditorMessages.getBundleForConstructedKeys(), "Editor.FindIncrementalReverse.", this, false); //$NON-NLS-1$
5437
action.setHelpContextId(IAbstractTextEditorHelpContextIds.FIND_INCREMENTAL_REVERSE_ACTION);
5438        action.setActionDefinitionId(IWorkbenchActionDefinitionIds.FIND_INCREMENTAL_REVERSE);
5439        setAction(ITextEditorActionConstants.FIND_INCREMENTAL_REVERSE, action);
5440
5441        action= new SaveAction(EditorMessages.getBundleForConstructedKeys(), "Editor.Save.", this); //$NON-NLS-1$
5442
action.setHelpContextId(IAbstractTextEditorHelpContextIds.SAVE_ACTION);
5443        /*
5444         * if the line below is uncommented then the key binding does not work any more
5445         * see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53417
5446         */

5447// action.setActionDefinitionId(ITextEditorActionDefinitionIds.SAVE);
5448
setAction(ITextEditorActionConstants.SAVE, action);
5449
5450        action= new RevertToSavedAction(EditorMessages.getBundleForConstructedKeys(), "Editor.Revert.", this); //$NON-NLS-1$
5451
action.setHelpContextId(IAbstractTextEditorHelpContextIds.REVERT_TO_SAVED_ACTION);
5452        action.setActionDefinitionId(IWorkbenchActionDefinitionIds.REVERT_TO_SAVED);
5453        setAction(ITextEditorActionConstants.REVERT_TO_SAVED, action);
5454
5455        action= new GotoLineAction(EditorMessages.getBundleForConstructedKeys(), "Editor.GotoLine.", this); //$NON-NLS-1$
5456
action.setHelpContextId(IAbstractTextEditorHelpContextIds.GOTO_LINE_ACTION);
5457        action.setActionDefinitionId(ITextEditorActionDefinitionIds.LINE_GOTO);
5458        setAction(ITextEditorActionConstants.GOTO_LINE, action);
5459
5460        action= new MoveLinesAction(EditorMessages.getBundleForConstructedKeys(), "Editor.MoveLinesUp.", this, true, false); //$NON-NLS-1$
5461
action.setHelpContextId(IAbstractTextEditorHelpContextIds.MOVE_LINES_ACTION);
5462        action.setActionDefinitionId(ITextEditorActionDefinitionIds.MOVE_LINES_UP);
5463        setAction(ITextEditorActionConstants.MOVE_LINE_UP, action);
5464
5465        action= new MoveLinesAction(EditorMessages.getBundleForConstructedKeys(), "Editor.MoveLinesDown.", this, false, false); //$NON-NLS-1$
5466
action.setHelpContextId(IAbstractTextEditorHelpContextIds.MOVE_LINES_ACTION);
5467        action.setActionDefinitionId(ITextEditorActionDefinitionIds.MOVE_LINES_DOWN);
5468        setAction(ITextEditorActionConstants.MOVE_LINE_DOWN, action);
5469
5470        action= new MoveLinesAction(EditorMessages.getBundleForConstructedKeys(), "Editor.CopyLineUp.", this, true, true); //$NON-NLS-1$
5471
action.setHelpContextId(IAbstractTextEditorHelpContextIds.COPY_LINES_ACTION);
5472        action.setActionDefinitionId(ITextEditorActionDefinitionIds.COPY_LINES_UP);
5473        setAction(ITextEditorActionConstants.COPY_LINE_UP, action);
5474
5475        action= new MoveLinesAction(EditorMessages.getBundleForConstructedKeys(), "Editor.CopyLineDown.", this, false, true); //$NON-NLS-1$
5476
action.setHelpContextId(IAbstractTextEditorHelpContextIds.COPY_LINES_ACTION);
5477        action.setActionDefinitionId(ITextEditorActionDefinitionIds.COPY_LINES_DOWN);
5478        setAction(ITextEditorActionConstants.COPY_LINE_DOWN, action);
5479
5480        action= new CaseAction(EditorMessages.getBundleForConstructedKeys(), "Editor.UpperCase.", this, true); //$NON-NLS-1$
5481
action.setHelpContextId(IAbstractTextEditorHelpContextIds.UPPER_CASE_ACTION);
5482        action.setActionDefinitionId(ITextEditorActionDefinitionIds.UPPER_CASE);
5483        setAction(ITextEditorActionConstants.UPPER_CASE, action);
5484
5485        action= new CaseAction(EditorMessages.getBundleForConstructedKeys(), "Editor.LowerCase.", this, false); //$NON-NLS-1$
5486
action.setHelpContextId(IAbstractTextEditorHelpContextIds.LOWER_CASE_ACTION);
5487        action.setActionDefinitionId(ITextEditorActionDefinitionIds.LOWER_CASE);
5488        setAction(ITextEditorActionConstants.LOWER_CASE, action);
5489
5490        action= new InsertLineAction(EditorMessages.getBundleForConstructedKeys(), "Editor.SmartEnter.", this, false); //$NON-NLS-1$
5491
action.setHelpContextId(IAbstractTextEditorHelpContextIds.SMART_ENTER_ACTION);
5492        action.setActionDefinitionId(ITextEditorActionDefinitionIds.SMART_ENTER);
5493        setAction(ITextEditorActionConstants.SMART_ENTER, action);
5494
5495        action= new InsertLineAction(EditorMessages.getBundleForConstructedKeys(), "Editor.SmartEnterInverse.", this, true); //$NON-NLS-1$
5496
action.setHelpContextId(IAbstractTextEditorHelpContextIds.SMART_ENTER_ACTION);
5497        action.setActionDefinitionId(ITextEditorActionDefinitionIds.SMART_ENTER_INVERSE);
5498        setAction(ITextEditorActionConstants.SMART_ENTER_INVERSE, action);
5499
5500        action= new ToggleInsertModeAction(EditorMessages.getBundleForConstructedKeys(), "Editor.ToggleInsertMode."); //$NON-NLS-1$
5501
action.setHelpContextId(IAbstractTextEditorHelpContextIds.TOGGLE_INSERT_MODE_ACTION);
5502        action.setActionDefinitionId(ITextEditorActionDefinitionIds.TOGGLE_INSERT_MODE);
5503        setAction(ITextEditorActionConstants.TOGGLE_INSERT_MODE, action);
5504
5505        action= new HippieCompleteAction(EditorMessages.getBundleForConstructedKeys(), "Editor.HippieCompletion.", this); //$NON-NLS-1$
5506
action.setHelpContextId(IAbstractTextEditorHelpContextIds.HIPPIE_COMPLETION_ACTION);
5507        action.setActionDefinitionId(ITextEditorActionDefinitionIds.HIPPIE_COMPLETION);
5508        setAction(ITextEditorActionConstants.HIPPIE_COMPLETION, action);
5509
5510        action= new TextOperationAction(EditorMessages.getBundleForConstructedKeys(), "Editor.QuickAssist.", this, ISourceViewer.QUICK_ASSIST); //$NON-NLS-1$
5511
action.setHelpContextId(IAbstractTextEditorHelpContextIds.QUICK_ASSIST_ACTION);
5512        action.setActionDefinitionId(ITextEditorActionDefinitionIds.QUICK_ASSIST);
5513        setAction(ITextEditorActionConstants.QUICK_ASSIST, action);
5514        markAsStateDependentAction(ITextEditorActionConstants.QUICK_ASSIST, true);
5515
5516        action= new GotoAnnotationAction(this, true);
5517        setAction(ITextEditorActionConstants.NEXT, action);
5518        action= new GotoAnnotationAction(this, false);
5519        setAction(ITextEditorActionConstants.PREVIOUS, action);
5520
5521        action= new RecenterAction(EditorMessages.getBundleForConstructedKeys(), "Editor.Recenter.", this); //$NON-NLS-1$
5522
action.setHelpContextId(IAbstractTextEditorHelpContextIds.RECENTER_ACTION);
5523        action.setActionDefinitionId(ITextEditorActionDefinitionIds.RECENTER);
5524        setAction(ITextEditorActionConstants.RECENTER, action);
5525        
5526        action= new ShowWhitespaceCharactersAction(EditorMessages.getBundleForConstructedKeys(), "Editor.ShowWhitespaceCharacters.", this, getPreferenceStore()); //$NON-NLS-1$
5527
action.setHelpContextId(IAbstractTextEditorHelpContextIds.SHOW_WHITESPACE_CHARACTERS_ACTION);
5528        action.setActionDefinitionId(ITextEditorActionDefinitionIds.SHOW_WHITESPACE_CHARACTERS);
5529        setAction(ITextEditorActionConstants.SHOW_WHITESPACE_CHARACTERS, action);
5530        
5531        ResourceAction resAction= new TextOperationAction(EditorMessages.getBundleForConstructedKeys(), "Editor.ShowInformation.", this, ISourceViewer.INFORMATION, true); //$NON-NLS-1$
5532
resAction= new InformationDispatchAction(EditorMessages.getBundleForConstructedKeys(), "Editor.ShowInformation.", (TextOperationAction) resAction); //$NON-NLS-1$
5533
action.setHelpContextId(IAbstractTextEditorHelpContextIds.SHOW_INFORMATION_ACTION);
5534        resAction.setActionDefinitionId(ITextEditorActionDefinitionIds.SHOW_INFORMATION);
5535        setAction(ITextEditorActionConstants.SHOW_INFORMATION, resAction);
5536        
5537
5538        PropertyDialogAction openProperties= new PropertyDialogAction(
5539                new IShellProvider() {
5540                    public Shell getShell() {
5541                        return getSite().getShell();
5542                    }
5543                },
5544                new ISelectionProvider() {
5545                    public void addSelectionChangedListener(ISelectionChangedListener listener) {
5546                    }
5547                    public ISelection getSelection() {
5548                        return new StructuredSelection(getEditorInput());
5549                    }
5550                    public void removeSelectionChangedListener(ISelectionChangedListener listener) {
5551                    }
5552                    public void setSelection(ISelection selection) {
5553                    }
5554                });
5555        openProperties.setActionDefinitionId(IWorkbenchActionDefinitionIds.PROPERTIES);
5556        setAction(ITextEditorActionConstants.PROPERTIES, openProperties);
5557
5558        markAsContentDependentAction(ITextEditorActionConstants.UNDO, true);
5559        markAsContentDependentAction(ITextEditorActionConstants.REDO, true);
5560        markAsContentDependentAction(ITextEditorActionConstants.FIND, true);
5561        markAsContentDependentAction(ITextEditorActionConstants.FIND_NEXT, true);
5562        markAsContentDependentAction(ITextEditorActionConstants.FIND_PREVIOUS, true);
5563        markAsContentDependentAction(ITextEditorActionConstants.FIND_INCREMENTAL, true);
5564        markAsContentDependentAction(ITextEditorActionConstants.FIND_INCREMENTAL_REVERSE, true);
5565
5566        markAsSelectionDependentAction(ITextEditorActionConstants.CUT, true);
5567        markAsSelectionDependentAction(ITextEditorActionConstants.COPY, true);
5568        markAsSelectionDependentAction(ITextEditorActionConstants.PASTE, true);
5569        markAsSelectionDependentAction(ITextEditorActionConstants.DELETE, true);
5570        markAsSelectionDependentAction(ITextEditorActionConstants.SHIFT_RIGHT, true);
5571        markAsSelectionDependentAction(ITextEditorActionConstants.SHIFT_RIGHT_TAB, true);
5572        markAsSelectionDependentAction(ITextEditorActionConstants.UPPER_CASE, true);
5573        markAsSelectionDependentAction(ITextEditorActionConstants.LOWER_CASE, true);
5574
5575        markAsPropertyDependentAction(ITextEditorActionConstants.UNDO, true);
5576        markAsPropertyDependentAction(ITextEditorActionConstants.REDO, true);
5577        markAsPropertyDependentAction(ITextEditorActionConstants.REVERT_TO_SAVED, true);
5578
5579        markAsStateDependentAction(ITextEditorActionConstants.UNDO, true);
5580        markAsStateDependentAction(ITextEditorActionConstants.REDO, true);
5581        markAsStateDependentAction(ITextEditorActionConstants.CUT, true);
5582        markAsStateDependentAction(ITextEditorActionConstants.PASTE, true);
5583        markAsStateDependentAction(ITextEditorActionConstants.DELETE, true);
5584        markAsStateDependentAction(ITextEditorActionConstants.SHIFT_RIGHT, true);
5585        markAsStateDependentAction(ITextEditorActionConstants.SHIFT_RIGHT_TAB, true);
5586        markAsStateDependentAction(ITextEditorActionConstants.SHIFT_LEFT, true);
5587        markAsStateDependentAction(ITextEditorActionConstants.FIND, true);
5588        markAsStateDependentAction(ITextEditorActionConstants.DELETE_LINE, true);
5589        markAsStateDependentAction(ITextEditorActionConstants.DELETE_LINE_TO_BEGINNING, true);
5590        markAsStateDependentAction(ITextEditorActionConstants.DELETE_LINE_TO_END, true);
5591        markAsStateDependentAction(ITextEditorActionConstants.MOVE_LINE_UP, true);
5592        markAsStateDependentAction(ITextEditorActionConstants.MOVE_LINE_DOWN, true);
5593        markAsStateDependentAction(ITextEditorActionConstants.CUT_LINE, true);
5594        markAsStateDependentAction(ITextEditorActionConstants.CUT_LINE_TO_BEGINNING, true);
5595        markAsStateDependentAction(ITextEditorActionConstants.CUT_LINE_TO_END, true);
5596
5597        setActionActivationCode(ITextEditorActionConstants.SHIFT_RIGHT_TAB,'\t', -1, SWT.NONE);
5598        setActionActivationCode(ITextEditorActionConstants.SHIFT_LEFT, '\t', -1, SWT.SHIFT);
5599    }
5600
5601    /**
5602     * Convenience method to add the action installed under the given action id to the given menu.
5603     * @param menu the menu to add the action to
5604     * @param actionId the id of the action to be added
5605     */

5606    protected final void addAction(IMenuManager menu, String JavaDoc actionId) {
5607        IAction action= getAction(actionId);
5608        if (action != null) {
5609            if (action instanceof IUpdate)
5610                ((IUpdate) action).update();
5611            menu.add(action);
5612        }
5613    }
5614
5615    /**
5616     * Convenience method to add the action installed under the given action id to the specified group of the menu.
5617     * @param menu the menu to add the action to
5618     * @param group the group in the menu
5619     * @param actionId the id of the action to add
5620     */

5621    protected final void addAction(IMenuManager menu, String JavaDoc group, String JavaDoc actionId) {
5622        IAction action= getAction(actionId);
5623        if (action != null) {
5624            if (action instanceof IUpdate)
5625                ((IUpdate) action).update();
5626
5627            IMenuManager subMenu= menu.findMenuUsingPath(group);
5628            if (subMenu != null)
5629                subMenu.add(action);
5630            else
5631                menu.appendToGroup(group, action);
5632        }
5633    }
5634
5635    /**
5636     * Convenience method to add a new group after the specified group.
5637     * @param menu the menu to add the new group to
5638     * @param existingGroup the group after which to insert the new group
5639     * @param newGroup the new group
5640     */

5641    protected final void addGroup(IMenuManager menu, String JavaDoc existingGroup, String JavaDoc newGroup) {
5642        IMenuManager subMenu= menu.findMenuUsingPath(existingGroup);
5643        if (subMenu != null)
5644            subMenu.add(new Separator(newGroup));
5645        else
5646            menu.appendToGroup(existingGroup, new Separator(newGroup));
5647    }
5648
5649    /**
5650     * Sets up the ruler context menu before it is made visible.
5651     * <p>
5652     * Subclasses may extend to add other actions.</p>
5653     *
5654     * @param menu the menu
5655     */

5656    protected void rulerContextMenuAboutToShow(IMenuManager menu) {
5657
5658        menu.add(new Separator(ITextEditorActionConstants.GROUP_REST));
5659        menu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
5660
5661        for (Iterator JavaDoc i= fRulerContextMenuListeners.iterator(); i.hasNext();)
5662            ((IMenuListener) i.next()).menuAboutToShow(menu);
5663
5664        addAction(menu, ITextEditorActionConstants.RULER_MANAGE_BOOKMARKS);
5665        addAction(menu, ITextEditorActionConstants.RULER_MANAGE_TASKS);
5666    }
5667
5668    /**
5669     * Sets up this editor's context menu before it is made visible.
5670     * <p>
5671     * Subclasses may extend to add other actions.</p>
5672     *
5673     * @param menu the menu
5674     */

5675    protected void editorContextMenuAboutToShow(IMenuManager menu) {
5676
5677        menu.add(new Separator(ITextEditorActionConstants.GROUP_UNDO));
5678        menu.add(new GroupMarker(ITextEditorActionConstants.GROUP_SAVE));
5679        menu.add(new Separator(ITextEditorActionConstants.GROUP_COPY));
5680        menu.add(new Separator(ITextEditorActionConstants.GROUP_PRINT));
5681        menu.add(new Separator(ITextEditorActionConstants.GROUP_EDIT));
5682        menu.add(new Separator(ITextEditorActionConstants.GROUP_FIND));
5683        menu.add(new Separator(IWorkbenchActionConstants.GROUP_ADD));
5684        menu.add(new Separator(ITextEditorActionConstants.GROUP_REST));
5685        menu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
5686
5687        if (isEditable()) {
5688            addAction(menu, ITextEditorActionConstants.GROUP_UNDO, ITextEditorActionConstants.UNDO);
5689            addAction(menu, ITextEditorActionConstants.GROUP_UNDO, ITextEditorActionConstants.REVERT_TO_SAVED);
5690            addAction(menu, ITextEditorActionConstants.GROUP_SAVE, ITextEditorActionConstants.SAVE);
5691            addAction(menu, ITextEditorActionConstants.GROUP_COPY, ITextEditorActionConstants.CUT);
5692            addAction(menu, ITextEditorActionConstants.GROUP_COPY, ITextEditorActionConstants.COPY);
5693            addAction(menu, ITextEditorActionConstants.GROUP_COPY, ITextEditorActionConstants.PASTE);
5694        } else {
5695            addAction(menu, ITextEditorActionConstants.GROUP_COPY, ITextEditorActionConstants.COPY);
5696        }
5697    }
5698
5699    /**
5700     * Returns the status line manager of this editor.
5701     *
5702     * @return the status line manager of this editor
5703     * @since 2.0, protected since 3.3
5704     */

5705    protected IStatusLineManager getStatusLineManager() {
5706        return getEditorSite().getActionBars().getStatusLineManager();
5707    }
5708
5709    /*
5710     * @see IAdaptable#getAdapter(java.lang.Class)
5711     */

5712    public Object JavaDoc getAdapter(Class JavaDoc required) {
5713
5714        if (IEditorStatusLine.class.equals(required)) {
5715            if (fEditorStatusLine == null) {
5716                IStatusLineManager statusLineManager= getStatusLineManager();
5717                ISelectionProvider selectionProvider= getSelectionProvider();
5718                if (statusLineManager != null && selectionProvider != null)
5719                    fEditorStatusLine= new EditorStatusLine(statusLineManager, selectionProvider);
5720            }
5721            return fEditorStatusLine;
5722        }
5723
5724        if (IVerticalRulerInfo.class.equals(required)) {
5725            if (fVerticalRuler != null)
5726                return fVerticalRuler;
5727        }
5728
5729        if (IMarkRegionTarget.class.equals(required)) {
5730            if (fMarkRegionTarget == null) {
5731                IStatusLineManager manager= getStatusLineManager();
5732                if (manager != null)
5733                    fMarkRegionTarget= (fSourceViewer == null ? null : new MarkRegionTarget(fSourceViewer, manager));
5734            }
5735            return fMarkRegionTarget;
5736        }
5737
5738        if (DeleteLineTarget.class.equals(required)){
5739            if (fDeleteLineTarget == null) {
5740                fDeleteLineTarget= new DeleteLineTarget(fSourceViewer);
5741            }
5742            return fDeleteLineTarget;
5743        }
5744
5745        if (IncrementalFindTarget.class.equals(required)) {
5746            if (fIncrementalFindTarget == null) {
5747                IStatusLineManager manager= getStatusLineManager();
5748                if (manager != null)
5749                    fIncrementalFindTarget= (fSourceViewer == null ? null : new IncrementalFindTarget(fSourceViewer, manager));
5750            }
5751            return fIncrementalFindTarget;
5752        }
5753
5754        if (IFindReplaceTarget.class.equals(required)) {
5755            if (fFindReplaceTarget == null) {
5756                IFindReplaceTarget target= (fSourceViewer == null ? null : fSourceViewer.getFindReplaceTarget());
5757                if (target != null) {
5758                    fFindReplaceTarget= new FindReplaceTarget(this, target);
5759                    if (fFindScopeHighlightColor != null)
5760                        fFindReplaceTarget.setScopeHighlightColor(fFindScopeHighlightColor);
5761                }
5762            }
5763            return fFindReplaceTarget;
5764        }
5765
5766        if (ITextOperationTarget.class.equals(required))
5767            return (fSourceViewer == null ? null : fSourceViewer.getTextOperationTarget());
5768
5769        if (IRewriteTarget.class.equals(required)) {
5770            if (fSourceViewer instanceof ITextViewerExtension) {
5771                ITextViewerExtension extension= (ITextViewerExtension) fSourceViewer;
5772                return extension.getRewriteTarget();
5773            }
5774            return null;
5775        }
5776
5777        if (Control.class.equals(required))
5778            return fSourceViewer != null ? fSourceViewer.getTextWidget() : null;
5779
5780        if (IColumnSupport.class.equals(required)) {
5781            if (fColumnSupport == null)
5782                fColumnSupport= createColumnSupport();
5783            return fColumnSupport;
5784        }
5785
5786        return super.getAdapter(required);
5787    }
5788
5789    /*
5790     * @see IWorkbenchPart#setFocus()
5791     */

5792    public void setFocus() {
5793        if (fSourceViewer != null && fSourceViewer.getTextWidget() != null)
5794            fSourceViewer.getTextWidget().setFocus();
5795    }
5796
5797    /*
5798     * @see ITextEditor#showsHighlightRangeOnly()
5799     */

5800    public boolean showsHighlightRangeOnly() {
5801        return fShowHighlightRangeOnly;
5802    }
5803
5804    /*
5805     * @see ITextEditor#showHighlightRangeOnly(boolean)
5806     */

5807    public void showHighlightRangeOnly(boolean showHighlightRangeOnly) {
5808        fShowHighlightRangeOnly= showHighlightRangeOnly;
5809    }
5810
5811    /*
5812     * @see ITextEditor#setHighlightRange(int, int, boolean)
5813     */

5814    public void setHighlightRange(int offset, int length, boolean moveCursor) {
5815        if (fSourceViewer == null)
5816            return;
5817
5818        if (fShowHighlightRangeOnly) {
5819            if (moveCursor)
5820                fSourceViewer.setVisibleRegion(offset, length);
5821        } else {
5822            IRegion rangeIndication= fSourceViewer.getRangeIndication();
5823            if (rangeIndication == null || offset != rangeIndication.getOffset() || length != rangeIndication.getLength())
5824                fSourceViewer.setRangeIndication(offset, length, moveCursor);
5825        }
5826    }
5827
5828    /*
5829     * @see ITextEditor#getHighlightRange()
5830     */

5831    public IRegion getHighlightRange() {
5832        if (fSourceViewer == null)
5833            return null;
5834
5835        if (fShowHighlightRangeOnly)
5836            return getCoverage(fSourceViewer);
5837
5838        return fSourceViewer.getRangeIndication();
5839    }
5840
5841    /*
5842     * @see ITextEditor#resetHighlightRange
5843     */

5844    public void resetHighlightRange() {
5845        if (fSourceViewer == null)
5846            return;
5847
5848        if (fShowHighlightRangeOnly)
5849            fSourceViewer.resetVisibleRegion();
5850        else
5851            fSourceViewer.removeRangeIndication();
5852    }
5853
5854    /**
5855     * Adjusts the highlight range so that at least the specified range
5856     * is highlighted.
5857     * <p>
5858     * Subclasses may re-implement this method.</p>
5859     *
5860     * @param offset the offset of the range which at least should be highlighted
5861     * @param length the length of the range which at least should be highlighted
5862     */

5863    protected void adjustHighlightRange(int offset, int length) {
5864        if (fSourceViewer == null)
5865            return;
5866
5867        if (fSourceViewer instanceof ITextViewerExtension5) {
5868            ITextViewerExtension5 extension= (ITextViewerExtension5) fSourceViewer;
5869            extension.exposeModelRange(new Region(offset, length));
5870        } else if (!isVisible(fSourceViewer, offset, length)) {
5871            fSourceViewer.resetVisibleRegion();
5872        }
5873    }
5874
5875    /*
5876     * @see ITextEditor#selectAndReveal(int, int)
5877     */

5878    public void selectAndReveal(int start, int length) {
5879        selectAndReveal(start, length, start, length);
5880    }
5881
5882    /**
5883     * Selects and reveals the specified ranges in this text editor.
5884     *
5885     * @param selectionStart the offset of the selection
5886     * @param selectionLength the length of the selection
5887     * @param revealStart the offset of the revealed range
5888     * @param revealLength the length of the revealed range
5889     * @since 3.0
5890     */

5891    protected void selectAndReveal(int selectionStart, int selectionLength, int revealStart, int revealLength) {
5892        if (fSourceViewer == null)
5893            return;
5894
5895        ISelection selection= getSelectionProvider().getSelection();
5896        if (selection instanceof ITextSelection) {
5897            ITextSelection textSelection= (ITextSelection) selection;
5898            if (textSelection.getOffset() != 0 || textSelection.getLength() != 0)
5899                markInNavigationHistory();
5900        }
5901
5902        StyledText widget= fSourceViewer.getTextWidget();
5903        widget.setRedraw(false);
5904        {
5905            adjustHighlightRange(revealStart, revealLength);
5906            fSourceViewer.revealRange(revealStart, revealLength);
5907
5908            fSourceViewer.setSelectedRange(selectionStart, selectionLength);
5909
5910            markInNavigationHistory();
5911        }
5912        widget.setRedraw(true);
5913    }
5914
5915    /*
5916     * @see org.eclipse.ui.INavigationLocationProvider#createNavigationLocation()
5917     * @since 2.1
5918     */

5919    public INavigationLocation createEmptyNavigationLocation() {
5920        return new TextSelectionNavigationLocation(this, false);
5921    }
5922
5923    /*
5924     * @see org.eclipse.ui.INavigationLocationProvider#createNavigationLocation()
5925     */

5926    public INavigationLocation createNavigationLocation() {
5927        return new TextSelectionNavigationLocation(this, true);
5928    }
5929
5930    /**
5931     * Writes a check mark of the given situation into the navigation history.
5932     * @since 2.1
5933     */

5934    protected void markInNavigationHistory() {
5935        getSite().getPage().getNavigationHistory().markLocation(this);
5936    }
5937
5938    /**
5939     * Hook which gets called when the editor has been saved.
5940     * Subclasses may extend.
5941     * @since 2.1
5942     */

5943    protected void editorSaved() {
5944        INavigationLocation[] locations= getSite().getPage().getNavigationHistory().getLocations();
5945        IEditorInput input= getEditorInput();
5946        for (int i= 0; i < locations.length; i++) {
5947            if (locations[i] instanceof TextSelectionNavigationLocation) {
5948                if(input.equals(locations[i].getInput())) {
5949                    TextSelectionNavigationLocation location= (TextSelectionNavigationLocation) locations[i];
5950                    location.partSaved(this);
5951                }
5952            }
5953        }
5954    }
5955
5956    /*
5957     * @see WorkbenchPart#firePropertyChange(int)
5958     */

5959    protected void firePropertyChange(int property) {
5960        super.firePropertyChange(property);
5961        updatePropertyDependentActions();
5962    }
5963
5964    /*
5965     * @see ITextEditorExtension#setStatusField(IStatusField, String)
5966     * @since 2.0
5967     */

5968    public void setStatusField(IStatusField field, String JavaDoc category) {
5969        Assert.isNotNull(category);
5970        if (field != null) {
5971
5972            if (fStatusFields == null)
5973                fStatusFields= new HashMap JavaDoc(3);
5974
5975            fStatusFields.put(category, field);
5976            updateStatusField(category);
5977
5978        } else if (fStatusFields != null)
5979            fStatusFields.remove(category);
5980
5981        if (fIncrementalFindTarget != null && ITextEditorActionConstants.STATUS_CATEGORY_FIND_FIELD.equals(category))
5982            fIncrementalFindTarget.setStatusField(field);
5983    }
5984
5985    /**
5986     * Returns the current status field for the given status category.
5987     *
5988     * @param category the status category
5989     * @return the current status field for the given status category
5990     * @since 2.0
5991     */

5992    protected IStatusField getStatusField(String JavaDoc category) {
5993        if (category != null && fStatusFields != null)
5994            return (IStatusField) fStatusFields.get(category);
5995        return null;
5996    }
5997
5998    /**
5999     * Returns whether this editor is in overwrite or insert mode.
6000     *
6001     * @return <code>true</code> if in insert mode, <code>false</code> for overwrite mode
6002     * @since 2.0
6003     */

6004    protected boolean isInInsertMode() {
6005        return !fIsOverwriting;
6006    }
6007
6008    /*
6009     * @see org.eclipse.ui.texteditor.ITextEditorExtension3#getInsertMode()
6010     * @since 3.0
6011     */

6012    public InsertMode getInsertMode() {
6013        return fInsertMode;
6014    }
6015
6016    /*
6017     * @see org.eclipse.ui.texteditor.ITextEditorExtension3#setInsertMode(org.eclipse.ui.texteditor.ITextEditorExtension3.InsertMode)
6018     * @since 3.0
6019     */

6020    public void setInsertMode(InsertMode newMode) {
6021        List JavaDoc legalModes= getLegalInsertModes();
6022        if (!legalModes.contains(newMode))
6023            throw new IllegalArgumentException JavaDoc();
6024
6025        fInsertMode= newMode;
6026
6027        handleInsertModeChanged();
6028    }
6029
6030    /**
6031     * Returns the set of legal insert modes. If insert modes are configured all defined insert modes
6032     * are legal.
6033     *
6034     * @return the set of legal insert modes
6035     * @since 3.0
6036     */

6037    protected List JavaDoc getLegalInsertModes() {
6038        if (fLegalInsertModes == null) {
6039            fLegalInsertModes= new ArrayList JavaDoc();
6040            fLegalInsertModes.add(SMART_INSERT);
6041            fLegalInsertModes.add(INSERT);
6042        }
6043        return fLegalInsertModes;
6044    }
6045
6046    private void switchToNextInsertMode() {
6047
6048        InsertMode mode= getInsertMode();
6049        List JavaDoc legalModes= getLegalInsertModes();
6050
6051        int i= 0;
6052        while (i < legalModes.size()) {
6053            if (legalModes.get(i) == mode) break;
6054            ++ i;
6055        }
6056
6057        i= (i + 1) % legalModes.size();
6058        InsertMode newMode= (InsertMode) legalModes.get(i);
6059        setInsertMode(newMode);
6060    }
6061
6062    private void toggleOverwriteMode() {
6063        if (fIsOverwriteModeEnabled) {
6064            fIsOverwriting= !fIsOverwriting;
6065            fSourceViewer.getTextWidget().invokeAction(ST.TOGGLE_OVERWRITE);
6066            handleInsertModeChanged();
6067        }
6068    }
6069
6070    /**
6071     * Configures the given insert mode as legal or illegal. This call is ignored if the set of legal
6072     * input modes would be empty after the call.
6073     *
6074     * @param mode the insert mode to be configured
6075     * @param legal <code>true</code> if the given mode is legal, <code>false</code> otherwise
6076     * @since 3.0
6077     */

6078    protected void configureInsertMode(InsertMode mode, boolean legal) {
6079        List JavaDoc legalModes= getLegalInsertModes();
6080        if (legal) {
6081            if (!legalModes.contains(mode))
6082                legalModes.add(mode);
6083        } else if (legalModes.size() > 1) {
6084            if (getInsertMode() == mode)
6085                switchToNextInsertMode();
6086            legalModes.remove(mode);
6087        }
6088    }
6089
6090    /**
6091     * Sets the overwrite mode enablement.
6092     *
6093     * @param enable <code>true</code> to enable new overwrite mode,
6094     * <code>false</code> to disable
6095     * @since 3.0
6096     */

6097    protected void enableOverwriteMode(boolean enable) {
6098        if (fIsOverwriting && !enable)
6099            toggleOverwriteMode();
6100        fIsOverwriteModeEnabled= enable;
6101    }
6102
6103    private Caret createOverwriteCaret(StyledText styledText) {
6104        Caret caret= new Caret(styledText, SWT.NULL);
6105        GC gc= new GC(styledText);
6106        // XXX this overwrite box is not proportional-font aware
6107
// take 'a' as a medium sized character
6108
Point charSize= gc.stringExtent("a"); //$NON-NLS-1$
6109

6110        // XXX: Filed request to get a caret with auto-height: https://bugs.eclipse.org/bugs/show_bug.cgi?id=118612
6111
caret.setSize(charSize.x, styledText.getLineHeight());
6112        caret.setFont(styledText.getFont());
6113        
6114        gc.dispose();
6115
6116        return caret;
6117    }
6118
6119    private Caret createInsertCaret(StyledText styledText) {
6120        Caret caret= new Caret(styledText, SWT.NULL);
6121
6122        // XXX: Filed request to get a caret with auto-height: https://bugs.eclipse.org/bugs/show_bug.cgi?id=118612
6123
caret.setSize(getCaretWidthPreference(), styledText.getLineHeight());
6124        caret.setFont(styledText.getFont());
6125        
6126        return caret;
6127    }
6128
6129    private Image createRawInsertModeCaretImage(StyledText styledText) {
6130
6131        PaletteData caretPalette= new PaletteData(new RGB[] {new RGB (0,0,0), new RGB (255,255,255)});
6132        int width= getCaretWidthPreference();
6133        int widthOffset= width - 1;
6134        
6135        // XXX: Filed request to get a caret with auto-height: https://bugs.eclipse.org/bugs/show_bug.cgi?id=118612
6136
ImageData imageData= new ImageData(4 + widthOffset, styledText.getLineHeight(), 1, caretPalette);
6137
6138        Display display= styledText.getDisplay();
6139        Image bracketImage= new Image(display, imageData);
6140        GC gc= new GC (bracketImage);
6141        gc.setForeground(display.getSystemColor(SWT.COLOR_WHITE));
6142        gc.setLineWidth(0); // NOTE: 0 means width is 1 but with optimized performance
6143
int height= imageData.height / 3;
6144        // gap between two bars of one third of the height
6145
// draw boxes using lines as drawing a line of a certain width produces
6146
// rounded corners.
6147
for (int i= 0; i < width ; i++) {
6148            gc.drawLine(i, 0, i, height - 1);
6149            gc.drawLine(i, imageData.height - height, i, imageData.height - 1);
6150        }
6151
6152        gc.dispose();
6153
6154        return bracketImage;
6155    }
6156
6157    private Caret createRawInsertModeCaret(StyledText styledText) {
6158        // don't draw special raw caret if no smart mode is enabled
6159
if (!getLegalInsertModes().contains(SMART_INSERT))
6160            return createInsertCaret(styledText);
6161
6162        Caret caret= new Caret(styledText, SWT.NULL);
6163        Image image= createRawInsertModeCaretImage(styledText);
6164        if (image != null)
6165            caret.setImage(image);
6166        else {
6167            // XXX: Filed request to get a caret with auto-height: https://bugs.eclipse.org/bugs/show_bug.cgi?id=118612
6168
caret.setSize(getCaretWidthPreference(), styledText.getLineHeight());
6169        }
6170
6171        caret.setFont(styledText.getFont());
6172
6173        return caret;
6174    }
6175
6176    private int getCaretWidthPreference() {
6177        if (getPreferenceStore() != null && getPreferenceStore().getBoolean(PREFERENCE_WIDE_CARET))
6178            return WIDE_CARET_WIDTH;
6179
6180        return SINGLE_CARET_WIDTH;
6181    }
6182
6183    private void updateCaret() {
6184
6185        if (fSourceViewer == null)
6186            return;
6187
6188        StyledText styledText= fSourceViewer.getTextWidget();
6189
6190        InsertMode mode= getInsertMode();
6191
6192        styledText.setCaret(null);
6193        disposeNonDefaultCaret();
6194
6195        if (getPreferenceStore() == null || !getPreferenceStore().getBoolean(PREFERENCE_USE_CUSTOM_CARETS))
6196            Assert.isTrue(fNonDefaultCaret == null);
6197        else if (fIsOverwriting)
6198            fNonDefaultCaret= createOverwriteCaret(styledText);
6199        else if (SMART_INSERT == mode)
6200            fNonDefaultCaret= createInsertCaret(styledText);
6201        else if (INSERT == mode)
6202            fNonDefaultCaret= createRawInsertModeCaret(styledText);
6203
6204        if (fNonDefaultCaret != null) {
6205            styledText.setCaret(fNonDefaultCaret);
6206            fNonDefaultCaretImage= fNonDefaultCaret.getImage();
6207        } else if (fInitialCaret != styledText.getCaret())
6208            styledText.setCaret(fInitialCaret);
6209    }
6210
6211    private void disposeNonDefaultCaret() {
6212        if (fNonDefaultCaretImage != null) {
6213            fNonDefaultCaretImage.dispose();
6214            fNonDefaultCaretImage= null;
6215        }
6216
6217        if (fNonDefaultCaret != null) {
6218            fNonDefaultCaret.dispose();
6219            fNonDefaultCaret= null;
6220        }
6221    }
6222
6223    /**
6224     * Handles a change of the editor's insert mode.
6225     * Subclasses may extend.
6226     *
6227     * @since 2.0
6228     */

6229    protected void handleInsertModeChanged() {
6230        updateInsertModeAction();
6231        updateCaret();
6232        updateStatusField(ITextEditorActionConstants.STATUS_CATEGORY_INPUT_MODE);
6233    }
6234
6235    private void updateInsertModeAction() {
6236
6237        // this may be called before the part is fully initialized (see configureInsertMode)
6238
// drop out in this case.
6239
if (getSite() == null)
6240            return;
6241
6242        IAction action= getAction(ITextEditorActionConstants.TOGGLE_INSERT_MODE);
6243        if (action != null) {
6244            action.setEnabled(!fIsOverwriting);
6245            action.setChecked(fInsertMode == SMART_INSERT);
6246        }
6247    }
6248
6249    /**
6250     * Handles a potential change of the cursor position.
6251     * Subclasses may extend.
6252     *
6253     * @since 2.0
6254     */

6255    protected void handleCursorPositionChanged() {
6256        updateStatusField(ITextEditorActionConstants.STATUS_CATEGORY_INPUT_POSITION);
6257    }
6258
6259    /**
6260     * Updates the status fields for the given category.
6261     *
6262     * @param category
6263     * @since 2.0
6264     */

6265    protected void updateStatusField(String JavaDoc category) {
6266
6267        if (category == null)
6268            return;
6269
6270        IStatusField field= getStatusField(category);
6271        if (field != null) {
6272
6273            String JavaDoc text= null;
6274
6275            if (ITextEditorActionConstants.STATUS_CATEGORY_INPUT_POSITION.equals(category))
6276                text= getCursorPosition();
6277            else if (ITextEditorActionConstants.STATUS_CATEGORY_ELEMENT_STATE.equals(category))
6278                text= isEditorInputReadOnly() ? fReadOnlyLabel : fWritableLabel;
6279            else if (ITextEditorActionConstants.STATUS_CATEGORY_INPUT_MODE.equals(category)) {
6280                InsertMode mode= getInsertMode();
6281                if (fIsOverwriting)
6282                    text= fOverwriteModeLabel;
6283                else if (INSERT == mode)
6284                    text= fInsertModeLabel;
6285                else if (SMART_INSERT == mode)
6286                    text= fSmartInsertModeLabel;
6287            }
6288
6289            field.setText(text == null ? fErrorLabel : text);
6290        }
6291    }
6292
6293    /**
6294     * Updates all status fields.
6295     *
6296     * @since 2.0
6297     */

6298    protected void updateStatusFields() {
6299        if (fStatusFields != null) {
6300            Iterator JavaDoc e= fStatusFields.keySet().iterator();
6301            while (e.hasNext())
6302                updateStatusField((String JavaDoc) e.next());
6303        }
6304    }
6305
6306    /**
6307     * Returns a description of the cursor position.
6308     *
6309     * @return a description of the cursor position
6310     * @since 2.0
6311     */

6312    protected String JavaDoc getCursorPosition() {
6313
6314        if (fSourceViewer == null)
6315            return fErrorLabel;
6316
6317        StyledText styledText= fSourceViewer.getTextWidget();
6318        int caret= widgetOffset2ModelOffset(fSourceViewer, styledText.getCaretOffset());
6319        IDocument document= fSourceViewer.getDocument();
6320
6321        if (document == null)
6322            return fErrorLabel;
6323
6324        try {
6325
6326            int line= document.getLineOfOffset(caret);
6327
6328            int lineOffset= document.getLineOffset(line);
6329            int tabWidth= styledText.getTabs();
6330            int column= 0;
6331            for (int i= lineOffset; i < caret; i++)
6332                if ('\t' == document.getChar(i))
6333                    column += tabWidth - (tabWidth == 0 ? 0 : column % tabWidth);
6334                else
6335                    column++;
6336
6337            fLineLabel.fValue= line + 1;
6338            fColumnLabel.fValue= column + 1;
6339            return NLSUtility.format(fPositionLabelPattern, fPositionLabelPatternArguments);
6340
6341        } catch (BadLocationException x) {
6342            return fErrorLabel;
6343        }
6344    }
6345
6346    /*
6347     * @see ITextEditorExtension#isEditorInputReadOnly()
6348     * @since 2.0
6349     */

6350    public boolean isEditorInputReadOnly() {
6351        IDocumentProvider provider= getDocumentProvider();
6352        if (provider instanceof IDocumentProviderExtension) {
6353            IDocumentProviderExtension extension= (IDocumentProviderExtension) provider;
6354            return extension.isReadOnly(getEditorInput());
6355        }
6356        return true;
6357    }
6358
6359    /*
6360     * @see ITextEditorExtension2#isEditorInputModifiable()
6361     * @since 2.1
6362     */

6363    public boolean isEditorInputModifiable() {
6364        IDocumentProvider provider= getDocumentProvider();
6365        if (provider instanceof IDocumentProviderExtension) {
6366            IDocumentProviderExtension extension= (IDocumentProviderExtension) provider;
6367            return extension.isModifiable(getEditorInput());
6368        }
6369        return true;
6370    }
6371
6372    /*
6373     * @see ITextEditorExtension#addRulerContextMenuListener(IMenuListener)
6374     * @since 2.0
6375     */

6376    public void addRulerContextMenuListener(IMenuListener listener) {
6377        fRulerContextMenuListeners.add(listener);
6378    }
6379
6380    /*
6381     * @see ITextEditorExtension#removeRulerContextMenuListener(IMenuListener)
6382     * @since 2.0
6383     */

6384    public void removeRulerContextMenuListener(IMenuListener listener) {
6385        fRulerContextMenuListeners.remove(listener);
6386    }
6387
6388    /**
6389     * Returns whether this editor can handle the move of the original element
6390     * so that it ends up being the moved element. By default this method
6391     * returns <code>true</code>. Subclasses may reimplement.
6392     *
6393     * @param originalElement the original element
6394     * @param movedElement the moved element
6395     * @return whether this editor can handle the move of the original element
6396     * so that it ends up being the moved element
6397     * @since 2.0
6398     */

6399    protected boolean canHandleMove(IEditorInput originalElement, IEditorInput movedElement) {
6400        return true;
6401    }
6402
6403    /**
6404     * Returns the offset of the given source viewer's document that corresponds
6405     * to the given widget offset or <code>-1</code> if there is no such offset.
6406     *
6407     * @param viewer the source viewer
6408     * @param widgetOffset the widget offset
6409     * @return the corresponding offset in the source viewer's document or <code>-1</code>
6410     * @since 2.1
6411     */

6412    protected final static int widgetOffset2ModelOffset(ISourceViewer viewer, int widgetOffset) {
6413        if (viewer instanceof ITextViewerExtension5) {
6414            ITextViewerExtension5 extension= (ITextViewerExtension5) viewer;
6415            return extension.widgetOffset2ModelOffset(widgetOffset);
6416        }
6417        return widgetOffset + viewer.getVisibleRegion().getOffset();
6418    }
6419
6420    /**
6421     * Returns the offset of the given source viewer's text widget that corresponds
6422     * to the given model offset or <code>-1</code> if there is no such offset.
6423     *
6424     * @param viewer the source viewer
6425     * @param modelOffset the model offset
6426     * @return the corresponding offset in the source viewer's text widget or <code>-1</code>
6427     * @since 3.0
6428     */

6429    protected final static int modelOffset2WidgetOffset(ISourceViewer viewer, int modelOffset) {
6430        if (viewer instanceof ITextViewerExtension5) {
6431            ITextViewerExtension5 extension= (ITextViewerExtension5) viewer;
6432            return extension.modelOffset2WidgetOffset(modelOffset);
6433        }
6434        return modelOffset - viewer.getVisibleRegion().getOffset();
6435    }
6436
6437    /**
6438     * Returns the minimal region of the given source viewer's document that completely
6439     * comprises everything that is visible in the viewer's widget.
6440     *
6441     * @param viewer the viewer go return the coverage for
6442     * @return the minimal region of the source viewer's document comprising the contents of the viewer's widget
6443     * @since 2.1
6444     */

6445    protected final static IRegion getCoverage(ISourceViewer viewer) {
6446        if (viewer instanceof ITextViewerExtension5) {
6447            ITextViewerExtension5 extension= (ITextViewerExtension5) viewer;
6448            return extension.getModelCoverage();
6449        }
6450        return viewer.getVisibleRegion();
6451    }
6452
6453    /**
6454     * Tells whether the given region is visible in the given source viewer.
6455     *
6456     * @param viewer the source viewer
6457     * @param offset the offset of the region
6458     * @param length the length of the region
6459     * @return <code>true</code> if visible
6460     * @since 2.1
6461     */

6462    protected static final boolean isVisible(ISourceViewer viewer, int offset, int length) {
6463        if (viewer instanceof ITextViewerExtension5) {
6464            ITextViewerExtension5 extension= (ITextViewerExtension5) viewer;
6465            IRegion overlap= extension.modelRange2WidgetRange(new Region(offset, length));
6466            return overlap != null;
6467        }
6468        return viewer.overlapsWithVisibleRegion(offset, length);
6469    }
6470
6471    /*
6472     * @see org.eclipse.ui.texteditor.ITextEditorExtension3#showChangeInformation(boolean)
6473     * @since 3.0
6474     */

6475    public void showChangeInformation(boolean show) {
6476        // do nothing
6477
}
6478
6479    /*
6480     * @see org.eclipse.ui.texteditor.ITextEditorExtension3#isChangeInformationShowing()
6481     * @since 3.0
6482     */

6483    public boolean isChangeInformationShowing() {
6484        return false;
6485    }
6486    
6487    /**
6488     * Sets the given message as error message to this editor's status line.
6489     *
6490     * @param message message to be set
6491     * @since 3.2
6492     */

6493    protected void setStatusLineErrorMessage(String JavaDoc message) {
6494        IEditorStatusLine statusLine= (IEditorStatusLine)getAdapter(IEditorStatusLine.class);
6495        if (statusLine != null)
6496            statusLine.setMessage(true, message, null);
6497    }
6498
6499    /**
6500     * Sets the given message as message to this editor's status line.
6501     *
6502     * @param message message to be set
6503     * @since 3.2
6504     */

6505    protected void setStatusLineMessage(String JavaDoc message) {
6506        IEditorStatusLine statusLine= (IEditorStatusLine)getAdapter(IEditorStatusLine.class);
6507        if (statusLine != null)
6508            statusLine.setMessage(false, message, null);
6509    }
6510    
6511    /**
6512     * Jumps to the next annotation according to the given direction.
6513     *
6514     * @param forward <code>true</code> if search direction is forward, <code>false</code> if backward
6515     * @return the selected annotation or <code>null</code> if none