Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKai Maetzel2002-09-24 16:56:43 +0000
committerKai Maetzel2002-09-24 16:56:43 +0000
commit14d37ec991e842df973b8c9e1196ba0a255df21e (patch)
tree3cc2a87ba91aaa43ea7919f6d8cc9f114ed96542
parentdb4ac57b04d3091f1e46fa274fe527444c03a1a0 (diff)
downloadeclipse.platform.text-14d37ec991e842df973b8c9e1196ba0a255df21e.tar.gz
eclipse.platform.text-14d37ec991e842df973b8c9e1196ba0a255df21e.tar.xz
eclipse.platform.text-14d37ec991e842df973b8c9e1196ba0a255df21e.zip
First cut of org.eclipse.ui splitFirst_cut_splitting_org_eclipse_ui_200209241530
-rw-r--r--org.eclipse.ui.workbench.texteditor/.classpath12
-rw-r--r--org.eclipse.ui.workbench.texteditor/.cvsignore1
-rw-r--r--org.eclipse.ui.workbench.texteditor/.project34
-rw-r--r--org.eclipse.ui.workbench.texteditor/build.properties4
-rw-r--r--org.eclipse.ui.workbench.texteditor/fragment.properties2
-rw-r--r--org.eclipse.ui.workbench.texteditor/fragment.xml21
-rw-r--r--org.eclipse.ui.workbench.texteditor/scripts/exportplugin.xml29
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractDocumentProvider.java791
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractMarkerAnnotationModel.java571
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractRulerActionDelegate.java145
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractTextEditor.java3550
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AddMarkerAction.java279
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/BasicMarkerUpdater.java92
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/BasicTextEditorActionContributor.java214
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/BookmarkRulerAction.java31
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ContentAssistAction.java126
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ConvertLineDelimitersAction.java286
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/DefaultRangeIndicator.java146
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/DeleteLineAction.java179
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/DocumentProviderRegistry.java287
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/EditorMessages.java30
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/EditorMessages.properties286
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/EditorStatusLine.java99
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindNextAction.java332
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceAction.java244
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceDialog.java1390
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/GotoLineAction.java188
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IAbstractTextEditorHelpContextIds.java227
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IDocumentProvider.java196
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IDocumentProviderExtension.java114
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IEditorStatusLine.java25
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IElementStateListener.java60
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IElementStateListenerExtension.java47
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IMarkerUpdater.java53
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IReadOnlyDependent.java37
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IStatusField.java39
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ITextEditor.java173
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ITextEditorActionConstants.java229
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ITextEditorActionDefinitionIds.java310
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ITextEditorExtension.java64
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IUpdate.java18
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IWorkbenchActionDefinitionIds.java124
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IncrementalFindAction.java101
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IncrementalFindTarget.java577
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/InfoForm.java227
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkAction.java73
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkRegionTarget.java107
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkerAnnotation.java262
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkerRulerAction.java417
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkerRulerInfoAction.java31
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkerUpdater.java59
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkerUtilities.java242
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/PropagatingFontFieldEditor.java23
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ResourceAction.java101
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ResourceMarkerAnnotationModel.java171
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/RetargetTextEditorAction.java149
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/RevertToSavedAction.java50
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/SaveAction.java50
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ShiftAction.java136
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/StatusLineContributionItem.java114
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/StatusTextEditor.java196
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/TextEditorAction.java66
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/TextNavigationAction.java258
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/TextOperationAction.java157
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/TextSelectionNavigationLocation.java238
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/TextUtilities.java109
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/WorkbenchChainedTextFontFieldEditor.java70
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/package.html30
68 files changed, 15099 insertions, 0 deletions
diff --git a/org.eclipse.ui.workbench.texteditor/.classpath b/org.eclipse.ui.workbench.texteditor/.classpath
new file mode 100644
index 000000000..4673a9a26
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/.classpath
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src/"/>
+ <classpathentry kind="src" path="/org.eclipse.core.resources"/>
+ <classpathentry kind="src" path="/org.eclipse.jface"/>
+ <classpathentry kind="src" path="/org.eclipse.core.runtime"/>
+ <classpathentry kind="src" path="/org.eclipse.jface.text"/>
+ <classpathentry kind="src" path="/org.eclipse.text"/>
+ <classpathentry kind="var" path="JRE_LIB" rootpath="JRE_SRCROOT" sourcepath="JRE_SRC"/>
+ <classpathentry kind="src" path="/org.eclipse.ui.workbench"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.ui.workbench.texteditor/.cvsignore b/org.eclipse.ui.workbench.texteditor/.cvsignore
new file mode 100644
index 000000000..c5e82d745
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/.cvsignore
@@ -0,0 +1 @@
+bin \ No newline at end of file
diff --git a/org.eclipse.ui.workbench.texteditor/.project b/org.eclipse.ui.workbench.texteditor/.project
new file mode 100644
index 000000000..a0fcf5e59
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/.project
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.ui.workbench.texteditor</name>
+ <comment></comment>
+ <projects>
+ <project>org.eclipse.core.resources</project>
+ <project>org.eclipse.core.runtime</project>
+ <project>org.eclipse.jface</project>
+ <project>org.eclipse.jface.text</project>
+ <project>org.eclipse.text</project>
+ <project>org.eclipse.ui.workbench</project>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/org.eclipse.ui.workbench.texteditor/build.properties b/org.eclipse.ui.workbench.texteditor/build.properties
new file mode 100644
index 000000000..8c60a3d3d
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/build.properties
@@ -0,0 +1,4 @@
+source.texteditor.jar = src/
+bin.includes = *.jar,\
+ fragment.xml,\
+ fragment.properties
diff --git a/org.eclipse.ui.workbench.texteditor/fragment.properties b/org.eclipse.ui.workbench.texteditor/fragment.properties
new file mode 100644
index 000000000..d08c2e1b8
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/fragment.properties
@@ -0,0 +1,2 @@
+fragmentName= Text Editor Framework Fragment
+providerName= Eclipse.org
diff --git a/org.eclipse.ui.workbench.texteditor/fragment.xml b/org.eclipse.ui.workbench.texteditor/fragment.xml
new file mode 100644
index 000000000..69ab2c6f3
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/fragment.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<fragment
+ id="org.eclipse.ui.workbench.texteditor"
+ name="%fragmentName"
+ version="2.1.0"
+ provider-name="%providerName"
+ plugin-id="org.eclipse.ui.workbench"
+ plugin-version="2.1.0">
+
+ <runtime>
+ <library name="texteditor.jar">
+ <export name="*"/>
+ </library>
+ </runtime>
+
+ <requires>
+ <import plugin="org.eclipse.text"/>
+ </requires>
+
+
+</fragment>
diff --git a/org.eclipse.ui.workbench.texteditor/scripts/exportplugin.xml b/org.eclipse.ui.workbench.texteditor/scripts/exportplugin.xml
new file mode 100644
index 000000000..7e4684ff7
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/scripts/exportplugin.xml
@@ -0,0 +1,29 @@
+<project name="Export Workbench Text Editor Fragment" default="export" basedir="..">
+ <target name="init">
+ <tstamp/>
+ <property name="destdir" value="../../plugin-export" />
+ <property name="plugin" value="org.eclipse.ui.workbench.texteditor" />
+ <property name="version" value="_2.1.0" />
+ <property name="dest" value="${destdir}/${plugin}${version}" />
+ </target>
+
+ <target name="build" depends="init">
+ <eclipse.incrementalBuild project="${plugin}" kind="incr"/>
+ </target>
+
+ <target name="export" depends="build">
+ <mkdir dir="${destdir}" />
+ <delete dir="${dest}" />
+ <mkdir dir="${dest}" />
+ <jar
+ jarfile="${dest}/texteditor.jar"
+ basedir="bin"
+ />
+ <copy file="fragment.xml" todir="${dest}"/>
+ <copy file="fragment.properties" todir="${dest}"/>
+ <zip zipfile="${dest}/texteditorsrc.jar">
+ <fileset dir="src" />
+ </zip>
+ </target>
+
+</project> \ No newline at end of file
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractDocumentProvider.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractDocumentProvider.java
new file mode 100644
index 000000000..a10ce6ef3
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractDocumentProvider.java
@@ -0,0 +1,791 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jface.text.DocumentEvent;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IDocumentListener;
+
+import org.eclipse.jface.text.source.IAnnotationModel;
+import org.eclipse.jface.util.Assert;
+
+import org.eclipse.ui.PlatformUI;
+
+import org.eclipse.core.resources.IResourceStatus;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+
+
+/**
+ * An abstract implementation of a shareable document provider.
+ * <p>
+ * Subclasses must implement <code>createDocument</code>,
+ * <code>createAnnotationModel</code>, and <code>doSaveDocument</code>.
+ * </p>
+ */
+public abstract class AbstractDocumentProvider implements IDocumentProvider, IDocumentProviderExtension {
+
+
+ /**
+ * Collection of all information managed for a connected element.
+ */
+ protected class ElementInfo implements IDocumentListener {
+
+ /** The element for which the info is stored */
+ public Object fElement;
+ /** How often the element has been connected */
+ public int fCount;
+ /** Can the element be saved */
+ public boolean fCanBeSaved;
+ /** The element's document */
+ public IDocument fDocument;
+ /** The element's annotation model */
+ public IAnnotationModel fModel;
+ /**
+ * Has element state been validated
+ * @since 2.0
+ */
+ public boolean fIsStateValidated;
+ /**
+ * The status of this element
+ * @since 2.0
+ */
+ public IStatus fStatus;
+
+
+ /**
+ * Creates a new element info, initialized with the given
+ * document and annotation model.
+ *
+ * @param document the document
+ * @param model the annotation model
+ */
+ public ElementInfo(IDocument document, IAnnotationModel model) {
+ fDocument= document;
+ fModel= model;
+ fCount= 0;
+ fCanBeSaved= false;
+ fIsStateValidated= false;
+ }
+
+ /**
+ * An element info equals another object if this object is an element info
+ * and if the documents of the two element infos are equal.
+ * @see Object#equals
+ */
+ public boolean equals(Object o) {
+ if (o instanceof ElementInfo) {
+ ElementInfo e= (ElementInfo) o;
+ return fDocument.equals(e.fDocument);
+ }
+ return false;
+ }
+
+ /*
+ * @see Object#hashCode
+ */
+ public int hashCode() {
+ return fDocument.hashCode();
+ }
+
+ /*
+ * @see IDocumentListener#documentChanged(DocumentEvent)
+ */
+ public void documentChanged(DocumentEvent event) {
+ fCanBeSaved= true;
+ removeUnchangedElementListeners(fElement, this);
+ fireElementDirtyStateChanged(fElement, fCanBeSaved);
+ }
+
+ /*
+ * @see IDocumentListener#documentAboutToBeChanged(DocumentEvent)
+ */
+ public void documentAboutToBeChanged(DocumentEvent event) {
+ }
+ };
+
+
+ /**
+ * Enables a certain behavior.
+ * Indicates whether this provider should behave as described in
+ * use case 5 of http://bugs.eclipse.org/bugs/show_bug.cgi?id=10806.
+ * Current value: <code>false</code>
+ * @since 2.0
+ */
+ static final protected boolean PR10806_UC5_ENABLED= false;
+
+ /**
+ * Enables a certain behavior.
+ * Indicates whether this provider should behave as described in
+ * http://bugs.eclipse.org/bugs/show_bug.cgi?id=14469
+ * Notes: This contradicts <code>PR10806_UC5_ENABLED</code>.
+ * Current value: <code>true</code>
+ * @since 2.0
+ */
+ static final protected boolean PR14469_ENABLED= true;
+
+ /**
+ * Constant for representing an ok status. This is considered a value object.
+ * @since 2.0
+ */
+ static final protected IStatus STATUS_OK= new Status(IStatus.OK, PlatformUI.PLUGIN_ID, IStatus.OK, "OK", null);
+
+ /**
+ * Constant for representing an error status. This is considered a value object.
+ * @since 2.0
+ */
+ static final protected IStatus STATUS_ERROR= new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, IStatus.INFO, "ERROR", null);
+
+
+ /** Information of all connected elements */
+ private Map fElementInfoMap= new HashMap();
+ /** The element state listeners */
+ private List fElementStateListeners= new ArrayList();
+
+
+ /**
+ * Creates a new document provider.
+ */
+ protected AbstractDocumentProvider() {
+ }
+
+ /**
+ * Creates the document for the given element.<p>
+ * Subclasses must implement this method.
+ *
+ * @param element the element
+ * @return the document
+ * @exception CoreException if the document could not be created
+ */
+ protected abstract IDocument createDocument(Object element) throws CoreException;
+
+ /**
+ * Creates an annotation model for the given element. <p>
+ * Subclasses must implement this method.
+ *
+ * @param element the element
+ * @return the annotation model
+ * @exception CoreException if the annotation model could not be created
+ */
+ protected abstract IAnnotationModel createAnnotationModel(Object element) throws CoreException;
+
+ /**
+ * Performs the actual work of saving the given document provided for the
+ * given element. <p>
+ * Subclasses must implement this method.
+ *
+ * @param monitor a progress monitor to report progress and request cancelation
+ * @param element the element
+ * @param document the document
+ * @param overwrite indicates whether an overwrite should happen if necessary
+ * @exception CoreException if document could not be stored to the given element
+ */
+ protected abstract void doSaveDocument(IProgressMonitor monitor, Object element, IDocument document, boolean overwrite) throws CoreException;
+
+
+ /**
+ * Returns the element info object for the given element.
+ *
+ * @param element the element
+ * @return the element info object, or <code>null</code> if none
+ */
+ protected ElementInfo getElementInfo(Object element) {
+ return (ElementInfo) fElementInfoMap.get(element);
+ }
+
+ /**
+ * Creates a new element info object for the given element.<p>
+ * This method is called from <code>connect</code> when an element info needs
+ * to be created. The <code>AbstractDocumentProvider</code> implementation
+ * of this method returns a new element info object whose document and
+ * annotation model are the values of <code>createDocument(element)</code>
+ * and <code>createAnnotationModel(element)</code>, respectively. Subclasses
+ * may override.
+ *
+ * @param element the element
+ * @return a new element info object
+ * @exception CoreException if the document or annotation model could not be created
+ */
+ protected ElementInfo createElementInfo(Object element) throws CoreException {
+ return new ElementInfo(createDocument(element), createAnnotationModel(element));
+ }
+
+ /**
+ * Disposes of the given element info object. <p>
+ * This method is called when an element info is disposed. The
+ * <code>AbstractDocumentProvider</code> implementation of this
+ * method does nothing. Subclasses may reimplement.
+ *
+ * @param element the element
+ * @param info the element info object
+ */
+ protected void disposeElementInfo(Object element, ElementInfo info) {
+ }
+
+ /**
+ * Called on initial creation and when the dirty state of the element
+ * changes to <code>false</code>. Adds all listeners which must be
+ * active as long as the element is not dirty. This method is called
+ * before <code>fireElementDirtyStateChanged</code> or <code>
+ * fireElementContentReplaced</code> is called.
+ * Subclasses may extend.
+ *
+ * @param element the element
+ * @param info the element info object
+ */
+ protected void addUnchangedElementListeners(Object element, ElementInfo info) {
+ if (info.fDocument != null)
+ info.fDocument.addDocumentListener(info);
+ }
+
+ /**
+ * Called when the given element gets dirty. Removes all listeners
+ * which must be active only when the element is not dirty. This
+ * method is called before <code>fireElementDirtyStateChanged</code>
+ * or <code>fireElementContentReplaced</code> is called.
+ * Subclasses may extend.
+ *
+ * @param element the element
+ * @param info the element info object
+ */
+ protected void removeUnchangedElementListeners(Object element, ElementInfo info) {
+ if (info.fDocument != null)
+ info.fDocument.removeDocumentListener(info);
+ }
+
+ /**
+ * Enumerates the elements connected via this document provider.
+ *
+ * @return the list of elements (element type: <code>Object</code>)
+ */
+ protected Iterator getConnectedElements() {
+ Set s= new HashSet();
+ Set keys= fElementInfoMap.keySet();
+ if (keys != null)
+ s.addAll(keys);
+ return s.iterator();
+ }
+
+ /*
+ * @see IDocumentProvider#connect
+ */
+ public final void connect(Object element) throws CoreException {
+ ElementInfo info= (ElementInfo) fElementInfoMap.get(element);
+ if (info == null) {
+
+ info= createElementInfo(element);
+ if (info == null)
+ info= new ElementInfo(null, null);
+
+ info.fElement= element;
+
+ addUnchangedElementListeners(element, info);
+
+ fElementInfoMap.put(element, info);
+ if (fElementInfoMap.size() == 1)
+ connected();
+ }
+ ++ info.fCount;
+ }
+
+ /**
+ * This hook method is called when this provider starts managing documents for
+ * elements. I.e. it is called when the first element gets connected to this provider.
+ * Subclasses may extend.
+ * @since 2.0
+ */
+ protected void connected() {
+ }
+
+ /*
+ * @see IDocumentProvider#disconnect
+ */
+ public final void disconnect(Object element) {
+ ElementInfo info= (ElementInfo) fElementInfoMap.get(element);
+
+ if (info == null)
+ return;
+
+ if (info.fCount == 1) {
+
+ fElementInfoMap.remove(element);
+ removeUnchangedElementListeners(element, info);
+ disposeElementInfo(element, info);
+
+ if (fElementInfoMap.size() == 0)
+ disconnected();
+
+ } else
+ -- info.fCount;
+ }
+
+ /**
+ * This hook method is called when this provider stops managing documents for
+ * element. I.e. it is called when the last element gets disconnected from this provider.
+ * Subcalles may extend.
+ * @since 2.0
+ */
+ protected void disconnected() {
+ }
+
+ /*
+ * @see IDocumentProvider#getDocument
+ */
+ public IDocument getDocument(Object element) {
+
+ if (element == null)
+ return null;
+
+ ElementInfo info= (ElementInfo) fElementInfoMap.get(element);
+ return (info != null ? info.fDocument : null);
+ }
+
+ /*
+ * @see IDocumentProvider#mustSaveDocument
+ */
+ public boolean mustSaveDocument(Object element) {
+
+ if (element == null)
+ return false;
+
+ ElementInfo info= (ElementInfo) fElementInfoMap.get(element);
+ return (info != null ? info.fCount == 1 && info.fCanBeSaved : false);
+ }
+
+ /*
+ * @see IDocumentProvider#getAnnotationModel
+ */
+ public IAnnotationModel getAnnotationModel(Object element) {
+
+ if (element == null)
+ return null;
+
+ ElementInfo info= (ElementInfo) fElementInfoMap.get(element);
+ return (info != null ? info.fModel : null);
+ }
+
+ /*
+ * @see IDocumentProvider#canSaveDocument(Object)
+ */
+ public boolean canSaveDocument(Object element) {
+
+ if (element == null)
+ return false;
+
+ ElementInfo info= (ElementInfo) fElementInfoMap.get(element);
+ return (info != null ? info.fCanBeSaved : false);
+ }
+
+ /*
+ * @see IDocumentProvider#resetDocument(Object)
+ */
+ public void resetDocument(Object element) throws CoreException {
+ if (element == null)
+ return;
+
+ ElementInfo info= (ElementInfo) fElementInfoMap.get(element);
+ if (info != null) {
+
+ IDocument original= null;
+ IStatus status= null;
+
+ try {
+ original= createDocument(element);
+ } catch (CoreException x) {
+ status= x.getStatus();
+ }
+
+ info.fStatus= status;
+
+ if (original != null) {
+ fireElementContentAboutToBeReplaced(element);
+ info.fDocument.set(original.get());
+ if (info.fCanBeSaved) {
+ info.fCanBeSaved= false;
+ addUnchangedElementListeners(element, info);
+ }
+ fireElementContentReplaced(element);
+ }
+ }
+ }
+
+ /*
+ * @see IDocumentProvider#saveDocument(IProgressMonitor, Object, IDocument, boolean)
+ */
+ public void saveDocument(IProgressMonitor monitor, Object element, IDocument document, boolean overwrite) throws CoreException {
+
+ if (element == null)
+ return;
+
+ ElementInfo info= (ElementInfo) fElementInfoMap.get(element);
+ if (info != null) {
+
+ if (info.fDocument != document) {
+ Status status= new Status(IStatus.WARNING, PlatformUI.PLUGIN_ID, IResourceStatus.ERROR, EditorMessages.getString("AbstractDocumentProvider.error.save.inuse"), null); //$NON-NLS-1$
+ throw new CoreException(status);
+ }
+
+ doSaveDocument(monitor, element, document, overwrite);
+ info.fCanBeSaved= false;
+ addUnchangedElementListeners(element, info);
+ fireElementDirtyStateChanged(element, false);
+
+ } else {
+ doSaveDocument(monitor, element, document, overwrite);
+ }
+ }
+
+ /**
+ * The <code>AbstractDocumentProvider</code> implementation of this
+ * <code>IDocumentProvider</code> method does nothing. Subclasses may
+ * reimplement.
+ *
+ * @param element the element
+ */
+ public void aboutToChange(Object element) {
+ }
+
+ /**
+ * The <code>AbstractDocumentProvider</code> implementation of this
+ * <code>IDocumentProvider</code> method does nothing. Subclasses may
+ * reimplement.
+ *
+ * @param element the element
+ */
+ public void changed(Object element) {
+ }
+
+ /*
+ * @see IDocumentProvider#addElementStateListener(IElementStateListener)
+ */
+ public void addElementStateListener(IElementStateListener listener) {
+ Assert.isNotNull(listener);
+ if (!fElementStateListeners.contains(listener))
+ fElementStateListeners.add(listener);
+ }
+
+ /*
+ * @see IDocumentProvider#removeElementStateListener(IElementStateListener)
+ */
+ public void removeElementStateListener(IElementStateListener listener) {
+ Assert.isNotNull(listener);
+ fElementStateListeners.remove(listener);
+ }
+
+ /**
+ * Informs all registered element state listeners about a change in the
+ * dirty state of the given element.
+ *
+ * @param element the element
+ * @param isDirty the new dirty state
+ * @see IElementStateListener#elementDirtyStateChanged
+ */
+ protected void fireElementDirtyStateChanged(Object element, boolean isDirty) {
+ Iterator e= new ArrayList(fElementStateListeners).iterator();
+ while (e.hasNext()) {
+ IElementStateListener l= (IElementStateListener) e.next();
+ l.elementDirtyStateChanged(element, isDirty);
+ }
+ }
+
+ /**
+ * Informs all registered element state listeners about an impending
+ * replace of the given element's content.
+ *
+ * @param element the element
+ * @see IElementStateListener#elementContentAboutToBeReplaced
+ */
+ protected void fireElementContentAboutToBeReplaced(Object element) {
+ Iterator e= new ArrayList(fElementStateListeners).iterator();
+ while (e.hasNext()) {
+ IElementStateListener l= (IElementStateListener) e.next();
+ l.elementContentAboutToBeReplaced(element);
+ }
+ }
+
+ /**
+ * Informs all registered element state listeners about the just-completed
+ * replace of the given element's content.
+ *
+ * @param element the element
+ * @see IElementStateListener#elementContentReplaced
+ */
+ protected void fireElementContentReplaced(Object element) {
+ Iterator e= new ArrayList(fElementStateListeners).iterator();
+ while (e.hasNext()) {
+ IElementStateListener l= (IElementStateListener) e.next();
+ l.elementContentReplaced(element);
+ }
+ }
+
+ /**
+ * Informs all registered element state listeners about the deletion
+ * of the given element.
+ *
+ * @param element the element
+ * @see IElementStateListener#elementDeleted
+ */
+ protected void fireElementDeleted(Object element) {
+ Iterator e= new ArrayList(fElementStateListeners).iterator();
+ while (e.hasNext()) {
+ IElementStateListener l= (IElementStateListener) e.next();
+ l.elementDeleted(element);
+ }
+ }
+
+ /**
+ * Informs all registered element state listeners about a move.
+ *
+ * @param originalElement the element before the move
+ * @param movedElement the element after the move
+ * @see IElementStateListener#elementMoved
+ */
+ protected void fireElementMoved(Object originalElement, Object movedElement) {
+ Iterator e= new ArrayList(fElementStateListeners).iterator();
+ while (e.hasNext()) {
+ IElementStateListener l= (IElementStateListener) e.next();
+ l.elementMoved(originalElement, movedElement);
+ }
+ }
+
+ /*
+ * @see IDocumentProvider#getModificationStamp(Object)
+ * @since 2.0
+ */
+ public long getModificationStamp(Object element) {
+ return 0;
+ }
+
+ /*
+ * @see IDocumentProvider#getSynchronizationStamp(Object)
+ * @since 2.0
+ */
+ public long getSynchronizationStamp(Object element) {
+ return 0;
+ }
+
+ /*
+ * @see IDocumentProvider#isDeleted(Object)
+ * @since 2.0
+ */
+ public boolean isDeleted(Object element) {
+ return false;
+ }
+
+ /*
+ * @see IDocumentProviderExtension#isReadOnly(Object)
+ * @since 2.0
+ */
+ public boolean isReadOnly(Object element) {
+ return true;
+ }
+
+ /*
+ * @see IDocumentProviderExtension#isModifiable(Object)
+ * @since 2.0
+ */
+ public boolean isModifiable(Object element) {
+ return false;
+ }
+
+ /**
+ * Returns whether <code>validateState</code> has been called for the given element
+ * since the element's state has potentially been invalidated.
+ *
+ * @param element the element
+ * @return whether <code>validateState</code> has been called for the given element
+ * @since 2.0
+ */
+ public boolean isStateValidated(Object element) {
+ ElementInfo info= (ElementInfo) fElementInfoMap.get(element);
+ if (info != null)
+ return info.fIsStateValidated;
+ return false;
+ }
+
+ /**
+ * Hook method for validating the state of the given element. Must not take care of cache updating etc.
+ * Default implementation is empty.
+ *
+ * @param element the element
+ * @param computationContext the context in which validation happens
+ * @exception CoreException in case validation fails
+ * @since 2.0
+ */
+ protected void doValidateState(Object element, Object computationContext) throws CoreException {
+ }
+
+ /*
+ * @see IDocumentProviderExtension#validateState(Object, Object)
+ * @since 2.0
+ */
+ final public void validateState(Object element, Object computationContext) throws CoreException {
+ ElementInfo info= (ElementInfo) fElementInfoMap.get(element);
+ if (info != null) {
+ doValidateState(element, computationContext);
+ doUpdateStateCache(element);
+ info.fIsStateValidated= true;
+ fireElementStateValidationChanged(element, true);
+ }
+ }
+
+ /**
+ * Hook method for updating the state of the given element.
+ * Default implementation is empty.
+ *
+ * @param element the element
+ * @exception CoreException in case state cache updating fails
+ * @since 2.0
+ */
+ protected void doUpdateStateCache(Object element) throws CoreException {
+ }
+
+ /**
+ * Returns whether the state of the element must be invalidated given its
+ * previous read-only state.
+ *
+ * @param element the element
+ * @param wasReadOnly the previous read-only state
+ * @return <code>true</code> if the state of the given element must be invalidated
+ * @since 2.0
+ */
+ protected boolean invalidatesState(Object element, boolean wasReadOnly) {
+ Assert.isTrue(PR10806_UC5_ENABLED != PR14469_ENABLED);
+ boolean readOnlyChanged= (isReadOnly(element) != wasReadOnly);
+ if (PR14469_ENABLED)
+ return readOnlyChanged && !canSaveDocument(element);
+ return readOnlyChanged;
+ }
+
+ /*
+ * @see IDocumentProviderExtension#updateStateCache(Object)
+ * @since 2.0
+ */
+ final public void updateStateCache(Object element) throws CoreException {
+ ElementInfo info= (ElementInfo) fElementInfoMap.get(element);
+ if (info != null) {
+ boolean wasReadOnly= isReadOnly(element);
+ doUpdateStateCache(element);
+ if (invalidatesState(element, wasReadOnly)) {
+ info.fIsStateValidated= false;
+ fireElementStateValidationChanged(element, false);
+ }
+ }
+ }
+
+ /*
+ * @see IDocumentProviderExtension#setCanSaveDocument(Object)
+ * @since 2.0
+ */
+ public void setCanSaveDocument(Object element) {
+ if (element != null) {
+ ElementInfo info= (ElementInfo) fElementInfoMap.get(element);
+ if (info != null) {
+ info.fCanBeSaved= true;
+ removeUnchangedElementListeners(element, info);
+ fireElementDirtyStateChanged(element, info.fCanBeSaved);
+ }
+ }
+ }
+
+ /**
+ * Informs all registered element state listeners about a change in the
+ * state validation of the given element.
+ *
+ * @param element the element
+ * @param isStateValidated
+ * @see IElementStateListenerExtension#elementStateValidationChanged(Object, boolean)
+ * @since 2.0
+ */
+ protected void fireElementStateValidationChanged(Object element, boolean isStateValidated) {
+ Iterator e= new ArrayList(fElementStateListeners).iterator();
+ while (e.hasNext()) {
+ Object o= e.next();
+ if (o instanceof IElementStateListenerExtension) {
+ IElementStateListenerExtension l= (IElementStateListenerExtension) o;
+ l.elementStateValidationChanged(element, isStateValidated);
+ }
+ }
+ }
+
+ /**
+ * Informs all registered element state listeners about the current
+ * change of the element
+ *
+ * @param element the element
+ * @see IElementStateListenerExtension#elementStateChanging(Object)
+ * @since 2.0
+ */
+ protected void fireElementStateChanging(Object element) {
+ Iterator e= new ArrayList(fElementStateListeners).iterator();
+ while (e.hasNext()) {
+ Object o= e.next();
+ if (o instanceof IElementStateListenerExtension) {
+ IElementStateListenerExtension l= (IElementStateListenerExtension) o;
+ l.elementStateChanging(element);
+ }
+ }
+ }
+
+ /**
+ * Informs all registered element state listeners about the failed
+ * change of the element
+ *
+ * @param element the element
+ * @see IElementStateListenerExtension#elementStateChangeFailed(Object)
+ * @since 2.0
+ */
+ protected void fireElementStateChangeFailed(Object element) {
+ Iterator e= new ArrayList(fElementStateListeners).iterator();
+ while (e.hasNext()) {
+ Object o= e.next();
+ if (o instanceof IElementStateListenerExtension) {
+ IElementStateListenerExtension l= (IElementStateListenerExtension) o;
+ l.elementStateChangeFailed(element);
+ }
+ }
+ }
+
+ /*
+ * @see IDocumentProviderExtension#getStatus(Object)
+ * @since 2.0
+ */
+ public IStatus getStatus(Object element) {
+ ElementInfo info= (ElementInfo) fElementInfoMap.get(element);
+ if (info != null) {
+ if (info.fStatus != null)
+ return info.fStatus;
+ return (info.fDocument == null ? STATUS_ERROR : STATUS_OK);
+ }
+
+ return STATUS_ERROR;
+ }
+
+ /*
+ * @see org.eclipse.ui.texteditor.IDocumentProviderExtension#synchronize(Object)
+ * @since 2.0
+ */
+ public void synchronize(Object element) throws CoreException {
+ }
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractMarkerAnnotationModel.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractMarkerAnnotationModel.java
new file mode 100644
index 000000000..d84e2bf21
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractMarkerAnnotationModel.java
@@ -0,0 +1,571 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.Position;
+import org.eclipse.jface.text.source.Annotation;
+import org.eclipse.jface.text.source.AnnotationModel;
+import org.eclipse.jface.util.Assert;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.ILog;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.ui.PlatformUI;
+
+
+/**
+ * Abstract implementation of a marker-based annotation model.
+ * <p>
+ * Markers are provided by an underlying source (a subclass responsibility).
+ * Markers whose textual range gets deleted during text editing are removed
+ * from the model on save. The <code>updateMarkers</code> method can be used
+ * to force the model to update the source's markers with any changes to their
+ * locations due to edits. Clients can register <code>IMarkerUpdater</code>
+ * objects in order to define the process of marker updating. Registration can be done
+ * using the <code>"org.eclipse.ui.markerUpdaters"</code> extension point.
+ * <p>
+ * Subclasses must implement the following methods:
+ * <ul>
+ * <li><code>retrieveMarkers</code></li>
+ * <li><code>isAcceptable</code></li>
+ * <li><code>deleteMarkers</code></li>
+ * <li><code>listenToMarkerChanges</code></li>
+ * </ul>
+ * </p>
+ */
+public abstract class AbstractMarkerAnnotationModel extends AnnotationModel {
+
+ /** List of annotations whose text range became invalid because of document changes */
+ private List fDeletedAnnotations= new ArrayList(2);
+ /** Reference counters to track how often an annotation model is connected to its document */
+ private HashMap fRefcountTable= new HashMap();
+ /** List of registered and instantiated marker updaters */
+ private List fInstantiatedMarkerUpdaters= null;
+ /** List of registered but not yet instantiated marker updaters */
+ private List fMarkerUpdaterSpecifications= null;
+
+
+ /**
+ * Retrieves all markers from this model.<p>
+ * Subclasses must implement this method.
+ *
+ * @return the list of markers
+ * @exception CoreException if there is a problem getting the markers
+ */
+ protected abstract IMarker[] retrieveMarkers() throws CoreException;
+
+ /**
+ * Deletes the given markers from this model.<p>
+ * Subclasses must implement this method.
+ *
+ * @param markers the list of markers
+ * @exception CoreException if there are problems deleting the markers
+ */
+ protected abstract void deleteMarkers(IMarker[] markers) throws CoreException;
+
+ /**
+ * Tells the model whether it should listen for marker changes. <p>
+ * Subclasses must implement this method.
+ *
+ * @param listen <code>true</code> if this model should listen, and
+ * <code>false</code> otherwise
+ */
+ protected abstract void listenToMarkerChanges(boolean listen);
+
+ /**
+ * Determines whether the marker is acceptable as an addition to this model.
+ * If the marker, say, represents an aspect or range of no interest to this
+ * model, the marker is rejected.<p>
+ * Subclasses must implement this method.
+ *
+ * @param marker the marker
+ * @return <code>true</code> if the marker is acceptable
+ */
+ protected abstract boolean isAcceptable(IMarker marker);
+
+ /**
+ * Creates a new annotation model. The annotation model does not manage any
+ * annotations and is not connected to any document.
+ */
+ protected AbstractMarkerAnnotationModel() {
+ }
+
+ /**
+ * Adds the given marker updater to this annotation model.
+ * It is client's responsibility to ensure the consitency of the
+ * set of registered marker updaters.
+ *
+ * @param markerUpdater the marker updater to be added
+ */
+ protected void addMarkerUpdater(IMarkerUpdater markerUpdater) {
+ if (!fInstantiatedMarkerUpdaters.contains(markerUpdater))
+ fInstantiatedMarkerUpdaters.add(markerUpdater);
+ }
+
+ /**
+ * Removes the given marker updater from this annotation model.
+ *
+ * @param markerUpdater the marker updater to be removed
+ */
+ protected void removeMarkerUpdater(IMarkerUpdater markerUpdater) {
+ fInstantiatedMarkerUpdaters.remove(markerUpdater);
+ }
+
+ /**
+ * Creates a new annotation for the given marker.<p>
+ * Subclasses may override.
+ *
+ * @param marker the marker
+ * @return the new marker annotation
+ */
+ protected MarkerAnnotation createMarkerAnnotation(IMarker marker) {
+ return new MarkerAnnotation(marker);
+ }
+
+ /**
+ * Handles an unanticipated <code>CoreException</code> in
+ * a standard manner.
+ *
+ * @param exception the exception
+ * @param message a message to aid debugging
+ */
+ protected void handleCoreException(CoreException exception, String message) {
+
+ ILog log= Platform.getPlugin(PlatformUI.PLUGIN_ID).getLog();
+
+ if (message != null)
+ log.log(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, message, null));
+
+ log.log(exception.getStatus());
+ }
+
+ /**
+ * Creates and returns the character position of the given marker based
+ * on its attributes. <p>
+ * Subclasses may override.
+ *
+ * @param marker the marker
+ * @return the new position or <code>null</code> if no valid position
+ */
+ protected Position createPositionFromMarker(IMarker marker) {
+
+ int start= MarkerUtilities.getCharStart(marker);
+ int end= MarkerUtilities.getCharEnd(marker);
+
+ if (start > end) {
+ end= start + end;
+ start= end - start;
+ end= end - start;
+ }
+
+ if (start == -1 && end == -1) {
+ // marker line number is 1-based
+ int line= MarkerUtilities.getLineNumber(marker);
+ if (line > 0 && fDocument != null) {
+ try {
+ start= fDocument.getLineOffset(line - 1);
+ end= start;
+ } catch (BadLocationException x) {
+ }
+ }
+ }
+
+ if (start > -1 && end > -1)
+ return new Position(start, end - start);
+
+ return null;
+ }
+
+ /**
+ * Creates an annotation for the given marker and adds it to this model.
+ * Does nothing if the marker is not acceptable to this model.
+ *
+ * @param marker the marker
+ * @see #isAcceptable
+ */
+ protected final void addMarkerAnnotation(IMarker marker) {
+
+ if (isAcceptable(marker)) {
+ Position p= createPositionFromMarker(marker);
+ if (p != null)
+ addAnnotation(createMarkerAnnotation(marker), p, false);
+ }
+ }
+
+ /**
+ * Connects to the source of markers as marker change listener.
+ * @see AnnotationModel#connected
+ */
+ protected void connected() {
+
+ listenToMarkerChanges(true);
+
+ try {
+ catchupWithMarkers();
+ } catch (CoreException x) {
+ handleCoreException(x, EditorMessages.getString("AbstractMarkerAnnotationModel.connected")); //$NON-NLS-1$
+ }
+
+ fireModelChanged();
+ }
+
+ /**
+ * Installs all marker updaters for this marker annotation model.
+ */
+ private void installMarkerUpdaters() {
+
+ // initialize lists - indicates that the initialization happened
+ fMarkerUpdaterSpecifications= new ArrayList(2);
+ fInstantiatedMarkerUpdaters= new ArrayList(2);
+
+ // populate list
+ IExtensionPoint extensionPoint= Platform.getPluginRegistry().getExtensionPoint(PlatformUI.PLUGIN_ID, "markerUpdaters"); //$NON-NLS-1$
+ if (extensionPoint != null) {
+ IConfigurationElement[] elements= extensionPoint.getConfigurationElements();
+ for (int i= 0; i < elements.length; i++)
+ fMarkerUpdaterSpecifications.add(elements[i]);
+ }
+ }
+
+ /**
+ * Uninstalls all marker updaters.
+ */
+ private void uninstallMarkerUpdaters() {
+ if (fInstantiatedMarkerUpdaters != null) {
+ fInstantiatedMarkerUpdaters.clear();
+ fInstantiatedMarkerUpdaters= null;
+ }
+
+ if (fMarkerUpdaterSpecifications != null) {
+ fMarkerUpdaterSpecifications.clear();
+ fMarkerUpdaterSpecifications= null;
+ }
+ }
+
+ /**
+ * Removes the marker change listener.
+ * @see AnnotationModel#disconnected
+ */
+ protected void disconnected() {
+ listenToMarkerChanges(false);
+ uninstallMarkerUpdaters();
+ }
+
+ /**
+ * Returns the position known to this annotation model for the given marker.
+ *
+ * @param marker the marker
+ * @return the position, or <code>null</code> if none
+ */
+ public Position getMarkerPosition(IMarker marker) {
+ MarkerAnnotation a= getMarkerAnnotation(marker);
+ if (a != null) {
+ return (Position) fAnnotations.get(a);
+ }
+ return null;
+ }
+
+ /**
+ * Updates the annotation corresponding to the given marker which has changed
+ * in some way. <p>
+ * Subclasses may override.
+ *
+ * @param marker the marker
+ */
+ protected void modifyMarkerAnnotation(IMarker marker) {
+ MarkerAnnotation a= getMarkerAnnotation(marker);
+ if (a != null) {
+
+ // update annotation presentation
+ a.update();
+
+ // update annotation position
+ Position p1= createPositionFromMarker(marker);
+ if (p1 != null) {
+ Position p0= (Position) fAnnotations.get(a);
+ p0.setOffset(p1.getOffset());
+ p0.setLength(p1.getLength());
+ }
+ }
+ }
+
+ /*
+ * @see AnnotationModel#removeAnnotations
+ */
+ protected void removeAnnotations(List annotations, boolean fireModelChanged, boolean modelInitiated) {
+ if (annotations != null && annotations.size() > 0) {
+
+ List markerAnnotations= new ArrayList();
+ for (Iterator e= annotations.iterator(); e.hasNext();) {
+ Annotation a= (Annotation) e.next();
+ if (a instanceof MarkerAnnotation)
+ markerAnnotations.add(a);
+
+ // remove annotations from annotation model
+ removeAnnotation(a, false);
+ }
+
+ if (markerAnnotations.size() > 0) {
+
+ if (modelInitiated) {
+ // if model initiated also remove it from the marker manager
+
+ listenToMarkerChanges(false);
+ try {
+
+ IMarker[] m= new IMarker[markerAnnotations.size()];
+ for (int i= 0; i < m.length; i++) {
+ MarkerAnnotation ma = (MarkerAnnotation) markerAnnotations.get(i);
+ m[i]= ma.getMarker();
+ }
+ deleteMarkers(m);
+
+ } catch (CoreException x) {
+ handleCoreException(x, EditorMessages.getString("AbstractMarkerAnnotationModel.removeAnnotations")); //$NON-NLS-1$
+ }
+ listenToMarkerChanges(true);
+
+ } else {
+ // remember deleted annotations in order to remove their markers later on
+ fDeletedAnnotations.addAll(markerAnnotations);
+ }
+ }
+
+ if (fireModelChanged)
+ fireModelChanged();
+ }
+ }
+
+ /**
+ * Removes the annotation corresponding to the given marker. Does nothing
+ * if there is no annotation for this marker.
+ *
+ * @param marker the marker
+ */
+ protected final void removeMarkerAnnotation(IMarker marker) {
+ MarkerAnnotation a= getMarkerAnnotation(marker);
+ if (a != null) {
+ removeAnnotation(a, false);
+ }
+ }
+
+ /**
+ * Re-populates this model with annotations for all markers retrieved
+ * from the maker source via <code>retrieveMarkers</code>.
+ *
+ * @exception CoreException if there is a problem getting the markers
+ */
+ private void catchupWithMarkers() throws CoreException {
+
+ for (Iterator e=getAnnotationIterator(false); e.hasNext();) {
+ Annotation a= (Annotation) e.next();
+ if (a instanceof MarkerAnnotation)
+ removeAnnotation(a, false);
+ }
+
+ IMarker[] markers= retrieveMarkers();
+ if (markers != null) {
+ for (int i= 0; i < markers.length; i++)
+ addMarkerAnnotation(markers[i]);
+ }
+ }
+
+ /**
+ * Returns this model's annotation for the given marker.
+ *
+ * @param marker the marker
+ * @return the annotation, or <code>null</code> if none
+ */
+ public final MarkerAnnotation getMarkerAnnotation(IMarker marker) {
+ Iterator e= getAnnotationIterator(false);
+ while (e.hasNext()) {
+ Object o= e.next();
+ if (o instanceof MarkerAnnotation) {
+ MarkerAnnotation a= (MarkerAnnotation) o;
+ if (marker.equals(a.getMarker())) {
+ return a;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Creates a marker updater as specified in the given configuration element.
+ *
+ * @param element the configuration element
+ * @return the created marker updater or <code>null</code> if none could be created
+ */
+ private IMarkerUpdater createMarkerUpdater(IConfigurationElement element) {
+ try {
+ return (IMarkerUpdater) element.createExecutableExtension("class"); //$NON-NLS-1$
+ } catch (CoreException x) {
+ handleCoreException(x, EditorMessages.getString("AbstractMarkerAnnotationModel.createMarkerUpdater")); //$NON-NLS-1$
+ }
+
+ return null;
+ }
+
+ /**
+ * Checks whether a marker updater is registered for the type of the
+ * given marker but not yet instantiated. If so, the method instantiates
+ * the marker updater and registers it with this model.
+ *
+ * @param marker the marker for which to look for an updater
+ * @since 2.0
+ */
+ private void checkMarkerUpdaters(IMarker marker) {
+ List toBeDeleted= new ArrayList();
+ for (int i= 0; i < fMarkerUpdaterSpecifications.size(); i++) {
+ IConfigurationElement spec= (IConfigurationElement) fMarkerUpdaterSpecifications.get(i);
+ String markerType= spec.getAttribute("markerType"); //$NON-NLS-1$
+ if (markerType == null || MarkerUtilities.isMarkerType(marker, markerType)) {
+ toBeDeleted.add(spec);
+ IMarkerUpdater updater= createMarkerUpdater(spec);
+ if (updater != null)
+ addMarkerUpdater(updater);
+ }
+ }
+
+ for (int i= 0; i < toBeDeleted.size(); i++)
+ fMarkerUpdaterSpecifications.remove(toBeDeleted.get(i));
+ }
+
+ /**
+ * Updates the given marker according to the given position in the given
+ * document. If the given position is <code>null</code>, the marker is
+ * assumed to carry the correct positional information. If it is detected
+ * that the marker is invalid and should thus be deleted, this method
+ * returns <code>false</code>.
+ *
+ * @param marker the marker to be updated
+ * @param document the document into which the given position points
+ * @param position the current position of the marker inside the given document
+ * @exception CoreException if there is a problem updating the marker
+ * @since 2.0
+ */
+ public boolean updateMarker(IMarker marker, IDocument document, Position position) throws CoreException {
+
+ if (fMarkerUpdaterSpecifications == null)
+ installMarkerUpdaters();
+
+ if (!fMarkerUpdaterSpecifications.isEmpty())
+ checkMarkerUpdaters(marker);
+
+ boolean isOK= true;
+
+ for (int i= 0; i < fInstantiatedMarkerUpdaters.size(); i++) {
+ IMarkerUpdater updater= (IMarkerUpdater) fInstantiatedMarkerUpdaters.get(i);
+ String markerType= updater.getMarkerType();
+ if (markerType == null || MarkerUtilities.isMarkerType(marker, markerType)) {
+
+ if (position == null) {
+ /* compatibility code */
+ position= createPositionFromMarker(marker);
+ }
+
+ isOK= (isOK && updater.updateMarker(marker, document, position));
+ }
+ }
+
+ return isOK;
+ }
+
+ /**
+ * Updates the markers managed by this annotation model by calling
+ * all registered marker updaters (<code>IMarkerUpdater</code>).
+ *
+ * @param document the document to which this model is currently connected
+ * @exception CoreException if there is a problem updating the markers
+ */
+ public void updateMarkers(IDocument document) throws CoreException {
+
+ Assert.isTrue(fDocument == document);
+
+ if (fAnnotations.size() == 0 && fDeletedAnnotations.size() == 0)
+ return;
+
+ if (fMarkerUpdaterSpecifications == null)
+ installMarkerUpdaters();
+
+ listenToMarkerChanges(false);
+
+ // update all markers with the positions known by the annotation model
+ for (Iterator e= getAnnotationIterator(false); e.hasNext();) {
+ Object o= e.next();
+ if (o instanceof MarkerAnnotation) {
+ MarkerAnnotation a= (MarkerAnnotation) o;
+ IMarker marker= a.getMarker();
+ Position position= (Position) fAnnotations.get(a);
+ if ( !updateMarker(marker, document, position)) {
+ if ( !fDeletedAnnotations.contains(a))
+ fDeletedAnnotations.add(a);
+ }
+ }
+ }
+
+ if (!fDeletedAnnotations.isEmpty()) {
+ removeAnnotations(fDeletedAnnotations, true, true);
+ fDeletedAnnotations.clear();
+ }
+
+ listenToMarkerChanges(true);
+ }
+
+ /**
+ * Resets all the markers to their original state.
+ */
+ public void resetMarkers() {
+
+ // reinitializes the positions from the markers
+ for (Iterator e= getAnnotationIterator(false); e.hasNext();) {
+ Object o= e.next();
+ if (o instanceof MarkerAnnotation) {
+ MarkerAnnotation a= (MarkerAnnotation) o;
+ Position p= createPositionFromMarker(a.getMarker());
+ if (p != null) {
+ removeAnnotation(a, false);
+ addAnnotation(a, p, false);
+ }
+ }
+ }
+
+ // add the markers of deleted positions back to the annotation model
+ for (Iterator e= fDeletedAnnotations.iterator(); e.hasNext();) {
+ Object o= e.next();
+ if (o instanceof MarkerAnnotation) {
+ MarkerAnnotation a= (MarkerAnnotation) o;
+ Position p= createPositionFromMarker(a.getMarker());
+ if (p != null)
+ addAnnotation(a, p, false);
+ }
+ }
+ fDeletedAnnotations.clear();
+
+ // fire annotation model changed
+ fireModelChanged();
+ }
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractRulerActionDelegate.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractRulerActionDelegate.java
new file mode 100644
index 000000000..5752dd163
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractRulerActionDelegate.java
@@ -0,0 +1,145 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+
+package org.eclipse.ui.texteditor;
+
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.text.source.IVerticalRulerInfo;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.widgets.Control;
+
+import org.eclipse.ui.IEditorActionDelegate;
+import org.eclipse.ui.IEditorPart;
+
+/**
+ * This class serves as an adapter for actions contributed to the vertical ruler's
+ * context menu. This adapter provides the contributed actions access to their editor
+ * and the editor's vertical ruler. These actions gain only limited access to the vertical
+ * ruler as defined by <code>IVerticalRulerInfo</code>. The adapter updates the
+ * adapter (inner) action on menu and mouse action on the vertical ruler.<p>
+ * Extending classes must implement the factory method
+ * <code>createAction(ITextEditor editor, IVerticalRulerInfo)</code>.
+ * @since 2.0
+ */
+public abstract class AbstractRulerActionDelegate implements IEditorActionDelegate, MouseListener, IMenuListener {
+
+ /** The editor. */
+ private IEditorPart fEditor;
+ /** The action calling the action delegate. */
+ private IAction fCallerAction;
+ /** The underlying action. */
+ private IAction fAction;
+
+ /**
+ * The factory method creating the underlying action.
+ *
+ * @param editor the editor the action to be created will work on
+ * @param rulerInfo the vertical ruler the action to be created will work on
+ * @return the created action
+ */
+ protected abstract IAction createAction(ITextEditor editor, IVerticalRulerInfo rulerInfo);
+
+
+ /*
+ * @see IEditorActionDelegate#setActiveEditor(IAction, IEditorPart)
+ */
+ public void setActiveEditor(IAction callerAction, IEditorPart targetEditor) {
+ if (fEditor != null) {
+ IVerticalRulerInfo rulerInfo= (IVerticalRulerInfo) fEditor.getAdapter(IVerticalRulerInfo.class);
+ if (rulerInfo != null) {
+ Control control= rulerInfo.getControl();
+ if (control != null && !control.isDisposed())
+ control.removeMouseListener(this);
+ }
+
+ if (fEditor instanceof ITextEditorExtension)
+ ((ITextEditorExtension) fEditor).removeRulerContextMenuListener(this);
+ }
+
+ fEditor= targetEditor;
+ fCallerAction= callerAction;
+ fAction= null;
+
+ if (fEditor != null && fEditor instanceof ITextEditor) {
+ if (fEditor instanceof ITextEditorExtension)
+ ((ITextEditorExtension) fEditor).addRulerContextMenuListener(this);
+
+ IVerticalRulerInfo rulerInfo= (IVerticalRulerInfo) fEditor.getAdapter(IVerticalRulerInfo.class);
+ if (rulerInfo != null) {
+ fAction= createAction((ITextEditor) fEditor, rulerInfo);
+ update();
+
+ Control control= rulerInfo.getControl();
+ if (control != null && !control.isDisposed())
+ control.addMouseListener(this);
+ }
+ }
+ }
+
+ /*
+ * @see IActionDelegate#run(IAction)
+ */
+ public void run(IAction callerAction) {
+ if (fAction != null)
+ fAction.run();
+ }
+
+ /*
+ * @see IActionDelegate#selectionChanged(IAction, ISelection)
+ */
+ public void selectionChanged(IAction action, ISelection selection) {
+ }
+
+ /**
+ * Requests the adaptee to update itself to the current state.
+ */
+ private void update() {
+ if (fAction != null && fAction instanceof IUpdate) {
+ ((IUpdate) fAction).update();
+ if (fCallerAction != null) {
+ fCallerAction.setText(fAction.getText());
+ fCallerAction.setEnabled(fAction.isEnabled());
+ }
+ }
+ }
+
+ /*
+ * @see IMenuListener#menuAboutToShow(IMenuManager)
+ */
+ public void menuAboutToShow(IMenuManager manager) {
+ update();
+ }
+
+ /*
+ * @see MouseListener#mouseDoubleClick(MouseEvent)
+ */
+ public void mouseDoubleClick(MouseEvent e) {
+ }
+
+ /*
+ * @see MouseListener#mouseDown(MouseEvent)
+ */
+ public void mouseDown(MouseEvent e) {
+ update();
+ }
+
+ /*
+ * @see MouseListener#mouseUp(MouseEvent)
+ */
+ public void mouseUp(MouseEvent e) {
+ }
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractTextEditor.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractTextEditor.java
new file mode 100644
index 000000000..8d2ca781f
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractTextEditor.java
@@ -0,0 +1,3550 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+
+package org.eclipse.ui.texteditor;
+
+
+import java.lang.reflect.InvocationTargetException;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ST;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.custom.VerifyKeyListener;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.ShellAdapter;
+import org.eclipse.swt.events.ShellEvent;
+import org.eclipse.swt.events.VerifyEvent;
+import org.eclipse.swt.events.VerifyListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Shell;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.ILog;
+import org.eclipse.core.runtime.IPluginDescriptor;
+import org.eclipse.core.runtime.IPluginPrerequisite;
+import org.eclipse.core.runtime.IPluginRegistry;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferenceConverter;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IFindReplaceTarget;
+import org.eclipse.jface.text.IFindReplaceTargetExtension;
+import org.eclipse.jface.text.IMarkRegionTarget;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.IRewriteTarget;
+import org.eclipse.jface.text.ITextInputListener;
+import org.eclipse.jface.text.ITextListener;
+import org.eclipse.jface.text.ITextOperationTarget;
+import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.text.ITextViewerExtension;
+import org.eclipse.jface.text.Position;
+import org.eclipse.jface.text.TextEvent;
+import org.eclipse.jface.text.TextSelection;
+import org.eclipse.jface.text.source.Annotation;
+import org.eclipse.jface.text.source.IAnnotationModel;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.text.source.IVerticalRuler;
+import org.eclipse.jface.text.source.IVerticalRulerExtension;
+import org.eclipse.jface.text.source.IVerticalRulerInfo;
+import org.eclipse.jface.text.source.SourceViewer;
+import org.eclipse.jface.text.source.SourceViewerConfiguration;
+import org.eclipse.jface.text.source.VerticalRuler;
+import org.eclipse.jface.util.Assert;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IEditorActionBarContributor;
+import org.eclipse.ui.IEditorDescriptor;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorRegistry;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IKeyBindingService;
+import org.eclipse.ui.INavigationLocationProvider;
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.IReusableEditor;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.NavigationLocation;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.WorkspaceModifyOperation;
+import org.eclipse.ui.help.WorkbenchHelp;
+import org.eclipse.ui.internal.EditorPluginAction;
+import org.eclipse.ui.part.EditorActionBarContributor;
+import org.eclipse.ui.part.EditorPart;
+
+
+
+
+/**
+ * Abstract base implementation of a text editor.
+ * <p>
+ * Subclasses are responsible for configuring the editor appropriately.
+ * The standard text editor, <code>TextEditor</code>, is one such example.
+ * </p>
+ * <p>
+ * If a subclass calls <code>setEditorContextMenuId</code> the arguments is
+ * used as the id under which the editor's context menu is registered for extensions.
+ * If no id is set, the context menu is registered under <b>[editor_id].EditorContext</b>
+ * whereby [editor_id] is replaced with the editor's part id. If the editor is instructed to
+ * run in version 1.0 context menu registration compatibility mode, the latter form of the
+ * registration even happens if a context menu id has been set via <code>setEditorContextMenuId</code>.
+ * If no id is set while in compatibility mode, the menu is registered under
+ * <code>DEFAULT_EDITOR_CONTEXT_MENU_ID</code>.
+ * </p>
+ * <p>
+ * If a subclass calls <code>setRulerContextMenuId</code> the arguments is
+ * used as the id under which the ruler's context menu is registered for extensions.
+ * If no id is set, the context menu is registered under <b>[editor_id].RulerContext</b>
+ * whereby [editor_id] is replaced with the editor's part id. If the editor is instructed to
+ * run in version 1.0 context menu registration compatibility mode, the latter form of the
+ * registration even happens if a context menu id has been set via <code>setRulerContextMenuId</code>.
+ * If no id is set while in compatibility mode, the menu is registered under
+ * <code>DEFAULT_RULER_CONTEXT_MENU_ID</code>.
+ * </p>
+ *
+ * @see org.eclipse.ui.editors.text.TextEditor
+ */
+public abstract class AbstractTextEditor extends EditorPart implements ITextEditor, IReusableEditor, ITextEditorExtension, INavigationLocationProvider {
+
+ /**
+ * Tag used in xml configuration files to specify editor action contributions.
+ * Current value: <code>editorContribution</code>
+ * @since 2.0
+ */
+ private static final String TAG_CONTRIBUTION_TYPE= "editorContribution"; //$NON-NLS-1$
+
+ /**
+ * Internal element state listener.
+ */
+ class ElementStateListener implements IElementStateListener, IElementStateListenerExtension {
+
+ /**
+ * Internal <code>VerifyListener</code> for performing the state validation of the
+ * editor input in case of the first attempted manipulation via typing on the keyboard.
+ * @since 2.0
+ */
+ class Validator implements VerifyListener {
+
+ /** Indicates whether the editor input changed during the process of state validation. */
+ private boolean fInputChanged;
+ /** Detector for editor input changes during the process of state validation. */
+ private ITextInputListener fInputListener= new ITextInputListener() {
+ public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) {}
+ public void inputDocumentChanged(IDocument oldInput, IDocument newInput) { fInputChanged= true; }
+ };
+
+ /*
+ * @see VerifyListener#verifyText(VerifyEvent)
+ */
+ public void verifyText(VerifyEvent e) {
+
+ ISourceViewer viewer= getSourceViewer();
+ fInputChanged= false;
+ viewer.addTextInputListener(fInputListener);
+ try {
+ validateState(getEditorInput());
+ sanityCheckState(getEditorInput());
+ if (isEditorInputReadOnly() || fInputChanged)
+ e.doit= false;
+ } finally {
+ viewer.removeTextInputListener(fInputListener);
+ }
+ }
+ };
+
+ /**
+ * The listener's validator.
+ * @since 2.0
+ */
+ private Validator fValidator;
+
+ /*
+ * @see IElementStateListenerExtension#elementStateValidationChanged(Object, boolean)
+ * @since 2.0
+ */
+ public void elementStateValidationChanged(Object element, boolean isStateValidated) {
+
+ if (element != null && element.equals(getEditorInput())) {
+
+ enableSanityChecking(true);
+
+ if (isStateValidated && fValidator != null) {
+ ISourceViewer viewer= getSourceViewer();
+ if (viewer != null) {
+ StyledText textWidget= viewer.getTextWidget();
+ if (textWidget != null && !textWidget.isDisposed())
+ textWidget.removeVerifyListener(fValidator);
+ fValidator= null;
+ }
+ } else if (!isStateValidated && fValidator == null) {
+ ISourceViewer viewer= getSourceViewer();
+ if (viewer != null) {
+ StyledText textWidget= viewer.getTextWidget();
+ if (textWidget != null && !textWidget.isDisposed()) {
+ fValidator= new Validator();
+ textWidget.addVerifyListener(fValidator);
+ }
+ }
+ }
+
+ }
+ }
+
+ /*
+ * @see IElementStateListener#elementDirtyStateChanged
+ */
+ public void elementDirtyStateChanged(Object element, boolean isDirty) {
+ if (element != null && element.equals(getEditorInput())) {
+ enableSanityChecking(true);
+ firePropertyChange(PROP_DIRTY);
+ }
+ }
+
+ /*
+ * @see IElementStateListener#elementContentAboutToBeReplaced
+ */
+ public void elementContentAboutToBeReplaced(Object element) {
+ if (element != null && element.equals(getEditorInput())) {
+ enableSanityChecking(true);
+ rememberSelection();
+ resetHighlightRange();
+ }
+ }
+
+ /*
+ * @see IElementStateListener#elementContentReplaced
+ */
+ public void elementContentReplaced(Object element) {
+ if (element != null && element.equals(getEditorInput())) {
+ enableSanityChecking(true);
+ firePropertyChange(PROP_DIRTY);
+ restoreSelection();
+ }
+ }
+
+ /*
+ * @see IElementStateListener#elementDeleted
+ */
+ public void elementDeleted(Object deletedElement) {
+ if (deletedElement != null && deletedElement.equals(getEditorInput())) {
+ enableSanityChecking(true);
+ close(false);
+ }
+ }
+
+ /*
+ * @see IElementStateListener#elementMoved
+ */
+ public void elementMoved(Object originalElement, Object movedElement) {
+
+ if (originalElement != null && originalElement.equals(getEditorInput())) {
+
+ enableSanityChecking(true);
+
+ if (!canHandleMove((IEditorInput) originalElement, (IEditorInput) movedElement)) {
+ close(true);
+ return;
+ }
+
+ if (movedElement == null || movedElement instanceof IEditorInput) {
+ rememberSelection();
+
+ IDocumentProvider d= getDocumentProvider();
+ IDocument changed= null;
+ if (isDirty())
+ changed= d.getDocument(getEditorInput());
+
+ setInput((IEditorInput) movedElement);
+
+ if (changed != null) {
+ d.getDocument(getEditorInput()).set(changed.get());
+ validateState(getEditorInput());
+ updateStatusField(ITextEditorActionConstants.STATUS_CATEGORY_ELEMENT_STATE);
+ }
+
+ restoreSelection();
+ }
+ }
+ }
+
+ /*
+ * @see IElementStateListenerExtension#elementStateChanging(Object)
+ * @since 2.0
+ */
+ public void elementStateChanging(Object element) {
+ if (element != null && element.equals(getEditorInput()))
+ enableSanityChecking(false);
+ }
+
+ /*
+ * @see IElementStateListenerExtension#elementStateChangeFailed(Object)
+ * @since 2.0
+ */
+ public void elementStateChangeFailed(Object element) {
+ if (element != null && element.equals(getEditorInput()))
+ enableSanityChecking(true);
+ }
+ };
+
+ /**
+ * Internal text listener for updating all content dependent
+ * actions. The updating is done asynchronously.
+ */
+ class TextListener implements ITextListener {
+
+ /** The posted updater code. */
+ private Runnable fRunnable= new Runnable() {
+ public void run() {
+ if (fSourceViewer != null) {
+ // check whether editor has not been disposed yet
+ updateContentDependentActions();
+ }
+ }
+ };
+
+ /** Display used for posting the updater code. */
+ private Display fDisplay;
+
+ /*
+ * @see ITextListener#textChanged(TextEvent)
+ */
+ public void textChanged(TextEvent event) {
+
+ /*
+ * Also works for text events which do not base on a DocumentEvent.
+ * This way, if the visible document of the viewer changes, all content
+ * dependent actions are updated as well.
+ */
+
+ if (fDisplay == null)
+ fDisplay= getSite().getShell().getDisplay();
+
+ fDisplay.asyncExec(fRunnable);
+ }
+ };
+
+ /**
+ * Compare configuration elements according to the prerequisite relation
+ * of their defining plug-ins.
+ * @since 2.0
+ */
+ static class ConfigurationElementComparator implements Comparator {
+
+ /*
+ * @see Comparator#compare(Object, Object)
+ * @since 2.0
+ */
+ public int compare(Object object0, Object object1) {
+
+ IConfigurationElement element0= (IConfigurationElement)object0;
+ IConfigurationElement element1= (IConfigurationElement)object1;
+
+ if (dependsOn(element0, element1))
+ return -1;
+
+ if (dependsOn(element1, element0))
+ return +1;
+
+ return 0;
+ }
+
+ /**
+ * Returns whether one configuration element depends on the other element. Does this by
+ * checking the dependency chain of the defining plugins.
+ *
+ * @param element0 the first element
+ * @param element1 the second element
+ * @return <code>true</code> if <code>element0</code> depends on <code>element1</code>.
+ * @since 2.0
+ */
+ private static boolean dependsOn(IConfigurationElement element0, IConfigurationElement element1) {
+ IPluginDescriptor descriptor0= element0.getDeclaringExtension().getDeclaringPluginDescriptor();
+ IPluginDescriptor descriptor1= element1.getDeclaringExtension().getDeclaringPluginDescriptor();
+
+ return dependsOn(descriptor0, descriptor1);
+ }
+
+ /**
+ * Returns whether one plugin depends on the other plugin.
+ *
+ * @param descriptor0 descriptor of the first plugin
+ * @param descriptor1 descriptor of the second plugin
+ * @return <code>true</code> if <code>descriptor0</code> depends on <code>descriptor1</code>.
+ * @since 2.0
+ */
+ private static boolean dependsOn(IPluginDescriptor descriptor0, IPluginDescriptor descriptor1) {
+
+ IPluginRegistry registry= Platform.getPluginRegistry();
+ IPluginPrerequisite[] prerequisites= descriptor0.getPluginPrerequisites();
+
+ for (int i= 0; i < prerequisites.length; i++) {
+ IPluginPrerequisite prerequisite= prerequisites[i];
+ String id= prerequisite.getUniqueIdentifier();
+ IPluginDescriptor descriptor= registry.getPluginDescriptor(id);
+
+ if (descriptor != null && (descriptor.equals(descriptor1) || dependsOn(descriptor, descriptor1)))
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ /**
+ * Internal property change listener for handling changes in the editor's preferences.
+ */
+ class PropertyChangeListener implements IPropertyChangeListener {
+ /*
+ * @see IPropertyChangeListener#propertyChange(PropertyChangeEvent)
+ */
+ public void propertyChange(PropertyChangeEvent event) {
+ handlePreferenceStoreChanged(event);
+ }
+ };
+
+ /**
+ * Internal key verify listener for triggering action activation codes.
+ */
+ class ActivationCodeTrigger implements VerifyKeyListener {
+
+ /** Indicates whether this trigger has been installed. */
+ private boolean fIsInstalled= false;
+ /**
+ * The key binding service to use.
+ * @since 2.0
+ */
+ private IKeyBindingService fKeyBindingService;
+
+ /*
+ * @see VerifyKeyListener#verifyKey(VerifyEvent)
+ */
+ public void verifyKey(VerifyEvent event) {
+
+ ActionActivationCode code= null;
+ int size= fActivationCodes.size();
+ for (int i= 0; i < size; i++) {
+ code= (ActionActivationCode) fActivationCodes.get(i);
+ if (code.matches(event)) {
+ IAction action= getAction(code.fActionId);
+ if (action != null) {
+
+ if (action instanceof IUpdate)
+ ((IUpdate) action).update();
+
+ if (!action.isEnabled() && action instanceof IReadOnlyDependent) {
+ IReadOnlyDependent dependent= (IReadOnlyDependent) action;
+ boolean writable= dependent.isEnabled(true);
+ if (writable) {
+ event.doit= false;
+ return;
+ }
+ } else if (action.isEnabled()) {
+ event.doit= false;
+ action.run();
+ return;
+ }
+ }
+ }
+ }
+ if (fKeyBindingService.processKey(event))
+ event.doit= false;
+ }
+
+ /**
+ * Installs this trigger on the editor's text widget.
+ * @since 2.0
+ */
+ public void install() {
+ if (!fIsInstalled) {
+
+ if (fSourceViewer instanceof ITextViewerExtension) {
+ ITextViewerExtension e= (ITextViewerExtension) fSourceViewer;
+ e.prependVerifyKeyListener(this);
+ } else {
+ StyledText text= fSourceViewer.getTextWidget();
+ text.addVerifyKeyListener(this);
+ }
+
+ fKeyBindingService= getEditorSite().getKeyBindingService();
+ fKeyBindingService.enable(true);
+ fIsInstalled= true;
+ }
+ }
+
+ /**
+ * Uninstalls this trigger from the editor's text widget.
+ * @since 2.0
+ */
+ public void uninstall() {
+ if (fIsInstalled) {
+
+ if (fSourceViewer instanceof ITextViewerExtension) {
+ ITextViewerExtension e= (ITextViewerExtension) fSourceViewer;
+ e.removeVerifyKeyListener(this);
+ } else if (fSourceViewer != null) {
+ StyledText text= fSourceViewer.getTextWidget();
+ if (text != null && !text.isDisposed())
+ text.removeVerifyKeyListener(fActivationCodeTrigger);
+ }
+
+ fIsInstalled= false;
+ fKeyBindingService= null;
+ }
+ }
+
+ /**
+ * Registers the given action for key activation.
+ * @param action the action to be registered
+ * @since 2.0
+ */
+ public void registerActionForKeyActivation(IAction action) {
+ if (action.getActionDefinitionId() != null)
+ fKeyBindingService.registerAction(action);
+ }
+
+ /**
+ * The given action is no longer available for key activation
+ * @param action the action to be unregistered
+ * @since 2.0
+ */
+ public void unregisterActionFromKeyActivation(IAction action) {
+ // No such action available on the service
+ }
+ };
+
+ /**
+ * Representation of action activation codes.
+ */
+ static class ActionActivationCode {
+
+ public String fActionId;
+ public char fCharacter;
+ public int fKeyCode= -1;
+ public int fStateMask= SWT.DEFAULT;
+
+ /**
+ * Creates a new action activation code for the given action id.
+ * @param actionId the action id
+ */
+ public ActionActivationCode(String actionId) {
+ fActionId= actionId;
+ }
+
+ /**
+ * Returns <code>true</code> if this activation code matches the given verify event.
+ * @param event the event to test for matching
+ */
+ public boolean matches(VerifyEvent event) {
+ return (event.character == fCharacter &&
+ (fKeyCode == -1 || event.keyCode == fKeyCode) &&
+ (fStateMask == SWT.DEFAULT || event.stateMask == fStateMask));
+ }
+ };
+
+ /**
+ * Internal part and shell activation listener for triggering state validation.
+ * @since 2.0
+ */
+ class ActivationListener extends ShellAdapter implements IPartListener {
+
+ /** Cache of the active workbench part. */
+ private IWorkbenchPart fActivePart;
+ /** Indicates whether activation handling is currently be done. */
+ private boolean fIsHandlingActivation= false;
+
+ /*
+ * @see IPartListener#partActivated(IWorkbenchPart)
+ */
+ public void partActivated(IWorkbenchPart part) {
+ fActivePart= part;
+ handleActivation();
+ }
+
+ /*
+ * @see IPartListener#partBroughtToTop(IWorkbenchPart)
+ */
+ public void partBroughtToTop(IWorkbenchPart part) {
+ }
+
+ /*
+ * @see IPartListener#partClosed(IWorkbenchPart)
+ */
+ public void partClosed(IWorkbenchPart part) {
+ }
+
+ /*
+ * @see IPartListener#partDeactivated(IWorkbenchPart)
+ */
+ public void partDeactivated(IWorkbenchPart part) {
+ fActivePart= null;
+ }
+
+ /*
+ * @see IPartListener#partOpened(IWorkbenchPart)
+ */
+ public void partOpened(IWorkbenchPart part) {
+ }
+
+ /*
+ * @see ShellListener#shellActivated(ShellEvent)
+ */
+ public void shellActivated(ShellEvent e) {
+ /*
+ * Workaround for problem described in
+ * http://dev.eclipse.org/bugs/show_bug.cgi?id=11731
+ * Will be removed when SWT has solved the problem.
+ */
+ e.widget.getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ handleActivation();
+ }
+ });
+ }
+
+ /**
+ * Handles the activation triggering a element state check in the editor.
+ */
+ private void handleActivation() {
+ if (fIsHandlingActivation)
+ return;
+
+ if (fActivePart == AbstractTextEditor.this) {
+ fIsHandlingActivation= true;
+ try {
+ safelySanityCheckState(getEditorInput());
+ } finally {
+ fIsHandlingActivation= false;
+ }
+ }
+ }
+ };
+
+ /**
+ * Internal interface for a cursor listener. I.e. aggregation
+ * of mouse and key listener.
+ * @since 2.0
+ */
+ interface ICursorListener extends MouseListener, KeyListener {
+ };
+
+ /**
+ * Maps an action definition id to an StyledText action.
+ * @since 2.0
+ */
+ static class IdMapEntry {
+
+ /** The action id */
+ private String fActionId;
+ /** The StyledText action */
+ private int fAction;
+
+ /**
+ * Creates a new mapping.
+ * @param actionId the action id
+ * @param action the StyledText action
+ */
+ public IdMapEntry(String actionId, int action) {
+ fActionId= actionId;
+ fAction= action;
+ }
+
+ /**
+ * Returns the action id.
+ * @return the action id
+ */
+ public String getActionId() {
+ return fActionId;
+ }
+
+ /**
+ * Returns the action
+ * @return the action
+ */
+ public int getAction() {
+ return fAction;
+ }
+ };
+
+ /**
+ * Internal action to scroll the editor's viewer by a specified number of lines.
+ * @since 2.0
+ */
+ class ScrollLinesAction extends Action {
+
+ /** Number of lines to scroll. */
+ private int fScrollIncrement;
+
+ /**
+ * Creates a new scroll action that scroll the given number of lines. If the
+ * increment is &lt 0, it's scrolling up, if &gt 0 it's scrolling down.
+ * @param scrollIncrement the number of lines to scroll
+ */
+ public ScrollLinesAction(int scrollIncrement) {
+ fScrollIncrement= scrollIncrement;
+ }
+
+ /*
+ * @see IAction#run()
+ */
+ public void run() {
+ ISourceViewer viewer= getSourceViewer();
+ int topIndex= viewer.getTopIndex();
+ int newTopIndex= Math.max(0, topIndex + fScrollIncrement);
+ viewer.setTopIndex(newTopIndex);
+ }
+ };
+
+ /**
+ * @since 2.1
+ */
+ class ToggleInsertModeAction extends TextNavigationAction {
+
+ public ToggleInsertModeAction(StyledText textWidget) {
+ super(textWidget, ST.TOGGLE_OVERWRITE);
+ }
+
+ /*
+ * @see org.eclipse.jface.action.IAction#run()
+ */
+ public void run() {
+ super.run();
+ fOverwriting= !fOverwriting;
+ handleInsertModeChanged();
+ }
+
+ };
+
+ /**
+ * Internal action to show the editor's ruler context menu (accessibility).
+ * @since 2.0
+ */
+ class ShowRulerContextMenuAction extends Action {
+
+ /*
+ * @see IAction#run()
+ */
+ public void run() {
+ if (fSourceViewer == null)
+ return;
+
+ StyledText text= fSourceViewer.getTextWidget();
+ if (text == null || text.isDisposed())
+ return;
+
+ Point location= text.getLocationAtOffset(text.getCaretOffset());
+ location.x= 0;
+
+ if (fVerticalRuler instanceof IVerticalRulerExtension)
+ ((IVerticalRulerExtension) fVerticalRuler).setLocationOfLastMouseButtonActivity(location.x, location.y);
+
+ location= text.toDisplay(location);
+ fRulerContextMenu.setLocation(location.x, location.y);
+ fRulerContextMenu.setVisible(true);
+ }
+ };
+
+
+ /**
+ * Editor specific selection provider which wraps the source viewer's selection provider.
+ *
+ */
+ class SelectionProvider implements ISelectionProvider {
+
+ /*
+ * @see org.eclipse.jface.viewers.ISelectionProvider#addSelectionChangedListener(ISelectionChangedListener)
+ */
+ public void addSelectionChangedListener(ISelectionChangedListener listener) {
+ if (fSourceViewer != null)
+ fSourceViewer.getSelectionProvider().addSelectionChangedListener(listener);
+ }
+
+ /*
+ * @see org.eclipse.jface.viewers.ISelectionProvider#getSelection()
+ */
+ public ISelection getSelection() {
+ return doGetSelection();
+ }
+
+ /*
+ * @see org.eclipse.jface.viewers.ISelectionProvider#removeSelectionChangedListener(ISelectionChangedListener)
+ */
+ public void removeSelectionChangedListener(ISelectionChangedListener listener) {
+ if (fSourceViewer != null)
+ fSourceViewer.getSelectionProvider().removeSelectionChangedListener(listener);
+ }
+
+ /*
+ * @see org.eclipse.jface.viewers.ISelectionProvider#setSelection(ISelection)
+ */
+ public void setSelection(ISelection selection) {
+ doSetSelection(selection);
+ }
+ };
+
+
+
+ /** Key used to look up font preference */
+ public final static String PREFERENCE_FONT= JFaceResources.TEXT_FONT;
+ /**
+ * Key used to look up foreground color preference
+ * Value: <code>AbstractTextEditor.Color.Foreground</code>
+ * @since 2.0
+ */
+ public final static String PREFERENCE_COLOR_FOREGROUND= "AbstractTextEditor.Color.Foreground"; //$NON-NLS-1$
+ /**
+ * Key used to look up background color preference
+ * Value: <code>AbstractTextEditor.Color.Background</code>
+ * @since 2.0
+ */
+ public final static String PREFERENCE_COLOR_BACKGROUND= "AbstractTextEditor.Color.Background"; //$NON-NLS-1$
+ /**
+ * Key used to look up foreground color system default preference
+ * Value: <code>AbstractTextEditor.Color.Foreground.SystemDefault</code>
+ * @since 2.0
+ */
+ public final static String PREFERENCE_COLOR_FOREGROUND_SYSTEM_DEFAULT= "AbstractTextEditor.Color.Foreground.SystemDefault"; //$NON-NLS-1$
+ /**
+ * Key used to look up background color system default preference
+ * Value: <code>AbstractTextEditor.Color.Background.SystemDefault</code>
+ * @since 2.0
+ */
+ public final static String PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT= "AbstractTextEditor.Color.Background.SystemDefault"; //$NON-NLS-1$
+ /**
+ * Key used to look up find scope background color preference
+ * Value: <code>AbstractTextEditor.Color.FindScope</code>
+ * @since 2.0
+ */
+ public final static String PREFERENCE_COLOR_FIND_SCOPE= "AbstractTextEditor.Color.FindScope"; //$NON-NLS-1$
+
+ /** Menu id for the editor context menu. */
+ public final static String DEFAULT_EDITOR_CONTEXT_MENU_ID= "#EditorContext"; //$NON-NLS-1$
+ /** Menu id for the ruler context menu. */
+ public final static String DEFAULT_RULER_CONTEXT_MENU_ID= "#RulerContext"; //$NON-NLS-1$
+
+ /** The width of the vertical ruler */
+ protected final static int VERTICAL_RULER_WIDTH= 12;
+
+ /**
+ * The complete mapping between action definition ids used by eclipse and StyledText actions.
+ * @since 2.0
+ */
+ protected final static IdMapEntry[] ACTION_MAP= new IdMapEntry[] {
+ // navigation
+ new IdMapEntry(ITextEditorActionDefinitionIds.LINE_UP, ST.LINE_UP),
+ new IdMapEntry(ITextEditorActionDefinitionIds.LINE_DOWN, ST.LINE_DOWN),
+ new IdMapEntry(ITextEditorActionDefinitionIds.LINE_START, ST.LINE_START),
+ new IdMapEntry(ITextEditorActionDefinitionIds.LINE_END, ST.LINE_END),
+ new IdMapEntry(ITextEditorActionDefinitionIds.COLUMN_PREVIOUS, ST.COLUMN_PREVIOUS),
+ new IdMapEntry(ITextEditorActionDefinitionIds.COLUMN_NEXT, ST.COLUMN_NEXT),
+ new IdMapEntry(ITextEditorActionDefinitionIds.PAGE_UP, ST.PAGE_UP),
+ new IdMapEntry(ITextEditorActionDefinitionIds.PAGE_DOWN, ST.PAGE_DOWN),
+ new IdMapEntry(ITextEditorActionDefinitionIds.WORD_PREVIOUS, ST.WORD_PREVIOUS),
+ new IdMapEntry(ITextEditorActionDefinitionIds.WORD_NEXT, ST.WORD_NEXT),
+ new IdMapEntry(ITextEditorActionDefinitionIds.TEXT_START, ST.TEXT_START),
+ new IdMapEntry(ITextEditorActionDefinitionIds.TEXT_END, ST.TEXT_END),
+ new IdMapEntry(ITextEditorActionDefinitionIds.WINDOW_START, ST.WINDOW_START),
+ new IdMapEntry(ITextEditorActionDefinitionIds.WINDOW_END, ST.WINDOW_END),
+ // selection
+ new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_LINE_UP, ST.SELECT_LINE_UP),
+ new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_LINE_DOWN, ST.SELECT_LINE_DOWN),
+ new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_LINE_START, ST.SELECT_LINE_START),
+ new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_LINE_END, ST.SELECT_LINE_END),
+ new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_COLUMN_PREVIOUS, ST.SELECT_COLUMN_PREVIOUS),
+ new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_COLUMN_NEXT, ST.SELECT_COLUMN_NEXT),
+ new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_PAGE_UP, ST.SELECT_PAGE_UP),
+ new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_PAGE_DOWN, ST.SELECT_PAGE_DOWN),
+ new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_WORD_PREVIOUS, ST.SELECT_WORD_PREVIOUS),
+ new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_WORD_NEXT, ST.SELECT_WORD_NEXT),
+ new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_TEXT_START, ST.SELECT_TEXT_START),
+ new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_TEXT_END, ST.SELECT_TEXT_END),
+ new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_WINDOW_START, ST.SELECT_WINDOW_START),
+ new IdMapEntry(ITextEditorActionDefinitionIds.SELECT_WINDOW_END, ST.SELECT_WINDOW_END),
+ // modification
+ new IdMapEntry(ITextEditorActionDefinitionIds.CUT, ST.CUT),
+ new IdMapEntry(ITextEditorActionDefinitionIds.COPY, ST.COPY),
+ new IdMapEntry(ITextEditorActionDefinitionIds.PASTE, ST.PASTE),
+ new IdMapEntry(ITextEditorActionDefinitionIds.DELETE_PREVIOUS, ST.DELETE_PREVIOUS),
+ new IdMapEntry(ITextEditorActionDefinitionIds.DELETE_NEXT, ST.DELETE_NEXT)
+ };
+
+
+ private final String fReadOnlyLabel = EditorMessages.getString("Editor.statusline.state.readonly.label"); //$NON-NLS-1$
+ private final String fWritableLabel = EditorMessages.getString("Editor.statusline.state.writable.label"); //$NON-NLS-1$
+ private final String fInsertModeLabel = EditorMessages.getString("Editor.statusline.mode.insert.label"); //$NON-NLS-1$
+ private final String fOverwriteModeLabel = EditorMessages.getString("Editor.statusline.mode.overwrite.label"); //$NON-NLS-1$
+
+ private static class PositionLabelValue {
+
+ public int fValue;
+
+ public String toString() {
+ return String.valueOf(fValue);
+ }
+ };
+
+ /** The error message shown in the status line in case of failed information look up. */
+ protected final String fErrorLabel= EditorMessages.getString("Editor.statusline.error.label"); //$NON-NLS-1$
+ private final String fPositionLabelPattern= EditorMessages.getString("Editor.statusline.position.pattern"); //$NON-NLS-1$
+ private final PositionLabelValue fLineLabel= new PositionLabelValue();
+ private final PositionLabelValue fColumnLabel= new PositionLabelValue();
+ private final Object[] fPositionLabelPatternArguments= new Object[] { fLineLabel, fColumnLabel };
+
+
+
+
+ /** The editor's internal document provider */
+ private IDocumentProvider fInternalDocumentProvider;
+ /** The editor's external document provider */
+ private IDocumentProvider fExternalDocumentProvider;
+ /** The editor's preference store */
+ private IPreferenceStore fPreferenceStore;
+ /** The editor's range indicator */
+ private Annotation fRangeIndicator;
+ /** The editor's source viewer configuration */
+ private SourceViewerConfiguration fConfiguration;
+ /** The editor's source viewer */
+ private ISourceViewer fSourceViewer;
+ /** The editor's selection provider */
+ private SelectionProvider fSelectionProvider= new SelectionProvider();
+ /** The editor's font */
+ private Font fFont;
+ /**
+ * The editor's foreground color
+ * @since 2.0
+ */
+ private Color fForegroundColor;
+ /**
+ * The editor's background color
+ * @since 2.0
+ */
+ private Color fBackgroundColor;
+ /**
+ * The find scope's highlight color
+ * @since 2.0
+ */
+ private Color fFindScopeHighlightColor;
+
+ /** The editor's status line */
+ private IEditorStatusLine fEditorStatusLine;
+ /** The editor's vertical ruler */
+ private IVerticalRuler fVerticalRuler;
+ /** The editor's context menu id */
+ private String fEditorContextMenuId;
+ /** The ruler's context menu id */
+ private String fRulerContextMenuId;
+ /** The editor's help context id */
+ private String fHelpContextId;
+ /** The editor's presentation mode */
+ private boolean fShowHighlightRangeOnly;
+ /** The actions registered with the editor */
+ private Map fActions= new HashMap(10);
+ /** The actions marked as selection dependent */
+ private List fSelectionActions= new ArrayList(5);
+ /** The actions marked as content dependent */
+ private List fContentActions= new ArrayList(5);
+ /**
+ * The actions marked as property dependent
+ * @since 2.0
+ */
+ private List fPropertyActions= new ArrayList(5);
+ /**
+ * The actions marked as state dependent
+ * @since 2.0
+ */
+ private List fStateActions= new ArrayList(5);
+ /** The editor's action activation codes */
+ private List fActivationCodes= new ArrayList(2);
+ /** The verify key listener for activation code triggering */
+ private ActivationCodeTrigger fActivationCodeTrigger= new ActivationCodeTrigger();
+ /** Context menu listener */
+ private IMenuListener fMenuListener;
+ /** Vertical ruler mouse listener */
+ private MouseListener fMouseListener;
+ /** Selection changed listener */
+ private ISelectionChangedListener fSelectionChangedListener;
+ /** Title image to be disposed */
+ private Image fTitleImage;
+ /** The text context menu to be disposed */
+ private Menu fTextContextMenu;
+ /** The ruler context menu to be disposed */
+ private Menu fRulerContextMenu;
+ /** The editor's element state listener */
+ private IElementStateListener fElementStateListener= new ElementStateListener();
+ /** The editor's text listener */
+ private ITextListener fTextListener= new TextListener();
+ /** The editor's property change listener */
+ private IPropertyChangeListener fPropertyChangeListener= new PropertyChangeListener();
+ /**
+ * The editor's activation listener
+ * @since 2.0
+ */
+ private ActivationListener fActivationListener= new ActivationListener();
+ /**
+ * The map of the editor's status fields
+ * @since 2.0
+ */
+ private Map fStatusFields;
+ /**
+ * The editor's cursor listener
+ * @since 2.0
+ */
+ private ICursorListener fCursorListener;
+ /**
+ * The editor's insert mode
+ * @since 2.0
+ */
+ private boolean fOverwriting= false;
+ /**
+ * The editor's remembered text selection
+ * @since 2.0
+ */
+ private ISelection fRememberedSelection;
+ /**
+ * Indicates whether the editor runs in 1.0 context menu registration compatibility mode
+ * @since 2.0
+ */
+ private boolean fCompatibilityMode= true;
+ /**
+ * The number of reentrances into error correction code while saving
+ * @since 2.0
+ */
+ private int fErrorCorrectionOnSave;
+ /**
+ * The incremental find target
+ * @since 2.0
+ */
+ private IncrementalFindTarget fIncrementalFindTarget;
+ /**
+ * The mark region target
+ * @since 2.0
+ */
+ private IMarkRegionTarget fMarkRegionTarget;
+ /**
+ * Cached modification stamp of the editor's input
+ * @since 2.0
+ */
+ private long fModificationStamp= -1;
+ /**
+ * Ruler context menu listeners.
+ * @since 2.0
+ */
+ private List fRulerContextMenuListeners= new ArrayList();
+ /**
+ * Indicates whether sanity checking in enabled.
+ * @since 2.0
+ */
+ private boolean fIsSanityCheckEnabled= true;
+
+
+
+ /**
+ * Creates a new text editor. If not explicitly set, this editor uses
+ * a <code>SourceViewerConfiguration</code> to configure its
+ * source viewer. This viewer does not have a range indicator installed,
+ * nor any menu id set. By default, the created editor runs in 1.0 context
+ * menu registration compatibility mode.
+ */
+ protected AbstractTextEditor() {
+ super();
+ fEditorContextMenuId= null;
+ fRulerContextMenuId= null;
+ fHelpContextId= null;
+ }
+
+ /*
+ * @see ITextEditor#getDocumentProvider
+ */
+ public IDocumentProvider getDocumentProvider() {
+ if (fInternalDocumentProvider != null)
+ return fInternalDocumentProvider;
+ return fExternalDocumentProvider;
+ }
+
+ /**
+ * Returns the editor's range indicator.
+ *
+ * @return the editor's range indicator
+ */
+ protected final Annotation getRangeIndicator() {
+ return fRangeIndicator;
+ }
+
+ /**
+ * Returns the editor's source viewer configuration.
+ *
+ * @return the editor's source viewer configuration
+ */
+ protected final SourceViewerConfiguration getSourceViewerConfiguration() {
+ return fConfiguration;
+ }
+
+ /**
+ * Returns the editor's source viewer.
+ *
+ * @return the editor's source viewer
+ */
+ protected final ISourceViewer getSourceViewer() {
+ return fSourceViewer;
+ }
+
+ /**
+ * Returns the editor's vertical ruler.
+ *
+ * @return the editor's vertical ruler
+ */
+ protected final IVerticalRuler getVerticalRuler() {
+ return fVerticalRuler;
+ }
+
+ /**
+ * Returns the editor's context menu id.
+ *
+ * @return the editor's context menu id
+ */
+ protected final String getEditorContextMenuId() {
+ return fEditorContextMenuId;
+ }
+
+ /**
+ * Returns the ruler's context menu id.
+ *
+ * @return the ruler's context menu id
+ */
+ protected final String getRulerContextMenuId() {
+ return fRulerContextMenuId;
+ }
+
+ /**
+ * Returns the editor's help context id.
+ *
+ * @return the editor's help context id
+ */
+ protected final String getHelpContextId() {
+ return fHelpContextId;
+ }
+
+ /**
+ * Returns this editor's preference store.
+ *
+ * @return this editor's preference store
+ */
+ protected final IPreferenceStore getPreferenceStore() {
+ return fPreferenceStore;
+ }
+
+ /**
+ * Sets this editor's document provider. This method must be
+ * called before the editor's control is created.
+ *
+ * @param provider the document provider
+ */
+ protected void setDocumentProvider(IDocumentProvider provider) {
+ Assert.isNotNull(provider);
+ fInternalDocumentProvider= provider;
+ }
+
+ /**
+ * Sets this editor's source viewer configuration used to configure its
+ * internal source viewer. This method must be called before the editor's
+ * control is created. If not, this editor uses a <code>SourceViewerConfiguration</code>.
+ *
+ * @param configuration the source viewer configuration object
+ */
+ protected void setSourceViewerConfiguration(SourceViewerConfiguration configuration) {
+ Assert.isNotNull(configuration);
+ fConfiguration= configuration;
+ }
+
+ /**
+ * Sets the annotation which this editor uses to represent the highlight
+ * range if the editor is configured to show the entire document. If the
+ * range indicator is not set, this editor uses a <code>DefaultRangeIndicator</code>.
+ *
+ * @param rangeIndicator the annotation
+ */
+ protected void setRangeIndicator(Annotation rangeIndicator) {
+ Assert.isNotNull(rangeIndicator);
+ fRangeIndicator= rangeIndicator;
+ }
+
+ /**
+ * Sets this editor's context menu id.
+ *
+ * @param contextMenuId the context menu id
+ */
+ protected void setEditorContextMenuId(String contextMenuId) {
+ Assert.isNotNull(contextMenuId);
+ fEditorContextMenuId= contextMenuId;
+ }
+
+ /**
+ * Sets the ruler's context menu id.
+ *
+ * @param contextMenuId the context menu id
+ */
+ protected void setRulerContextMenuId(String contextMenuId) {
+ Assert.isNotNull(contextMenuId);
+ fRulerContextMenuId= contextMenuId;
+ }
+
+ /**
+ * Sets the context menu registration 1.0 compatibility mode. (See class
+ * description for more details.)
+ *
+ * @param compatible <code>true</code> if compatibility mode is enabled
+ * @since 2.0
+ */
+ protected final void setCompatibilityMode(boolean compatible) {
+ fCompatibilityMode= compatible;
+ }
+
+ /**
+ * Sets the editor's help context id.
+ *
+ * @param helpContextId the help context id
+ */
+ protected void setHelpContextId(String helpContextId) {
+ Assert.isNotNull(helpContextId);
+ fHelpContextId= helpContextId;
+ }
+
+ /**
+ * Sets this editor's preference store. This method must be
+ * called before the editor's control is created.
+ *
+ * @param store the new preference store
+ */
+ protected void setPreferenceStore(IPreferenceStore store) {
+ if (fPreferenceStore != null)
+ fPreferenceStore.removePropertyChangeListener(fPropertyChangeListener);
+
+ fPreferenceStore= store;
+
+ if (fPreferenceStore != null)
+ fPreferenceStore.addPropertyChangeListener(fPropertyChangeListener);
+ }
+
+ /*
+ * @see ITextEditor#isEditable
+ */
+ public boolean isEditable() {
+ IDocumentProvider provider= getDocumentProvider();
+ if (provider instanceof IDocumentProviderExtension) {
+ IDocumentProviderExtension extension= (IDocumentProviderExtension) provider;
+ return extension.isModifiable(getEditorInput());
+ }
+ return false;
+ }
+
+ /*
+ * @see ITextEditor#getSelectionProvider
+ */
+ public ISelectionProvider getSelectionProvider() {
+ return fSelectionProvider;
+ }
+
+ /**
+ * Remembers the current selection of this editor. This method is called when, e.g.,
+ * the content of the editor is about to be reverted to the saved state. This method
+ * remembers the selection in a semantic format, i.e., in a format which allows to
+ * restore the selection even if the originally selected text is no longer part of the
+ * editor's content.<p>
+ * Subclasses should implement this method including all necessary state. This
+ * default implementation remembers the textual range only and is thus purely
+ * syntactic.
+ *
+ * @see #restoreSelection
+ * @since 2.0
+ */
+ protected void rememberSelection() {
+ fRememberedSelection= doGetSelection();
+ }
+
+ /**
+ * Returns the current selection.
+ * @return ISelection
+ */
+ protected ISelection doGetSelection() {
+ ISelectionProvider sp= null;
+ if (fSourceViewer != null)
+ sp= fSourceViewer.getSelectionProvider();
+ return (sp == null ? null : sp.getSelection());
+ }
+
+ /**
+ * Restores a selection previously remembered by <code>rememberSelection</code>.
+ * Subclasses may reimplement this method and thereby semantically adapt the
+ * remembered selection. This default implementation just selects the
+ * remembered textual range.
+ *
+ * @see #rememberSelection
+ * @since 2.0
+ */
+ protected void restoreSelection() {
+ doSetSelection(fRememberedSelection);
+ fRememberedSelection= null;
+ }
+
+ /**
+ * Sets the given selection.
+ * @param selection
+ */
+ protected void doSetSelection(ISelection selection) {
+ if (selection instanceof ITextSelection) {
+ ITextSelection textSelection= (ITextSelection) selection;
+ selectAndReveal(textSelection.getOffset(), textSelection.getLength());
+ }
+ }
+
+ /**
+ * Creates and returns the listener on this editor's context menus.
+ *
+ * @return the menu listener
+ */
+ protected final IMenuListener getContextMenuListener() {
+ if (fMenuListener == null) {
+ fMenuListener= new IMenuListener() {
+
+ public void menuAboutToShow(IMenuManager menu) {
+ String id= menu.getId();
+ if (getRulerContextMenuId().equals(id)) {
+ setFocus();
+ rulerContextMenuAboutToShow(menu);
+ } else if (getEditorContextMenuId().equals(id)) {
+ setFocus();
+ editorContextMenuAboutToShow(menu);
+ }
+ }
+ };
+ }
+ return fMenuListener;
+ }
+
+ /**
+ * Creates and returns the listener on this editor's vertical ruler.
+ *
+ * @return the mouse listener
+ */
+ protected final MouseListener getRulerMouseListener() {
+ if (fMouseListener == null) {
+ fMouseListener= new MouseListener() {
+
+ private boolean fDoubleClicked= false;
+
+ private void triggerAction(String actionID) {
+ IAction action= getAction(actionID);
+ if (action != null) {
+ if (action instanceof IUpdate)
+ ((IUpdate) action).update();
+ if (action.isEnabled())
+ action.run();
+ }
+ }
+
+ public void mouseUp(MouseEvent e) {
+ setFocus();
+ if (1 == e.button && !fDoubleClicked)
+ triggerAction(ITextEditorActionConstants.RULER_CLICK);
+ fDoubleClicked= false;
+ }
+
+ public void mouseDoubleClick(MouseEvent e) {
+ if (1 == e.button) {
+ fDoubleClicked= true;
+ triggerAction(ITextEditorActionConstants.RULER_DOUBLE_CLICK);
+ }
+ }
+
+ public void mouseDown(MouseEvent e) {
+ StyledText text= fSourceViewer.getTextWidget();
+ if (text != null && !text.isDisposed()) {
+ Display display= text.getDisplay();
+ Point location= display.getCursorLocation();
+ fRulerContextMenu.setLocation(location.x, location.y);
+ }
+ }
+ };
+ }
+ return fMouseListener;
+ }
+
+ /**
+ * Returns this editor's selection changed listener to be installed
+ * on the editor's source viewer.
+ *
+ * @return the listener
+ */
+ protected final ISelectionChangedListener getSelectionChangedListener() {
+ if (fSelectionChangedListener == null) {
+ fSelectionChangedListener= new ISelectionChangedListener() {
+
+ private Runnable fRunnable= new Runnable() {
+ public void run() {
+ // check whether editor has not been disposed yet
+ if (fSourceViewer != null) {
+ updateSelectionDependentActions();
+ handleCursorPositionChanged();
+ }
+ }
+ };
+
+ private Display fDisplay;
+
+ public void selectionChanged(SelectionChangedEvent event) {
+ if (fDisplay == null)
+ fDisplay= getSite().getShell().getDisplay();
+ fDisplay.asyncExec(fRunnable);
+ }
+ };
+ }
+
+ return fSelectionChangedListener;
+ }
+
+ /**
+ * Returns this editor's "cursor" listener to be installed on the editor's
+ * source viewer. This listener is listening to key and mouse button events.
+ * It triggers the updating of the status line by calling
+ * <code>handleCursorPositionChanged()</code>.
+ *
+ * @return the listener
+ * @since 2.0
+ */
+ protected final ICursorListener getCursorListener() {
+ if (fCursorListener == null) {
+ fCursorListener= new ICursorListener() {
+
+ public void keyPressed(KeyEvent e) {
+ }
+
+ public void keyReleased(KeyEvent e) {
+ handleCursorPositionChanged();
+ }
+
+ public void mouseDoubleClick(MouseEvent e) {
+ }
+
+ public void mouseDown(MouseEvent e) {
+ }
+
+ public void mouseUp(MouseEvent e) {
+ handleCursorPositionChanged();
+ }
+ };
+ }
+ return fCursorListener;
+ }
+
+ /*
+ * @see IEditorPart#init
+ */
+ public void init(IEditorSite site, IEditorInput input) throws PartInitException {
+
+ setSite(site);
+
+ try {
+ doSetInput(input);
+ } catch (CoreException x) {
+ throw new PartInitException(x.getStatus());
+ }
+
+ IWorkbenchWindow window= getSite().getWorkbenchWindow();
+ window.getPartService().addPartListener(fActivationListener);
+ window.getShell().addShellListener(fActivationListener);
+ }
+
+ /**
+ * Creates the vertical ruler to be used by this editor.
+ * Subclasses may re-implement this method.
+ *
+ * @return the vertical ruler
+ */
+ protected IVerticalRuler createVerticalRuler() {
+ return new VerticalRuler(VERTICAL_RULER_WIDTH);
+ }
+
+ /**
+ * Creates the source viewer to be used by this editor.
+ * Subclasses may re-implement this method.
+ *
+ * @param parent the parent control
+ * @param ruler the vertical ruler
+ * @param styles style bits
+ * @return the source viewer
+ */
+ protected ISourceViewer createSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
+ return new SourceViewer(parent, ruler, styles);
+ }
+
+ /**
+ * The <code>AbstractTextEditor</code> implementation of this
+ * <code>IWorkbenchPart</code> method creates the vertical ruler and
+ * source viewer. Subclasses may extend.
+ */
+ public void createPartControl(Composite parent) {
+
+ fVerticalRuler= createVerticalRuler();
+
+ int styles= SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION;
+ fSourceViewer= createSourceViewer(parent, fVerticalRuler, styles);
+
+ if (fConfiguration == null)
+ fConfiguration= new SourceViewerConfiguration();
+ fSourceViewer.configure(fConfiguration);
+
+ if (fRangeIndicator != null)
+ fSourceViewer.setRangeIndicator(fRangeIndicator);
+
+ fSourceViewer.addTextListener(fTextListener);
+ getSelectionProvider().addSelectionChangedListener(getSelectionChangedListener());
+
+ initializeViewerFont(fSourceViewer);
+ initializeViewerColors(fSourceViewer);
+ initializeFindScopeColor(fSourceViewer);
+
+ StyledText styledText= fSourceViewer.getTextWidget();
+ styledText.addMouseListener(getCursorListener());
+ styledText.addKeyListener(getCursorListener());
+
+ if (getHelpContextId() != null)
+ WorkbenchHelp.setHelp(styledText, getHelpContextId());
+
+
+ String id= fEditorContextMenuId != null ? fEditorContextMenuId : DEFAULT_EDITOR_CONTEXT_MENU_ID;
+
+ MenuManager manager= new MenuManager(id, id);
+ manager.setRemoveAllWhenShown(true);
+ manager.addMenuListener(getContextMenuListener());
+ fTextContextMenu= manager.createContextMenu(styledText);
+ styledText.setMenu(fTextContextMenu);
+
+ if (fEditorContextMenuId != null)
+ getSite().registerContextMenu(fEditorContextMenuId, manager, getSelectionProvider());
+ else if (fCompatibilityMode)
+ getSite().registerContextMenu(DEFAULT_EDITOR_CONTEXT_MENU_ID, manager, getSelectionProvider());
+
+ if ((fEditorContextMenuId != null && fCompatibilityMode) || fEditorContextMenuId == null) {
+ String partId= getSite().getId();
+ if (partId != null)
+ getSite().registerContextMenu(partId + ".EditorContext", manager, getSelectionProvider()); //$NON-NLS-1$
+ }
+
+ if (fEditorContextMenuId == null)
+ fEditorContextMenuId= DEFAULT_EDITOR_CONTEXT_MENU_ID;
+
+
+ id= fRulerContextMenuId != null ? fRulerContextMenuId : DEFAULT_RULER_CONTEXT_MENU_ID;
+ manager= new MenuManager(id, id);
+ manager.setRemoveAllWhenShown(true);
+ manager.addMenuListener(getContextMenuListener());
+
+ Control rulerControl= fVerticalRuler.getControl();
+ fRulerContextMenu= manager.createContextMenu(rulerControl);
+ rulerControl.setMenu(fRulerContextMenu);
+ rulerControl.addMouseListener(getRulerMouseListener());
+
+ if (fRulerContextMenuId != null)
+ getSite().registerContextMenu(fRulerContextMenuId, manager, getSelectionProvider());
+ else if (fCompatibilityMode)
+ getSite().registerContextMenu(DEFAULT_RULER_CONTEXT_MENU_ID, manager, getSelectionProvider());
+
+ if ((fRulerContextMenuId != null && fCompatibilityMode) || fRulerContextMenuId == null) {
+ String partId= getSite().getId();
+ if (partId != null)
+ getSite().registerContextMenu(partId + ".RulerContext", manager, getSelectionProvider()); //$NON-NLS-1$
+ }
+
+ if (fRulerContextMenuId == null)
+ fRulerContextMenuId= DEFAULT_RULER_CONTEXT_MENU_ID;
+
+ getSite().setSelectionProvider(getSelectionProvider());
+
+ fActivationCodeTrigger.install();
+ createNavigationActions();
+ createAccessibilityActions();
+ createActions();
+
+ initializeSourceViewer(getEditorInput());
+ }
+
+ /**
+ * Initializes the given viewer's font.
+ *
+ * @param viewer the viewer
+ * @since 2.0
+ */
+ private void initializeViewerFont(ISourceViewer viewer) {
+
+ IPreferenceStore store= getPreferenceStore();
+ if (store != null) {
+
+ FontData data= null;
+
+ if (store.contains(PREFERENCE_FONT) && !store.isDefault(PREFERENCE_FONT))
+ data= PreferenceConverter.getFontData(store, PREFERENCE_FONT);
+ else
+ data= PreferenceConverter.getDefaultFontData(store, PREFERENCE_FONT);
+
+ if (data != null) {
+
+ Font font= new Font(viewer.getTextWidget().getDisplay(), data);
+ setFont(viewer, font);
+
+ if (fFont != null)
+ fFont.dispose();
+
+ fFont= font;
+ return;
+ }
+ }
+
+ // if all the preferences failed
+ setFont(viewer, JFaceResources.getTextFont());
+ }
+
+ /**
+ * Sets the font for the given viewer sustaining selection and scroll position.
+ *
+ * @param sourceViewer the source viewer
+ * @param font the font
+ * @since 2.0
+ */
+ private void setFont(ISourceViewer sourceViewer, Font font) {
+ if (sourceViewer.getDocument() != null) {
+
+ Point selection= sourceViewer.getSelectedRange();
+ int topIndex= sourceViewer.getTopIndex();
+
+ StyledText styledText= sourceViewer.getTextWidget();
+ Control parent= styledText;
+ if (sourceViewer instanceof ITextViewerExtension) {
+ ITextViewerExtension extension= (ITextViewerExtension) sourceViewer;
+ parent= extension.getControl();
+ }
+
+ parent.setRedraw(false);
+
+ styledText.setFont(font);
+
+ if (fVerticalRuler instanceof IVerticalRulerExtension) {
+ IVerticalRulerExtension e= (IVerticalRulerExtension) fVerticalRuler;
+ e.setFont(font);
+ }
+
+ sourceViewer.setSelectedRange(selection.x , selection.y);
+ sourceViewer.setTopIndex(topIndex);
+
+ if (parent instanceof Composite) {
+ Composite composite= (Composite) parent;
+ composite.layout(true);
+ }
+
+ parent.setRedraw(true);
+
+
+ } else {
+
+ StyledText styledText= sourceViewer.getTextWidget();
+ styledText.setFont(font);
+
+ if (fVerticalRuler instanceof IVerticalRulerExtension) {
+ IVerticalRulerExtension e= (IVerticalRulerExtension) fVerticalRuler;
+ e.setFont(font);
+ }
+ }
+ }
+
+ /**
+ * Creates a color from the information stored in the given preference store.
+ * Returns <code>null</code> if there is no such information available.
+ *
+ * @param store the store to read from
+ * @param key the key used for the lookup in the preference store
+ * @param display the display used create the color
+ * @return the created color according to the specification in the preference store
+ * @since 2.0
+ */
+ private Color createColor(IPreferenceStore store, String key, Display display) {
+
+ RGB rgb= null;
+
+ if (store.contains(key)) {
+
+ if (store.isDefault(key))
+ rgb= PreferenceConverter.getDefaultColor(store, key);
+ else
+ rgb= PreferenceConverter.getColor(store, key);
+
+ if (rgb != null)
+ return new Color(display, rgb);
+ }
+
+ return null;
+ }
+
+ /**
+ * Initializes the given viewer's colors.
+ *
+ * @param viewer the viewer to be initialized
+ * @since 2.0
+ */
+ private void initializeViewerColors(ISourceViewer viewer) {
+
+ IPreferenceStore store= getPreferenceStore();
+ if (store != null) {
+
+ StyledText styledText= viewer.getTextWidget();
+
+ // ----------- foreground color --------------------
+ Color color= store.getBoolean(PREFERENCE_COLOR_FOREGROUND_SYSTEM_DEFAULT)
+ ? null
+ : createColor(store, PREFERENCE_COLOR_FOREGROUND, styledText.getDisplay());
+ styledText.setForeground(color);
+
+ if (fForegroundColor != null)
+ fForegroundColor.dispose();
+
+ fForegroundColor= color;
+
+ // ---------- background color ----------------------
+ color= store.getBoolean(PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT)
+ ? null
+ : createColor(store, PREFERENCE_COLOR_BACKGROUND, styledText.getDisplay());
+ styledText.setBackground(color);
+
+ if (fBackgroundColor != null)
+ fBackgroundColor.dispose();
+
+ fBackgroundColor= color;
+ }
+ }
+
+ /**
+ * Initializes the background color used for highlighting the document ranges
+ * defining search scopes.
+ * @param viewer the viewer to initialize
+ * @since 2.0
+ */
+ private void initializeFindScopeColor(ISourceViewer viewer) {
+
+ IPreferenceStore store= getPreferenceStore();
+ if (store != null) {
+
+ StyledText styledText= viewer.getTextWidget();
+
+ Color color= createColor(store, PREFERENCE_COLOR_FIND_SCOPE, styledText.getDisplay());
+
+ IFindReplaceTarget target= viewer.getFindReplaceTarget();
+ if (target != null && target instanceof IFindReplaceTargetExtension)
+ ((IFindReplaceTargetExtension) target).setScopeHighlightColor(color);
+
+ if (fFindScopeHighlightColor != null)
+ fFindScopeHighlightColor.dispose();
+
+ fFindScopeHighlightColor= color;
+ }
+ }
+
+
+ /**
+ * Initializes the editor's source viewer based on the given editor input.
+ *
+ * @param input the editor input to be used to initialize the source viewer
+ */
+ private void initializeSourceViewer(IEditorInput input) {
+
+ IAnnotationModel model= getDocumentProvider().getAnnotationModel(input);
+ IDocument document= getDocumentProvider().getDocument(input);
+
+ if (document != null) {
+ fSourceViewer.setDocument(document, model);
+ fSourceViewer.setEditable(isEditable());
+ fSourceViewer.showAnnotations(model != null);
+ }
+
+ if (fElementStateListener instanceof IElementStateListenerExtension) {
+ IElementStateListenerExtension extension= (IElementStateListenerExtension) fElementStateListener;
+ extension.elementStateValidationChanged(input, false);
+ }
+ }
+
+ /**
+ * Initializes the editor's title based on the given editor input.
+ *
+ * @param input the editor input to be used
+ */
+ private void initializeTitle(IEditorInput input) {
+
+ Image oldImage= fTitleImage;
+ fTitleImage= null;
+ String title= ""; //$NON-NLS-1$
+
+ if (input != null) {
+ IEditorRegistry editorRegistry = getEditorSite().getPage().getWorkbenchWindow().getWorkbench().getEditorRegistry();
+ IEditorDescriptor editorDesc= editorRegistry.findEditor(getSite().getId());
+ ImageDescriptor imageDesc= editorDesc != null ? editorDesc.getImageDescriptor() : null;
+
+ fTitleImage= imageDesc != null ? imageDesc.createImage() : null;
+ title= input.getName();
+ }
+
+ setTitleImage(fTitleImage);
+ setTitle(title);
+
+ firePropertyChange(PROP_DIRTY);
+
+ if (oldImage != null && !oldImage.isDisposed())
+ oldImage.dispose();
+ }
+
+ /**
+ * If there is no implicit document provider set, the external one is
+ * re-initialized based on the given editor input.
+ *
+ * @param input the editor input.
+ */
+ private void updateDocumentProvider(IEditorInput input) {
+ if (getDocumentProvider() != null)
+ getDocumentProvider().removeElementStateListener(fElementStateListener);
+
+ if (fInternalDocumentProvider == null)
+ fExternalDocumentProvider= DocumentProviderRegistry.getDefault().getDocumentProvider(input);
+
+ if (getDocumentProvider() != null)
+ getDocumentProvider().addElementStateListener(fElementStateListener);
+ }
+
+ /**
+ * Internal <code>setInput</code> method.
+ *
+ * @param input the input to be set
+ * @exception CoreException if input cannot be connected to the document provider
+ */
+ protected void doSetInput(IEditorInput input) throws CoreException {
+
+ if (input == null)
+
+ close(isSaveOnCloseNeeded());
+
+ else {
+
+ IEditorInput oldInput= getEditorInput();
+ if (oldInput != null)
+ getDocumentProvider().disconnect(oldInput);
+
+ super.setInput(input);
+
+ updateDocumentProvider(input);
+
+ IDocumentProvider provider= getDocumentProvider();
+ if (provider == null) {
+ IStatus s= new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, IStatus.OK, EditorMessages.getString("Editor.error.no_provider"), null); //$NON-NLS-1$
+ throw new CoreException(s);
+ }
+
+ provider.connect(input);
+
+ initializeTitle(input);
+ if (fSourceViewer != null)
+ initializeSourceViewer(input);
+
+ updateStatusField(ITextEditorActionConstants.STATUS_CATEGORY_ELEMENT_STATE);
+ }
+ }
+
+ /*
+ * @see EditorPart#setInput
+ */
+ public final void setInput(IEditorInput input) {
+
+ try {
+
+ doSetInput(input);
+
+ } catch (CoreException x) {
+ String title= EditorMessages.getString("Editor.error.setinput.title"); //$NON-NLS-1$
+ String msg= EditorMessages.getString("Editor.error.setinput.message"); //$NON-NLS-1$
+ Shell shell= getSite().getShell();
+ ErrorDialog.openError(shell, title, msg, x.getStatus());
+ }
+ }
+
+ /*
+ * @see ITextEditor#close
+ */
+ public void close(final boolean save) {
+
+ enableSanityChecking(false);
+
+ Display display= getSite().getShell().getDisplay();
+ display.asyncExec(new Runnable() {
+ public void run() {
+ if (fSourceViewer != null) {
+ // check whether editor has not been disposed yet
+ getSite().getPage().closeEditor(AbstractTextEditor.this, save);
+ }
+ }
+ });
+ }
+
+ /**
+ * The <code>AbstractTextEditor</code> implementation of this
+ * <code>IWorkbenchPart</code> method may be extended by subclasses.
+ * Subclasses must call <code>super.dispose()</code>.
+ */
+ public void dispose() {
+
+ if (fActivationListener != null) {
+ IWorkbenchWindow window= getSite().getWorkbenchWindow();
+ window.getPartService().removePartListener(fActivationListener);
+ Shell shell= window.getShell();
+ if (shell != null && !shell.isDisposed())
+ shell.removeShellListener(fActivationListener);
+ fActivationListener= null;
+ }
+
+ if (fTitleImage != null) {
+ fTitleImage.dispose();
+ fTitleImage= null;
+ }
+
+ if (fFont != null) {
+ fFont.dispose();
+ fFont= null;
+ }
+
+ if (fPropertyChangeListener != null) {
+ if (fPreferenceStore != null) {
+ fPreferenceStore.removePropertyChangeListener(fPropertyChangeListener);
+ fPreferenceStore= null;
+ }
+ fPropertyChangeListener= null;
+ }
+
+ if (fActivationCodeTrigger != null) {
+ fActivationCodeTrigger.uninstall();
+ fActivationCodeTrigger= null;
+ }
+
+ IDocumentProvider provider= getDocumentProvider();
+ if (provider != null) {
+
+ IEditorInput input= getEditorInput();
+ if (input != null)
+ provider.disconnect(input);
+
+ if (fElementStateListener != null) {
+ provider.removeElementStateListener(fElementStateListener);
+ fElementStateListener= null;
+ }
+
+ fInternalDocumentProvider= null;
+ fExternalDocumentProvider= null;
+ }
+
+ if (fSourceViewer != null) {
+
+ if (fTextListener != null) {
+ fSourceViewer.removeTextListener(fTextListener);
+ fTextListener= null;
+ }
+
+ fSelectionProvider= null;
+ fSourceViewer= null;
+ }
+
+ if (fTextContextMenu != null) {
+ fTextContextMenu.dispose();
+ fTextContextMenu= null;
+ }
+
+ if (fRulerContextMenu != null) {
+ fRulerContextMenu.dispose();
+ fRulerContextMenu= null;
+ }
+
+ if (fActions != null) {
+ fActions.clear();
+ fActions= null;
+ }
+
+ if (fSelectionActions != null) {
+ fSelectionActions.clear();
+ fSelectionActions= null;
+ }
+
+ if (fContentActions != null) {
+ fContentActions.clear();
+ fContentActions= null;
+ }
+
+ if (fPropertyActions != null) {
+ fPropertyActions.clear();
+ fPropertyActions= null;
+ }
+
+ if (fStateActions != null) {
+ fStateActions.clear();
+ fStateActions= null;
+ }
+
+ if (fActivationCodes != null) {
+ fActivationCodes.clear();
+ fActivationCodes= null;
+ }
+
+ if (fEditorStatusLine != null)
+ fEditorStatusLine= null;
+
+ super.setInput(null);
+
+ super.dispose();
+ }
+
+ /**
+ * Determines whether the given preference change affects the editor's
+ * presentation. This implementation always returns <code>false</code>.
+ * May be reimplemented by subclasses.
+ *
+ * @param event the event which should be investigated
+ * @return <code>true</code> if the event describes a preference change affecting the editor's presentation
+ * @since 2.0
+ */
+ protected boolean affectsTextPresentation(PropertyChangeEvent event) {
+ return false;
+ }
+
+ /**
+ * Handles a property change event describing a change
+ * of the editor's preference store and updates the preference
+ * related editor properties.
+ *
+ * @param event the property change event
+ */
+ protected void handlePreferenceStoreChanged(PropertyChangeEvent event) {
+
+ if (fSourceViewer == null)
+ return;
+
+ String property= event.getProperty();
+
+ if (PREFERENCE_FONT.equals(property)) {
+ initializeViewerFont(fSourceViewer);
+
+ } else if (PREFERENCE_COLOR_FOREGROUND.equals(property) || PREFERENCE_COLOR_FOREGROUND_SYSTEM_DEFAULT.equals(property) ||
+ PREFERENCE_COLOR_BACKGROUND.equals(property) || PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT.equals(property))
+ {
+ initializeViewerColors(fSourceViewer);
+ } else if (PREFERENCE_COLOR_FIND_SCOPE.equals(property)) {
+ initializeFindScopeColor(fSourceViewer);
+ }
+
+ if (affectsTextPresentation(event))
+ fSourceViewer.invalidateTextPresentation();
+ }
+
+ /**
+ * Handles an external change of the editor's input element.
+ */
+ protected void handleEditorInputChanged() {
+
+ String title;
+ String msg;
+ Shell shell= getSite().getShell();
+
+ IDocumentProvider provider= getDocumentProvider();
+ if (provider == null) {
+ // fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=15066
+ close(false);
+ return;
+ }
+
+ IEditorInput input= getEditorInput();
+ if (provider.isDeleted(input)) {
+
+ if (isSaveAsAllowed()) {
+
+ title= EditorMessages.getString("Editor.error.activated.deleted.save.title"); //$NON-NLS-1$
+ msg= EditorMessages.getString("Editor.error.activated.deleted.save.message"); //$NON-NLS-1$
+
+ String[] buttons= {
+ EditorMessages.getString("Editor.error.activated.deleted.save.button.save"), //$NON-NLS-1$
+ EditorMessages.getString("Editor.error.activated.deleted.save.button.close"), //$NON-NLS-1$
+ };
+
+ MessageDialog dialog= new MessageDialog(shell, title, null, msg, MessageDialog.QUESTION, buttons, 0);
+
+ if (dialog.open() == 0) {
+ NullProgressMonitor pm= new NullProgressMonitor();
+ performSaveAs(pm);
+ if (pm.isCanceled())
+ handleEditorInputChanged();
+ } else {
+ close(false);
+ }
+
+ } else {
+
+ title= EditorMessages.getString("Editor.error.activated.deleted.close.title"); //$NON-NLS-1$
+ msg= EditorMessages.getString("Editor.error.activated.deleted.close.message"); //$NON-NLS-1$
+ if (MessageDialog.openConfirm(shell, title, msg))
+ close(false);
+ }
+
+ } else {
+
+ title= EditorMessages.getString("Editor.error.activated.outofsync.title"); //$NON-NLS-1$
+ msg= EditorMessages.getString("Editor.error.activated.outofsync.message"); //$NON-NLS-1$
+
+ if (MessageDialog.openQuestion(shell, title, msg)) {
+ try {
+
+ if (provider instanceof IDocumentProviderExtension) {
+ IDocumentProviderExtension extension= (IDocumentProviderExtension) provider;
+ extension.synchronize(input);
+ } else {
+ doSetInput(input);
+ }
+
+
+ } catch (CoreException x) {
+ title= EditorMessages.getString("Editor.error.refresh.outofsync.title"); //$NON-NLS-1$
+ msg= EditorMessages.getString("Editor.error.refresh.outofsync.message"); //$NON-NLS-1$
+ ErrorDialog.openError(shell, title, msg, x.getStatus());
+ }
+ }
+
+// // disabled because of http://bugs.eclipse.org/bugs/show_bug.cgi?id=15166
+// else {
+// markEditorAsDirty();
+// }
+
+ }
+ }
+
+ /**
+ * Marks this editor and its editor input as dirty.
+ * @since 2.0
+ */
+ private void markEditorAsDirty() {
+
+ if (isDirty())
+ return;
+
+ IDocumentProvider provider= getDocumentProvider();
+ if (provider instanceof IDocumentProviderExtension) {
+
+ provider.removeElementStateListener(fElementStateListener);
+ try {
+
+ IDocumentProviderExtension extension= (IDocumentProviderExtension) provider;
+ extension.setCanSaveDocument(getEditorInput());
+ firePropertyChange(PROP_DIRTY);
+
+ } finally {
+ provider.addElementStateListener(fElementStateListener);
+ }
+
+ }
+ }
+
+ /**
+ * The <code>AbstractTextEditor</code> implementation of this
+ * <code>IEditorPart</code> method calls <code>oerformSaveAs</code>.
+ * Subclasses may reimplement.
+ */
+ public void doSaveAs() {
+ /*
+ * 1GEUSSR: ITPUI:ALL - User should never loose changes made in the editors.
+ * Changed Behavior to make sure that if called inside a regular save (because
+ * of deletion of input element) there is a way to report back to the caller.
+ */
+ performSaveAs(new NullProgressMonitor());
+ }
+
+ /**
+ * Performs a save as and reports the result state back to the
+ * given progress monitor. This default implementation does nothing.
+ * Subclasses may reimplement.
+ *
+ * @param progressMonitor the progress monitor for communicating result state or <code>null</code>
+ */
+ protected void performSaveAs(IProgressMonitor progressMonitor) {
+ }
+
+ /**
+ * The <code>AbstractTextEditor</code> implementation of this
+ * <code>IEditorPart</code> method may be extended by subclasses.
+ */
+ public void doSave(IProgressMonitor progressMonitor) {
+
+ IDocumentProvider p= getDocumentProvider();
+ if (p == null)
+ return;
+
+ if (p.isDeleted(getEditorInput())) {
+
+ if (isSaveAsAllowed()) {
+
+ /*
+ * 1GEUSSR: ITPUI:ALL - User should never loose changes made in the editors.
+ * Changed Behavior to make sure that if called inside a regular save (because
+ * of deletion of input element) there is a way to report back to the caller.
+ */
+ performSaveAs(progressMonitor);
+
+ } else {
+
+ Shell shell= getSite().getShell();
+ String title= EditorMessages.getString("Editor.error.save.deleted.title"); //$NON-NLS-1$
+ String msg= EditorMessages.getString("Editor.error.save.deleted.message"); //$NON-NLS-1$
+ MessageDialog.openError(shell, title, msg);
+ }
+
+ } else {
+
+ performSaveOperation(createSaveOperation(false), progressMonitor);
+ }
+ }
+
+ /**
+ * Enables/Disabled sanity checking.
+ * @param enable <code>true</code> if santity checking should be enabled, <code>false</code> otherwise
+ * @since 2.0
+ */
+ protected void enableSanityChecking(boolean enable) {
+ synchronized (this) {
+ fIsSanityCheckEnabled= enable;
+ }
+ }
+
+ /**
+ * Checks the state of the given editor input if sanity checking is enabled.
+ * @param input the editor input whose state is to be checked
+ * @since 2.0
+ */
+ protected void safelySanityCheckState(IEditorInput input) {
+ boolean enabled= false;
+
+ synchronized (this) {
+ enabled= fIsSanityCheckEnabled;
+ }
+
+ if (enabled)
+ sanityCheckState(input);
+ }
+
+ /**
+ * Checks the state of the given editor input.
+ * @param input the editor input whose state is to be checked
+ * @since 2.0
+ */
+ protected void sanityCheckState(IEditorInput input) {
+
+ IDocumentProvider p= getDocumentProvider();
+ if (p == null)
+ return;
+
+ if (fModificationStamp == -1)
+ fModificationStamp= p.getSynchronizationStamp(input);
+
+ long stamp= p.getModificationStamp(input);
+ if (stamp != fModificationStamp) {
+ fModificationStamp= stamp;
+ if (stamp != p.getSynchronizationStamp(input))
+ handleEditorInputChanged();
+ }
+
+ updateState(getEditorInput());
+ updateStatusField(ITextEditorActionConstants.STATUS_CATEGORY_ELEMENT_STATE);
+ }
+
+ /**
+ * Validates the state of the given editor input. The predominate intent
+ * of this method is to take any action propably necessary to ensure that
+ * the input can persistently be changed.
+ *
+ * @param input the input to be validated
+ * @since 2.0
+ */
+ protected void validateState(IEditorInput input) {
+ IDocumentProvider provider= getDocumentProvider();
+ if (provider instanceof IDocumentProviderExtension) {
+ IDocumentProviderExtension extension= (IDocumentProviderExtension) provider;
+ try {
+
+ boolean wasReadOnly= isEditorInputReadOnly();
+
+ extension.validateState(input, getSite().getShell());
+
+ if (fSourceViewer != null)
+ fSourceViewer.setEditable(isEditable());
+
+ if (wasReadOnly != isEditorInputReadOnly())
+ updateStateDependentActions();
+
+ } catch (CoreException x) {
+ ILog log= Platform.getPlugin(PlatformUI.PLUGIN_ID).getLog();
+ log.log(x.getStatus());
+ }
+ }
+ }
+
+ /**
+ * Updates the state of the given editor input such as read-only flag etc.
+ *
+ * @param input the input to be validated
+ * @since 2.0
+ */
+ protected void updateState(IEditorInput input) {
+ IDocumentProvider provider= getDocumentProvider();
+ if (provider instanceof IDocumentProviderExtension) {
+ IDocumentProviderExtension extension= (IDocumentProviderExtension) provider;
+ try {
+
+ boolean wasReadOnly= isEditorInputReadOnly();
+ extension.updateStateCache(input);
+
+ if (fSourceViewer != null)
+ fSourceViewer.setEditable(isEditable());
+
+ if (wasReadOnly != isEditorInputReadOnly())
+ updateStateDependentActions();
+
+ } catch (CoreException x) {
+ ILog log= Platform.getPlugin(PlatformUI.PLUGIN_ID).getLog();
+ log.log(x.getStatus());
+ }
+ }
+ }
+
+ /**
+ * Creates a workspace modify operation which saves the content of the editor
+ * to the editor's input element. <code>overwrite</code> indicates whether
+ * the editor input element may be overwritten if necessary. Clients may
+ * reimplement this method.
+ *
+ * @param overwrite indicates whether or not overwrititng is allowed
+ * @return the save operation
+ */
+ protected WorkspaceModifyOperation createSaveOperation(final boolean overwrite) {
+ return new WorkspaceModifyOperation() {
+ public void execute(final IProgressMonitor monitor) throws CoreException {
+ IEditorInput input= getEditorInput();
+ getDocumentProvider().saveDocument(monitor, input, getDocumentProvider().getDocument(input), overwrite);
+ }
+ };
+ }
+
+ /**
+ * Performs the given save operation and handles errors appropriatly.
+ *
+ * @param operation the operation to be performed
+ * @param progressMonitor the monitor in which to run the operation
+ */
+ protected void performSaveOperation(WorkspaceModifyOperation operation, IProgressMonitor progressMonitor) {
+
+ IDocumentProvider provider= getDocumentProvider();
+
+ try {
+
+ provider.aboutToChange(getEditorInput());
+ operation.run(progressMonitor);
+ editorSaved();
+
+ } catch (InterruptedException x) {
+ } catch (InvocationTargetException x) {
+
+ Throwable t= x.getTargetException();
+ if (t instanceof CoreException)
+ handleExceptionOnSave((CoreException) t, progressMonitor);
+ else {
+ Shell shell= getSite().getShell();
+ String title= EditorMessages.getString("Editor.error.save.title"); //$NON-NLS-1$
+ String msg= EditorMessages.getString("Editor.error.save.message"); //$NON-NLS-1$
+ MessageDialog.openError(shell, title, msg + t.getMessage());
+ }
+
+ } finally {
+ provider.changed(getEditorInput());
+ }
+ }
+
+ /**
+ * Handles the given exception. If the exception reports an out-of-sync
+ * situation, this is reported to the user. Otherwise, the exception
+ * is generically reported.
+ *
+ * @param exception the exception to handle
+ * @param progressMonitor the progress monitor
+ */
+ protected void handleExceptionOnSave(CoreException exception, IProgressMonitor progressMonitor) {
+
+ try {
+ ++ fErrorCorrectionOnSave;
+
+ Shell shell= getSite().getShell();
+
+ IDocumentProvider p= getDocumentProvider();
+ long modifiedStamp= p.getModificationStamp(getEditorInput());
+ long synchStamp= p.getSynchronizationStamp(getEditorInput());
+
+ if (fErrorCorrectionOnSave == 1 && modifiedStamp != synchStamp) {
+
+ String title= EditorMessages.getString("Editor.error.save.outofsync.title"); //$NON-NLS-1$
+ String msg= EditorMessages.getString("Editor.error.save.outofsync.message"); //$NON-NLS-1$
+
+ if (MessageDialog.openQuestion(shell, title, msg))
+ performSaveOperation(createSaveOperation(true), progressMonitor);
+ else {
+ /*
+ * 1GEUPKR: ITPJUI:ALL - Loosing work with simultaneous edits
+ * Set progress monitor to canceled in order to report back
+ * to enclosing operations.
+ */
+ if (progressMonitor != null)
+ progressMonitor.setCanceled(true);
+ }
+ } else {
+
+ String title= EditorMessages.getString("Editor.error.save.title"); //$NON-NLS-1$
+ String msg= EditorMessages.getString("Editor.error.save.message"); //$NON-NLS-1$
+ ErrorDialog.openError(shell, title, msg, exception.getStatus());
+
+ /*
+ * 1GEUPKR: ITPJUI:ALL - Loosing work with simultaneous edits
+ * Set progress monitor to canceled in order to report back
+ * to enclosing operations.
+ */
+ if (progressMonitor != null)
+ progressMonitor.setCanceled(true);
+ }
+
+ } finally {
+ -- fErrorCorrectionOnSave;
+ }
+ }
+
+ /**
+ * The <code>AbstractTextEditor</code> implementation of this
+ * <code>IEditorPart</code> method returns <code>false</code>. Subclasses
+ * may override.
+ */
+ public boolean isSaveAsAllowed() {
+ return false;
+ }
+
+ /*
+ * @see IEditorPart#isSaveOnCloseNeeded()
+ */
+ public boolean isSaveOnCloseNeeded() {
+ IDocumentProvider p= getDocumentProvider();
+ return p == null ? false : p.mustSaveDocument(getEditorInput());
+ }
+
+ /*
+ * @see IEditorPart#isDirty
+ */
+ public boolean isDirty() {
+ IDocumentProvider p= getDocumentProvider();
+ return p == null ? false : p.canSaveDocument(getEditorInput());
+ }
+
+ /**
+ * The <code>AbstractTextEditor</code> implementation of this
+ * <code>ITextEditor</code> method may be extended by subclasses.
+ */
+ public void doRevertToSaved() {
+
+ IDocumentProvider p= getDocumentProvider();
+ if (p == null)
+ return;
+
+ try {
+
+ p.resetDocument(getEditorInput());
+
+ IAnnotationModel model= p.getAnnotationModel(getEditorInput());
+ if (model instanceof AbstractMarkerAnnotationModel) {
+ AbstractMarkerAnnotationModel markerModel= (AbstractMarkerAnnotationModel) model;
+ markerModel.resetMarkers();
+ }
+
+ firePropertyChange(PROP_DIRTY);
+
+ } catch (CoreException x) {
+ String title= EditorMessages.getString("Editor.error.revert.title"); //$NON-NLS-1$
+ String msg= EditorMessages.getString("Editor.error.revert.message"); //$NON-NLS-1$
+ Shell shell= getSite().getShell();
+ ErrorDialog.openError(shell, title, msg, x.getStatus());
+ }
+ }
+
+ /*
+ * @see ITextEditor#setAction
+ */
+ public void setAction(String actionID, IAction action) {
+ Assert.isNotNull(actionID);
+ if (action == null) {
+ action= (IAction) fActions.remove(actionID);
+ if (action != null)
+ fActivationCodeTrigger.unregisterActionFromKeyActivation(action);
+ } else {
+ fActions.put(actionID, action);
+ fActivationCodeTrigger.registerActionForKeyActivation(action);
+ }
+ }
+
+ /*
+ * @see ITextEditor#setActionActivationCode(String, char, int, int)
+ */
+ public void setActionActivationCode(String actionID, char activationCharacter, int activationKeyCode, int activationStateMask) {
+
+ Assert.isNotNull(actionID);
+
+ ActionActivationCode found= findActionActivationCode(actionID);
+ if (found == null) {
+ found= new ActionActivationCode(actionID);
+ fActivationCodes.add(found);
+ }
+
+ found.fCharacter= activationCharacter;
+ found.fKeyCode= activationKeyCode;
+ found.fStateMask= activationStateMask;
+ }
+
+ /**
+ * Returns the activation code registered for the specified action.
+ *
+ * @param actionID the action id
+ * @return the registered activation code or <code>null</code> if no code has been installed
+ */
+ private ActionActivationCode findActionActivationCode(String actionID) {
+ int size= fActivationCodes.size();
+ for (int i= 0; i < size; i++) {
+ ActionActivationCode code= (ActionActivationCode) fActivationCodes.get(i);
+ if (actionID.equals(code.fActionId))
+ return code;
+ }
+ return null;
+ }
+
+ /*
+ * @see ITextEditor#removeActionActivationCode(String)
+ */
+ public void removeActionActivationCode(String actionID) {
+ Assert.isNotNull(actionID);
+ ActionActivationCode code= findActionActivationCode(actionID);
+ if (code != null)
+ fActivationCodes.remove(code);
+ }
+
+ /*
+ * @see ITextEditor#getAction
+ */
+ public IAction getAction(String actionID) {
+ Assert.isNotNull(actionID);
+ IAction action= (IAction) fActions.get(actionID);
+
+ if (action == null) {
+ action= findContributedAction(actionID);
+ if (action != null)
+ setAction(actionID, action);
+ }
+
+ return action;
+ }
+
+ /**
+ * Returns the action with the given action id that has been contributed via xml to this editor.
+ * The lookup honors the dependencies of plugins.
+ *
+ * @param actionID the action id to look up
+ * @return the action that has been contributed
+ * @since 2.0
+ */
+ private IAction findContributedAction(String actionID) {
+ IExtensionPoint extensionPoint= Platform.getPluginRegistry().getExtensionPoint(PlatformUI.PLUGIN_ID, "editorActions"); //$NON-NLS-1$
+ if (extensionPoint != null) {
+ IConfigurationElement[] elements= extensionPoint.getConfigurationElements();
+
+ List actions= new ArrayList();
+ for (int i= 0; i < elements.length; i++) {
+ IConfigurationElement element= elements[i];
+ if (TAG_CONTRIBUTION_TYPE.equals(element.getName())) {
+ if (!getSite().getId().equals(element.getAttribute("targetID"))) //$NON-NLS-1$
+ continue;
+
+ IConfigurationElement[] children= element.getChildren("action"); //$NON-NLS-1$
+ for (int j= 0; j < children.length; j++) {
+ IConfigurationElement child= children[j];
+ if (actionID.equals(child.getAttribute("actionID"))) //$NON-NLS-1$
+ actions.add(child);
+ }
+ }
+ }
+ Collections.sort(actions, new ConfigurationElementComparator());
+
+ if (actions.size() != 0) {
+ IConfigurationElement element= (IConfigurationElement) actions.get(0);
+ return new EditorPluginAction(element, "class", this); //$NON-NLS-1$
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Updates the specified action by calling <code>IUpdate.update</code>
+ * if applicable.
+ *
+ * @param actionId the action id
+ */
+ private void updateAction(String actionId) {
+ Assert.isNotNull(actionId);
+ if (fActions != null) {
+ IAction action= (IAction) fActions.get(actionId);
+ if (action instanceof IUpdate)
+ ((IUpdate) action).update();
+ }
+ }
+
+ /**
+ * Marks or unmarks the given action to be updated on text selection changes.
+ *
+ * @param actionId the action id
+ * @param mark <code>true</code> if the action is selection dependent
+ */
+ public void markAsSelectionDependentAction(String actionId, boolean mark) {
+ Assert.isNotNull(actionId);
+ if (mark) {
+ if (!fSelectionActions.contains(actionId))
+ fSelectionActions.add(actionId);
+ } else
+ fSelectionActions.remove(actionId);
+ }
+
+ /**
+ * Marks or unmarks the given action to be updated on content changes.
+ *
+ * @param actionId the action id
+ * @param mark <code>true</code> if the action is content dependent
+ */
+ public void markAsContentDependentAction(String actionId, boolean mark) {
+ Assert.isNotNull(actionId);
+ if (mark) {
+ if (!fContentActions.contains(actionId))
+ fContentActions.add(actionId);
+ } else
+ fContentActions.remove(actionId);
+ }
+
+ /**
+ * Marks or unmarks the given action to be updated on property changes.
+ *
+ * @param actionId the action id
+ * @param mark <code>true</code> if the action is property dependent
+ * @since 2.0
+ */
+ public void markAsPropertyDependentAction(String actionId, boolean mark) {
+ Assert.isNotNull(actionId);
+ if (mark) {
+ if (!fPropertyActions.contains(actionId))
+ fPropertyActions.add(actionId);
+ } else
+ fPropertyActions.remove(actionId);
+ }
+
+ /**
+ * Marks or unmarks the given action to be updated on state changes.
+ *
+ * @param actionId the action id
+ * @param mark <code>true</code> if the action is state dependent
+ * @since 2.0
+ */
+ public void markAsStateDependentAction(String actionId, boolean mark) {
+ Assert.isNotNull(actionId);
+ if (mark) {
+ if (!fStateActions.contains(actionId))
+ fStateActions.add(actionId);
+ } else
+ fStateActions.remove(actionId);
+ }
+
+ /**
+ * Updates all selection dependent actions.
+ */
+ protected void updateSelectionDependentActions() {
+ if (fSelectionActions != null) {
+ Iterator e= fSelectionActions.iterator();
+ while (e.hasNext())
+ updateAction((String) e.next());
+ }
+ }
+
+ /**
+ * Updates all content dependent actions.
+ */
+ protected void updateContentDependentActions() {
+ if (fContentActions != null) {
+ Iterator e= fContentActions.iterator();
+ while (e.hasNext())
+ updateAction((String) e.next());
+ }
+ }
+
+ /**
+ * Updates all property dependent actions.
+ * @since 2.0
+ */
+ protected void updatePropertyDependentActions() {
+ if (fPropertyActions != null) {
+ Iterator e= fPropertyActions.iterator();
+ while (e.hasNext())
+ updateAction((String) e.next());
+ }
+ }
+
+ /**
+ * Updates all state dependent actions.
+ * @since 2.0
+ */
+ protected void updateStateDependentActions() {
+ if (fStateActions != null) {
+ Iterator e= fStateActions.iterator();
+ while (e.hasNext())
+ updateAction((String) e.next());
+ }
+ }
+
+ /**
+ * Creates this editor's standard navigation actions.
+ * <p>
+ * Subclasses may extend.
+ * </p>
+ * @since 2.0
+ */
+ protected void createNavigationActions() {
+
+ IAction action;
+
+ StyledText textWidget= getSourceViewer().getTextWidget();
+ for (int i= 0; i < ACTION_MAP.length; i++) {
+ IdMapEntry entry= (IdMapEntry) ACTION_MAP[i];
+ action= new TextNavigationAction(textWidget, entry.getAction());
+ action.setActionDefinitionId(entry.getActionId());
+ setAction(entry.getActionId(), action);
+ }
+
+ action= new ToggleInsertModeAction(textWidget);
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.TOGGLE_OVERWRITE);
+ setAction(ITextEditorActionDefinitionIds.TOGGLE_OVERWRITE, action);
+
+ action= new ScrollLinesAction(-1);
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.SCROLL_LINE_UP);
+ setAction(ITextEditorActionDefinitionIds.SCROLL_LINE_UP, action);
+
+ action= new ScrollLinesAction(1);
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.SCROLL_LINE_DOWN);
+ setAction(ITextEditorActionDefinitionIds.SCROLL_LINE_DOWN, action);
+ }
+
+ /**
+ * Creates this editor's accessibility actions.
+ * @since 2.0
+ */
+ private void createAccessibilityActions() {
+ IAction action= new ShowRulerContextMenuAction();
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.SHOW_RULER_CONTEXT_MENU);
+ setAction(ITextEditorActionDefinitionIds.SHOW_RULER_CONTEXT_MENU, action);
+ }
+
+ /**
+ * Creates this editor's standard actions and connects them with the global
+ * workbench actions.
+ * <p>
+ * Subclasses may extend.
+ * </p>
+ */
+ protected void createActions() {
+
+ ResourceAction action;
+
+ action= new TextOperationAction(EditorMessages.getResourceBundle(), "Editor.Undo.", this, ITextOperationTarget.UNDO); //$NON-NLS-1$
+ action.setHelpContextId(IAbstractTextEditorHelpContextIds.UNDO_ACTION);
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.UNDO);
+ setAction(ITextEditorActionConstants.UNDO, action);
+
+ action= new TextOperationAction(EditorMessages.getResourceBundle(), "Editor.Redo.", this, ITextOperationTarget.REDO); //$NON-NLS-1$
+ action.setHelpContextId(IAbstractTextEditorHelpContextIds.REDO_ACTION);
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.REDO);
+ setAction(ITextEditorActionConstants.REDO, action);
+
+ action= new TextOperationAction(EditorMessages.getResourceBundle(), "Editor.Cut.", this, ITextOperationTarget.CUT); //$NON-NLS-1$
+ action.setHelpContextId(IAbstractTextEditorHelpContextIds.CUT_ACTION);
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.CUT);
+ setAction(ITextEditorActionConstants.CUT, action);
+
+ action= new TextOperationAction(EditorMessages.getResourceBundle(), "Editor.Copy.", this, ITextOperationTarget.COPY, true); //$NON-NLS-1$
+ action.setHelpContextId(IAbstractTextEditorHelpContextIds.COPY_ACTION);
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.COPY);
+ setAction(ITextEditorActionConstants.COPY, action);
+
+ action= new TextOperationAction(EditorMessages.getResourceBundle(), "Editor.Paste.", this, ITextOperationTarget.PASTE); //$NON-NLS-1$
+ action.setHelpContextId(IAbstractTextEditorHelpContextIds.PASTE_ACTION);
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.PASTE);
+ setAction(ITextEditorActionConstants.PASTE, action);
+
+ action= new TextOperationAction(EditorMessages.getResourceBundle(), "Editor.Delete.", this, ITextOperationTarget.DELETE); //$NON-NLS-1$
+ action.setHelpContextId(IAbstractTextEditorHelpContextIds.DELETE_ACTION);
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.DELETE);
+ setAction(ITextEditorActionConstants.DELETE, action);
+
+ action= new DeleteLineAction(EditorMessages.getResourceBundle(), "Editor.DeleteLine.", this, DeleteLineAction.WHOLE); //$NON-NLS-1$
+ action.setHelpContextId(IAbstractTextEditorHelpContextIds.DELETE_LINE_ACTION);
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.DELETE_LINE);
+ setAction(ITextEditorActionConstants.DELETE_LINE, action);
+
+ action= new DeleteLineAction(EditorMessages.getResourceBundle(), "Editor.DeleteLineToBeginning.", this, DeleteLineAction.TO_BEGINNING); //$NON-NLS-1$
+ action.setHelpContextId(IAbstractTextEditorHelpContextIds.DELETE_LINE_TO_BEGINNING_ACTION);
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.DELETE_LINE_TO_BEGINNING);
+ setAction(ITextEditorActionConstants.DELETE_LINE_TO_BEGINNING, action);
+
+ action= new DeleteLineAction(EditorMessages.getResourceBundle(), "Editor.DeleteLineToEnd.", this, DeleteLineAction.TO_END); //$NON-NLS-1$
+ action.setHelpContextId(IAbstractTextEditorHelpContextIds.DELETE_LINE_TO_END_ACTION);
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.DELETE_LINE_TO_END);
+ setAction(ITextEditorActionConstants.DELETE_LINE_TO_END, action);
+
+ action= new MarkAction(EditorMessages.getResourceBundle(), "Editor.SetMark.", this, MarkAction.SET_MARK); //$NON-NLS-1$
+ action.setHelpContextId(IAbstractTextEditorHelpContextIds.SET_MARK_ACTION);
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.SET_MARK);
+ setAction(ITextEditorActionConstants.SET_MARK, action);
+
+ action= new MarkAction(EditorMessages.getResourceBundle(), "Editor.ClearMark.", this, MarkAction.CLEAR_MARK); //$NON-NLS-1$
+ action.setHelpContextId(IAbstractTextEditorHelpContextIds.CLEAR_MARK_ACTION);
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.CLEAR_MARK);
+ setAction(ITextEditorActionConstants.CLEAR_MARK, action);
+
+ action= new MarkAction(EditorMessages.getResourceBundle(), "Editor.SwapMark.", this, MarkAction.SWAP_MARK); //$NON-NLS-1$
+ action.setHelpContextId(IAbstractTextEditorHelpContextIds.SWAP_MARK_ACTION);
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.SWAP_MARK);
+ setAction(ITextEditorActionConstants.SWAP_MARK, action);
+
+ action= new TextOperationAction(EditorMessages.getResourceBundle(), "Editor.SelectAll.", this, ITextOperationTarget.SELECT_ALL, true); //$NON-NLS-1$
+ action.setHelpContextId(IAbstractTextEditorHelpContextIds.SELECT_ALL_ACTION);
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.SELECT_ALL);
+ setAction(ITextEditorActionConstants.SELECT_ALL, action);
+
+ action= new ShiftAction(EditorMessages.getResourceBundle(), "Editor.ShiftRight.", this, ITextOperationTarget.SHIFT_RIGHT); //$NON-NLS-1$
+ action.setHelpContextId(IAbstractTextEditorHelpContextIds.SHIFT_RIGHT_ACTION);
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.SHIFT_RIGHT);
+ setAction(ITextEditorActionConstants.SHIFT_RIGHT, action);
+
+ action= new ShiftAction(EditorMessages.getResourceBundle(), "Editor.ShiftLeft.", this, ITextOperationTarget.SHIFT_LEFT); //$NON-NLS-1$
+ action.setHelpContextId(IAbstractTextEditorHelpContextIds.SHIFT_LEFT_ACTION);
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.SHIFT_LEFT);
+ setAction(ITextEditorActionConstants.SHIFT_LEFT, action);
+
+ action= new TextOperationAction(EditorMessages.getResourceBundle(), "Editor.Print.", this, ITextOperationTarget.PRINT, true); //$NON-NLS-1$
+ action.setHelpContextId(IAbstractTextEditorHelpContextIds.PRINT_ACTION);
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.PRINT);
+ setAction(ITextEditorActionConstants.PRINT, action);
+
+ action= new FindReplaceAction(EditorMessages.getResourceBundle(), "Editor.FindReplace.", this); //$NON-NLS-1$
+ action.setHelpContextId(IAbstractTextEditorHelpContextIds.FIND_ACTION);
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.FIND_REPLACE);
+ setAction(ITextEditorActionConstants.FIND, action);
+
+ action= new FindNextAction(EditorMessages.getResourceBundle(), "Editor.FindNext.", this, true); //$NON-NLS-1$
+ action.setHelpContextId(IAbstractTextEditorHelpContextIds.FIND_NEXT_ACTION);
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.FIND_NEXT);
+ setAction(ITextEditorActionConstants.FIND_NEXT, action);
+
+ action= new FindNextAction(EditorMessages.getResourceBundle(), "Editor.FindPrevious.", this, false); //$NON-NLS-1$
+ action.setHelpContextId(IAbstractTextEditorHelpContextIds.FIND_PREVIOUS_ACTION);
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.FIND_PREVIOUS);
+ setAction(ITextEditorActionConstants.FIND_PREVIOUS, action);
+
+ action= new IncrementalFindAction(EditorMessages.getResourceBundle(), "Editor.FindIncremental.", this); //$NON-NLS-1$
+ action.setHelpContextId(IAbstractTextEditorHelpContextIds.FIND_INCREMENTAL_ACTION);
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.FIND_INCREMENTAL);
+ setAction(ITextEditorActionConstants.FIND_INCREMENTAL, action);
+
+ action= new AddMarkerAction(EditorMessages.getResourceBundle(), "Editor.AddBookmark.", this, IMarker.BOOKMARK, true); //$NON-NLS-1$
+ action.setHelpContextId(IAbstractTextEditorHelpContextIds.BOOKMARK_ACTION);
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.ADD_BOOKMARK);
+ setAction(ITextEditorActionConstants.BOOKMARK, action);
+
+// FIXME: need another way to contribute this action
+// action= new AddTaskAction(EditorMessages.getResourceBundle(), "Editor.AddTask.", this); //$NON-NLS-1$
+// action.setHelpContextId(IAbstractTextEditorHelpContextIds.ADD_TASK_ACTION);
+// action.setActionDefinitionId(ITextEditorActionDefinitionIds.ADD_TASK);
+// setAction(ITextEditorActionConstants.ADD_TASK, action);
+
+ action= new SaveAction(EditorMessages.getResourceBundle(), "Editor.Save.", this); //$NON-NLS-1$
+ action.setHelpContextId(IAbstractTextEditorHelpContextIds.SAVE_ACTION);
+ // action.setActionDefinitionId(ITextEditorActionDefinitionIds.SAVE);
+ setAction(ITextEditorActionConstants.SAVE, action);
+
+ action= new RevertToSavedAction(EditorMessages.getResourceBundle(), "Editor.Revert.", this); //$NON-NLS-1$
+ action.setHelpContextId(IAbstractTextEditorHelpContextIds.REVERT_TO_SAVED_ACTION);
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.REVERT_TO_SAVED);
+ setAction(ITextEditorActionConstants.REVERT_TO_SAVED, action);
+
+ action= new GotoLineAction(EditorMessages.getResourceBundle(), "Editor.GotoLine.", this); //$NON-NLS-1$
+ action.setHelpContextId(IAbstractTextEditorHelpContextIds.GOTO_LINE_ACTION);
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.LINE_GOTO);
+ setAction(ITextEditorActionConstants.GOTO_LINE, action);
+
+ markAsContentDependentAction(ITextEditorActionConstants.UNDO, true);
+ markAsContentDependentAction(ITextEditorActionConstants.REDO, true);
+ markAsContentDependentAction(ITextEditorActionConstants.FIND, true);
+ markAsContentDependentAction(ITextEditorActionConstants.FIND_NEXT, true);
+ markAsContentDependentAction(ITextEditorActionConstants.FIND_PREVIOUS, true);
+ markAsContentDependentAction(ITextEditorActionConstants.FIND_INCREMENTAL, true);
+
+ markAsSelectionDependentAction(ITextEditorActionConstants.CUT, true);
+ markAsSelectionDependentAction(ITextEditorActionConstants.COPY, true);
+ markAsSelectionDependentAction(ITextEditorActionConstants.PASTE, true);
+ markAsSelectionDependentAction(ITextEditorActionConstants.DELETE, true);
+ markAsSelectionDependentAction(ITextEditorActionConstants.SHIFT_RIGHT, true);
+ markAsSelectionDependentAction(ITextEditorActionConstants.SHIFT_LEFT, true);
+
+ markAsPropertyDependentAction(ITextEditorActionConstants.REVERT_TO_SAVED, true);
+
+ markAsStateDependentAction(ITextEditorActionConstants.UNDO, true);
+ markAsStateDependentAction(ITextEditorActionConstants.REDO, true);
+ markAsStateDependentAction(ITextEditorActionConstants.CUT, true);
+ markAsStateDependentAction(ITextEditorActionConstants.PASTE, true);
+ markAsStateDependentAction(ITextEditorActionConstants.DELETE, true);
+ markAsStateDependentAction(ITextEditorActionConstants.SHIFT_RIGHT, true);
+ markAsStateDependentAction(ITextEditorActionConstants.SHIFT_LEFT, true);
+ markAsStateDependentAction(ITextEditorActionConstants.FIND, true);
+ markAsStateDependentAction(ITextEditorActionConstants.DELETE_LINE, true);
+ markAsStateDependentAction(ITextEditorActionConstants.DELETE_LINE_TO_BEGINNING, true);
+ markAsStateDependentAction(ITextEditorActionConstants.DELETE_LINE_TO_END, true);
+
+ setActionActivationCode(ITextEditorActionConstants.SHIFT_RIGHT,'\t', -1, SWT.NONE);
+ setActionActivationCode(ITextEditorActionConstants.SHIFT_LEFT, '\t', -1, SWT.SHIFT);
+ }
+
+ /**
+ * Convenience method to add the action installed under the given action id to the given menu.
+ * @param menu the menu to add the action to
+ * @param actionId the id of the action to be added
+ */
+ protected final void addAction(IMenuManager menu, String actionId) {
+ IAction action= getAction(actionId);
+ if (action != null) {
+ if (action instanceof IUpdate)
+ ((IUpdate) action).update();
+ menu.add(action);
+ }
+ }
+
+ /**
+ * Convenience method to add the action installed under the given action id to the specified group of the menu.
+ * @param menu the menu to add the action to
+ * @param group the group in the menu
+ * @param actionId the id of the action to add
+ */
+ protected final void addAction(IMenuManager menu, String group, String actionId) {
+ IAction action= getAction(actionId);
+ if (action != null) {
+ if (action instanceof IUpdate)
+ ((IUpdate) action).update();
+
+ IMenuManager subMenu= menu.findMenuUsingPath(group);
+ if (subMenu != null)
+ subMenu.add(action);
+ else
+ menu.appendToGroup(group, action);
+ }
+ }
+
+ /**
+ * Convenience method to add a new group after the specified group.
+ * @param menu the menu to add the new group to
+ * @param existingGroup the group after which to insert the new group
+ * @param newGroup the new group
+ */
+ protected final void addGroup(IMenuManager menu, String existingGroup, String newGroup) {
+ IMenuManager subMenu= menu.findMenuUsingPath(existingGroup);
+ if (subMenu != null)
+ subMenu.add(new Separator(newGroup));
+ else
+ menu.appendToGroup(existingGroup, new Separator(newGroup));
+ }
+
+ /**
+ * Sets up the ruler context menu before it is made visible.
+ * <p>
+ * Subclasses may extend to add other actions.
+ * </p>
+ *
+ * @param menu the menu
+ */
+ protected void rulerContextMenuAboutToShow(IMenuManager menu) {
+
+ for (Iterator i = fRulerContextMenuListeners.iterator(); i.hasNext();)
+ ((IMenuListener) i.next()).menuAboutToShow(menu);
+
+ addAction(menu, ITextEditorActionConstants.RULER_MANAGE_BOOKMARKS);
+ addAction(menu, ITextEditorActionConstants.RULER_MANAGE_TASKS);
+
+ menu.add(new Separator(ITextEditorActionConstants.GROUP_REST));
+ menu.add(new Separator(ITextEditorActionConstants.MB_ADDITIONS));
+ }
+
+ /**
+ * Sets up this editor's context menu before it is made visible.
+ * <p>
+ * Subclasses may extend to add other actions.
+ * </p>
+ *
+ * @param menu the menu
+ */
+ protected void editorContextMenuAboutToShow(IMenuManager menu) {
+
+ menu.add(new Separator(ITextEditorActionConstants.GROUP_UNDO));
+ menu.add(new Separator(ITextEditorActionConstants.GROUP_COPY));
+ menu.add(new Separator(ITextEditorActionConstants.GROUP_PRINT));
+ menu.add(new Separator(ITextEditorActionConstants.GROUP_EDIT));
+ menu.add(new Separator(ITextEditorActionConstants.GROUP_FIND));
+ menu.add(new Separator(ITextEditorActionConstants.GROUP_ADD));
+ menu.add(new Separator(ITextEditorActionConstants.GROUP_REST));
+ menu.add(new Separator(ITextEditorActionConstants.MB_ADDITIONS));
+ menu.add(new Separator(ITextEditorActionConstants.GROUP_SAVE));
+
+ if (isEditable()) {
+ addAction(menu, ITextEditorActionConstants.GROUP_UNDO, ITextEditorActionConstants.UNDO);
+ addAction(menu, ITextEditorActionConstants.GROUP_UNDO, ITextEditorActionConstants.REVERT_TO_SAVED);
+ addAction(menu, ITextEditorActionConstants.GROUP_COPY, ITextEditorActionConstants.CUT);
+ addAction(menu, ITextEditorActionConstants.GROUP_COPY, ITextEditorActionConstants.COPY);
+ addAction(menu, ITextEditorActionConstants.GROUP_COPY, ITextEditorActionConstants.PASTE);
+ addAction(menu, ITextEditorActionConstants.GROUP_SAVE, ITextEditorActionConstants.SAVE);
+ } else {
+ addAction(menu, ITextEditorActionConstants.GROUP_COPY, ITextEditorActionConstants.COPY);
+ }
+ }
+
+ /**
+ * Returns the status line manager of this editor.
+ * @return the status line manager of this editor
+ * @since 2.0
+ */
+ private IStatusLineManager getStatusLineManager() {
+
+ IEditorActionBarContributor contributor= getEditorSite().getActionBarContributor();
+ if (!(contributor instanceof EditorActionBarContributor))
+ return null;
+
+ IActionBars actionBars= ((EditorActionBarContributor) contributor).getActionBars();
+ if (actionBars == null)
+ return null;
+
+ return actionBars.getStatusLineManager();
+ }
+
+ /*
+ * @see IAdaptable#getAdapter(Class)
+ */
+ public Object getAdapter(Class required) {
+
+ if (IEditorStatusLine.class.equals(required)) {
+ if (fEditorStatusLine == null) {
+ IStatusLineManager statusLineManager= getStatusLineManager();
+ ISelectionProvider selectionProvider= getSelectionProvider();
+ if (statusLineManager != null && selectionProvider != null)
+ fEditorStatusLine= new EditorStatusLine(statusLineManager, selectionProvider);
+ }
+ return fEditorStatusLine;
+ }
+
+ if (IVerticalRulerInfo.class.equals(required)) {
+ if (fVerticalRuler instanceof IVerticalRulerInfo)
+ return fVerticalRuler;
+ }
+
+ if (IMarkRegionTarget.class.equals(required)) {
+ if (fMarkRegionTarget == null) {
+ IStatusLineManager manager= getStatusLineManager();
+ if (manager != null)
+ fMarkRegionTarget= (fSourceViewer == null ? null : new MarkRegionTarget(fSourceViewer, manager));
+ }
+ return fMarkRegionTarget;
+ }
+
+ if (IncrementalFindTarget.class.equals(required)) {
+ if (fIncrementalFindTarget == null) {
+ IStatusLineManager manager= getStatusLineManager();
+ if (manager != null)
+ fIncrementalFindTarget= (fSourceViewer == null ? null : new IncrementalFindTarget(fSourceViewer, manager));
+ }
+ return fIncrementalFindTarget;
+ }
+
+ if (IFindReplaceTarget.class.equals(required)) {
+ IFindReplaceTarget target= (fSourceViewer == null ? null : fSourceViewer.getFindReplaceTarget());
+ if (target != null && target instanceof IFindReplaceTargetExtension)
+ ((IFindReplaceTargetExtension) target).setScopeHighlightColor(fFindScopeHighlightColor);
+ return target;
+ }
+
+ if (ITextOperationTarget.class.equals(required))
+ return (fSourceViewer == null ? null : fSourceViewer.getTextOperationTarget());
+
+ if (IRewriteTarget.class.equals(required)) {
+ if (fSourceViewer instanceof ITextViewerExtension) {
+ ITextViewerExtension extension= (ITextViewerExtension) fSourceViewer;
+ return extension.getRewriteTarget();
+ }
+ return null;
+ }
+
+ return super.getAdapter(required);
+ }
+
+ /*
+ * @see IDesktopPart#setFocus()
+ */
+ public void setFocus() {
+ if (fSourceViewer != null && fSourceViewer.getTextWidget() != null)
+ fSourceViewer.getTextWidget().setFocus();
+ }
+
+ /**
+ * If the editor can be saved all marker ranges have been changed according to
+ * the text manipulations. However, those changes are not yet propagated to the
+ * marker manager. Thus, when opening a marker, the marker's position in the editor
+ * must be determined as it might differ from the position stated in the marker.
+ * @param marker the marker to go to
+ * @see EditorPart#gotoMarker
+ */
+ public void gotoMarker(IMarker marker) {
+
+ if (fSourceViewer == null)
+ return;
+
+ int start= MarkerUtilities.getCharStart(marker);
+ int end= MarkerUtilities.getCharEnd(marker);
+
+ if (start < 0 || end < 0) {
+
+ // there is only a line number
+ int line= MarkerUtilities.getLineNumber(marker);
+ if (line > -1) {
+
+ // marker line numbers are 1-based
+ -- line;
+
+ try {
+
+ IDocument document= getDocumentProvider().getDocument(getEditorInput());
+ selectAndReveal(document.getLineOffset(line), document.getLineLength(line));
+
+ } catch (BadLocationException x) {
+ // marker refers to invalid text position -> do nothing
+ }
+ }
+
+ } else {
+
+ // look up the current range of the marker when the document has been edited
+ IAnnotationModel model= getDocumentProvider().getAnnotationModel(getEditorInput());
+ if (model instanceof AbstractMarkerAnnotationModel) {
+
+ AbstractMarkerAnnotationModel markerModel= (AbstractMarkerAnnotationModel) model;
+ Position pos= markerModel.getMarkerPosition(marker);
+ if (pos == null || pos.isDeleted()) {
+ // do nothing if position has been deleted
+ return;
+ }
+
+ start= pos.getOffset();
+ end= pos.getOffset() + pos.getLength();
+ }
+
+ IDocument document= getDocumentProvider().getDocument(getEditorInput());
+ int length= document.getLength();
+ if (end - 1 < length && start < length)
+ selectAndReveal(start, end - start);
+ }
+ }
+
+ /*
+ * @see ITextEditor#showsHighlightRangeOnly
+ */
+ public boolean showsHighlightRangeOnly() {
+ return fShowHighlightRangeOnly;
+ }
+
+ /*
+ * @see ITextEditor#showHighlightRangeOnly
+ */
+ public void showHighlightRangeOnly(boolean showHighlightRangeOnly) {
+ fShowHighlightRangeOnly= showHighlightRangeOnly;
+ }
+
+ /*
+ * @see ITextEditor#setHighlightRange
+ */
+ public void setHighlightRange(int start, int length, boolean moveCursor) {
+ if (fSourceViewer == null)
+ return;
+
+ if (fShowHighlightRangeOnly) {
+ if (moveCursor) {
+ IRegion visibleRegion= fSourceViewer.getVisibleRegion();
+ if (start != visibleRegion.getOffset() || length != visibleRegion.getLength())
+ fSourceViewer.setVisibleRegion(start, length);
+ }
+ } else {
+ IRegion rangeIndication= fSourceViewer.getRangeIndication();
+ if (rangeIndication == null || start != rangeIndication.getOffset() || length != rangeIndication.getLength())
+ fSourceViewer.setRangeIndication(start, length, moveCursor);
+ }
+ }
+
+ /*
+ * @see ITextEditor#getHighlightRange
+ */
+ public IRegion getHighlightRange() {
+ if (fSourceViewer == null)
+ return null;
+
+ if (fShowHighlightRangeOnly)
+ return fSourceViewer.getVisibleRegion();
+
+ return fSourceViewer.getRangeIndication();
+ }
+
+ /*
+ * @see ITextEditor#resetHighlightRange
+ */
+ public void resetHighlightRange() {
+ if (fSourceViewer == null)
+ return;
+
+ if (fShowHighlightRangeOnly)
+ fSourceViewer.resetVisibleRegion();
+ else
+ fSourceViewer.removeRangeIndication();
+ }
+
+ /**
+ * Adjusts the highlight range so that at least the specified range
+ * is highlighted. <p>
+ * Subclasses may re-implement this method.
+ *
+ * @param offset the offset of the range which at least should be highlighted
+ * @param length the length of the range which at least should be highlighted
+ */
+ protected void adjustHighlightRange(int offset, int length) {
+ if (fSourceViewer == null)
+ return;
+
+ if (!fSourceViewer.overlapsWithVisibleRegion(offset, length))
+ fSourceViewer.resetVisibleRegion();
+ }
+
+ /*
+ * @see ITextEditor#selectAndReveal
+ */
+ public void selectAndReveal(int start, int length) {
+ if (fSourceViewer == null)
+ return;
+
+ ISelection selection= getSelectionProvider().getSelection();
+ if (selection instanceof TextSelection) {
+ TextSelection textSelection= (TextSelection) selection;
+ if (textSelection.getOffset() != 0 || textSelection.getLength() != 0)
+ markInNavigationHistory();
+ }
+
+ StyledText widget= fSourceViewer.getTextWidget();
+ widget.setRedraw(false);
+ {
+ adjustHighlightRange(start, length);
+
+ fSourceViewer.revealRange(start, length);
+ fSourceViewer.setSelectedRange(start, length);
+
+ markInNavigationHistory();
+ }
+ widget.setRedraw(true);
+ }
+
+ /*
+ * @see org.eclipse.ui.INavigationLocationProvider#createNavigationLocation()
+ * 2.1 - WORK_IN_PROGRESS do not use.
+ */
+ public NavigationLocation createNavigationLocation() {
+ return new TextSelectionNavigationLocation(this);
+ }
+
+ /**
+ * Writes a check mark of the given situation into the navigation history.
+ * 2.1 - WORK_IN_PROGRESS do not use.
+ */
+ protected void markInNavigationHistory() {
+ IWorkbenchPage page= getEditorSite().getPage();
+ page.addNavigationHistoryEntry(this, createNavigationLocation());
+ }
+
+ /**
+ * Subclasses may extend.
+ * 2.1 - WORK_IN_PROGRESS do not use.
+ */
+ protected void editorSaved() {
+ IWorkbenchPage page= getEditorSite().getPage();
+ NavigationLocation[] locations= page.getNavigationHistoryEntries(getEditorInput());
+ for (int i= 0; i < locations.length; i++) {
+ if (locations[i] instanceof TextSelectionNavigationLocation) {
+ TextSelectionNavigationLocation location= (TextSelectionNavigationLocation) locations[i];
+ location.partSaved(this);
+ }
+ }
+ }
+
+ /*
+ * @see EditorPart#firePropertyChange
+ */
+ protected void firePropertyChange(int property) {
+ super.firePropertyChange(property);
+ updatePropertyDependentActions();
+ }
+
+ /*
+ * @see ITextEditorExtension#setStatusField(IStatusField, String)
+ * @since 2.0
+ */
+ public void setStatusField(IStatusField field, String category) {
+ Assert.isNotNull(category);
+ if (field != null) {
+
+ if (fStatusFields == null)
+ fStatusFields= new HashMap(3);
+
+ fStatusFields.put(category, field);
+ updateStatusField(category);
+
+ } else if (fStatusFields != null)
+ fStatusFields.remove(category);
+ }
+
+ /**
+ * Returns the current status field for the given status category.
+ *
+ * @param category the status category
+ * @return the current status field for the given status category.
+ * @since 2.0
+ */
+ protected IStatusField getStatusField(String category) {
+ if (category != null && fStatusFields != null)
+ return (IStatusField) fStatusFields.get(category);
+ return null;
+ }
+
+ /**
+ * Returns whether this editor is in overwrite or insert mode.
+ *
+ * @return <code>true</code> if in insert mode, <code>false</code> for overwrite mode
+ * @since 2.0
+ */
+ protected boolean isInInsertMode() {
+ return !fOverwriting;
+ }
+
+ /**
+ * Handles a potential change of the cursor position. Subclasses may extend.
+ * @since 2.0
+ */
+ protected void handleCursorPositionChanged() {
+ updateStatusField(ITextEditorActionConstants.STATUS_CATEGORY_INPUT_POSITION);
+ }
+
+ /**
+ * Handles a change of the editor's insert mode. Subclasses may extend.
+ * @since 2.0
+ */
+ protected void handleInsertModeChanged() {
+ updateStatusField(ITextEditorActionConstants.STATUS_CATEGORY_INPUT_MODE);
+ }
+
+ /**
+ * Updates the status fields for the given category.
+ * @param category
+ * @since 2.0
+ */
+ protected void updateStatusField(String category) {
+
+ if (category == null)
+ return;
+
+ IStatusField field= getStatusField(category);
+ if (field != null) {
+
+ String text= null;
+
+ if (ITextEditorActionConstants.STATUS_CATEGORY_INPUT_POSITION.equals(category))
+ text= getCursorPosition();
+ else if (ITextEditorActionConstants.STATUS_CATEGORY_ELEMENT_STATE.equals(category))
+ text= isEditorInputReadOnly() ? fReadOnlyLabel : fWritableLabel;
+ else if (ITextEditorActionConstants.STATUS_CATEGORY_INPUT_MODE.equals(category))
+ text= isInInsertMode() ? fInsertModeLabel : fOverwriteModeLabel;
+
+ field.setText(text == null ? fErrorLabel : text);
+ }
+ }
+
+ /**
+ * Updates all status fields.
+ * @since 2.0
+ */
+ protected void updateStatusFields() {
+ if (fStatusFields != null) {
+ Iterator e= fStatusFields.keySet().iterator();
+ while (e.hasNext())
+ updateStatusField((String) e.next());
+ }
+ }
+
+ /**
+ * Returns a description of the cursor position.
+ * @return a description of the cursor position
+ * @since 2.0
+ */
+ protected String getCursorPosition() {
+
+ if (fSourceViewer == null)
+ return fErrorLabel;
+
+ StyledText styledText= fSourceViewer.getTextWidget();
+
+ int offset= fSourceViewer.getVisibleRegion().getOffset();
+ int caret= offset + styledText.getCaretOffset();
+ IDocument document= fSourceViewer.getDocument();
+
+ if (document == null)
+ return fErrorLabel;
+
+ try {
+
+ int line= document.getLineOfOffset(caret);
+
+ int lineOffset= document.getLineOffset(line);
+ int tabWidth= styledText.getTabs();
+ int column= 0;
+ for (int i= lineOffset; i < caret; i++)
+ if ('\t' == document.getChar(i))
+ column += tabWidth - (column % tabWidth);
+ else
+ column++;
+
+ fLineLabel.fValue= line + 1;
+ fColumnLabel.fValue= column + 1;
+ return MessageFormat.format(fPositionLabelPattern, fPositionLabelPatternArguments);
+
+ } catch (BadLocationException x) {
+ return fErrorLabel;
+ }
+ }
+
+ /*
+ * @see ITextEditorExtension#isEditorInputReadOnly()
+ * @since 2.0
+ */
+ public boolean isEditorInputReadOnly() {
+ IDocumentProvider provider= getDocumentProvider();
+ if (provider instanceof IDocumentProviderExtension) {
+ IDocumentProviderExtension extension= (IDocumentProviderExtension) provider;
+ return extension.isReadOnly(getEditorInput());
+ }
+ return true;
+ }
+
+ /*
+ * @see ITextEditorExtension#addRulerContextMenuListener(IMenuListener)
+ * @since 2.0
+ */
+ public void addRulerContextMenuListener(IMenuListener listener) {
+ fRulerContextMenuListeners.add(listener);
+ }
+
+ /*
+ * @see ITextEditorExtension#removeRulerContextMenuListener(IMenuListener)
+ * @since 2.0
+ */
+ public void removeRulerContextMenuListener(IMenuListener listener) {
+ fRulerContextMenuListeners.remove(listener);
+ }
+
+ /**
+ * Returns wether this editor can handle the move of the original element
+ * so that it ends up being the moved element. By default this method returns
+ * <code>true</code>. Subclasses may reimplement.
+ * @param originalElement the original element
+ * @param movedElement the moved element
+ * @since 2.0
+ */
+ protected boolean canHandleMove(IEditorInput originalElement, IEditorInput movedElement) {
+ return true;
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AddMarkerAction.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AddMarkerAction.java
new file mode 100644
index 000000000..b01473659
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AddMarkerAction.java
@@ -0,0 +1,279 @@
+package org.eclipse.ui.texteditor;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+
+import java.util.HashMap; import java.util.Map; import java.util.ResourceBundle; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.Platform; import org.eclipse.swt.widgets.Shell; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.dialogs.IInputValidator;
+import org.eclipse.jface.dialogs.InputDialog; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.window.Window; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.PlatformUI;
+
+
+
+/**
+ * Action for creating a marker of a specified type for the editor's
+ * input element based on the editor's selection. If required, the
+ * action asks the user to provide a marker label. The action is initially
+ * associated with a text editor via the constructor, but that can be
+ * subsequently changed using <code>setEditor</code>.
+ * <p>
+ * The following keys, prepended by the given option prefix,
+ * are used for retrieving resources from the given bundle:
+ * <ul>
+ * <li><code>"dialog.title"</code> - the input dialog's title</li>
+ * <li><code>"dialog.message"</code> - the input dialog's message</li>
+ * <li><code>"error.dialog.title"</code> - the error dialog's title</li>
+ * <li><code>"error.dialog.message"</code> - the error dialog's message</li>
+ * </ul>
+ * This class may be instantiated but is not intended for subclassing.
+ * </p>
+ */
+public class AddMarkerAction extends TextEditorAction {
+
+
+ /** The type for newly created markers */
+ private String fMarkerType;
+ /** Should the user be asked for a label? */
+ private boolean fAskForLabel;
+ /** The action's resource bundle */
+ private ResourceBundle fBundle;
+ /** The prefix used for resource bundle lookup */
+ private String fPrefix;
+
+
+ /**
+ * Creates a new action for the given text editor. The action configures its
+ * visual representation from the given resource bundle.
+ *
+ * @param bundle the resource bundle
+ * @param prefix a prefix to be prepended to the various resource keys
+ * (described in <code>ResourceAction</code> constructor), or
+ * <code>null</code> if none
+ * @param editor the text editor
+ * @param markerType the type of marker to add
+ * @param askForLabel <code>true</code> if the user should be asked for
+ * a label for the new marker
+ * @see ResourceAction#ResourceAction
+ */
+ public AddMarkerAction(ResourceBundle bundle, String prefix, ITextEditor textEditor, String markerType, boolean askForLabel) {
+ super(bundle, prefix, textEditor);
+ fBundle= bundle;
+ fPrefix= prefix;
+ fMarkerType= markerType;
+ fAskForLabel= askForLabel;
+ }
+
+ /**
+ * Returns this action's resource bundle.
+ *
+ * @return this action's resource bundle
+ */
+ protected ResourceBundle getResourceBundle() {
+ return fBundle;
+ }
+
+ /**
+ * Returns this action's resource key prefix.
+ *
+ * @return this action's resource key prefix
+ */
+ protected String getResourceKeyPrefix() {
+ return fPrefix;
+ }
+
+ /*
+ * @see IAction#run()
+ */
+ public void run() {
+ IResource resource= getResource();
+ if (resource == null)
+ return;
+ Map attributes= getInitialAttributes();
+ if (fAskForLabel) {
+ if (!askForLabel(attributes))
+ return;
+ }
+
+ try {
+ MarkerUtilities.createMarker(resource, attributes, fMarkerType);
+ } catch (CoreException x) {
+
+ Platform.getPlugin(PlatformUI.PLUGIN_ID).getLog().log(x.getStatus());
+
+ Shell shell= getTextEditor().getSite().getShell();
+ String title= getString(fBundle, fPrefix + "error.dialog.title", fPrefix + "error.dialog.title"); //$NON-NLS-2$ //$NON-NLS-1$
+ String msg= getString(fBundle, fPrefix + "error.dialog.message", fPrefix + "error.dialog.message"); //$NON-NLS-2$ //$NON-NLS-1$
+
+ ErrorDialog.openError(shell, title, msg, x.getStatus());
+ }
+ }
+
+ /*
+ * @see TextEditorAction#update()
+ */
+ public void update() {
+ setEnabled(getResource() != null);
+ }
+
+ /**
+ * Asks the user for a marker label. Returns <code>true</code> if a label
+ * is entered, <code>false</code> if the user cancels the input dialog.
+ * The value for the attribute <code>message</code> is modified in the given
+ * attribute map.
+ *
+ * @param attributes the attributes map
+ * @return <code>true</code> if a label has been entered
+ */
+ protected boolean askForLabel(Map attributes) {
+
+ Object o= attributes.get("message"); //$NON-NLS-1$
+ String proposal= (o instanceof String) ? (String) o : ""; //$NON-NLS-1$
+ if (proposal == null)
+ proposal= ""; //$NON-NLS-1$
+
+ String title= getString(fBundle, fPrefix + "dialog.title", fPrefix + "dialog.title"); //$NON-NLS-2$ //$NON-NLS-1$
+ String message= getString(fBundle, fPrefix + "dialog.message", fPrefix + "dialog.message"); //$NON-NLS-2$ //$NON-NLS-1$
+ IInputValidator inputValidator = new IInputValidator() {
+ public String isValid(String newText) {
+ return (newText == null || newText.length() == 0) ? " " : null; //$NON-NLS-1$
+ }
+ };
+ InputDialog dialog= new InputDialog(getTextEditor().getSite().getShell(), title, message, proposal, inputValidator);
+
+ String label= null;
+ if (dialog.open() != Window.CANCEL)
+ label= dialog.getValue();
+
+ if (label == null)
+ return false;
+
+ label= label.trim();
+ if (label.length() == 0)
+ return false;
+
+ attributes.put("message", label); //$NON-NLS-1$
+ return true;
+ }
+
+ /**
+ * Returns the attributes the new marker will be initialized with.
+ * Subclasses may extend or replace this method.
+ *
+ * @return the attributes the new marker will be initialized with
+ */
+ protected Map getInitialAttributes() {
+
+ Map attributes= new HashMap(11);
+
+ ITextSelection selection= (ITextSelection) getTextEditor().getSelectionProvider().getSelection();
+ if (!selection.isEmpty()) {
+
+ int start= selection.getOffset();
+ int length= selection.getLength();
+
+ if (length < 0) {
+ length= -length;
+ start -= length;
+ }
+
+ MarkerUtilities.setCharStart(attributes, start);
+ MarkerUtilities.setCharEnd(attributes, start + length);
+
+ // marker line numbers are 1-based
+ int line= selection.getStartLine();
+ MarkerUtilities.setLineNumber(attributes, line == -1 ? -1 : line + 1);
+
+ IDocument document= getTextEditor().getDocumentProvider().getDocument(getTextEditor().getEditorInput());
+ MarkerUtilities.setMessage(attributes, getLabelProposal(document, start, length));
+
+ }
+
+ return attributes;
+ }
+
+ /**
+ * Returns the initial label for the marker.
+ *
+ * @param document the document from which to extract a label proposal
+ * @param offset the document offset of the range from which to extract the label proposal
+ * @param length the length of the range from which to extract the label proposal
+ * @return the label proposal
+ */
+ protected String getLabelProposal(IDocument document, int offset, int length) {
+
+
+ try {
+
+
+ if (length > 0)
+ return document.get(offset, length);
+
+
+ char ch;
+
+ // Get the first white char before the selection.
+ int left= offset;
+
+ int line= document.getLineOfOffset(offset);
+ int limit= document.getLineOffset(line);
+
+ while (left > limit) {
+ ch= document.getChar(left);
+ if (Character.isWhitespace(ch))
+ break;
+ --left;
+ }
+
+ limit += document.getLineLength(line);
+
+ // Now get the first letter.
+ while (left <= limit) {
+ ch= document.getChar(left);
+ if (!Character.isWhitespace(ch))
+ break;
+ ++left;
+ }
+
+ if (left > limit)
+ return null;
+
+ // Get the next white char.
+ int right= (offset + length > limit ? limit : offset + length);
+ while (right < limit) {
+ ch= document.getChar(right);
+ if (Character.isWhitespace(ch))
+ break;
+ ++right;
+ }
+
+ // Trim the string and return it.
+ if (left != right) {
+ String label= document.get(left, right - left);
+ return label.trim();
+ }
+
+ } catch (BadLocationException x) {
+ // don't proposal label then
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the resource on which to create the marker,
+ * or <code>null</code> if there is no applicable resource. This
+ * queries the editor's input using <code>getAdapter(IResource.class)</code>.
+ * Subclasses may override this method.
+ *
+ * @return the resource to which to attach the newly created marker
+ */
+ protected IResource getResource() {
+ ITextEditor editor= getTextEditor();
+ if (editor != null) {
+ IEditorInput input= editor.getEditorInput();
+ return (IResource) ((IAdaptable) input).getAdapter(IResource.class);
+ }
+ return null;
+ }
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/BasicMarkerUpdater.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/BasicMarkerUpdater.java
new file mode 100644
index 000000000..a21e707f4
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/BasicMarkerUpdater.java
@@ -0,0 +1,92 @@
+package org.eclipse.ui.texteditor;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.Position;
+
+import org.eclipse.core.resources.IMarker;
+
+
+/**
+ * Updates a marker's positional attributes which are
+ * start position, end position, and line number.
+ */
+public final class BasicMarkerUpdater implements IMarkerUpdater {
+
+ private final static String[] ATTRIBUTES= {
+ IMarker.CHAR_START,
+ IMarker.CHAR_END,
+ IMarker.LINE_NUMBER
+ };
+
+ /**
+ * Creates a new basic marker updater.
+ */
+ public BasicMarkerUpdater() {
+ super();
+ }
+
+ /*
+ * @see IMarkerUpdater#getAttribute()
+ */
+ public String[] getAttribute() {
+ return ATTRIBUTES;
+ }
+
+ /*
+ * @see IMarkerUpdater#getMarkerType()
+ */
+ public String getMarkerType() {
+ return null;
+ }
+
+ /*
+ * @see IMarkerUpdater#updateMarker(IMarker, IDocument, Position)
+ */
+ public boolean updateMarker(IMarker marker, IDocument document, Position position) {
+
+ if (position == null)
+ return true;
+
+ if (position.isDeleted())
+ return false;
+
+ boolean offsetsInitialized= false;
+ boolean offsetsChanged= false;
+ int markerStart= MarkerUtilities.getCharStart(marker);
+ int markerEnd= MarkerUtilities.getCharEnd(marker);
+
+ if (markerStart != -1 && markerEnd != -1) {
+
+ offsetsInitialized= true;
+
+ int offset= position.getOffset();
+ if (markerStart != offset) {
+ MarkerUtilities.setCharStart(marker, offset);
+ offsetsChanged= true;
+ }
+
+ offset += position.getLength();
+ if (markerEnd != offset) {
+ MarkerUtilities.setCharEnd(marker, offset);
+ offsetsChanged= true;
+ }
+ }
+
+ if (!offsetsInitialized || (offsetsChanged && MarkerUtilities.getLineNumber(marker) != -1)) {
+ try {
+ // marker line numbers are 1-based
+ MarkerUtilities.setLineNumber(marker, document.getLineOfOffset(position.getOffset()) + 1);
+ } catch (BadLocationException x) {
+ }
+ }
+
+ return true;
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/BasicTextEditorActionContributor.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/BasicTextEditorActionContributor.java
new file mode 100644
index 000000000..a544ae147
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/BasicTextEditorActionContributor.java
@@ -0,0 +1,214 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ResourceBundle; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager;
+ import org.eclipse.jface.action.IStatusLineManager;
+
+import org.eclipse.ui.IActionBars; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.part.EditorActionBarContributor;
+
+
+
+/**
+ * Manages the installation and deinstallation of global actions for
+ * the same type of editors.
+ * <p>
+ * If instantiated and used as-is, this contributor connects to all of the workbench defined
+ * global editor actions the corresponding actions of the current editor. It also adds addition
+ * actions for searching and navigation (go to line) as well as a set of status fields.
+ * <p>
+ * Subclasses may override the following methods:
+ * <ul>
+ * <li><code>contributeToMenu</code> - extend to contribute to menu</li>
+ * <li><code>contributeToToolBar</code> - reimplement to contribute to toolbar</li>
+ * <li><code>contributeToStatusLine</code> - reimplement to contribute to status line</li>
+ * <li><code>setActiveEditor</code> - extend to react to editor changes</li>
+ * </ul>
+ * </p>
+ * #see ITextEditorActionConstants
+ */
+public class BasicTextEditorActionContributor extends EditorActionBarContributor {
+
+ /** The global actions to be connected with editor actions */
+ private final static String[] ACTIONS= {
+ ITextEditorActionConstants.UNDO,
+ ITextEditorActionConstants.REDO,
+ ITextEditorActionConstants.CUT,
+ ITextEditorActionConstants.COPY,
+ ITextEditorActionConstants.PASTE,
+ ITextEditorActionConstants.DELETE,
+ ITextEditorActionConstants.SELECT_ALL,
+ ITextEditorActionConstants.FIND,
+ ITextEditorActionConstants.BOOKMARK,
+ ITextEditorActionConstants.ADD_TASK,
+ ITextEditorActionConstants.PRINT,
+ ITextEditorActionConstants.REVERT
+ };
+
+ /**
+ * The status fields to be set to the editor
+ * @since 2.0
+ */
+ private final static String[] STATUSFIELDS= {
+ ITextEditorActionConstants.STATUS_CATEGORY_ELEMENT_STATE,
+ ITextEditorActionConstants.STATUS_CATEGORY_INPUT_MODE,
+ ITextEditorActionConstants.STATUS_CATEGORY_INPUT_POSITION
+ };
+
+ /** The active editor part */
+ private IEditorPart fActiveEditorPart;
+ /**
+ * The find next action
+ * @since 2.0
+ */
+ private RetargetTextEditorAction fFindNext;
+ /**
+ * The find previous action
+ * @since 2.0
+ */
+ private RetargetTextEditorAction fFindPrevious;
+ /**
+ * The incremental find action
+ * @since 2.0
+ */
+ private RetargetTextEditorAction fIncrementalFind;
+ /** The go to line action */
+ private RetargetTextEditorAction fGotoLine;
+ /**
+ * The map of status fields
+ * @since 2.0
+ */
+ private Map fStatusFields;
+
+
+ /**
+ * Creates an empty editor action bar contributor. The action bars are
+ * furnished later via the <code>init</code> method.
+ *
+ * @see org.eclipse.ui.IEditorActionBarContributor#init
+ */
+ public BasicTextEditorActionContributor() {
+
+ fFindNext= new RetargetTextEditorAction(EditorMessages.getResourceBundle(), "Editor.FindNext."); //$NON-NLS-1$
+ fFindPrevious= new RetargetTextEditorAction(EditorMessages.getResourceBundle(), "Editor.FindPrevious."); //$NON-NLS-1$
+ fIncrementalFind= new RetargetTextEditorAction(EditorMessages.getResourceBundle(), "Editor.FindIncremental."); //$NON-NLS-1$
+ fGotoLine= new RetargetTextEditorAction(EditorMessages.getResourceBundle(), "Editor.GotoLine."); //$NON-NLS-1$
+
+ fStatusFields= new HashMap(3);
+ for (int i= 0; i < STATUSFIELDS.length; i++)
+ fStatusFields.put(STATUSFIELDS[i], new StatusLineContributionItem(STATUSFIELDS[i]));
+ }
+
+ /**
+ * Returns the active editor part.
+ *
+ * @return the active editor part
+ */
+ protected final IEditorPart getActiveEditorPart() {
+ return fActiveEditorPart;
+ }
+
+ /**
+ * Returns the action registered with the given text editor.
+ *
+ * @param editor the editor, or <code>null</code>
+ * @param actionId the action id
+ * @return the action, or <code>null</code> if none
+ */
+ protected final IAction getAction(ITextEditor editor, String actionId) {
+ return (editor == null ? null : editor.getAction(actionId));
+ }
+
+ /**
+ * The method installs the global action handlers for the given text editor.
+ * This method cannot be overridden by subclasses.
+ * @since 2.0
+ */
+ private void doSetActiveEditor(IEditorPart part) {
+
+ if (fActiveEditorPart == part)
+ return;
+
+ if (fActiveEditorPart instanceof ITextEditorExtension) {
+ ITextEditorExtension extension= (ITextEditorExtension) fActiveEditorPart;
+ for (int i= 0; i < STATUSFIELDS.length; i++)
+ extension.setStatusField(null, STATUSFIELDS[i]);
+ }
+
+ fActiveEditorPart= part;
+ ITextEditor editor= (part instanceof ITextEditor) ? (ITextEditor) part : null;
+
+ IActionBars actionBars= getActionBars();
+ if (actionBars != null) {
+ for (int i= 0; i < ACTIONS.length; i++)
+ actionBars.setGlobalActionHandler(ACTIONS[i], getAction(editor, ACTIONS[i]));
+ }
+
+ fFindNext.setAction(getAction(editor, ITextEditorActionConstants.FIND_NEXT));
+ fFindPrevious.setAction(getAction(editor, ITextEditorActionConstants.FIND_PREVIOUS));
+ fIncrementalFind.setAction(getAction(editor, ITextEditorActionConstants.FIND_INCREMENTAL));
+ fGotoLine.setAction(getAction(editor, ITextEditorActionConstants.GOTO_LINE));
+
+ if (fActiveEditorPart instanceof ITextEditorExtension) {
+ ITextEditorExtension extension= (ITextEditorExtension) fActiveEditorPart;
+ for (int i= 0; i < STATUSFIELDS.length; i++)
+ extension.setStatusField((IStatusField) fStatusFields.get(STATUSFIELDS[i]), STATUSFIELDS[i]);
+ }
+ }
+
+ /**
+ * The <code>BasicTextEditorActionContributor</code> implementation of this
+ * <code>IEditorActionBarContributor</code> method installs the global
+ * action handler for the given text editor by calling a private helper
+ * method. Subclasses may extend.
+ */
+ public void setActiveEditor(IEditorPart part) {
+ doSetActiveEditor(part);
+ }
+
+ /*
+ * @see EditorActionBarContributor#contributeToMenu(IMenuManager)
+ */
+ public void contributeToMenu(IMenuManager menu) {
+
+ IMenuManager editMenu= menu.findMenuUsingPath(IWorkbenchActionConstants.M_EDIT);
+ if (editMenu != null) {
+ editMenu.appendToGroup(IWorkbenchActionConstants.FIND_EXT, fFindNext);
+ editMenu.appendToGroup(IWorkbenchActionConstants.FIND_EXT,fFindPrevious);
+ editMenu.appendToGroup(IWorkbenchActionConstants.FIND_EXT,fIncrementalFind);
+ editMenu.appendToGroup(IWorkbenchActionConstants.FIND_EXT,fGotoLine);
+ }
+ }
+
+ /*
+ * @see EditorActionBarContributor#contributeToStatusLine(IStatusLineManager)
+ * @since 2.0
+ */
+ public void contributeToStatusLine(IStatusLineManager statusLineManager) {
+ super.contributeToStatusLine(statusLineManager);
+ for (int i= 0; i < STATUSFIELDS.length; i++)
+ statusLineManager.add((IContributionItem) fStatusFields.get(STATUSFIELDS[i]));
+ }
+
+ /*
+ * @see IEditorActionBarContributor#dispose()
+ * @since 2.0
+ */
+ public void dispose() {
+ doSetActiveEditor(null);
+ super.dispose();
+ }
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/BookmarkRulerAction.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/BookmarkRulerAction.java
new file mode 100644
index 000000000..4444508b1
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/BookmarkRulerAction.java
@@ -0,0 +1,31 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v0.5
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v05.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.text.source.IVerticalRulerInfo;
+
+/**
+ * Adapter for the managing bookmark action.
+ * @since 2.0
+ */
+public class BookmarkRulerAction extends AbstractRulerActionDelegate {
+
+ /*
+ * @see AbstractRulerActionDelegate#createAction(ITextEditor, IVerticalRulerInfo)
+ */
+ protected IAction createAction(ITextEditor editor, IVerticalRulerInfo rulerInfo) {
+ return new MarkerRulerAction(EditorMessages.getResourceBundle(), "Editor.ManageBookmarks.", editor, rulerInfo, IMarker.BOOKMARK, true); //$NON-NLS-1$
+ }
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ContentAssistAction.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ContentAssistAction.java
new file mode 100644
index 000000000..b8d4e2101
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ContentAssistAction.java
@@ -0,0 +1,126 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+
+import java.util.ResourceBundle;
+
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+import org.eclipse.jface.text.ITextOperationTarget;
+import org.eclipse.jface.text.ITextOperationTargetExtension;
+import org.eclipse.jface.text.source.ISourceViewer;
+
+import org.eclipse.ui.IWorkbenchPartSite;
+
+
+/**
+ * A content asisst action which gets its target from its text editor.
+ * <p>
+ * The action is initially associated with a text editor via the constructor,
+ * but can subsequently be changed using <code>setEditor</code>.
+ * </p>
+ * <p>
+ * If this class is used as is, it works by asking the text editor for its text operation target
+ * (using <code>getAdapter(ITextOperationTarget.class)</code> and runs the content assist
+ * operation on this target.
+ * </p>
+ * @since 2.0
+ */
+public final class ContentAssistAction extends TextEditorAction {
+
+ /** The text operation target */
+ private ITextOperationTarget fOperationTarget;
+
+ /**
+ * Creates and initializes the action for the given text editor.
+ * The action configures its visual representation from the given resource
+ * bundle. The action works by asking the text editor at the time for its
+ * text operation target adapter (using
+ * <code>getAdapter(ITextOperationTarget.class)</code>. The action runs the
+ * content assist operation on this target.
+ *
+ * @param bundle the resource bundle
+ * @param prefix a prefix to be prepended to the various resource keys
+ * (described in <code>ResourceAction</code> constructor), or
+ * <code>null</code> if none
+ * @param editor the text editor
+ * @see ResourceAction#ResourceAction
+ */
+ public ContentAssistAction(ResourceBundle bundle, String prefix, ITextEditor editor) {
+ super(bundle, prefix, editor);
+ update();
+ }
+
+ /**
+ * Runs the content assist operation on the editor's text operation target.
+ */
+ public void run() {
+ if (fOperationTarget != null) {
+
+ ITextEditor editor= getTextEditor();
+ if (editor != null) {
+
+ Display display= null;
+
+ IWorkbenchPartSite site= editor.getSite();
+ Shell shell= site.getShell();
+ if (shell != null && !shell.isDisposed())
+ display= shell.getDisplay();
+
+ BusyIndicator.showWhile(display, new Runnable() {
+ public void run() {
+ fOperationTarget.doOperation(ISourceViewer.CONTENTASSIST_PROPOSALS);
+ }
+ });
+ }
+ }
+ }
+
+ /**
+ * The <code>ContentAssistAction</code> implementation of this
+ * <code>IUpdate</code> method discovers the operation through the current
+ * editor's <code>ITextOperationTarget</code> adapter, and sets the
+ * enabled state accordingly.
+ */
+ public void update() {
+
+ ITextEditor editor= getTextEditor();
+
+ if (fOperationTarget == null && editor!= null)
+ fOperationTarget= (ITextOperationTarget) editor.getAdapter(ITextOperationTarget.class);
+
+ if (fOperationTarget == null) {
+ setEnabled(false);
+ return;
+ }
+
+ if (editor instanceof ITextEditorExtension && fOperationTarget instanceof ITextOperationTargetExtension) {
+ ITextEditorExtension extension= (ITextEditorExtension) editor;
+ ITextOperationTargetExtension targetExtension= (ITextOperationTargetExtension) fOperationTarget;
+ boolean isEnabled= !extension.isEditorInputReadOnly();
+ targetExtension.enableOperation(ISourceViewer.CONTENTASSIST_PROPOSALS, isEnabled);
+ }
+
+ setEnabled(fOperationTarget.canDoOperation(ISourceViewer.CONTENTASSIST_PROPOSALS));
+ }
+
+ /*
+ * @see TextEditorAction#setEditor(ITextEditor)
+ */
+ public void setEditor(ITextEditor editor) {
+ super.setEditor(editor);
+ fOperationTarget= null;
+ }
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ConvertLineDelimitersAction.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ConvertLineDelimitersAction.java
new file mode 100644
index 000000000..7c41f48f6
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ConvertLineDelimitersAction.java
@@ -0,0 +1,286 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ResourceBundle;
+
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.widgets.Shell;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IDocumentExtension;
+import org.eclipse.jface.text.IDocumentPartitioner;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.IRewriteTarget;
+
+
+/**
+ * An action to convert line delimiters of a text editor document to a particular line
+ * delimiter.
+ * @since 2.0
+ */
+public class ConvertLineDelimitersAction extends TextEditorAction {
+
+ /** The target line delimiter. */
+ private final String fLineDelimiter;
+
+ /**
+ * Creates a line delimiter conversion action.
+ *
+ * @param editor the editor
+ * @param lineDelimiter the target line delimiter to convert the editor's document to
+ */
+ public ConvertLineDelimitersAction(ITextEditor editor, String lineDelimiter) {
+ this(EditorMessages.getResourceBundle(), "dummy", editor, lineDelimiter); //$NON-NLS-1$
+ }
+
+ /**
+ * Creates a line delimiter conversion action.
+ *
+ * @param bundle the resource bundle
+ * @param prefix the prefix for the resource bundle lookup
+ * @param editor the editor
+ * @param lineDelimiter the target line delimiter to convert the editor's document to
+ */
+ public ConvertLineDelimitersAction(ResourceBundle bundle, String prefix, ITextEditor editor, String lineDelimiter) {
+ super(bundle, prefix, editor);
+ fLineDelimiter= lineDelimiter;
+
+ String platformLineDelimiter= System.getProperty("line.separator"); //$NON-NLS-1$
+ setText(EditorMessages.getString(getLabelKey(fLineDelimiter, platformLineDelimiter)));
+
+ update();
+ }
+
+ /*
+ * @see Action#run()
+ */
+ public void run() {
+
+ try {
+
+ ITextEditor editor= getTextEditor();
+ if (editor == null)
+ return;
+
+ Object adapter= editor.getAdapter(IRewriteTarget.class);
+ if (adapter instanceof IRewriteTarget) {
+
+ IRewriteTarget target= (IRewriteTarget) adapter;
+ IDocument document= target.getDocument();
+ if (document != null) {
+ Shell shell= getTextEditor().getSite().getShell();
+ ConvertRunnable runnable= new ConvertRunnable(target, fLineDelimiter);
+
+ if (document.getNumberOfLines() < 40) {
+ BusyIndicator.showWhile(shell.getDisplay(), runnable);
+
+ } else {
+ ProgressMonitorDialog dialog= new ProgressMonitorDialog(shell);
+ dialog.run(false, true, runnable);
+ }
+ }
+ }
+
+ } catch (InterruptedException e) {
+ // action cancelled
+
+ } catch (InvocationTargetException e) {
+ // should not happen
+ }
+ }
+
+ /**
+ * Converts all line delimiters of the document to <code>lineDelimiter</code>.
+ */
+ private static class ConvertRunnable implements IRunnableWithProgress, Runnable {
+
+ private final IRewriteTarget fRewriteTarget;
+ private final String fLineDelimiter;
+
+ public ConvertRunnable(IRewriteTarget rewriteTarget, String lineDelimiter) {
+ fRewriteTarget= rewriteTarget;
+ fLineDelimiter= lineDelimiter;
+ }
+
+ private static class DummyMonitor implements IProgressMonitor {
+ public void beginTask(String name, int totalWork) {}
+ public void done() {}
+ public void internalWorked(double work) {}
+ public boolean isCanceled() {return false;}
+ public void setCanceled(boolean value) {}
+ public void setTaskName(String name) {}
+ public void subTask(String name) {}
+ public void worked(int work) {}
+ }
+
+ /*
+ * @see IRunnableWithProgress#run(IProgressMonitor)
+ */
+ public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+
+ IDocument document= fRewriteTarget.getDocument();
+ final int lineCount= document.getNumberOfLines();
+ monitor.beginTask(EditorMessages.getString("Editor.ConvertLineDelimiter.title"), lineCount); //$NON-NLS-1$
+
+ fRewriteTarget.setRedraw(false);
+ fRewriteTarget.beginCompoundChange();
+
+ if (document instanceof IDocumentExtension)
+ ((IDocumentExtension) document).startSequentialRewrite(true);
+
+ IDocumentPartitioner partitioner= document.getDocumentPartitioner();
+ if (partitioner != null) {
+ partitioner.disconnect();
+ document.setDocumentPartitioner(null);
+ }
+
+ try {
+ for (int i= 0; i < lineCount; i++) {
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+
+ final String delimiter= document.getLineDelimiter(i);
+ if (delimiter != null && delimiter.length() > 0 && !delimiter.equals(fLineDelimiter)) {
+ IRegion region= document.getLineInformation(i);
+ document.replace(region.getOffset() + region.getLength(), delimiter.length(), fLineDelimiter);
+ }
+
+ monitor.worked(1);
+ }
+
+ } catch (BadLocationException e) {
+ throw new InvocationTargetException(e);
+
+ } finally {
+
+ if (partitioner != null) {
+ partitioner.connect(document);
+ document.setDocumentPartitioner(partitioner);
+ }
+
+ if (document instanceof IDocumentExtension)
+ ((IDocumentExtension) document).stopSequentialRewrite();
+
+ fRewriteTarget.endCompoundChange();
+ fRewriteTarget.setRedraw(true);
+
+ monitor.done();
+ }
+ }
+
+ /*
+ * @see Runnable#run()
+ */
+ public void run() {
+ try {
+ run(new DummyMonitor());
+
+ } catch (InterruptedException e) {
+ // cancelled, can't happen with dummy monitor
+
+ } catch (InvocationTargetException e) {
+ // should not happen
+ }
+ }
+ }
+
+ /**
+ * Returns whether the given document uses only the given line delimiter.
+ * @param document the document to check
+ * @param lineDelimiter the line delimiter to check for
+ */
+ private static boolean usesLineDelimiterExclusively(IDocument document, String lineDelimiter) {
+
+ try {
+ final int lineCount= document.getNumberOfLines();
+ for (int i= 0; i < lineCount; i++) {
+ final String delimiter= document.getLineDelimiter(i);
+ if (delimiter != null && delimiter.length() > 0 && !delimiter.equals(lineDelimiter))
+ return false;
+ }
+
+ } catch (BadLocationException e) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Computes and returns the key to be used to lookup the action's label in
+ * its resource bundle.
+ *
+ * @param lineDelimiter the line delimiter
+ * @param platformLineDelimiter the platform line delimiter
+ */
+ private static String getLabelKey(String lineDelimiter, String platformLineDelimiter) {
+ if (lineDelimiter.equals(platformLineDelimiter)) {
+
+ if (lineDelimiter.equals("\r\n")) //$NON-NLS-1$
+ return "Editor.ConvertLineDelimiter.toWindows.default.label"; //$NON-NLS-1$
+
+ if (lineDelimiter.equals("\n")) //$NON-NLS-1$
+ return "Editor.ConvertLineDelimiter.toUNIX.default.label"; //$NON-NLS-1$
+
+ if (lineDelimiter.equals("\r")) //$NON-NLS-1$
+ return "Editor.ConvertLineDelimiter.toMac.default.label"; //$NON-NLS-1$
+
+ } else {
+
+ if (lineDelimiter.equals("\r\n")) //$NON-NLS-1$
+ return "Editor.ConvertLineDelimiter.toWindows.label"; //$NON-NLS-1$
+
+ if (lineDelimiter.equals("\n")) //$NON-NLS-1$
+ return "Editor.ConvertLineDelimiter.toUNIX.label"; //$NON-NLS-1$
+
+ if (lineDelimiter.equals("\r")) //$NON-NLS-1$
+ return "Editor.ConvertLineDelimiter.toMac.label"; //$NON-NLS-1$
+ }
+
+ return null;
+ }
+
+ /**
+ * Internally sets the enable state of this action.
+ */
+ private boolean doEnable() {
+ ITextEditor editor= getTextEditor();
+ if (editor == null)
+ return false;
+
+ if (editor instanceof ITextEditorExtension && ((ITextEditorExtension) editor).isEditorInputReadOnly())
+ return false;
+
+// IDocument document= getDocument();
+// if (document == null || usesLineDelimiterExclusively(document, fLineDelimiter))
+// return false;
+
+ return isEnabled();
+ }
+
+ /*
+ * @see IUpdate#update()
+ */
+ public void update() {
+ super.update();
+ setEnabled(doEnable());
+ }
+
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/DefaultRangeIndicator.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/DefaultRangeIndicator.java
new file mode 100644
index 000000000..347627564
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/DefaultRangeIndicator.java
@@ -0,0 +1,146 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+
+import org.eclipse.jface.text.source.Annotation;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.PaletteData;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+
+
+/**
+ * Specialized annotation to indicate a particular range of text lines.
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * This class is instantiated automatically by <code>AbstractTextEditor</code>.
+ * </p>
+ */
+public class DefaultRangeIndicator extends Annotation {
+
+ private static PaletteData fgPaletteData;
+ private Image fImage;
+
+ /**
+ * Creates a new range indicator.
+ */
+ public DefaultRangeIndicator() {
+ super();
+ setLayer(0);
+ }
+
+ /*
+ * @see Annotation#paint
+ */
+ public void paint(GC gc, Canvas canvas, Rectangle bounds) {
+
+ Point canvasSize= canvas.getSize();
+
+ int x= 0;
+ int y= bounds.y;
+ int w= canvasSize.x;
+ int h= bounds.height;
+ int b= 1;
+
+ if (y + h > canvasSize.y)
+ h= canvasSize.y - y;
+
+ if (y < 0) {
+ h= h + y;
+ y= 0;
+ }
+
+ if (h <= 0)
+ return;
+
+ Image image = getImage(canvas);
+ gc.drawImage(image, 0, 0, w, h, x, y, w, h);
+
+ gc.setBackground(canvas.getDisplay().getSystemColor(SWT.COLOR_LIST_SELECTION));
+ gc.fillRectangle(x, bounds.y, w, b);
+ gc.fillRectangle(x, bounds.y + bounds.height - b, w, b);
+ }
+
+ private Image getImage(Control control) {
+ if (fImage == null) {
+ fImage= createImage(control.getDisplay(), control.getSize());
+
+ control.addDisposeListener(new DisposeListener() {
+ public void widgetDisposed(DisposeEvent e) {
+ if (fImage != null && !fImage.isDisposed()) {
+ fImage.dispose();
+ fImage= null;
+ }
+ }
+ });
+ } else {
+ Rectangle imageRectangle= fImage.getBounds();
+ Point controlSize= control.getSize();
+
+ if (imageRectangle.width < controlSize.x || imageRectangle.height < controlSize.y) {
+ fImage.dispose();
+ fImage= createImage(control.getDisplay(), controlSize);
+ }
+ }
+
+ return fImage;
+ }
+
+ private static Image createImage(Display display, Point size) {
+
+ int width= size.x;
+ int height= size.y;
+
+ if (fgPaletteData == null)
+ fgPaletteData= createPalette(display);
+
+ ImageData imageData= new ImageData(width, height, 1, fgPaletteData);
+
+ for (int y= 0; y < height; y++)
+ for (int x= 0; x < width; x++)
+ imageData.setPixel(x, y, (x + y) % 2);
+
+ return new Image(display, imageData);
+ }
+
+ private static PaletteData createPalette(Display display) {
+ Color c1;
+ Color c2;
+
+ if (false) {
+ // range lighter
+ c1= display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
+ c2= display.getSystemColor(SWT.COLOR_LIST_BACKGROUND);
+ } else {
+ // range darker
+ c1= display.getSystemColor(SWT.COLOR_LIST_SELECTION);
+ c2= display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
+ }
+
+ RGB rgbs[]= new RGB[] {
+ new RGB(c1.getRed(), c1.getGreen(), c1.getBlue()),
+ new RGB(c2.getRed(), c2.getGreen(), c2.getBlue())};
+
+ return new PaletteData(rgbs);
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/DeleteLineAction.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/DeleteLineAction.java
new file mode 100644
index 000000000..880c485b3
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/DeleteLineAction.java
@@ -0,0 +1,179 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v0.5
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v05.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+
+import java.util.ResourceBundle;
+
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextSelection;
+
+
+/**
+ * An action to delete a whole line, the fraction of the line that is left from the cursor
+ * or the fraction that is right from the cursor.
+ * @since 2.0
+ */
+public class DeleteLineAction extends TextEditorAction {
+
+ /** Delete the whole line. */
+ public static final int WHOLE= 0;
+ /** Delete to the beginning of line. */
+ public static final int TO_BEGINNING= 1;
+ /** Delete to the end of line. */
+ public static final int TO_END= 2;
+
+ /** The type of deletion */
+ private final int fType;
+
+ /**
+ * Creates a line delimiter conversion action.
+ *
+ * @param editor the editor
+ * @param type the line deletion type, must be one of
+ * <code>WHOLE_LINE</code>, <code>TO_BEGINNING</code> or <code>TO_END</code>
+ */
+ public DeleteLineAction(ResourceBundle bundle, String prefix, ITextEditor editor, int type) {
+ super(bundle, prefix, editor);
+ fType= type;
+ }
+
+
+ /**
+ * Returns the editor's document.
+ * @param editor the editor
+ * @return teh editor's document
+ */
+ private static IDocument getDocument(ITextEditor editor) {
+
+ IDocumentProvider documentProvider= editor.getDocumentProvider();
+ if (documentProvider == null)
+ return null;
+
+ IDocument document= documentProvider.getDocument(editor.getEditorInput());
+ if (document == null)
+ return null;
+
+ return document;
+ }
+
+
+ /**
+ * Returns the editor's selection.
+ * @param editor the editor
+ * @return the editor's selection
+ */
+ private static ITextSelection getSelection(ITextEditor editor) {
+
+ ISelectionProvider selectionProvider= editor.getSelectionProvider();
+ if (selectionProvider == null)
+ return null;
+
+ ISelection selection= selectionProvider.getSelection();
+ if (!(selection instanceof ITextSelection))
+ return null;
+
+ return (ITextSelection) selection;
+ }
+
+ /*
+ * @see IAction#run()
+ */
+ public void run() {
+
+ ITextEditor editor= getTextEditor();
+ if (editor == null)
+ return;
+
+ IDocument document= getDocument(editor);
+ if (document == null)
+ return;
+
+ ITextSelection selection= getSelection(editor);
+ if (selection == null)
+ return;
+
+ try {
+ deleteLine(document, selection.getOffset(), fType);
+ } catch (BadLocationException e) {
+ // should not happen
+ }
+ }
+
+ /**
+ * Deletes the specified fraction of the line of the given offset.
+ * @param document the document
+ * @param position the offset
+ * @param type the specification of what to delete
+ * @throws BadLocationException if position is not valid in the given document
+ */
+ private static void deleteLine(IDocument document, int position, int type) throws BadLocationException {
+
+ int line= document.getLineOfOffset(position);
+ int offset= 0;
+ int length= 0;
+
+ switch (type) {
+ case WHOLE:
+ offset= document.getLineOffset(line);
+ length= document.getLineLength(line);
+ break;
+
+ case TO_BEGINNING:
+ offset= document.getLineOffset(line);
+ length= position - offset;
+ break;
+
+ case TO_END:
+ offset= position;
+
+ IRegion lineRegion= document.getLineInformation(line);
+ int end= lineRegion.getOffset() + lineRegion.getLength();
+
+ if (position == end) {
+ String lineDelimiter= document.getLineDelimiter(line);
+ length= lineDelimiter == null ? 0 : lineDelimiter.length();
+
+ } else {
+ length= end - offset;
+ }
+ break;
+
+ default:
+ return;
+ }
+
+ if (length != 0)
+ document.replace(offset, length, ""); //$NON-NLS-1$
+ }
+
+ /*
+ * @see IUpdate#update()
+ */
+ public void update() {
+
+ ITextEditor editor= getTextEditor();
+ if (editor instanceof ITextEditorExtension) {
+ ITextEditorExtension extension= (ITextEditorExtension) editor;
+ if (extension.isEditorInputReadOnly()) {
+ setEnabled(false);
+ return;
+ }
+ }
+
+ super.update();
+ }
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/DocumentProviderRegistry.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/DocumentProviderRegistry.java
new file mode 100644
index 000000000..21cbe7418
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/DocumentProviderRegistry.java
@@ -0,0 +1,287 @@
+package org.eclipse.ui.texteditor;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.ILog;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.PlatformUI;
+
+
+
+
+/**
+ * This registry manages shareable document provider. Document
+ * providers are specified in <code>plugin.xml</code> either
+ * per name extension or per editor input type. A name extension
+ * rule always overrules an editor input type rule. Editor input
+ * type rules follow the same rules <code>IAdapterManager</code>
+ * used to find object adapters.
+ *
+ * @see org.eclipse.core.runtime.IAdapterManager
+ */
+public class DocumentProviderRegistry {
+
+ /** The registry singleton. */
+ private static DocumentProviderRegistry fgRegistry;
+
+ /**
+ * Returns the standard document provider registry.
+ */
+ public static DocumentProviderRegistry getDefault() {
+ if (fgRegistry == null)
+ fgRegistry= new DocumentProviderRegistry();
+ return fgRegistry;
+ }
+
+
+ /** The mapping between name extensions and configuration elements. */
+ private Map fExtensionMapping= new HashMap();
+ /** The mapping between editor input type names and configuration elements. */
+ private Map fInputTypeMapping= new HashMap();
+ /** The mapping between configuration elements and instantiated document providers. */
+ private Map fInstances= new HashMap();
+
+
+ /**
+ * Creates a new document provider registry and intializes it with the information
+ * found in the plugin registry.
+ */
+ private DocumentProviderRegistry() {
+ initialize();
+ }
+
+ /**
+ * Reads the comma-separated value of the given configuration element
+ * for the given attribute name and remembers the configuration element
+ * in the given map under the individual tokens of the attribute value.
+ */
+ private void read(Map map, IConfigurationElement element, String attributeName) {
+ String value= element.getAttribute(attributeName);
+ if (value != null) {
+ StringTokenizer tokenizer= new StringTokenizer(value, ","); //$NON-NLS-1$
+ while (tokenizer.hasMoreTokens()) {
+ String token= tokenizer.nextToken().trim();
+
+ Set s= (Set) map.get(token);
+ if (s == null) {
+ s= new HashSet();
+ map.put(token, s);
+ }
+ s.add(element);
+ }
+ }
+ }
+
+ /**
+ * Initializes the document provider registry. It retrieves all implementers of the <code>documentProviders</code>
+ * extension point and remembers those implementers based on the name extensions and the editor input
+ * types they are for.
+ */
+ private void initialize() {
+
+ IExtensionPoint extensionPoint;
+ extensionPoint= Platform.getPluginRegistry().getExtensionPoint(PlatformUI.PLUGIN_ID, "documentProviders"); //$NON-NLS-1$
+
+ if (extensionPoint == null) {
+ String msg= MessageFormat.format(EditorMessages.getString("DocumentProviderRegistry.error.extension_point_not_found"), new Object[] { PlatformUI.PLUGIN_ID }); //$NON-NLS-1$
+ ILog log= Platform.getPlugin(PlatformUI.PLUGIN_ID).getLog();
+ log.log(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, msg, null));
+ return;
+ }
+
+ IConfigurationElement[] elements= extensionPoint.getConfigurationElements();
+ for (int i= 0; i < elements.length; i++) {
+ read(fExtensionMapping, elements[i], "extensions"); //$NON-NLS-1$
+ read(fInputTypeMapping, elements[i], "inputTypes"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Returns the document provider for the given configuration element.
+ * If there is no instantiated document provider remembered for this
+ * element, a new document provider is created and put into the cache.
+ */
+ private IDocumentProvider getDocumentProvider(IConfigurationElement entry) {
+ IDocumentProvider provider= (IDocumentProvider) fInstances.get(entry);
+ if (provider == null) {
+ try {
+ provider= (IDocumentProvider) entry.createExecutableExtension("class"); //$NON-NLS-1$
+ fInstances.put(entry, provider);
+ } catch (CoreException x) {
+ }
+ }
+ return provider;
+ }
+
+ /**
+ * Returns the first enumerated element of the given set.
+ */
+ private IConfigurationElement selectConfigurationElement(Set set) {
+ if (set != null && !set.isEmpty()) {
+ Iterator e= set.iterator();
+ return (IConfigurationElement) e.next();
+ }
+ return null;
+ }
+
+ /**
+ * Returns a shareable document provider for the given name extension.
+ *
+ * @param extension the name extension to be used for lookup
+ * @return the shareable document provider
+ */
+ public IDocumentProvider getDocumentProvider(String extension) {
+
+ Set set= (Set) fExtensionMapping.get(extension);
+ if (set != null) {
+ IConfigurationElement entry= selectConfigurationElement(set);
+ return getDocumentProvider(entry);
+ }
+ return null;
+ }
+
+ /**
+ * Computes the class hierarchy of the given type. The type is
+ * part of the computed hierarchy.
+ */
+ private List computeClassList(Class type) {
+
+ List result= new ArrayList();
+
+ Class c= type;
+ while (c != null) {
+ result.add(c);
+ c= c.getSuperclass();
+ }
+
+ return result;
+ }
+
+ /**
+ * Computes the list of all interfaces for the given list of
+ * classes. The interface lists of the given classes are
+ * concatenated.
+ */
+ private List computeInterfaceList(List classes) {
+
+ List result= new ArrayList(4);
+ Hashtable visited= new Hashtable(4);
+
+ Iterator e= classes.iterator();
+ while (e.hasNext()) {
+ Class c= (Class) e.next();
+ computeInterfaceList(c.getInterfaces(), result, visited);
+ }
+
+ return result;
+ }
+
+ /**
+ * Computes the list of all interfaces of the given list of interfaces,
+ * taking a depth-first approach.
+ */
+ private void computeInterfaceList(Class[] interfaces, List result, Hashtable visited) {
+
+ List toBeVisited= new ArrayList(interfaces.length);
+
+ for (int i= 0; i < interfaces.length; i++) {
+ Class iface= interfaces[i];
+ if (visited.get(iface) == null) {
+ visited.put(iface, iface);
+ result.add(iface);
+ toBeVisited.add(iface);
+ }
+ }
+
+ Iterator e= toBeVisited.iterator();
+ while(e.hasNext()) {
+ Class iface= (Class) e.next();
+ computeInterfaceList(iface.getInterfaces(), result, visited);
+ }
+ }
+
+ /**
+ * Returns the configuration elements for the first class in the list
+ * of given classes for which configuration elements have been remembered.
+ */
+ private Object getFirstInputTypeMapping(List classes) {
+ Iterator e= classes.iterator();
+ while (e.hasNext()) {
+ Class c= (Class) e.next();
+ Object mapping= fInputTypeMapping.get(c.getName());
+ if (mapping != null)
+ return mapping;
+ }
+ return null;
+ }
+
+ /**
+ * Returns the appropriate configuration element for the given type. If
+ * there is no configuration element for the type's name, first the list of
+ * super classes is searched, and if not successful the list of all interfaces.
+ */
+ private Object findInputTypeMapping(Class type) {
+
+ if (type == null)
+ return null;
+
+ Object mapping= fInputTypeMapping.get(type.getName());
+ if (mapping != null)
+ return mapping;
+
+ List classList= computeClassList(type);
+ mapping= getFirstInputTypeMapping(classList);
+ if (mapping != null)
+ return mapping;
+
+ return getFirstInputTypeMapping(computeInterfaceList(classList));
+ }
+
+ /**
+ * Returns the shareable document for the type of the given editor input.
+ *
+ * @param editorInput the input for whose type the provider is looked up
+ * @return the shareable document provider
+ */
+ public IDocumentProvider getDocumentProvider(IEditorInput editorInput) {
+
+ IDocumentProvider provider= null;
+
+ IFile file= (IFile) editorInput.getAdapter(IFile.class);
+ if (file != null)
+ provider= getDocumentProvider(file.getFileExtension());
+
+ if (provider == null) {
+ Set set= (Set) findInputTypeMapping(editorInput.getClass());
+ if (set != null) {
+ IConfigurationElement entry= selectConfigurationElement(set);
+ provider= getDocumentProvider(entry);
+ }
+ }
+
+ return provider;
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/EditorMessages.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/EditorMessages.java
new file mode 100644
index 000000000..6d672762a
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/EditorMessages.java
@@ -0,0 +1,30 @@
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+package org.eclipse.ui.texteditor;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+class EditorMessages {
+
+ private static final String RESOURCE_BUNDLE= "org.eclipse.ui.texteditor.EditorMessages";//$NON-NLS-1$
+
+ private static ResourceBundle fgResourceBundle= ResourceBundle.getBundle(RESOURCE_BUNDLE);
+
+ private EditorMessages() {
+ }
+
+ public static String getString(String key) {
+ try {
+ return fgResourceBundle.getString(key);
+ } catch (MissingResourceException e) {
+ return "!" + key + "!";//$NON-NLS-2$ //$NON-NLS-1$
+ }
+ }
+
+ public static ResourceBundle getResourceBundle() {
+ return fgResourceBundle;
+ }
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/EditorMessages.properties b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/EditorMessages.properties
new file mode 100644
index 000000000..743474dfd
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/EditorMessages.properties
@@ -0,0 +1,286 @@
+#############################################################
+#
+# (c) Copyright IBM Corp. 2000, 2001.
+# All Rights Reserved.
+#
+#############################################################
+
+
+## Errors ##
+
+Editor.error.no_provider=Text editor does not have a document provider
+
+Editor.error.save.title=Save problems
+Editor.error.save.message=Save could not be completed.
+
+Editor.error.save.deleted.title=Cannot Save
+Editor.error.save.deleted.message=The file has been deleted.
+
+
+Editor.error.save.outofsync.title=Update conflict
+Editor.error.save.outofsync.message=The file has been changed on the file system. Do you want to overwrite the changes?
+
+Editor.error.activated.outofsync.title=File Changed
+Editor.error.activated.outofsync.message=The file has been changed on the file system. Do you want to load the changes?
+
+Editor.error.activated.deleted.save.title=File Deleted
+Editor.error.activated.deleted.save.message=The file has been deleted from the file system. Do you want to save your changes or close the editor without saving?
+Editor.error.activated.deleted.save.button.save=Save
+Editor.error.activated.deleted.save.button.close=Close
+Editor.error.activated.deleted.close.title=File Deleted
+Editor.error.activated.deleted.close.message=The file has been deleted from the file system. This editor will be closed.
+
+Editor.error.refresh.outofsync.title=Problems loading File
+Editor.error.refresh.outofsync.message=The file could not be loaded from the file system.
+
+Editor.error.revert.title=Problems while reverting to saved state
+Editor.error.revert.message=Could not revert to saved state.
+Editor.error.setinput.title=Problem while opening
+Editor.error.setinput.message=Cannot open input element:
+Editor.error.no_input=Unable to read text editor input
+Editor.error.invalid_input=Invalid text editor input
+
+AbstractDocumentProvider.error.save.inuse=File is either open in another editor or in use by an operation.
+
+DocumentProviderRegistry.error.extension_point_not_found=Extension point: {0}.documentProviders not found
+
+
+
+## Actions ##
+
+Editor.Undo.label=&Undo@Ctrl+Z
+Editor.Undo.tooltip=Undo
+Editor.Undo.image=
+Editor.Undo.description=Undo
+
+Editor.Redo.label=&Redo@Ctrl+Y
+Editor.Redo.tooltip=Redo
+Editor.Redo.image=
+Editor.Redo.description=Redo
+
+Editor.Cut.label=Cu&t@Ctrl+X
+Editor.Cut.tooltip=Cut
+Editor.Cut.image=
+Editor.Cut.description=Cut
+
+Editor.Copy.label=&Copy@Ctrl+C
+Editor.Copy.tooltip=Copy
+Editor.Copy.image=
+Editor.Copy.description=Copy
+
+Editor.Paste.label=&Paste@Ctrl+V
+Editor.Paste.tooltip=Paste
+Editor.Paste.image=
+Editor.Paste.description=Paste
+
+Editor.Delete.label=&Delete@Delete
+Editor.Delete.tooltip=Delete
+Editor.Delete.image=
+Editor.Delete.description=Delete
+
+Editor.Print.label=&Print@Ctrl+P
+Editor.Print.tooltip=Print
+Editor.Print.image=
+Editor.Print.description=Print
+
+Editor.SelectAll.label=Select &All@Ctrl+A
+Editor.SelectAll.tooltip=Select All
+Editor.SelectAll.image=
+Editor.SelectAll.description=Select All
+
+Editor.ShiftRight.label=Sh&ift Right
+Editor.ShiftRight.tooltip=Shift Right
+Editor.ShiftRight.image=
+Editor.ShiftRight.description=Shift Right
+
+Editor.ShiftLeft.label=S&hift Left
+Editor.ShiftLeft.tooltip=Shift Left
+Editor.ShiftLeft.image=
+Editor.ShiftLeft.description=Shift Left
+
+Editor.delete.line.submenu.label=D&elete Line
+
+Editor.DeleteLine.label=&Whole
+Editor.DeleteLine.tooltip=Delete Line
+Editor.DeleteLine=
+Editor.DeleteLine.description=Delete Line
+
+Editor.DeleteLineToBeginning.label=To &Beginning
+Editor.DeleteLineToBeginning.tooltip=Delete Line to Beginning
+Editor.DeleteLineToBeginning=
+Editor.DeleteLineToBeginning.description=Delete Line to Beginning
+
+Editor.DeleteLineToEnd.label=To &End
+Editor.DeleteLineToEnd.tooltip=Delete Line to End
+Editor.DeleteLineToEnd=
+Editor.DeleteLineToEnd.description=Delete Line to End
+
+Editor.mark.status.message.mark.set=Mark set
+Editor.mark.status.message.mark.cleared=Mark cleared
+Editor.mark.status.message.mark.swapped=Mark swapped
+Editor.mark.status.error.message.mark.not.set=Mark not set
+Editor.mark.status.error.message.mark.not.visible=Mark not in visible region
+
+Editor.mark.submenu.label=&Mark
+
+Editor.SetMark.label=&Set
+Editor.SetMark.tooltip=Set Mark
+Editor.SetMark=
+Editor.SetMark.description=Set Mark
+
+Editor.ClearMark.label=&Clear
+Editor.ClearMark.tooltip=Clear Mark
+Editor.ClearMark=
+Editor.ClearMark.description=Clear Mark
+
+Editor.SwapMark.label=S&wap
+Editor.SwapMark.tooltip=Swap Mark
+Editor.SwapMark=
+Editor.SwapMark.description=Swap Mark
+
+Editor.FindReplace.label=&Find/Replace...@Ctrl+F
+Editor.FindReplace.tooltip=Find/Replace
+Editor.FindReplace.image=
+Editor.FindReplace.description=Find/Replace
+
+Editor.FindNext.label=Find &Next@Ctrl+K
+Editor.FindNext.tooltip=Find Next
+Editor.FindNext.image=
+Editor.FindNext.description=Find Next
+
+Editor.FindPrevious.label=Find Pre&vious@Ctrl+Shift+K
+Editor.FindPrevious.tooltip=Find Previous
+Editor.FindPrevious.image=
+Editor.FindPrevious.description=Find Previous
+
+Editor.FindIncremental.label=&Incremental Find@Ctrl+J
+Editor.FindIncremental.tooltip=Incremental Find
+Editor.FindIncremental.image=
+Editor.FindIncremental.description=Incremental Find
+Editor.FindIncremental.not_found.pattern={0} Incremental Find: {1} not found
+Editor.FindIncremental.found.pattern={0} Incremental Find: {1}
+Editor.FindIncremental.render.tab=<TAB>
+Editor.FindIncremental.wrapped =Wrapped
+
+Editor.AddBookmark.label=Boo&kmark...
+Editor.AddBookmark.tooltip=Add Bookmark
+Editor.AddBookmark.image=
+Editor.AddBookmark.description=Add Bookmark
+Editor.AddBookmark.dialog.title=Add Bookmark
+Editor.AddBookmark.dialog.message=Enter Bookmark name
+Editor.AddBookmark.error.dialog.title=Add Bookmark
+Editor.AddBookmark.error.dialog.message=Problems adding new bookmark
+
+Editor.AddTask.label=&Task...
+Editor.AddTask.tooltip=Add Task
+Editor.AddTask.image=
+Editor.AddTask.description=Add Task
+Editor.AddTask.dialog.title=Add Task
+Editor.AddTask.dialog.message=Enter Task description
+Editor.AddTask.error.dialog.title=Add Task
+Editor.AddTask.error.dialog.message=Problems adding new task
+
+Editor.Save.label=&Save@Ctrl+S
+Editor.Save.tooltip=Save
+Editor.Save.image=
+Editor.Save.description=Save
+
+Editor.Revert.label=Re&vert
+Editor.Revert.tooltip=Revert
+Editor.Revert.image=
+Editor.Revert.description=Revert
+
+Editor.GotoLine.label=&Go to Line...@Ctrl+L
+Editor.GotoLine.tooltip=Go to Line
+Editor.GotoLine.image=
+Editor.GotoLine.description=Go to Line
+Editor.GotoLine.dialog.title=Go to Line
+Editor.GotoLine.dialog.message=Enter line number (1..{0}):
+Editor.GotoLine.dialog.invalid_input=Not a number
+Editor.GotoLine.dialog.invalid_range=Line number out of range
+
+Editor.ManageBookmarks.tooltip=Adds and Removes Bookmarks
+Editor.ManageBookmarks.image=
+Editor.ManageBookmarks.description=Adds and removes Bookmarks
+Editor.ManageBookmarks.add.label=Add Boo&kmark...
+Editor.ManageBookmarks.remove.label=Remove Boo&kmark
+Editor.ManageBookmarks.add.dialog.title=Add Bookmark
+Editor.ManageBookmarks.add.dialog.message=Enter Bookmark name
+Editor.ManageBookmarks.error.dialog.title=Managing Bookmarks
+Editor.ManageBookmarks.error.dialog.message=Problems managing bookmarks
+
+Editor.ManageTasks.tooltip=Adds and Removes Tasks
+Editor.ManageTasks.image=
+Editor.ManageTasks.description=Adds and removes Tasks
+Editor.ManageTasks.add.label=Add &Task...
+Editor.ManageTasks.remove.label=Remove &Task
+Editor.ManageTasks.add.dialog.title=Add Task
+Editor.ManageTasks.add.dialog.message=Enter Task description
+Editor.ManageTasks.error.dialog.title=Managing Tasks
+Editor.ManageTasks.error.dialog.message=Problems managing tasks
+
+Editor.SelectMarker.tooltip=Selects the marker's range
+Editor.SelectMarker.image=
+Editor.SelectMarker.description=Selects the Marker's Range
+Editor.SelectMarker.label=Select &Marker Range
+Editor.SelectMarker.error.dialog.title=Selecting Marker Range
+Editor.SelectMarker.error.dialog.message=Problems selecting marker range
+
+Editor.ConvertLineDelimiter.title=Converting line delimiters...
+Editor.ConvertLineDelimiter.toWindows.label=to CRLF (&Windows)
+Editor.ConvertLineDelimiter.toWindows.default.label=to CRLF (&Windows) [default]
+Editor.ConvertLineDelimiter.toUNIX.label=to LF (&UNIX, MacOS X)
+Editor.ConvertLineDelimiter.toUNIX.default.label=to LF (&UNIX, MacOS X) [default]
+Editor.ConvertLineDelimiter.toMac.label=to CR (Classic &MacOS)
+Editor.ConvertLineDelimiter.toMac.default.label=to CR (Classic &MacOS) [default]
+
+## Status line ##
+
+Editor.statusline.state.readonly.label=Read Only
+Editor.statusline.state.writable.label=Writable
+Editor.statusline.mode.insert.label=Insert
+Editor.statusline.mode.overwrite.label=Overwrite
+Editor.statusline.position.pattern={0} : {1}
+Editor.statusline.error.label=?
+
+## Others ##
+
+AbstractMarkerAnnotationModel.connected=AbstractMarkerAnnotationModel.connected
+AbstractMarkerAnnotationModel.createMarkerUpdater=AbstractMarkerAnnotationModel.createMarkerUpdater
+AbstractMarkerAnnotationModel.removeAnnotations=AbstractMarkerAnnotationModel.removeAnnotations
+
+ResourceMarkerAnnotationModel.resourceChanged=ResourceMarkerAnnotationModel.resourceChanged
+
+WorkbenchChainedTextFontFieldEditor.defaultWorkbenchTextFont=<Using Workbench Text Font>
+
+FindReplace.title= Find/Replace
+FindReplace.Find.label=&Find:
+FindReplace.Replace.label=R&eplace With:
+FindReplace.Direction=Direction
+FindReplace.ForwardRadioButton.label=F&orward
+FindReplace.BackwardRadioButton.label=&Backward
+FindReplace.Scope=Scope
+FindReplace.GlobalRadioButton.label=A&ll
+FindReplace.SelectedRangeRadioButton.label=Selec&ted Lines
+FindReplace.Options=Options
+FindReplace.CaseCheckBox.label=&Case Sensitive
+FindReplace.WrapCheckBox.label=Wra&p Search
+FindReplace.WholeWordCheckBox.label=&Whole Word
+FindReplace.IncrementalCheckBox.label=&Incremental
+FindReplace.FindNextButton.label=Fi&nd
+FindReplace.ReplaceFindButton.label=Replace/Fin&d
+FindReplace.ReplaceSelectionButton.label=&Replace
+FindReplace.ReplaceAllButton.label=Replace &All
+FindReplace.CloseButton.label=Close
+FindReplace.Status.noMatch.label=String Not Found
+FindReplace.Status.replacement.label=1 Match replaced
+FindReplace.Status.replacements.label={0} matches replaced
+
+FindNext.Status.noMatch.label=String Not Found
+
+MarkerRulerAction.addMarker=MarkerRulerAction.addMarker
+MarkerRulerAction.getMarker=MarkerRulerAction.getMarker
+MarkerRulerAction.removeMarkers=MarkerRulerAction.removeMarkers
+
+SelectMarkerRulerAction.getMarker=SelectMarkerRulerAction.getMarker
+SelectMarkerRulerInfoAction.getMarker=SelectMarkerRulerInfoAction.getMarker
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/EditorStatusLine.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/EditorStatusLine.java
new file mode 100644
index 000000000..0a3197c38
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/EditorStatusLine.java
@@ -0,0 +1,99 @@
+package org.eclipse.ui.texteditor;
+
+import org.eclipse.swt.graphics.Image;
+
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.jface.util.Assert;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+
+/**
+ * An editor status line.
+ * The selection provider of the editor triggers the status line to be cleared.
+ * @since 2.1
+ */
+class EditorStatusLine implements IEditorStatusLine {
+
+ /**
+ * Clears the status line on selection changed.
+ */
+ private class StatusLineClearer implements ISelectionChangedListener {
+ public void selectionChanged(SelectionChangedEvent event) {
+ fStatusLineManager.setErrorMessage(null);
+
+ Assert.isTrue(this == fStatusLineClearer);
+ uninstallStatusLineClearer();
+ }
+ };
+
+ /** The status line manager. */
+ private final IStatusLineManager fStatusLineManager;
+
+ /** The selection provider. */
+ private final ISelectionProvider fSelectionProvider;
+
+ /** The status line clearer, <code>null</code> if not installed. */
+ private StatusLineClearer fStatusLineClearer;
+
+ /**
+ * Constructor for EditorStatusLine.
+ */
+ public EditorStatusLine(IStatusLineManager statusLineManager, ISelectionProvider selectionProvider) {
+
+ Assert.isNotNull(statusLineManager);
+ Assert.isNotNull(selectionProvider);
+
+ fStatusLineManager= statusLineManager;
+ fSelectionProvider= selectionProvider;
+ }
+
+ /**
+ * Returns the status line manager.
+ */
+ public IStatusLineManager getStatusLineManager() {
+ return fStatusLineManager;
+ }
+
+ /**
+ * Returns the selection provider. */
+ public ISelectionProvider getSelectionProvider() {
+ return fSelectionProvider;
+ }
+
+ /*
+ * @see org.eclipse.ui.texteditor.IStatusLine#setMessage(boolean, String, Image) */
+ public void setMessage(boolean error, String message, Image image) {
+
+ if (error)
+ fStatusLineManager.setErrorMessage(image, message);
+ else
+ fStatusLineManager.setMessage(image, message);
+
+ if (isMessageEmpty(message))
+ uninstallStatusLineClearer();
+ else
+ installStatusLineClearer();
+ }
+
+ private static boolean isMessageEmpty(String message) {
+ return message == null || message.trim().length() == 0;
+ }
+
+ private void uninstallStatusLineClearer() {
+ if (fStatusLineClearer == null)
+ return;
+
+ fSelectionProvider.removeSelectionChangedListener(fStatusLineClearer);
+ fStatusLineClearer= null;
+ }
+
+ private void installStatusLineClearer() {
+ if (fStatusLineClearer != null)
+ return;
+
+ StatusLineClearer statusLineClearer= new StatusLineClearer();
+ fSelectionProvider.addSelectionChangedListener(statusLineClearer);
+ fStatusLineClearer= statusLineClearer;
+ }
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindNextAction.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindNextAction.java
new file mode 100644
index 000000000..e596d05aa
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindNextAction.java
@@ -0,0 +1,332 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ResourceBundle;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.text.IFindReplaceTarget;
+import org.eclipse.jface.text.IFindReplaceTargetExtension;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.ui.IEditorActionBarContributor;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.part.EditorActionBarContributor;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+
+/**
+ * An action which finds the next/previous occurrence of the last search or
+ * the current selection if present.
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ * @since 2.0
+ */
+public class FindNextAction extends ResourceAction implements IUpdate {
+
+ /** The action's target */
+ private IFindReplaceTarget fTarget;
+ /** The part the action is bound to */
+ private IWorkbenchPart fWorkbenchPart;
+ /** The workbench window */
+ private IWorkbenchWindow fWorkbenchWindow;
+ /** The dialog settings to retrieve the last search */
+ private IDialogSettings fDialogSettings;
+ /** The find history as initially given in the dialog settings. */
+ private List fFindHistory= new ArrayList();
+ /** The find string as initially given in the dialog settings. */
+ private String fFindString;
+ /** The search direction as initially given in the dialog settings. */
+ private boolean fForward;
+ /** The warpping flag as initially given in the dialog settings. */
+ private boolean fWrapInit;
+ /** The case flag as initially given in the dialog settings. */
+ private boolean fCaseInit;
+ /** The whole word flag as initially given in the dialog settings. */
+ private boolean fWholeWordInit;
+
+ /**
+ * Creates a new find/replace action for the given text editor.
+ * The action configures its visual representation from the given
+ * resource bundle.
+ *
+ * @param bundle the resource bundle
+ * @param prefix a prefix to be prepended to the various resource keys
+ * (described in <code>ResourceAction</code> constructor), or
+ * <code>null</code> if none
+ * @param editor the text editor
+ * @param forward the search direction
+ * @see ResourceAction#ResourceAction
+ */
+ public FindNextAction(ResourceBundle bundle, String prefix, IWorkbenchPart workbenchPart, boolean forward) {
+ super(bundle, prefix);
+ fWorkbenchPart= workbenchPart;
+ fForward= forward;
+ update();
+ }
+
+ /**
+ * Creates a new find/replace action for the given text editor.
+ * The action configures its visual representation from the given
+ * resource bundle.
+ *
+ * @param bundle the resource bundle
+ * @param prefix a prefix to be prepended to the various resource keys
+ * (described in <code>ResourceAction</code> constructor), or
+ * <code>null</code> if none
+ * @param workbenchWindow the workbench window
+ * @param forward the search direction
+ * @see ResourceAction#ResourceAction
+ *
+ * @deprecated use FindReplaceAction(ResourceBundle, String, IWorkbenchPart) instead
+ */
+ public FindNextAction(ResourceBundle bundle, String prefix, IWorkbenchWindow workbenchWindow, boolean forward) {
+ super(bundle, prefix);
+ fWorkbenchWindow= workbenchWindow;
+ fForward= forward;
+ update();
+ }
+
+ /**
+ * Returns the find string based on the selection or the find history.
+ * @return the find string
+ */
+ private String getFindString() {
+ String string= getSelectionString();
+
+ if (string == null && !fFindHistory.isEmpty())
+ string= (String) fFindHistory.get(0);
+
+ return string;
+ }
+
+ /**
+ * Returns the status line manager of the active editor.
+ * @return the status line manager of the active editor
+ */
+ private IStatusLineManager getStatusLineManager() {
+
+ IEditorPart editor= fWorkbenchPart.getSite().getPage().getActiveEditor();
+ if (editor == null)
+ return null;
+
+ IEditorActionBarContributor contributor= editor.getEditorSite().getActionBarContributor();
+ if (contributor instanceof EditorActionBarContributor) {
+ return ((EditorActionBarContributor) contributor).getActionBars().getStatusLineManager();
+ }
+ return null;
+ }
+
+ /**
+ * Sets the "no matches found" error message to the status line.
+ */
+ private void statusError() {
+ fWorkbenchPart.getSite().getShell().getDisplay().beep();
+
+ IStatusLineManager manager= getStatusLineManager();
+ if (manager == null)
+ return;
+
+ manager.setErrorMessage(EditorMessages.getString("FindNext.Status.noMatch.label")); //$NON-NLS-1$
+ manager.setMessage(""); //$NON-NLS-1$
+ }
+
+ /**
+ * Clears the status line.
+ */
+ private void statusClear() {
+ IStatusLineManager manager= getStatusLineManager();
+ if (manager == null)
+ return;
+
+ manager.setErrorMessage(""); //$NON-NLS-1$
+ manager.setMessage(""); //$NON-NLS-1$
+ }
+
+ /*
+ * @see IAction#run
+ */
+ public void run() {
+ if (fTarget != null) {
+ readConfiguration();
+
+ fFindString= getFindString();
+ if (fFindString == null) {
+ statusError();
+ return;
+ }
+
+ if (!findNext(fFindString, fForward, fCaseInit, fWrapInit, fWholeWordInit)) {
+ statusError();
+ } else {
+ statusClear();
+ }
+
+ writeConfiguration();
+ }
+ }
+
+ /*
+ * @see IUpdate#update()
+ */
+ public void update() {
+
+ if (fWorkbenchPart == null && fWorkbenchWindow != null)
+ fWorkbenchPart= fWorkbenchWindow.getPartService().getActivePart();
+
+ if (fWorkbenchPart != null)
+ fTarget= (IFindReplaceTarget) fWorkbenchPart.getAdapter(IFindReplaceTarget.class);
+ else
+ fTarget= null;
+
+ setEnabled(fTarget != null && fTarget.canPerformFind());
+ }
+
+ /**
+ * @see FindReplaceDialog#findIndex(String, int, boolean, boolean, boolean, boolean)
+ */
+ private int findIndex(String findString, int startPosition, boolean forwardSearch, boolean caseSensitive, boolean wrapSearch, boolean wholeWord) {
+
+ if (forwardSearch) {
+ if (wrapSearch) {
+ int index= fTarget.findAndSelect(startPosition, findString, true, caseSensitive, wholeWord);
+ if (index == -1)
+ index= fTarget.findAndSelect(-1, findString, true, caseSensitive, wholeWord);
+ return index;
+ }
+ return fTarget.findAndSelect(startPosition, findString, true, caseSensitive, wholeWord);
+ }
+
+ // backward
+ if (wrapSearch) {
+ int index= fTarget.findAndSelect(startPosition - 1, findString, false, caseSensitive, wholeWord);
+ if (index == -1) {
+ index= fTarget.findAndSelect(-1, findString, false, caseSensitive, wholeWord);
+ }
+ return index;
+ }
+ return fTarget.findAndSelect(startPosition - 1, findString, false, caseSensitive, wholeWord);
+ }
+
+ /**
+ * Returns whether the specified search string can be found using the given options.
+ * @param findString the string to search for
+ * @param forwardSearch the search direction
+ * @param caseSensitive should the search honor cases
+ * @param wrapSearch should the search wrap to the start/end if end/start reached
+ * @param wholeWord does the find string represent a complete word
+ * @return <code>true</code> if the find string can be found using the given options
+ */
+ private boolean findNext(String findString, boolean forwardSearch, boolean caseSensitive, boolean wrapSearch, boolean wholeWord) {
+
+ Point r= fTarget.getSelection();
+ int findReplacePosition= r.x;
+ if (forwardSearch)
+ findReplacePosition += r.y;
+
+ int index= findIndex(findString, findReplacePosition, forwardSearch, caseSensitive, wrapSearch, wholeWord);
+
+ if (index != -1)
+ return true;
+
+ return false;
+ }
+
+ //--------------- configuration handling --------------
+
+ /**
+ * Returns the dialog settings object used to share state
+ * between several find/replace dialogs.
+ *
+ * @return the dialog settings to be used
+ */
+ private IDialogSettings getDialogSettings() {
+ AbstractUIPlugin plugin= (AbstractUIPlugin) Platform.getPlugin(PlatformUI.PLUGIN_ID);
+ IDialogSettings settings= plugin.getDialogSettings();
+ fDialogSettings= settings.getSection(FindReplaceDialog.class.getName());
+ if (fDialogSettings == null)
+ fDialogSettings= settings.addNewSection(FindReplaceDialog.class.getName());
+ return fDialogSettings;
+ }
+
+ /**
+ * Initializes itself from the dialog settings with the same state
+ * as at the previous invocation.
+ */
+ private void readConfiguration() {
+ IDialogSettings s= getDialogSettings();
+
+ fWrapInit= s.getBoolean("wrap"); //$NON-NLS-1$
+ fCaseInit= s.getBoolean("casesensitive"); //$NON-NLS-1$
+ fWholeWordInit= s.getBoolean("wholeword"); //$NON-NLS-1$
+
+ String[] findHistory= s.getArray("findhistory"); //$NON-NLS-1$
+ if (findHistory != null) {
+ fFindHistory.clear();
+ for (int i= 0; i < findHistory.length; i++)
+ fFindHistory.add(findHistory[i]);
+ }
+ }
+
+ /**
+ * Stores it current configuration in the dialog store.
+ */
+ private void writeConfiguration() {
+ IDialogSettings s= getDialogSettings();
+
+ if (fFindString == null)
+ return;
+
+ if (!fFindHistory.isEmpty() && fFindString.equals(fFindHistory.get(0)))
+ return;
+
+ int index= fFindHistory.indexOf(fFindString);
+ if (index != -1)
+ fFindHistory.remove(index);
+ fFindHistory.add(0, fFindString);
+
+ while (fFindHistory.size() > 8)
+ fFindHistory.remove(8);
+ String[] names= new String[fFindHistory.size()];
+ fFindHistory.toArray(names);
+ s.put("findhistory", names); //$NON-NLS-1$
+ }
+
+ /**
+ * Returns the actual selection of the find replace target
+ */
+ private String getSelectionString() {
+
+ /*
+ * 1GF86V3: ITPUI:WINNT - Internal errors using Find/Replace Dialog
+ * Now uses TextUtilities rather than focussing on '\n'
+ */
+ String selection= fTarget.getSelectionText();
+ if (selection != null && selection.length() > 0) {
+ int[] info= TextUtilities.indexOf(TextUtilities.fgDelimiters, selection, 0);
+ if (info[0] > 0)
+ return selection.substring(0, info[0]);
+ else if (info[0] == -1)
+ return selection;
+ }
+ return null;
+ }
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceAction.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceAction.java
new file mode 100644
index 000000000..8cb344485
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceAction.java
@@ -0,0 +1,244 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+
+import java.util.ResourceBundle; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.widgets.Shell; import org.eclipse.jface.text.IFindReplaceTarget; import org.eclipse.ui.IPartListener; import org.eclipse.ui.IPartService; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchPartSite; import org.eclipse.ui.IWorkbenchWindow;
+
+
+/**
+ * An action which opens a Find/Replace dialog.
+ * The dialog while open, tracks the active workbench part
+ * and retargets itself to the active find/replace target.
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ *
+ * @see IFindReplaceTarget
+ */
+public class FindReplaceAction extends ResourceAction implements IUpdate {
+
+ /**
+ * Represents the "global" find/replace dialog. It tracks the active
+ * part and retargets the find/replace dialog accordingly. The find/replace
+ * target is retrieved from the active part using
+ * <code>getAdapter(IFindReplaceTarget.class)</code>.
+ * <p>
+ * The stub has the same life cycle as the find/replace dialog.
+ */
+ class FindReplaceDialogStub implements IPartListener, DisposeListener {
+
+ private IWorkbenchPart fPart;
+ private IWorkbenchPart fPreviousPart;
+ private IFindReplaceTarget fPreviousTarget;
+
+ private IWorkbenchWindow fWindow;
+ private FindReplaceDialog fDialog;
+
+ /**
+ * Creates a new find/replace dialog accessor anchored at the given part site.
+ * @param site the part site
+ */
+ public FindReplaceDialogStub(IWorkbenchPartSite site) {
+
+ fWindow= site.getWorkbenchWindow();
+
+ fDialog= new FindReplaceDialog(site.getShell());
+ fDialog.create();
+ fDialog.getShell().addDisposeListener(this);
+
+ IPartService service= fWindow.getPartService();
+ service.addPartListener(this);
+ partActivated(service.getActivePart());
+ }
+
+ /**
+ * Returns the find/replace dialog.
+ * @return the find/replace dialog
+ */
+ public FindReplaceDialog getDialog() {
+ return fDialog;
+ }
+
+ /*
+ * @see IPartListener#partActivated(IWorkbenchPart)
+ */
+ public void partActivated(IWorkbenchPart part) {
+
+ IFindReplaceTarget target= part == null ? null : (IFindReplaceTarget) part.getAdapter(IFindReplaceTarget.class);
+ fPreviousPart= fPart;
+ fPart= target == null ? null : part;
+
+ if (fPreviousTarget != target) {
+ fPreviousTarget= target;
+ if (fDialog != null) {
+ boolean isEditable= false;
+ if (fPart instanceof ITextEditorExtension) {
+ ITextEditorExtension extension= (ITextEditorExtension) fPart;
+ isEditable= !extension.isEditorInputReadOnly();
+ }
+ fDialog.updateTarget(target, isEditable);
+ }
+ }
+ }
+
+ /*
+ * @see IPartListener#partClosed(IWorkbenchPart)
+ */
+ public void partClosed(IWorkbenchPart part) {
+
+ if (part == fPreviousPart) {
+ fPreviousPart= null;
+ fPreviousTarget= null;
+ }
+
+ if (part == fPart)
+ partActivated(null);
+ }
+
+ /*
+ * @see DisposeListener#widgetDisposed(DisposeEvent)
+ */
+ public void widgetDisposed(DisposeEvent event) {
+
+ if (fgFindReplaceDialogStub == this)
+ fgFindReplaceDialogStub= null;
+
+ if (fWindow != null) {
+ fWindow.getPartService().removePartListener(this);
+ fWindow= null;
+ }
+ fDialog= null;
+ fPart= null;
+ fPreviousPart= null;
+ fPreviousTarget= null;
+ }
+
+ /*
+ * @see IPartListener#partOpened(IWorkbenchPart)
+ */
+ public void partOpened(IWorkbenchPart part) {}
+
+ /*
+ * @see IPartListener#partDeactivated(IWorkbenchPart)
+ */
+ public void partDeactivated(IWorkbenchPart part) {}
+
+ /*
+ * @see IPartListener#partBroughtToTop(IWorkbenchPart)
+ */
+ public void partBroughtToTop(IWorkbenchPart part) {}
+ };
+
+
+ /** Lister for disabling the dialog on editor close */
+ private static FindReplaceDialogStub fgFindReplaceDialogStub;
+ /** The action's target */
+ private IFindReplaceTarget fTarget;
+ /** The part the action is bound to */
+ private IWorkbenchPart fWorkbenchPart;
+ /** The workbench window */
+ private IWorkbenchWindow fWorkbenchWindow;
+ /**
+ * Indicates whether the find/replace target is editable
+ * @since 2.0
+ */
+ private boolean fIsTargetEditable= false;
+
+ /**
+ * Creates a new find/replace action for the given text editor.
+ * The action configures its visual representation from the given
+ * resource bundle.
+ *
+ * @param bundle the resource bundle
+ * @param prefix a prefix to be prepended to the various resource keys
+ * (described in <code>ResourceAction</code> constructor), or
+ * <code>null</code> if none
+ * @param editor the text editor
+ * @see ResourceAction#ResourceAction
+ */
+ public FindReplaceAction(ResourceBundle bundle, String prefix, IWorkbenchPart workbenchPart) {
+ super(bundle, prefix);
+ fWorkbenchPart= workbenchPart;
+ update();
+ }
+
+ /**
+ * Creates a new find/replace action for the given text editor.
+ * The action configures its visual representation from the given
+ * resource bundle.
+ *
+ * @param bundle the resource bundle
+ * @param prefix a prefix to be prepended to the various resource keys
+ * (described in <code>ResourceAction</code> constructor), or
+ * <code>null</code> if none
+ * @param workbenchWindow the workbench window
+ * @see ResourceAction#ResourceAction
+ *
+ * @deprecated use FindReplaceAction(ResourceBundle, String, IWorkbenchPart) instead
+ */
+ public FindReplaceAction(ResourceBundle bundle, String prefix, IWorkbenchWindow workbenchWindow) {
+ super(bundle, prefix);
+ fWorkbenchWindow= workbenchWindow;
+ update();
+ }
+
+ /*
+ * @see IAction#run
+ */
+ public void run() {
+ if (fTarget != null) {
+
+ if (fgFindReplaceDialogStub != null) {
+ Shell shell= fWorkbenchPart.getSite().getShell();
+ FindReplaceDialog dialog= fgFindReplaceDialogStub.getDialog();
+ if (dialog != null && shell != dialog.getParentShell()) {
+ fgFindReplaceDialogStub= null; // here to avoid timing issues
+ dialog.close();
+ }
+ }
+
+ if (fgFindReplaceDialogStub == null)
+ fgFindReplaceDialogStub= new FindReplaceDialogStub(fWorkbenchPart.getSite());
+
+ FindReplaceDialog dialog= fgFindReplaceDialogStub.getDialog();
+ dialog.updateTarget(fTarget, fIsTargetEditable);
+ dialog.open();
+ }
+ }
+
+ /*
+ * @see IUpdate#update()
+ */
+ public void update() {
+
+ if (fWorkbenchPart == null && fWorkbenchWindow != null)
+ fWorkbenchPart= fWorkbenchWindow.getPartService().getActivePart();
+
+ if (fWorkbenchPart instanceof ITextEditorExtension) {
+ ITextEditorExtension extension= (ITextEditorExtension) fWorkbenchPart;
+ fIsTargetEditable= !extension.isEditorInputReadOnly();
+ }
+
+ if (fWorkbenchPart != null)
+ fTarget= (IFindReplaceTarget) fWorkbenchPart.getAdapter(IFindReplaceTarget.class);
+ else
+ fTarget= null;
+
+ setEnabled(fTarget != null && fTarget.canPerformFind());
+
+// if (fgFindReplaceDialogStub != null) {
+// FindReplaceDialog dialog= fgFindReplaceDialogStub.getDialog();
+// dialog.updateTarget(fTarget, fIsTargetEditable);
+// }
+ }
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceDialog.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceDialog.java
new file mode 100644
index 000000000..8b02cc1ce
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceDialog.java
@@ -0,0 +1,1390 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.events.ShellAdapter;
+import org.eclipse.swt.events.ShellEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+
+import org.eclipse.core.runtime.Platform;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.text.IFindReplaceTarget;
+import org.eclipse.jface.text.IFindReplaceTargetExtension;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.Region;
+
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.help.WorkbenchHelp;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+
+
+/**
+ * Find/Replace dialog. The dialog is opened on a particular
+ * target but can be re-targeted. Internally used by the <code>FindReplaceAction</code>
+ */
+class FindReplaceDialog extends Dialog {
+
+ /**
+ * Updates the find replace dialog on activation changes.
+ */
+ class ActivationListener extends ShellAdapter {
+
+ /*
+ * @see ShellListener#shellActivated(ShellEvent)
+ */
+ public void shellActivated(ShellEvent e) {
+
+ String oldText= fFindField.getText(); // XXX workaround for 10766
+ List oldList= new ArrayList();
+ oldList.addAll(fFindHistory);
+
+ readConfiguration();
+ updateCombo(fFindField, fFindHistory);
+
+ fFindField.removeModifyListener(fFindModifyListener);
+ if (!fFindHistory.equals(oldList) && !fFindHistory.isEmpty())
+ fFindField.setText((String) fFindHistory.get(0));
+ else
+ fFindField.setText(oldText);
+ fFindField.addModifyListener(fFindModifyListener);
+
+ fActiveShell= (Shell) e.widget;
+ updateButtonState();
+ if (getShell() == fActiveShell && !fFindField.isDisposed())
+ fFindField.setFocus();
+ }
+
+ /*
+ * @see ShellListener#shellDeactivated(ShellEvent)
+ */
+ public void shellDeactivated(ShellEvent e) {
+ storeSettings();
+
+ fGlobalRadioButton.setSelection(true);
+ fSelectedRangeRadioButton.setSelection(false);
+
+ if (fTarget != null && (fTarget instanceof IFindReplaceTargetExtension))
+ ((IFindReplaceTargetExtension) fTarget).setScope(null);
+
+ fOldScope= null;
+
+ fActiveShell= null;
+ updateButtonState();
+ }
+ }
+
+ /**
+ * Modify listener to update the search result in case of incremental search.
+ * @since 2.0
+ */
+ private class FindModifyListener implements ModifyListener {
+
+ /*
+ * @see ModifyListener#modifyText(ModifyEvent)
+ */
+ public void modifyText(ModifyEvent e) {
+ if (isIncrementalSearch()) {
+ if (fFindField.getText().equals("") && fTarget != null) { //$NON-NLS-1$
+ // empty selection at base location
+ int offset= isForwardSearch()
+ ? fIncrementalBaseLocation.x + fIncrementalBaseLocation.y
+ : fIncrementalBaseLocation.x;
+
+ fTarget.findAndSelect(offset, "", isForwardSearch(), isCaseSensitiveSearch(), isWholeWordSearch()); //$NON-NLS-1$
+ } else {
+ performSearch();
+ }
+ }
+
+ updateButtonState();
+ }
+ }
+
+ /** The size of the dialogs search history. */
+ private static final int HISTORY_SIZE= 5;
+
+ private Point fLocation;
+ private Point fIncrementalBaseLocation;
+ private boolean fWrapInit, fCaseInit, fWholeWordInit, fForwardInit, fGlobalInit, fIncrementalInit;
+ private List fFindHistory;
+ private List fReplaceHistory;
+ private IRegion fOldScope;
+
+ private boolean fIsTargetEditable;
+ private IFindReplaceTarget fTarget;
+ private Shell fParentShell;
+ private Shell fActiveShell;
+
+ private ActivationListener fActivationListener= new ActivationListener();
+ private ModifyListener fFindModifyListener= new FindModifyListener();
+
+ private Label fReplaceLabel, fStatusLabel;
+ private Button fForwardRadioButton, fGlobalRadioButton, fSelectedRangeRadioButton;
+ private Button fCaseCheckBox, fWrapCheckBox, fWholeWordCheckBox, fIncrementalCheckBox;
+ private Button fReplaceSelectionButton, fReplaceFindButton, fFindNextButton, fReplaceAllButton;
+ private Combo fFindField, fReplaceField;
+ private Rectangle fDialogPositionInit;
+
+ private IDialogSettings fDialogSettings;
+
+ /**
+ * Creates a new dialog with the given shell as parent.
+ * @param parentShell the parent shell
+ */
+ public FindReplaceDialog(Shell parentShell) {
+ super(parentShell);
+
+ fParentShell= null;
+ fTarget= null;
+
+ fDialogPositionInit= null;
+ fFindHistory= new ArrayList(HISTORY_SIZE - 1);
+ fReplaceHistory= new ArrayList(HISTORY_SIZE - 1);
+
+ fWrapInit= false;
+ fCaseInit= false;
+ fWholeWordInit= false;
+ fIncrementalInit= false;
+ fGlobalInit= true;
+ fForwardInit= true;
+
+ readConfiguration();
+
+ setShellStyle(SWT.CLOSE | SWT.MODELESS | SWT.BORDER | SWT.TITLE);
+ setBlockOnOpen(false);
+ }
+
+ /**
+ * Returns this dialog's parent shell.
+ * @return the dialog's parent shell
+ */
+ public Shell getParentShell() {
+ return super.getParentShell();
+ }
+
+
+ /**
+ * Returns <code>true</code> if control can be used
+ *
+ * @param control the control to be checked
+ * @return <code>true</code> if control can be used
+ */
+ private boolean okToUse(Control control) {
+ return control != null && !control.isDisposed();
+ }
+
+ /*
+ * @see Window#create
+ */
+ public void create() {
+
+ super.create();
+
+ Shell shell= getShell();
+ shell.addShellListener(fActivationListener);
+ if (fLocation != null)
+ shell.setLocation(fLocation);
+
+ // set help context
+ WorkbenchHelp.setHelp(shell, IAbstractTextEditorHelpContextIds.FIND_REPLACE_DIALOG);
+
+ // fill in combo contents
+ updateCombo(fFindField, fFindHistory);
+ updateCombo(fReplaceField, fReplaceHistory);
+
+ // get find string
+ initFindStringFromSelection();
+
+ // set dialog position
+ if (fDialogPositionInit != null)
+ shell.setBounds(fDialogPositionInit);
+
+ shell.setText(EditorMessages.getString("FindReplace.title")); //$NON-NLS-1$
+ // shell.setImage(null);
+ }
+
+ /**
+ * Create the button section of the find/replace dialog
+ *
+ * @param parent the parent composite
+ * @return the button section
+ */
+ private Composite createButtonSection(Composite parent) {
+
+ Composite panel= new Composite(parent, SWT.NULL);
+ GridLayout layout= new GridLayout();
+ layout.numColumns= -2;
+ layout.makeColumnsEqualWidth= true;
+ panel.setLayout(layout);
+
+ fFindNextButton= makeButton(panel, "FindReplace.FindNextButton.label", 102, true, new SelectionAdapter() { //$NON-NLS-1$
+ public void widgetSelected(SelectionEvent e) {
+ if (isIncrementalSearch())
+ initIncrementalBaseLocation();
+
+ performSearch();
+ updateFindHistory();
+ fFindNextButton.setFocus();
+ }
+ });
+ setGridData(fFindNextButton, GridData.FILL, true, GridData.FILL, false);
+
+ fReplaceFindButton= makeButton(panel, "FindReplace.ReplaceFindButton.label", 103, false, new SelectionAdapter() { //$NON-NLS-1$
+ public void widgetSelected(SelectionEvent e) {
+ performReplaceSelection();
+ performSearch();
+ updateFindAndReplaceHistory();
+ fReplaceFindButton.setFocus();
+ }
+ });
+ setGridData(fReplaceFindButton, GridData.FILL, true, GridData.FILL, false);
+
+ fReplaceSelectionButton= makeButton(panel, "FindReplace.ReplaceSelectionButton.label", 104, false, new SelectionAdapter() { //$NON-NLS-1$
+ public void widgetSelected(SelectionEvent e) {
+ performReplaceSelection();
+ updateFindAndReplaceHistory();
+ fFindNextButton.setFocus();
+ }
+ });
+ setGridData(fReplaceSelectionButton, GridData.FILL, true, GridData.FILL, false);
+
+ fReplaceAllButton= makeButton(panel, "FindReplace.ReplaceAllButton.label", 105, false, new SelectionAdapter() { //$NON-NLS-1$
+ public void widgetSelected(SelectionEvent e) {
+ performReplaceAll();
+ updateFindAndReplaceHistory();
+ fFindNextButton.setFocus();
+ }
+ });
+ setGridData(fReplaceAllButton, GridData.FILL, true, GridData.FILL, false);
+
+ // Make the all the buttons the same size as the Remove Selection button.
+ fReplaceAllButton.setEnabled(isEditable());
+
+ return panel;
+ }
+
+ /**
+ * Creates the options configuration section of the find replace dialog.
+ *
+ * @param parent the parent composite
+ * @return the options configuration section
+ */
+ private Composite createConfigPanel(Composite parent) {
+
+ Composite panel= new Composite(parent, SWT.NULL);
+ GridLayout layout= new GridLayout();
+ layout.numColumns= 2;
+ layout.makeColumnsEqualWidth= true;
+ panel.setLayout(layout);
+
+ Composite directionGroup= createDirectionGroup(panel);
+ setGridData(directionGroup, GridData.FILL, true, GridData.FILL, false);
+ Composite scopeGroup= createScopeGroup(panel);
+ setGridData(scopeGroup, GridData.FILL, true, GridData.FILL, false);
+
+ Composite optionsGroup= createOptionsGroup(panel);
+ setGridData(optionsGroup, GridData.FILL, true, GridData.FILL, false);
+ GridData data= (GridData) optionsGroup.getLayoutData();
+ data.horizontalSpan= 2;
+ optionsGroup.setLayoutData(data);
+
+ return panel;
+ }
+
+ /*
+ * @see Window#createContents
+ */
+ protected Control createContents(Composite parent) {
+
+ Composite panel= new Composite(parent, SWT.NULL);
+ GridLayout layout= new GridLayout();
+ layout.numColumns= 1;
+ layout.makeColumnsEqualWidth= true;
+ panel.setLayout(layout);
+
+ Composite inputPanel= createInputPanel(panel);
+ setGridData(inputPanel, GridData.FILL, true, GridData.CENTER, false);
+
+ Composite configPanel= createConfigPanel(panel);
+ setGridData(configPanel, GridData.FILL, true, GridData.CENTER, true);
+
+ Composite buttonPanelB= createButtonSection(panel);
+ setGridData(buttonPanelB, GridData.FILL, true, GridData.CENTER, false);
+
+ Composite statusBar= createStatusAndCloseButton(panel);
+ setGridData(statusBar, GridData.FILL, true, GridData.CENTER, false);
+
+ updateButtonState();
+
+ return panel;
+ }
+
+ /**
+ * Creates the direction defining part of the options defining section
+ * of the find replace dialog.
+ *
+ * @param parent the parent composite
+ * @return the direction defining part
+ */
+ private Composite createDirectionGroup(Composite parent) {
+
+ Composite panel= new Composite(parent, SWT.NONE);
+ GridLayout layout= new GridLayout();
+ layout.marginWidth= 0;
+ layout.marginHeight= 0;
+ panel.setLayout(layout);
+
+ Group group= new Group(panel, SWT.SHADOW_ETCHED_IN);
+ group.setText(EditorMessages.getString("FindReplace.Direction")); //$NON-NLS-1$
+ GridLayout groupLayout= new GridLayout();
+ group.setLayout(groupLayout);
+ group.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ SelectionListener selectionListener= new SelectionListener() {
+ public void widgetSelected(SelectionEvent e) {
+ if (isIncrementalSearch())
+ initIncrementalBaseLocation();
+ }
+
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+ };
+
+ fForwardRadioButton= new Button(group, SWT.RADIO | SWT.LEFT);
+ fForwardRadioButton.setText(EditorMessages.getString("FindReplace.ForwardRadioButton.label")); //$NON-NLS-1$
+ setGridData(fForwardRadioButton, GridData.BEGINNING, false, GridData.CENTER, false);
+ fForwardRadioButton.addSelectionListener(selectionListener);
+
+ Button backwardRadioButton= new Button(group, SWT.RADIO | SWT.LEFT);
+ backwardRadioButton.setText(EditorMessages.getString("FindReplace.BackwardRadioButton.label")); //$NON-NLS-1$
+ setGridData(backwardRadioButton, GridData.BEGINNING, false, GridData.CENTER, false);
+ backwardRadioButton.addSelectionListener(selectionListener);
+
+ backwardRadioButton.setSelection(!fForwardInit);
+ fForwardRadioButton.setSelection(fForwardInit);
+
+ return panel;
+ }
+
+ /**
+ * Creates the scope defining part of the find replace dialog.
+ *
+ * @param parent the parent composite
+ * @return the scope defining part
+ * @since 2.0
+ */
+ private Composite createScopeGroup(Composite parent) {
+
+ Composite panel= new Composite(parent, SWT.NONE);
+ GridLayout layout= new GridLayout();
+ layout.marginWidth= 0;
+ layout.marginHeight= 0;
+ panel.setLayout(layout);
+
+ Group group= new Group(panel, SWT.SHADOW_ETCHED_IN);
+ group.setText(EditorMessages.getString("FindReplace.Scope")); //$NON-NLS-1$
+ GridLayout groupLayout= new GridLayout();
+ group.setLayout(groupLayout);
+ group.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ fGlobalRadioButton= new Button(group, SWT.RADIO | SWT.LEFT);
+ fGlobalRadioButton.setText(EditorMessages.getString("FindReplace.GlobalRadioButton.label")); //$NON-NLS-1$
+ setGridData(fGlobalRadioButton, GridData.BEGINNING, false, GridData.CENTER, false);
+ fGlobalRadioButton.setSelection(fGlobalInit);
+ fGlobalRadioButton.addSelectionListener(new SelectionListener() {
+ public void widgetSelected(SelectionEvent e) {
+ if (!fGlobalRadioButton.getSelection())
+ return;
+
+ useSelectedLines(false);
+ }
+
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+ });
+
+ fSelectedRangeRadioButton= new Button(group, SWT.RADIO | SWT.LEFT);
+ fSelectedRangeRadioButton.setText(EditorMessages.getString("FindReplace.SelectedRangeRadioButton.label")); //$NON-NLS-1$
+ setGridData(fSelectedRangeRadioButton, GridData.BEGINNING, false, GridData.CENTER, false);
+ fSelectedRangeRadioButton.setSelection(!fGlobalInit);
+ fSelectedRangeRadioButton.addSelectionListener(new SelectionListener() {
+ public void widgetSelected(SelectionEvent e) {
+ if (!fSelectedRangeRadioButton.getSelection())
+ return;
+
+ useSelectedLines(true);
+ }
+
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+ });
+
+ return panel;
+ }
+
+ /**
+ * Tells the dialog to perform searches only in the scope given by the actually selected lines.
+ * @param selectedLines <code>true</code> if selected lines should be used
+ * @since 2.0
+ */
+ private void useSelectedLines(boolean selectedLines) {
+ if (isIncrementalSearch())
+ initIncrementalBaseLocation();
+
+ if (fTarget == null || !(fTarget instanceof IFindReplaceTargetExtension))
+ return;
+
+ IFindReplaceTargetExtension extensionTarget= (IFindReplaceTargetExtension) fTarget;
+
+ if (selectedLines) {
+
+ IRegion scope;
+ if (fOldScope == null) {
+ Point lineSelection= extensionTarget.getLineSelection();
+ scope= new Region(lineSelection.x, lineSelection.y);
+ } else {
+ scope= fOldScope;
+ fOldScope= null;
+ }
+
+ int offset= isForwardSearch()
+ ? scope.getOffset()
+ : scope.getOffset() + scope.getLength();
+
+ extensionTarget.setSelection(offset, 0);
+ extensionTarget.setScope(scope);
+ } else {
+ fOldScope= extensionTarget.getScope();
+ extensionTarget.setScope(null);
+ }
+ }
+
+ /**
+ * Create the panel where the user specifies the text to search
+ * for and the optional replacement text
+ *
+ * @param parent the parent composite
+ * @return the input panel
+ */
+ private Composite createInputPanel(Composite parent) {
+
+ ModifyListener listener= new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ updateButtonState();
+ }
+ };
+
+ Composite panel= new Composite(parent, SWT.NULL);
+ GridLayout layout= new GridLayout();
+ layout.numColumns= 2;
+ panel.setLayout(layout);
+
+ Label findLabel= new Label(panel, SWT.LEFT);
+ findLabel.setText(EditorMessages.getString("FindReplace.Find.label")); //$NON-NLS-1$
+ setGridData(findLabel, GridData.BEGINNING, false, GridData.CENTER, false);
+
+ fFindField= new Combo(panel, SWT.DROP_DOWN | SWT.BORDER);
+ setGridData(fFindField, GridData.FILL, true, GridData.CENTER, false);
+ fFindField.addModifyListener(fFindModifyListener);
+
+ fReplaceLabel= new Label(panel, SWT.LEFT);
+ fReplaceLabel.setText(EditorMessages.getString("FindReplace.Replace.label")); //$NON-NLS-1$
+ setGridData(fReplaceLabel, GridData.BEGINNING, false, GridData.CENTER, false);
+
+ fReplaceField= new Combo(panel, SWT.DROP_DOWN | SWT.BORDER);
+ setGridData(fReplaceField, GridData.FILL, true, GridData.CENTER, false);
+ fReplaceField.addModifyListener(listener);
+
+ return panel;
+ }
+
+ /**
+ * Creates the functional options part of the options defining
+ * section of the find replace dialog.
+ *
+ * @param the parent composite
+ * @return the options group
+ */
+ private Composite createOptionsGroup(Composite parent) {
+
+ Composite panel= new Composite(parent, SWT.NULL);
+ GridLayout layout= new GridLayout();
+ layout.marginWidth= 0;
+ layout.marginHeight= 0;
+ panel.setLayout(layout);
+
+ Group group= new Group(panel, SWT.SHADOW_NONE);
+ group.setText(EditorMessages.getString("FindReplace.Options")); //$NON-NLS-1$
+ GridLayout groupLayout= new GridLayout();
+ groupLayout.numColumns= 2;
+ groupLayout.makeColumnsEqualWidth= true;
+ group.setLayout(groupLayout);
+ group.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ SelectionListener selectionListener= new SelectionListener() {
+ public void widgetSelected(SelectionEvent e) {
+ storeSettings();
+ }
+
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+ };
+
+ fCaseCheckBox= new Button(group, SWT.CHECK | SWT.LEFT);
+ fCaseCheckBox.setText(EditorMessages.getString("FindReplace.CaseCheckBox.label")); //$NON-NLS-1$
+ setGridData(fCaseCheckBox, GridData.BEGINNING, false, GridData.CENTER, false);
+ fCaseCheckBox.setSelection(fCaseInit);
+ fCaseCheckBox.addSelectionListener(selectionListener);
+
+ fWrapCheckBox= new Button(group, SWT.CHECK | SWT.LEFT);
+ fWrapCheckBox.setText(EditorMessages.getString("FindReplace.WrapCheckBox.label")); //$NON-NLS-1$
+ setGridData(fWrapCheckBox, GridData.BEGINNING, false, GridData.CENTER, false);
+ fWrapCheckBox.setSelection(fWrapInit);
+ fWrapCheckBox.addSelectionListener(selectionListener);
+
+ fWholeWordCheckBox= new Button(group, SWT.CHECK | SWT.LEFT);
+ fWholeWordCheckBox.setText(EditorMessages.getString("FindReplace.WholeWordCheckBox.label")); //$NON-NLS-1$
+ setGridData(fWholeWordCheckBox, GridData.BEGINNING, false, GridData.CENTER, false);
+ fWholeWordCheckBox.setSelection(fWholeWordInit);
+ fWholeWordCheckBox.addSelectionListener(selectionListener);
+
+ fIncrementalCheckBox= new Button(group, SWT.CHECK | SWT.LEFT);
+ fIncrementalCheckBox.setText(EditorMessages.getString("FindReplace.IncrementalCheckBox.label")); //$NON-NLS-1$
+ setGridData(fIncrementalCheckBox, GridData.BEGINNING, false, GridData.CENTER, false);
+ fIncrementalCheckBox.setSelection(fIncrementalInit);
+ fIncrementalCheckBox.addSelectionListener(new SelectionListener() {
+ public void widgetSelected(SelectionEvent e) {
+ if (isIncrementalSearch())
+ initIncrementalBaseLocation();
+
+ storeSettings();
+ }
+
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+ });
+
+ return panel;
+ }
+
+ /**
+ * Creates the status and close section of the dialog.
+ *
+ * @param parent the parent composite
+ * @return the status and close button
+ */
+ private Composite createStatusAndCloseButton(Composite parent) {
+
+ Composite panel= new Composite(parent, SWT.NULL);
+ GridLayout layout= new GridLayout();
+ layout.numColumns= 2;
+ layout.marginWidth= 0;
+ layout.marginHeight= 0;
+ panel.setLayout(layout);
+
+ fStatusLabel= new Label(panel, SWT.LEFT);
+ setGridData(fStatusLabel, GridData.FILL, true, GridData.CENTER, false);
+
+ String label= EditorMessages.getString("FindReplace.CloseButton.label"); //$NON-NLS-1$
+ Button closeButton= createButton(panel, 101, label, false);
+ setGridData(closeButton, GridData.END, false, GridData.END, false);
+
+ return panel;
+ }
+
+ /*
+ * @see Dialog#buttonPressed
+ */
+ protected void buttonPressed(int buttonID) {
+ if (buttonID == 101)
+ close();
+ }
+
+
+
+ // ------- action invocation ---------------------------------------
+
+ /**
+ * Returns the position of the specified search string, or <code>-1</code> if the string can
+ * not be found when searching using the given options.
+ *
+ * @param findString the string to search for
+ * @param startPosition the position at which to start the search
+ * @param forwardSearch the direction of the search
+ * @param caseSensitive should the search be case sensitive
+ * @param wrapSearch should the search wrap to the start/end if arrived at the end/start
+ * @param wholeWord does the search string represent a complete word
+ * @return the occurrence of the find string following the options or <code>-1</code> if nothing found
+ */
+ private int findIndex(String findString, int startPosition, boolean forwardSearch, boolean caseSensitive, boolean wrapSearch, boolean wholeWord) {
+
+ if (forwardSearch) {
+ if (wrapSearch) {
+ int index= fTarget.findAndSelect(startPosition, findString, true, caseSensitive, wholeWord);
+ if (index == -1)
+ index= fTarget.findAndSelect(-1, findString, true, caseSensitive, wholeWord);
+ return index;
+ }
+ return fTarget.findAndSelect(startPosition, findString, true, caseSensitive, wholeWord);
+ }
+
+ // backward
+ if (wrapSearch) {
+ int index= fTarget.findAndSelect(startPosition - 1, findString, false, caseSensitive, wholeWord);
+ if (index == -1) {
+ index= fTarget.findAndSelect(-1, findString, false, caseSensitive, wholeWord);
+ }
+ return index;
+ }
+ return fTarget.findAndSelect(startPosition - 1, findString, false, caseSensitive, wholeWord);
+ }
+
+ /**
+ * Returns whether the specified search string can be found using the given options.
+ *
+ * @param findString the string to search for
+ * @param forwardSearch the direction of the search
+ * @param caseSensitive should the search be case sensitive
+ * @param wrapSearch should the search wrap to the start/end if arrived at the end/start
+ * @param wholeWord does the search string represent a complete word
+ * @param incremental is this an incremental search
+ * @param global is the search scope the whoel document
+ * @return <code>true</code> if the search string can be found using the given options
+ * @since 2.0
+ */
+ private boolean findNext(String findString, boolean forwardSearch, boolean caseSensitive, boolean wrapSearch, boolean wholeWord, boolean incremental, boolean global) {
+
+ if (fTarget == null)
+ return false;
+
+ Point r= fTarget.getSelection();
+ int findReplacePosition= r.x;
+ if (forwardSearch)
+ findReplacePosition += r.y;
+
+ if (incremental)
+ findReplacePosition= forwardSearch
+ ? fIncrementalBaseLocation.x + fIncrementalBaseLocation.y
+ : fIncrementalBaseLocation.x;
+
+ int index= findIndex(findString, findReplacePosition, forwardSearch, caseSensitive, wrapSearch, wholeWord);
+
+ if (index != -1)
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Returns the dialog's boundaries.
+ * @return the dialog's boundaries
+ */
+ private Rectangle getDialogBoundaries() {
+ if (okToUse(getShell())) {
+ return getShell().getBounds();
+ } else {
+ return fDialogPositionInit;
+ }
+ }
+
+ /**
+ * Returns the dialog's history.
+ * @return the dialog's history
+ */
+ private List getFindHistory() {
+ return fFindHistory;
+ }
+
+ // ------- accessors ---------------------------------------
+
+ /**
+ * Retrieves the string to search for from the appriopriate text input field and returns it.
+ * @return the search string
+ */
+ private String getFindString() {
+ if (okToUse(fFindField)) {
+ return fFindField.getText();
+ }
+ return ""; //$NON-NLS-1$
+ }
+
+ /**
+ * Returns the dialog's replace history.
+ * @return the dialog's replace history
+ */
+ private List getReplaceHistory() {
+ return fReplaceHistory;
+ }
+
+ /**
+ * Retrieves the replacement string from the appriopriate text input field and returns it.
+ * @return the replacement string
+ */
+ private String getReplaceString() {
+ if (okToUse(fReplaceField)) {
+ return fReplaceField.getText();
+ }
+ return ""; //$NON-NLS-1$
+ }
+
+ // ------- init / close ---------------------------------------
+
+ /**
+ * Returns the actual selection of the find replace target
+ * @return the selection of the target
+ */
+ private String getSelectionString() {
+
+ /*
+ * 1GF86V3: ITPUI:WINNT - Internal errors using Find/Replace Dialog
+ * Now uses TextUtilities rather than focussing on '\n'
+ */
+ String selection= fTarget.getSelectionText();
+ if (selection != null && selection.length() > 0) {
+ int[] info= TextUtilities.indexOf(TextUtilities.fgDelimiters, selection, 0);
+ if (info[0] > 0)
+ return selection.substring(0, info[0]);
+ else if (info[0] == -1)
+ return selection;
+ }
+ return null;
+ }
+
+ /*
+ * @see Window#close()
+ */
+ public boolean close() {
+ handleDialogClose();
+ return super.close();
+ }
+
+ /**
+ * Removes focus changed listener from browser and stores settings for re-open.
+ */
+ private void handleDialogClose() {
+
+ // remove listeners
+ if (fParentShell != null) {
+ fParentShell.removeShellListener(fActivationListener);
+ fParentShell= null;
+ }
+
+ getShell().removeShellListener(fActivationListener);
+
+ // store current settings in case of re-open
+ storeSettings();
+
+ if (fTarget != null && fTarget instanceof IFindReplaceTargetExtension)
+ ((IFindReplaceTargetExtension) fTarget).endSession();
+
+ // prevent leaks
+ fActiveShell= null;
+ fTarget= null;
+ }
+
+ /**
+ * Stores the current state in the dialog settings.
+ * @since 2.0
+ */
+ private void storeSettings() {
+ fDialogPositionInit= getDialogBoundaries();
+ fWrapInit= isWrapSearch();
+ fWholeWordInit= isWholeWordSearch();
+ fCaseInit= isCaseSensitiveSearch();
+ fIncrementalInit= isIncrementalSearch();
+ fForwardInit= isForwardSearch();
+
+ writeConfiguration();
+ }
+
+ /**
+ * Initializes the string to search for and the appropriate
+ * text inout field based on the selection found in the
+ * action's target.
+ */
+ private void initFindStringFromSelection() {
+ if (fTarget != null && okToUse(fFindField)) {
+ String selection= getSelectionString();
+ fFindField.removeModifyListener(fFindModifyListener);
+ if (selection != null) {
+ fFindField.setText(selection);
+ if (!selection.equals(fTarget.getSelectionText())) {
+ useSelectedLines(true);
+ fGlobalRadioButton.setSelection(false);
+ fSelectedRangeRadioButton.setSelection(true);
+ }
+ } else {
+ if ("".equals(fFindField.getText())) { //$NON-NLS-1$
+ if (fFindHistory.size() > 0)
+ fFindField.setText((String) fFindHistory.get(0));
+ else
+ fFindField.setText(""); //$NON-NLS-1$
+ }
+ }
+ fFindField.addModifyListener(fFindModifyListener);
+ }
+ }
+
+ /**
+ * Initializes the anchor used as starting point for incremental searching.
+ * @since 2.0
+ */
+ private void initIncrementalBaseLocation() {
+ if (fTarget != null && isIncrementalSearch()) {
+ fIncrementalBaseLocation= fTarget.getSelection();
+ } else {
+ fIncrementalBaseLocation= new Point(0, 0);
+ }
+ }
+
+ // ------- history ---------------------------------------
+
+ /**
+ * Initialize the find history.
+ * @param history the history to be initialized
+ * @param init the initialization data
+ */
+ private void initHistory(List history, List init) {
+ history.clear();
+ for (int i= 0; i < init.size() && i < HISTORY_SIZE - 1; i++) {
+ history.add(init.get(i));
+ }
+ }
+
+ /**
+ * Retrieves and returns the option case sensitivity from the appropriate check box.
+ * @return <code>true</code> if case sensitive
+ */
+ private boolean isCaseSensitiveSearch() {
+ if (okToUse(fCaseCheckBox)) {
+ return fCaseCheckBox.getSelection();
+ }
+ return fCaseInit;
+ }
+
+ /**
+ * Retrieves and returns the option search direction from the appropriate check box.
+ * @return <code>true</code> if searching forward
+ */
+ private boolean isForwardSearch() {
+ if (okToUse(fForwardRadioButton)) {
+ return fForwardRadioButton.getSelection();
+ }
+ return fForwardInit;
+ }
+
+ /**
+ * Retrieves and returns the option global scope from the appropriate check box.
+ * @return <code>true</code> if searching globally
+ * @since 2.0
+ */
+ private boolean isGlobalSearch() {
+ if (okToUse(fGlobalRadioButton)) {
+ return fGlobalRadioButton.getSelection();
+ }
+ return fGlobalInit;
+ }
+
+ /**
+ * Retrieves and returns the option search whole words from the appropriate check box.
+ * @return <code>true</code> if searching for whole words
+ */
+ private boolean isWholeWordSearch() {
+ if (okToUse(fWholeWordCheckBox)) {
+ return fWholeWordCheckBox.getSelection();
+ }
+ return fWholeWordInit;
+ }
+
+ /**
+ * Retrieves and returns the option wrap search from the appropriate check box.
+ * @return <code>true</code> if wrapping while searching
+ */
+ private boolean isWrapSearch() {
+ if (okToUse(fWrapCheckBox)) {
+ return fWrapCheckBox.getSelection();
+ }
+ return fWrapInit;
+ }
+
+ /**
+ * Retrieves and returns the option incremental search from the appropriate check box.
+ * @return <code>true</code> if incremental search
+ * @since 2.0
+ */
+ private boolean isIncrementalSearch() {
+ if (okToUse(fIncrementalCheckBox)) {
+ return fIncrementalCheckBox.getSelection();
+ }
+ return fIncrementalInit;
+ }
+
+ /**
+ * Creates a button.
+ * @param parent the parent control
+ * @param key the key to lookup the button label
+ * @param id the button id
+ * @param dfltButton is this button the default button
+ * @param listener a button pressed listener
+ * @return teh new button
+ */
+ private Button makeButton(Composite parent, String key, int id, boolean dfltButton, SelectionListener listener) {
+ String label= EditorMessages.getString(key);
+ Button b= createButton(parent, id, label, dfltButton);
+ b.addSelectionListener(listener);
+ return b;
+ }
+
+ /**
+ * Returns the status line manager of the active editor or <code>null</code> if there is no such editor.
+ * @return the status line manager of the active editor
+ */
+ private IEditorStatusLine getStatusLineManager() {
+ AbstractUIPlugin plugin= (AbstractUIPlugin) Platform.getPlugin(PlatformUI.PLUGIN_ID);
+ IWorkbenchWindow window= plugin.getWorkbench().getActiveWorkbenchWindow();
+ if (window == null)
+ return null;
+
+ IWorkbenchPage page= window.getActivePage();
+ if (page == null)
+ return null;
+
+ IEditorPart editor= page.getActiveEditor();
+ if (editor == null)
+ return null;
+
+ return (IEditorStatusLine) editor.getAdapter(IEditorStatusLine.class);
+ }
+
+ /**
+ * Sets the given error message in the status line.
+ * @param message the error message
+ */
+ private void statusMessage(boolean error, String message) {
+ fStatusLabel.setText(message);
+
+ IEditorStatusLine statusLine= getStatusLineManager();
+ if (statusLine != null)
+ statusLine.setMessage(error, message, null);
+
+ if (error)
+ getShell().getDisplay().beep();
+ }
+
+ /**
+ * Sets the given error message in the status line.
+ * @param message the message
+ */
+ private void statusError(String message) {
+ statusMessage(true, message);
+ }
+
+ /**
+ * Sets the given message in the status line.
+ * @param message the message
+ */
+ private void statusMessage(String message) {
+ statusMessage(false, message);
+ }
+
+ /**
+ * Replaces all occurrences of the user's findString with
+ * the replace string. Indicate to the user the number of replacements
+ * that occur.
+ */
+ private void performReplaceAll() {
+
+ int replaceCount= 0;
+ String replaceString= getReplaceString();
+ String findString= getFindString();
+
+ if (replaceString == null)
+ replaceString= ""; //$NON-NLS-1$
+
+ if (findString != null && findString.length() > 0) {
+
+ replaceCount= replaceAll(findString, replaceString, isForwardSearch(), isCaseSensitiveSearch(), isWrapSearch(), isWholeWordSearch(), isGlobalSearch());
+
+ if (replaceCount != 0) {
+ if (replaceCount == 1) { // not plural
+ statusMessage(EditorMessages.getString("FindReplace.Status.replacement.label")); //$NON-NLS-1$
+ } else {
+ String msg= EditorMessages.getString("FindReplace.Status.replacements.label"); //$NON-NLS-1$
+ msg= MessageFormat.format(msg, new Object[] {String.valueOf(replaceCount)});
+ statusMessage(msg);
+ }
+ } else {
+ statusError(EditorMessages.getString("FindReplace.Status.noMatch.label")); //$NON-NLS-1$
+ }
+ }
+
+ updateButtonState();
+ }
+
+ /**
+ * Replaces the current selection of the target with the user's
+ * replace string.
+ */
+ private void performReplaceSelection() {
+
+ String replaceString= getReplaceString();
+ if (replaceString == null)
+ replaceString= ""; //$NON-NLS-1$
+
+ fTarget.replaceSelection(replaceString);
+ updateButtonState();
+ }
+
+ /**
+ * Locates the user's findString in the text of the target.
+ */
+ private void performSearch() {
+
+ String findString= getFindString();
+
+ if (findString != null && findString.length() > 0) {
+
+ boolean somethingFound= findNext(findString, isForwardSearch(), isCaseSensitiveSearch(), isWrapSearch(), isWholeWordSearch(), isIncrementalSearch(), isGlobalSearch());
+
+ if (somethingFound) {
+ statusMessage(""); //$NON-NLS-1$
+ } else {
+ statusError(EditorMessages.getString("FindReplace.Status.noMatch.label")); //$NON-NLS-1$
+ }
+ }
+
+ updateButtonState();
+ }
+
+ /**
+ * Replaces all occurrences of the user's findString with
+ * the replace string. Returns the number of replacements
+ * that occur.
+ *
+ * @param findString the string to search for
+ * @param replaceString the replacement string
+ * @param forwardSearch the search direction
+ * @param caseSensitive should the search be case sensitive
+ * @param wrapSearch should search wrap to start/end if end/start is reached
+ * @param wholeWord does the search string represent a complete word
+ * @param global is the search performed globally
+ * @return the number of occurrences
+ * @since 2.0
+ */
+ private int replaceAll(String findString, String replaceString, boolean forwardSearch, boolean caseSensitive, boolean wrapSearch, boolean wholeWord, boolean global) {
+
+ int replaceCount= 0;
+ int findReplacePosition= 0;
+
+ if (wrapSearch) { // search the whole text
+ findReplacePosition= 0;
+ forwardSearch= true;
+ } else if (fTarget.getSelectionText() != null) {
+ // the cursor is set to the end or beginning of the selected text
+ Point selection= fTarget.getSelection();
+ findReplacePosition= selection.x;
+ }
+
+ if (fTarget instanceof IFindReplaceTargetExtension)
+ ((IFindReplaceTargetExtension) fTarget).setReplaceAllMode(true);
+
+ try {
+ int index= 0;
+ while (index != -1) {
+ index= fTarget.findAndSelect(findReplacePosition, findString, forwardSearch, caseSensitive, wholeWord);
+ if (index != -1) { // substring not contained from current position
+ if (forwardSearch)
+ findReplacePosition= index + replaceString.length();
+ else
+ findReplacePosition= index - replaceString.length();
+ fTarget.replaceSelection(replaceString);
+ replaceCount++;
+ }
+ }
+ } finally {
+ if (fTarget instanceof IFindReplaceTargetExtension)
+ ((IFindReplaceTargetExtension) fTarget).setReplaceAllMode(false);
+ }
+
+ return replaceCount;
+ }
+
+ // ------- ui creation ---------------------------------------
+
+ /**
+ * Attaches the given layout specification to the <code>component</code>
+ *
+ * @param component the component
+ * @param horizontalAlignment horizontal alignment
+ * @param grabExcessHorizontalSpace grab excess horizontal space
+ * @param verticalAlignment vertical alignment
+ * @param grabExcessVerticalSpace grab excess vertical space
+ */
+ private void setGridData(Control component, int horizontalAlignment, boolean grabExcessHorizontalSpace, int verticalAlignment, boolean grabExcessVerticalSpace) {
+ GridData gd= new GridData();
+ gd.horizontalAlignment= horizontalAlignment;
+ gd.grabExcessHorizontalSpace= grabExcessHorizontalSpace;
+ gd.verticalAlignment= verticalAlignment;
+ gd.grabExcessVerticalSpace= grabExcessVerticalSpace;
+ component.setLayoutData(gd);
+ }
+
+ /**
+ * Updates the enabled state of the buttons.
+ */
+ private void updateButtonState() {
+ if (okToUse(getShell()) && okToUse(fFindNextButton)) {
+ String selectedText= null;
+ if (fTarget != null) {
+ selectedText= fTarget.getSelectionText();
+ }
+
+ boolean selection= (selectedText != null && selectedText.length() > 0);
+
+ boolean enable= fTarget != null && (fActiveShell == fParentShell || fActiveShell == getShell());
+ String str= getFindString();
+ boolean findString= (str != null && str.length() > 0);
+
+ fFindNextButton.setEnabled(enable && findString);
+ fReplaceSelectionButton.setEnabled(enable && isEditable() && selection);
+ fReplaceFindButton.setEnabled(enable && isEditable() && findString && selection);
+ fReplaceAllButton.setEnabled(enable && isEditable() && findString);
+ }
+ }
+
+ /**
+ * Updates the given combo with the given content.
+ * @param combo combo to be updated
+ * @param content to be put into the combo
+ */
+ private void updateCombo(Combo combo, List content) {
+ combo.removeAll();
+ for (int i= 0; i < content.size(); i++) {
+ combo.add(content.get(i).toString());
+ }
+ }
+
+ // ------- open / reopen ---------------------------------------
+
+ /**
+ * Called after executed find/replace action to update the history
+ */
+ private void updateFindAndReplaceHistory() {
+ updateFindHistory();
+ if (okToUse(fReplaceField)) {
+ updateHistory(fReplaceField, fReplaceHistory);
+ }
+
+ }
+
+ /**
+ * Called after executed find action to update the history
+ */
+ private void updateFindHistory() {
+ if (okToUse(fFindField)) {
+ fFindField.removeModifyListener(fFindModifyListener);
+ updateHistory(fFindField, fFindHistory);
+ fFindField.addModifyListener(fFindModifyListener);
+ }
+ }
+
+ /**
+ * Updates the combo with the history.
+ * @param combo to be updated
+ * @param history to be put into the combo
+ */
+ private void updateHistory(Combo combo, List history) {
+ String findString= combo.getText();
+ int index= history.indexOf(findString);
+ if (index != 0) {
+ if (index != -1) {
+ history.remove(index);
+ }
+ history.add(0, findString);
+ updateCombo(combo, history);
+ combo.setText(findString);
+ }
+ }
+
+ /**
+ * Returns whether the target is editable
+ * @return <code>true</code> if target is editable
+ */
+ private boolean isEditable() {
+ boolean isEditable= (fTarget == null ? false : fTarget.isEditable());
+ return fIsTargetEditable && isEditable;
+ }
+
+ /**
+ * Updates this dialog because of a different target.
+ * @param target the new target
+ * @param isTargetEditable <code>true</code> if the new target can be modifed
+ * @since 2.0
+ */
+ public void updateTarget(IFindReplaceTarget target, boolean isTargetEditable) {
+
+ fIsTargetEditable= isTargetEditable;
+
+ if (target != fTarget) {
+ if (fTarget != null && fTarget instanceof IFindReplaceTargetExtension)
+ ((IFindReplaceTargetExtension) fTarget).endSession();
+
+ fTarget= target;
+
+ if (fTarget != null && fTarget instanceof IFindReplaceTargetExtension) {
+ ((IFindReplaceTargetExtension) fTarget).beginSession();
+
+ fGlobalInit= true;
+ fGlobalRadioButton.setSelection(fGlobalInit);
+ fSelectedRangeRadioButton.setSelection(!fGlobalInit);
+ }
+ }
+
+ if (okToUse(fReplaceLabel)) {
+ fReplaceLabel.setEnabled(isEditable());
+ fReplaceField.setEnabled(isEditable());
+ initFindStringFromSelection();
+ initIncrementalBaseLocation();
+ updateButtonState();
+ }
+ }
+
+ /**
+ * Sets the parent shell of this dialog to be the given shell.
+ *
+ * @param shell the new parent shell
+ */
+ public void setParentShell(Shell shell) {
+ if (shell != fParentShell) {
+
+ if (fParentShell != null)
+ fParentShell.removeShellListener(fActivationListener);
+
+ fParentShell= shell;
+ fParentShell.addShellListener(fActivationListener);
+ }
+
+ fActiveShell= shell;
+ }
+
+
+ //--------------- configuration handling --------------
+
+ /**
+ * Returns the dialog settings object used to share state
+ * between several find/replace dialogs.
+ *
+ * @return the dialog settings to be used
+ */
+ private IDialogSettings getDialogSettings() {
+ AbstractUIPlugin plugin= (AbstractUIPlugin) Platform.getPlugin(PlatformUI.PLUGIN_ID);
+ IDialogSettings settings= plugin.getDialogSettings();
+ fDialogSettings= settings.getSection(getClass().getName());
+ if (fDialogSettings == null)
+ fDialogSettings= settings.addNewSection(getClass().getName());
+ return fDialogSettings;
+ }
+
+ /**
+ * Initializes itself from the dialog settings with the same state
+ * as at the previous invocation.
+ */
+ private void readConfiguration() {
+ IDialogSettings s= getDialogSettings();
+
+ try {
+ int x= s.getInt("x"); //$NON-NLS-1$
+ int y= s.getInt("y"); //$NON-NLS-1$
+ fLocation= new Point(x, y);
+ } catch (NumberFormatException e) {
+ fLocation= null;
+ }
+
+ fWrapInit= s.getBoolean("wrap"); //$NON-NLS-1$
+ fCaseInit= s.getBoolean("casesensitive"); //$NON-NLS-1$
+ fWholeWordInit= s.getBoolean("wholeword"); //$NON-NLS-1$
+ fIncrementalInit= s.getBoolean("incremental"); //$NON-NLS-1$
+
+ String[] findHistory= s.getArray("findhistory"); //$NON-NLS-1$
+ if (findHistory != null) {
+ List history= getFindHistory();
+ history.clear();
+ for (int i= 0; i < findHistory.length; i++)
+ history.add(findHistory[i]);
+ }
+
+ String[] replaceHistory= s.getArray("replacehistory"); //$NON-NLS-1$
+ if (replaceHistory != null) {
+ List history= getReplaceHistory();
+ history.clear();
+ for (int i= 0; i < replaceHistory.length; i++)
+ history.add(replaceHistory[i]);
+ }
+ }
+
+ /**
+ * Stores it current configuration in the dialog store.
+ */
+ private void writeConfiguration() {
+ IDialogSettings s= getDialogSettings();
+
+ Point location= getShell().getLocation();
+ s.put("x", location.x); //$NON-NLS-1$
+ s.put("y", location.y); //$NON-NLS-1$
+
+ s.put("wrap", fWrapInit); //$NON-NLS-1$
+ s.put("casesensitive", fCaseInit); //$NON-NLS-1$
+ s.put("wholeword", fWholeWordInit); //$NON-NLS-1$
+ s.put("incremental", fIncrementalInit); //$NON-NLS-1$
+
+ List history= getFindHistory();
+ while (history.size() > 8)
+ history.remove(8);
+ String[] names= new String[history.size()];
+ history.toArray(names);
+ s.put("findhistory", names); //$NON-NLS-1$
+
+ history= getReplaceHistory();
+ while (history.size() > 8)
+ history.remove(8);
+ names= new String[history.size()];
+ history.toArray(names);
+ s.put("replacehistory", names); //$NON-NLS-1$
+ }
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/GotoLineAction.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/GotoLineAction.java
new file mode 100644
index 000000000..5250e6f1d
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/GotoLineAction.java
@@ -0,0 +1,188 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+
+import java.text.MessageFormat;
+import java.util.ResourceBundle;
+
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+
+import org.eclipse.jface.dialogs.IInputValidator;
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.viewers.ISelectionProvider;
+
+import org.eclipse.ui.IWorkbenchPage;
+
+
+/**
+ * Action for jumping to a particular line if the editor's text viewer.
+ * The user is requested to enter the line number into an input dialog.
+ * The action is initially associated with a text editor via the constructor,
+ * but that can be subsequently changed using <code>setEditor</code>.
+ * <p>
+ * The following keys, prepended by the given option prefix,
+ * are used for retrieving resources from the given bundle:
+ * <ul>
+ * <li><code>"dialog.invalid_range"</code> - to indicate an invalid line number</li>
+ * <li><code>"dialog.invalid_input"</code> - to indicate an invalid line number format</li>
+ * <li><code>"dialog.title"</code> - the input dialog's title</li>
+ * <li><code>"dialog.message"</code> - the input dialog's message</li>
+ * </ul>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ */
+public class GotoLineAction extends TextEditorAction {
+
+ /**
+ * Validates whether the text found in the input field of the
+ * dialog forms a valid line number. A number is valid if it is
+ * one to which can be jumped.
+ */
+ class NumberValidator implements IInputValidator {
+
+ /*
+ * @see IInputValidator#isValid(String)
+ */
+ public String isValid(String input) {
+
+ if (input == null || input.length() == 0)
+ return " "; //$NON-NLS-1$
+
+ try {
+ int i= Integer.parseInt(input);
+ if (i <= 0 || fLastLine < i)
+ return fBundle.getString(fPrefix + "dialog.invalid_range"); //$NON-NLS-1$
+
+ } catch (NumberFormatException x) {
+ return fBundle.getString(fPrefix + "dialog.invalid_input"); //$NON-NLS-1$
+ }
+
+ return null;
+ }
+ };
+
+ /**
+ * Standard input dialog which additionally sets the focus to the
+ * text input field. Workaround for <code>InputDialog</code> issue.
+ * 1GIJZOO: ITPSRCEDIT:ALL - Gotodialog's edit field has no initial focus
+ * @since 2.0
+ */
+ class GotoLineDialog extends InputDialog {
+
+ /*
+ * @see InputDialog#InputDialog
+ */
+ public GotoLineDialog(Shell parent, String title, String message, String initialValue, IInputValidator validator) {
+ super(parent, title, message, initialValue, validator);
+ }
+
+ /*
+ * @see InputDialog#createDialogArea(Composite)
+ */
+ protected Control createDialogArea(Composite parent) {
+ Control result= super.createDialogArea(parent);
+ getText().setFocus();
+ return result;
+ }
+ };
+
+ /** The biggest valid line number of the presented document */
+ private int fLastLine;
+ /** This action's resource bundle */
+ private ResourceBundle fBundle;
+ /** This action's prefix used for accessing the resource bundle */
+ private String fPrefix;
+
+ /**
+ * Creates a new action for the given text editor. The action configures its
+ * visual representation from the given resource bundle.
+ *
+ * @param bundle the resource bundle
+ * @param prefix a prefix to be prepended to the various resource keys
+ * (described in <code>ResourceAction</code> constructor), or
+ * <code>null</code> if none
+ * @param editor the text editor
+ * @see ResourceAction#ResourceAction
+ */
+ public GotoLineAction(ResourceBundle bundle, String prefix, ITextEditor editor) {
+ super(bundle, prefix, editor);
+ fBundle= bundle;
+ fPrefix= prefix;
+ }
+
+ /**
+ * Jumps to the given line.
+ *
+ * @param line the line to jump to
+ */
+ private void gotoLine(int line) {
+
+ ITextEditor editor= getTextEditor();
+
+ IDocumentProvider provider= editor.getDocumentProvider();
+ IDocument document= provider.getDocument(editor.getEditorInput());
+ try {
+
+ int start= document.getLineOffset(line);
+ editor.selectAndReveal(start, 0);
+
+ IWorkbenchPage page= editor.getSite().getPage();
+ page.activate(editor);
+
+ } catch (BadLocationException x) {
+ // ignore
+ }
+ }
+
+ /*
+ * @see Action#run()
+ */
+ public void run() {
+ try {
+
+ ITextEditor editor= getTextEditor();
+
+ if (editor == null)
+ return;
+
+ IDocumentProvider docProvider= editor.getDocumentProvider();
+ if (docProvider == null)
+ return;
+
+ IDocument document= docProvider.getDocument(editor.getEditorInput());
+ if (document == null)
+ return;
+
+ fLastLine= document.getLineOfOffset(document.getLength()) + 1;
+
+ String title= fBundle.getString(fPrefix + "dialog.title"); //$NON-NLS-1$
+ String message= MessageFormat.format(fBundle.getString(fPrefix + "dialog.message"), new Object[] {new Integer(fLastLine)}); //$NON-NLS-1$
+
+ GotoLineDialog d= new GotoLineDialog(editor.getSite().getShell(), title, message, "", new NumberValidator()); //$NON-NLS-1$
+ if (d.open() == d.OK) {
+ try {
+ int line= Integer.parseInt(d.getValue());
+ gotoLine(line - 1);
+ } catch (NumberFormatException x) {
+ }
+ }
+
+ } catch (BadLocationException x) {
+ }
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IAbstractTextEditorHelpContextIds.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IAbstractTextEditorHelpContextIds.java
new file mode 100644
index 000000000..02cf4fbbe
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IAbstractTextEditorHelpContextIds.java
@@ -0,0 +1,227 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+
+import org.eclipse.ui.PlatformUI;
+
+
+/**
+ * Help context ids for the text editor.
+ * <p>
+ * This interface contains constants only; it is not intended to be implemented.
+ * </p>
+ */
+public interface IAbstractTextEditorHelpContextIds {
+
+ /**
+ * The string with which all other defined ids are prefixed to construct help context ids.
+ * Value: <code>"org.eclipse.ui."</code>
+ */
+ public static final String PREFIX= PlatformUI.PLUGIN_ID + "."; //$NON-NLS-1$
+
+ /**
+ * The string which is appended to action ids to construct help context ids.
+ * Value: <code>"_action_context"</code>
+ */
+ public static final String ACTION_POSTFIX= "_action_context"; //$NON-NLS-1$
+
+
+
+
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.undo_action_context"</code>
+ */
+ public static final String UNDO_ACTION= PREFIX + ITextEditorActionConstants.UNDO + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.redo_action_context"</code>
+ */
+ public static final String REDO_ACTION= PREFIX + ITextEditorActionConstants.REDO + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.cut_action_context"</code>
+ */
+ public static final String CUT_ACTION= PREFIX + ITextEditorActionConstants.CUT + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.copy_action_context"</code>
+ */
+ public static final String COPY_ACTION= PREFIX + ITextEditorActionConstants.COPY + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.paste_action_context"</code>
+ */
+ public static final String PASTE_ACTION= PREFIX + ITextEditorActionConstants.PASTE + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.delete_action_context"</code>
+ */
+ public static final String DELETE_ACTION= PREFIX + ITextEditorActionConstants.DELETE + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.DeleteLine_action_context"</code>
+ * @since 2.0
+ */
+ public static final String DELETE_LINE_ACTION= PREFIX + ITextEditorActionConstants.DELETE_LINE + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.DeleteLineToBeginning_action_context"</code>
+ * @since 2.0
+ */
+ public static final String DELETE_LINE_TO_BEGINNING_ACTION= PREFIX + ITextEditorActionConstants.DELETE_LINE_TO_BEGINNING + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.DeleteLineToEnd_action_context"</code>
+ * @since 2.0
+ */
+ public static final String DELETE_LINE_TO_END_ACTION= PREFIX + ITextEditorActionConstants.DELETE_LINE_TO_END + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.SetMark_action_context"</code>
+ * @since 2.0
+ */
+ public static final String SET_MARK_ACTION= PREFIX + ITextEditorActionConstants.SET_MARK + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.ClearMark_action_context"</code>
+ * @since 2.0
+ */
+ public static final String CLEAR_MARK_ACTION= PREFIX + ITextEditorActionConstants.CLEAR_MARK + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.SwapMark_action_context"</code>
+ * @since 2.0
+ */
+ public static final String SWAP_MARK_ACTION= PREFIX + ITextEditorActionConstants.SWAP_MARK + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.selectAll_action_context"</code>
+ */
+ public static final String SELECT_ALL_ACTION= PREFIX + ITextEditorActionConstants.SELECT_ALL + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.ShiftRight_action_context"</code>
+ */
+ public static final String SHIFT_RIGHT_ACTION= PREFIX + ITextEditorActionConstants.SHIFT_RIGHT + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.ShiftLeft_action_context"</code>
+ */
+ public static final String SHIFT_LEFT_ACTION= PREFIX + ITextEditorActionConstants.SHIFT_LEFT + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.find_action_context"</code>
+ */
+ public static final String FIND_ACTION= PREFIX + ITextEditorActionConstants.FIND + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.FindNext_action_context"</code>
+ * @since 2.0
+ */
+ public static final String FIND_NEXT_ACTION = PREFIX + ITextEditorActionConstants.FIND_NEXT + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.FindPrevious_action_context"</code>
+ * @since 2.0
+ */
+ public static final String FIND_PREVIOUS_ACTION = PREFIX + ITextEditorActionConstants.FIND_PREVIOUS + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.FindIncremental_action_context"</code>
+ * @since 2.0
+ */
+ public static final String FIND_INCREMENTAL_ACTION = PREFIX + ITextEditorActionConstants.FIND_INCREMENTAL + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.bookmark_action_context"</code>
+ */
+ public static final String BOOKMARK_ACTION= PREFIX + ITextEditorActionConstants.BOOKMARK + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.addTask_action_context"</code>
+ */
+ public static final String ADD_TASK_ACTION= PREFIX + ITextEditorActionConstants.ADD_TASK + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.save_action_context"</code>
+ */
+ public static final String SAVE_ACTION= PREFIX + ITextEditorActionConstants.SAVE + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.revert_action_context"</code>
+ */
+ public static final String REVERT_TO_SAVED_ACTION= PREFIX + ITextEditorActionConstants.REVERT_TO_SAVED + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.GotoLine_action_context"</code>
+ */
+ public static final String GOTO_LINE_ACTION= PREFIX + ITextEditorActionConstants.GOTO_LINE + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.print_action_context"</code>
+ */
+ public static final String PRINT_ACTION= PREFIX + ITextEditorActionConstants.PRINT + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.ConvertLineDelimitersToWindows_action_context"</code>
+ * @since 2.0
+ */
+ public static final String CONVERT_LINE_DELIMITERS_TO_WINDOWS= PREFIX + ITextEditorActionConstants.CONVERT_LINE_DELIMITERS_TO_WINDOWS + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.ConvertLineDelimitersToUNIX_action_context"</code>
+ * @since 2.0
+ */
+ public static final String CONVERT_LINE_DELIMITERS_TO_UNIX= PREFIX + ITextEditorActionConstants.CONVERT_LINE_DELIMITERS_TO_UNIX + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.ConvertLineDelimitersToMAC_action_context"</code>
+ * @since 2.0
+ */
+ public static final String CONVERT_LINE_DELIMITERS_TO_MAC= PREFIX + ITextEditorActionConstants.CONVERT_LINE_DELIMITERS_TO_MAC + ACTION_POSTFIX;
+
+ /**
+ * Help context id for the action.
+ * Value: <code>"org.eclipse.ui.find_replace_dialog_context"</code>
+ */
+ public static final String FIND_REPLACE_DIALOG= PREFIX + "find_replace_dialog_context"; //$NON-NLS-1$
+} \ No newline at end of file
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IDocumentProvider.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IDocumentProvider.java
new file mode 100644
index 000000000..aac92d96a
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IDocumentProvider.java
@@ -0,0 +1,196 @@
+package org.eclipse.ui.texteditor;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+
+
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.source.IAnnotationModel;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+
+
+/**
+ * A document provider maps between domain elements and documents.
+ * A document provider has the following responsibilities:
+ * <ul>
+ * <li> create an annotation model of a domain model element
+ * <li> create and manage a textual representation, i.e., a document, of a domain model element
+ * <li> create and save the content of domain model elements based on given documents
+ * <li> update the documents this document provider manages for domain model elements
+ * to changes directly applied to those domain model elements
+ * <li> notify all element state listeners about changes directly applied to domain model
+ * elements this document provider manages a document for, i.e. the document
+ * provider must know which changes of a domain model element are to be interpreted
+ * as element moves, deletes, etc.
+ * </ul>
+ * Text editors use document providers to bridge the gap between their input elements and the
+ * documents they work on. A single document provider may be shared between multiple editors;
+ * the methods take the editors' input elements as a parameter.<p>
+ * This interface may be implemented by clients; or subclass the standard
+ * abstract base class <code>AbstractDocumentProvider</code>.
+ *
+ * @see IDocument
+ * @see AbstractDocumentProvider
+ */
+public interface IDocumentProvider {
+
+ /**
+ * Connects the given element to this document provider. This tells the provider
+ * that caller of this method is interested to work with the document provided for
+ * the given domain model element. By counting the invokations of this method and
+ * <code>disconnect(Object)</code> this provider can assume to know the
+ * correct number of clients working with the document provided for that
+ * domain model element. <p>
+ * The given element must not be <code>null</code>.
+ *
+ * @param element the element
+ * @exception CoreException if the textual representation or the annotation model
+ * of the element could not be created
+ */
+ void connect(Object element) throws CoreException;
+
+ /**
+ * Disconnects the given element from this document provider. This tells the provider
+ * that the caller of this method is no longer interested in working with the document
+ * provided for the given domain model element. By counting the invokations of
+ * <code>connect(Object)</code> and of this method this provider can assume to
+ * know the correct number of clients working with the document provided for that
+ * domain model element. <p>
+ * The given element must not be <code>null</code>.
+ *
+ * @param element the element
+ */
+ void disconnect(Object element);
+
+ /**
+ * Returns the document for the given element. Usually the document contains
+ * a textual presentation of the content of the element, or is the element itself.
+ *
+ * @param element the element, or <code>null</code>
+ * @return the document, or <code>null</code> if none
+ */
+ IDocument getDocument(Object element);
+
+ /**
+ * Resets the given element's document to its last saved state.
+ * Element state listeners are notified both before (<code>elementContentAboutToBeReplaced</code>)
+ * and after (<code>elementContentReplaced</code>) the content is changed.
+ *
+ * @param element the element, or <code>null</code>
+ */
+ void resetDocument(Object element) throws CoreException;
+
+ /**
+ * Saves the given document provided for the given element.
+ *
+ * @param monitor a progress monitor to report progress and request cancelation
+ * @param element the element, or <code>null</code>
+ * @param document the document
+ * @param overwrite indicates whether overwrite should be performed
+ * while saving the given element if necessary
+ * @exception CoreException if document could not be stored to the given element
+ */
+ void saveDocument(IProgressMonitor monitor, Object element, IDocument document, boolean overwrite) throws CoreException;
+
+ /**
+ * Returns the modification stamp of the given element.
+ *
+ * @param element the element
+ * @return the modification stamp of the given element
+ */
+ long getModificationStamp(Object element);
+
+ /**
+ * Returns the time stamp of the last synchronization of
+ * the given element and it's provided document.
+ *
+ * @param element the element
+ * @return the sysnchronization stamp of the given element
+ */
+ long getSynchronizationStamp(Object element);
+
+ /**
+ * Returns whether the given element has been deleted.
+ *
+ * @param element the element
+ * @return <code>true</code> if the element has been deleted
+ */
+ boolean isDeleted(Object element);
+
+ /**
+ * Returns whether the document provided for the given element must be saved.
+ *
+ * @param element the element, or <code>null</code>
+ * @return <code>true</code> if the document must be saved, and
+ * <code>false</code> otherwise (including the element is <code>null</code>)
+ */
+ boolean mustSaveDocument(Object element);
+
+ /**
+ * Returns whether the document provided for the given element differs from
+ * its original state which would required that it be saved.
+ *
+ * @param element the element, or <code>null</code>
+ * @return <code>true</code> if the document can be saved, and
+ * <code>false</code> otherwise (including the element is <code>null</code>)
+ */
+ boolean canSaveDocument(Object element);
+
+ /**
+ * Returns the annotation model for the given element.
+ *
+ * @param element the element, or <code>null</code>
+ * @return the annotation model, or <code>null</code> if none
+ */
+ IAnnotationModel getAnnotationModel(Object element);
+
+ /**
+ * Informs this document provider about upcoming changes of the given element.
+ * The changes might cause change notifications specific for the type of the given element.
+ * If this provider manages a document for the given element, the document provider
+ * must not change the document because of the notifications received after <code>
+ * aboutToChange</code> has been and before <code>changed</code> is called. In this case,
+ * it is assumed that the document is already up to date, e.g., a save operation is a
+ * typical case. <p>
+ * The concrete nature of the change notification depends on the concrete type of the
+ * given element. If the element is, e.g., an <code>IResource</code> the notification
+ * is a resource delta.
+ *
+ * @param element the element, or <code>null</code>
+ */
+ void aboutToChange(Object element);
+
+ /**
+ * Informs this document provider that the given element has been changed.
+ * All notifications have been sent out. If this provider manages a document
+ * for the given element, the document provider must from now on change the
+ * document on the receipt of change notifications. The concrete nature of the change
+ * notification depends on the concrete type of the given element. If the element is,
+ * e.g., an <code>IResource</code> the notification is a resource delta.
+ *
+ * @param element the element, or <code>null</code>
+ */
+ void changed(Object element);
+
+ /**
+ * Adds the given element state listener to this document provider.
+ * Has no effect if an identical listener is already registered.
+ *
+ * @param listener the listener
+ */
+ void addElementStateListener(IElementStateListener listener);
+
+ /**
+ * Removes the given element state listener from this document provider.
+ * Has no affect if an identical listener is not registered.
+ *
+ * @param listener the listener
+ */
+ void removeElementStateListener(IElementStateListener listener);
+} \ No newline at end of file
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IDocumentProviderExtension.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IDocumentProviderExtension.java
new file mode 100644
index 000000000..27d14c601
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IDocumentProviderExtension.java
@@ -0,0 +1,114 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+
+
+/**
+ * Extension interface for <code>IDocumentProvider</code>. It adds the following
+ * functions:
+ * <ul>
+ * <li> dealing with immutable domain elements
+ * <li> state validation
+ * <li> persistent status of domain element operations
+ * <li> extended synchronization support
+ * </ul>
+ * @since 2.0
+ */
+public interface IDocumentProviderExtension {
+
+ /**
+ * Returns whether the document provider thinks that the given element is read-only.
+ * If this method returns <code>true</code>, <code>saveDocument</code> could fail.
+ * This method does not say anything about the document constructed from the given
+ * element. If the given element is not connected to this document provider, the return
+ * value is undefined. Document providers are allowed to use a cache to answer this
+ * question, i.e. there can be a difference between the "real" state of the element and
+ * the return value.
+ *
+ * @param element the element
+ * @return <code>true</code> if the given element is read-only, <code>false</code> otherwise
+ */
+ boolean isReadOnly(Object element);
+
+ /**
+ * Returns whether the document provider thinks that the given element can persistently be modified.
+ * This is orthogonal to <code>isReadOnly</code> as read-only elements may be modifiable and
+ * writable elements may not be modifiable. If the given element is not connected to this document
+ * provider, the result is undefined. Document providers are allowed to use a cache to answer this
+ * question, i.e. there can be a difference between the "real" state of the element and the return
+ * value.
+ *
+ * @param element the element
+ * @return <code>true</code> if the given element is modifiable, <code>false</code> otherwise
+ */
+ boolean isModifiable(Object element);
+
+ /**
+ * Validates the state of the given element. This method may change the "real" state of the
+ * element. If using, it also updates the internal caches, so that this method may also change
+ * the results returned by <code>isReadOnly</code> and <code>isModifiable</code>. If the
+ * given element is not connected to this document provider, the effect is undefined.
+ *
+ * @param element the element
+ * @param computationContext the context in which the computation is performed, e.g., a SWT shell
+ * @exception CoreException if validating fails
+ */
+ void validateState(Object element, Object computationContext) throws CoreException;
+
+ /**
+ * Returns whether the state of the given element has been validated.
+ *
+ * @param element the element
+ */
+ boolean isStateValidated(Object element);
+
+ /**
+ * Updates the state cache for the given element. This method may change the result returned
+ * by <code>isReadOnly</code> and <code>isModifiable</code>. If the given element is not
+ * connected to this document provider, the effect is undefined.
+ *
+ * @param element the element
+ * @exception CoreException if validating fails
+ */
+ void updateStateCache(Object element) throws CoreException;
+
+ /**
+ * Marks the document managed for the given element as saveable. I.e.
+ * <code>canBeSaved(element)</code> will return <code>true</code>
+ * afterwards.
+ *
+ * @param element the element
+ */
+ void setCanSaveDocument(Object element);
+
+ /**
+ * Returns the status of the given element.
+ *
+ * @param element the element
+ * @return the status of the given element
+ */
+ IStatus getStatus(Object element);
+
+ /**
+ * Synchronizes the document provided for the given element with the
+ * given element. After that call <code>getSynchronizationTimeStamp</code>
+ * and <code>getModificationTimeStamp</code> return the same value.
+ *
+ * @param element the element
+ * @exception CoreException if the synchronization could not be performed
+ */
+ void synchronize(Object element) throws CoreException;
+} \ No newline at end of file
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IEditorStatusLine.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IEditorStatusLine.java
new file mode 100644
index 000000000..0c908044b
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IEditorStatusLine.java
@@ -0,0 +1,25 @@
+package org.eclipse.ui.texteditor;
+
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * An interface to use the status line of an editor.
+ *
+ * @since 2.1
+ */
+public interface IEditorStatusLine {
+ /**
+ * Sets the image and message to be displayed on the status line.
+ * <p>
+ * The error flag indicates that the message is an error message.
+ * If the error flag is set, a potential non-error message is overridden.
+ * If the error message is <code>null</code>, the non-error message is displayed.
+ * </p>
+ *
+ * @param error indicates that the message is an error message
+ * @param message the message to set (may be <code>null</code> to clear the message)
+ * @param image the image to set (may be <code>null</code> to clear the image)
+ */
+ void setMessage(boolean error, String message, Image image);
+
+} \ No newline at end of file
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IElementStateListener.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IElementStateListener.java
new file mode 100644
index 000000000..cfae2352d
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IElementStateListener.java
@@ -0,0 +1,60 @@
+package org.eclipse.ui.texteditor;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+/**
+ * Interface for parties interested in standardized element changes. These
+ * changes are:
+ * <ul>
+ * <li> dirty state changes
+ * <li> content replacements
+ * <li> moves
+ * <li> deletions
+ * </ul>
+ * The notifications sent to the element state listeners inform about those standardized,
+ * abstract changes. The concrete change applied might differ from the one the listeners
+ * are notified about, but should be interpreted as the one the listeners receive.
+ */
+public interface IElementStateListener {
+
+ /**
+ * Notifies that the dirty state of the given element has changed.
+ *
+ * @param element the element
+ * @param isDirty the new dirty state
+ */
+ void elementDirtyStateChanged(Object element, boolean isDirty);
+
+ /**
+ * Notifies that the content of the given element is about to be replaced.
+ *
+ * @param element the element
+ */
+ void elementContentAboutToBeReplaced(Object element);
+
+ /**
+ * Notifies that the content of the given element has been replaced.
+ *
+ * @param element the element
+ */
+ void elementContentReplaced(Object element);
+
+ /**
+ * Notifies that the given element has been deleted.
+ *
+ * @param element the element
+ */
+ void elementDeleted(Object element);
+
+ /**
+ * Notifies that the element has moved. If <code>movedElement</code>
+ * is <code>null</code> it is similar to <code>elementDeleted(originalElement)</code>.
+ *
+ * @param originalElement the element before the move
+ * @param movedElement the element after the move
+ */
+ void elementMoved(Object originalElement, Object movedElement);
+} \ No newline at end of file
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IElementStateListenerExtension.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IElementStateListenerExtension.java
new file mode 100644
index 000000000..fea039942
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IElementStateListenerExtension.java
@@ -0,0 +1,47 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+/**
+ * Extension interface for <code>IElementStateListener</code>.
+ * It adds
+ * <ul>
+ * <li> state validation notification
+ * <li>a notion of session, i.e. a notification about an upcoming element change and error handling.
+ * </ul>
+ * @since 2.0
+ */
+public interface IElementStateListenerExtension {
+
+ /**
+ * Notifies that the state validation of the given element has changed.
+ *
+ * @param element the element
+ * @param isStateValidated the flag indicating whether state validation is done
+ */
+ void elementStateValidationChanged(Object element, boolean isStateValidated);
+
+ /**
+ * Notifies that the given element is currently being changed. This method may
+ * be sent from a non-ui thread.
+ *
+ * @param element the element
+ */
+ void elementStateChanging(Object element);
+
+ /**
+ * Notifies that changing the given element has failed.
+ *
+ * @param element the element
+ */
+ void elementStateChangeFailed(Object element);
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IMarkerUpdater.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IMarkerUpdater.java
new file mode 100644
index 000000000..55676c36e
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IMarkerUpdater.java
@@ -0,0 +1,53 @@
+package org.eclipse.ui.texteditor;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.Position;
+
+import org.eclipse.core.resources.IMarker;
+
+
+/**
+ * A marker updater is responsible for saving changes to markers.
+ * Marker updaters either update markers of a specific types or
+ * any type. Also they either assume update responsibility for a
+ * specific set of marker attributes or any marker attribute.
+ * Marker updater must be registered with an <code>AbstractMarkerAnnotationModel</code>.
+ */
+public interface IMarkerUpdater {
+
+ /**
+ * Returns the marker type for which this updater is responsible. If
+ * the result is <code>null</code>, the updater assumes responsibility
+ * for any marker type.
+ *
+ * @return the marker type or <code>null</code> for any marker type
+ */
+ String getMarkerType();
+
+ /**
+ * Returns the attributes for which this updater is responsible. If the
+ * result is <code>null</code>, the updater assumes responsibility for
+ * any attributes.
+ *
+ * @return the attributes or <code>null</code> for any attribute
+ */
+ String[] getAttribute();
+
+ /**
+ * Updates the given marker according to the position of the given document.
+ * If the given position is <code>null</code>, the marker is assumed to
+ * carry the correct positional information. If the updater recognizes that
+ * the marker should be deleted, it returns <code>false</code>.
+ *
+ * @param marker the marker to be updated
+ * @param document the document into which the given position points
+ * @param position the current position of the marker inside the given document
+ */
+ boolean updateMarker(IMarker marker, IDocument document, Position position);
+} \ No newline at end of file
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IReadOnlyDependent.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IReadOnlyDependent.java
new file mode 100644
index 000000000..3146d7a35
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IReadOnlyDependent.java
@@ -0,0 +1,37 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v0.5
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v05.html
+
+Contributors:
+ IBM Corporation - Initial API and implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+
+
+/**
+ * Extension interface for actions. Actions implementing this interface not
+ * only manage an enable/disable state but also manage a "hypothetical"
+ * enable state, depending on whether the target they work on is writable
+ * or read-only.
+ * @since 2.0
+ */
+public interface IReadOnlyDependent {
+
+ /**
+ * Returns whether the actions would be enabled if its target
+ * would be enabled given the writable state described by <code>isWritable</code>.
+ * <code>isEnabled()</code> and <code>isEnabled(boolean)</code> holds the following
+ * invariants:
+ * isEnabled() == false, iff isEnabled(true) == false || isEnabled(false) == false
+ * isEnabled() == true, iff isEnabled(true) == true || isEnabled(false) == true
+ *
+ * @param isWritable
+ * @return the hypothetical enable state of the action
+ */
+ boolean isEnabled(boolean isWritable);
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IStatusField.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IStatusField.java
new file mode 100644
index 000000000..712dc4b4d
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IStatusField.java
@@ -0,0 +1,39 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+
+import org.eclipse.swt.graphics.Image;
+
+
+/**
+ * Interface of a status field of a text editor. The field that shows up in the
+ * workbench's status line if the contributing editor is active.
+ * @since 2.0
+ */
+public interface IStatusField {
+
+ /**
+ * Sets the text of this status field.
+ *
+ * @param text the text shown in the status field
+ */
+ void setText(String text);
+
+ /**
+ * Sets the image of this status field.
+ *
+ * @param image the image shown in the status field
+ */
+ void setImage(Image image);
+}
+
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ITextEditor.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ITextEditor.java
new file mode 100644
index 000000000..e4ceb3c3c
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ITextEditor.java
@@ -0,0 +1,173 @@
+package org.eclipse.ui.texteditor;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.viewers.ISelectionProvider;
+
+import org.eclipse.ui.IEditorPart;
+
+
+/**
+ * Interface to a text editor. This interface defines functional extensions to
+ * <code>IEditorPart</code> as well as the configuration capabilities of a text editor.
+ * <p>
+ * Text editors are configured with an <code>IDocumentProvider</code> which
+ * delivers a textual presentation (<code>IDocument</code>) of the editor's input.
+ * The editor works on the document and forwards all input element related calls,
+ * such as <code>save</code>, to the document provider. The provider also delivers
+ * the input's annotation model which is used to control the editor's vertical ruler.
+ * </p>
+ * <p>
+ * Clients may implement this interface from scratch, but the recommended way is to
+ * subclass the abstract base class <code>AbstractTextEditor</code>.
+ * </p>
+ *
+ * @see IDocumentProvider
+ * @see org.eclipse.jface.text.source.IAnnotationModel
+ */
+public interface ITextEditor extends IEditorPart {
+
+ /**
+ * Returns this text editor's document provider.
+ *
+ * @return the document provider
+ */
+ IDocumentProvider getDocumentProvider();
+
+ /**
+ * Closes this text editor after optionally saving changes.
+ *
+ * @param save <code>true</code> if unsaved changed should be saved, and
+ * <code>false</code> if unsaved changed should be discarded
+ */
+ void close(boolean save);
+
+ /**
+ * Returns whether the text in this text editor can be changed by the user.
+ *
+ * @return <code>true</code> if it can be edited, and <code>false</code>
+ * if it is read-only
+ */
+ boolean isEditable();
+
+ /**
+ * Abandons all modifications applied to this text editor's input element's
+ * textual presentation since the last save operation.
+ */
+ void doRevertToSaved();
+
+ /**
+ * Installs the given action under the given action id.
+ *
+ * @param actionId the action id
+ * @param action the action, or <code>null</code> to clear it
+ * @see #getAction
+ */
+ void setAction(String actionID, IAction action);
+
+ /**
+ * Returns the action installed under the given action id.
+ *
+ * @param actionId the action id
+ * @return the action, or <code>null</code> if none
+ * @see #setAction
+ */
+ IAction getAction(String actionId);
+
+ /**
+ * Sets the given activation code for the specified action. If
+ * there is an activation code already registered, it is replaced.
+ * The activation code consists of the same information as
+ * a <code>KeyEvent</code>. If the activation code is triggered
+ * and the associated action is enabled, the action is performed
+ * and the triggering <code>KeyEvent</code> is considered consumed.
+ * If the action is disabled, the <code>KeyEvent</code> is passed
+ * on unmodified. Thus, action activation codes and action accelerators
+ * differ in their model of event consumption. The key code parameter
+ * can be <code>-1</code> to indicate a wild card. The state mask
+ * parameter can be SWT.DEFAULT to indicate a wild card
+ *
+ * @param actionId the action id
+ * @param character the activation code character
+ * @param keyCode the activation code key code or <code>-1</code> for wild card
+ * @param stateMask the activation code state mask or <code>SWT.DEFAULT</code> for wild card
+ */
+ void setActionActivationCode(String actionId, char activationCharacter, int activationKeyCode, int activationStateMask);
+
+ /**
+ * Removes any installed activation code for the specified action.
+ * If no activation code is installed, this method does not have
+ * any effect.
+ *
+ * @param actionId the action id
+ */
+ void removeActionActivationCode(String actionId);
+
+ /**
+ * Returns whether this text editor is configured to show only the
+ * highlighted range of the text.
+ *
+ * @return <code>true</code> if only the highlighted range is shown, and
+ * <code>false</code> if this editor shows the entire text of the document
+ * @see #showHighlightRangeOnly
+ */
+ boolean showsHighlightRangeOnly();
+
+ /**
+ * Configures this text editor to show only the highlighted range of the
+ * text.
+ *
+ * @param showHighlightRangeOnly <code>true</code> if only the highlighted
+ * range is shown, and <code>false</code> if this editor shows the entire
+ * text of the document
+ * @see #showsHighlightRangeOnly
+ */
+ void showHighlightRangeOnly(boolean showHighlightRangeOnly);
+
+ /**
+ * Sets the highlighted range of this text editor to the specified region.
+ *
+ * @param offset the offset of the highlighted range
+ * @param length the length of the highlighted range
+ * @param moveCursor <code>true</code> if the cursor should be moved to
+ * the start of the highlighted range, and <code>false</code> to leave
+ * the cursor unaffected
+ * @see #getHighlightRange
+ */
+ void setHighlightRange(int offset, int length, boolean moveCursor);
+
+ /**
+ * Returns the highlighted range of this text editor.
+ *
+ * @return the highlighted range
+ * @see #setHighlightRange
+ */
+ IRegion getHighlightRange();
+
+ /**
+ * Resets the highlighted range of this text editor.
+ */
+ void resetHighlightRange();
+
+ /**
+ * Returns this text editor's selection provider. Repeated calls to this
+ * method return the same selection provider.
+ *
+ * @return the selection provider
+ */
+ ISelectionProvider getSelectionProvider();
+
+ /**
+ * Selects and reveals the specified range in this text editor.
+ *
+ * @param offset the offset of the selection
+ * @param length the length of the selection
+ */
+ void selectAndReveal(int offset, int length);
+} \ No newline at end of file
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ITextEditorActionConstants.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ITextEditorActionConstants.java
new file mode 100644
index 000000000..9cd3eb2df
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ITextEditorActionConstants.java
@@ -0,0 +1,229 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+
+import org.eclipse.ui.IWorkbenchActionConstants;
+
+
+/**
+ * Defines the names of those actions which are preregistered with the
+ * <code>AbstractTextEditor</code>. <code>RULER_DOUBLE_CLICK</code> defines
+ * the action which is registered as being executed when the editor's
+ * ruler has been double clicked. This interface extends the set of names
+ * available from <code>IWorkbenchActionConstants</code>. It also defines the
+ * names of the menu groups in a text editor's context menu.
+ */
+public interface ITextEditorActionConstants extends IWorkbenchActionConstants {
+
+ /**
+ * Context menu group for undo/redo related actions.
+ * Value: <code>"group.undo"</code>
+ */
+ static final String GROUP_UNDO= "group.undo"; //$NON-NLS-1$
+
+ /**
+ * Context menu group for copy/paste related actions.
+ * Value: <code>"group.copy"</code>
+ */
+ static final String GROUP_COPY= "group.copy"; //$NON-NLS-1$
+
+ /**
+ * Context menu group for text manipulation actions.
+ * Value: <code>"group.edit"</code>
+ */
+ static final String GROUP_EDIT= "group.edit"; //$NON-NLS-1$
+
+ /**
+ * Context menu group for print related actions.
+ * Value: <code>"group.print"</code>
+ */
+ static final String GROUP_PRINT= "group.print"; //$NON-NLS-1$
+
+ /**
+ * Context menu group for find/replace related actions.
+ * Value: <code>"group.find"</code>
+ */
+ static final String GROUP_FIND= "group.find"; //$NON-NLS-1$
+
+ /**
+ * Context menu group for save related actions.
+ * Value: <code>"group.save"</code>
+ */
+ static final String GROUP_SAVE= "group.save"; //$NON-NLS-1$
+
+ /**
+ * Context menu group for actions which do not fit in one of the other categories.
+ * Value: <code>"group.rest"</code>
+ */
+ static final String GROUP_REST= "group.rest"; //$NON-NLS-1$
+
+
+
+ /**
+ * Name of the action for shifting text blocks to the right.
+ * Value: <code>"ShiftRight"</code>
+ */
+ static final String SHIFT_RIGHT= "ShiftRight"; //$NON-NLS-1$
+
+ /**
+ * Name of the action for shifting text blocks to the left.
+ * Value: <code>"ShiftLeft"</code>
+ */
+ static final String SHIFT_LEFT= "ShiftLeft"; //$NON-NLS-1$
+
+ /**
+ * Name of the action for re-establishing the state after the
+ * most recent save operation.
+ * Value: <code>"IWorkbenchActionConstants.REVERT"</code>
+ */
+ static final String REVERT_TO_SAVED= REVERT;
+
+ /**
+ * Name of the action to delete the current line.
+ * Value: <code>"DeleteLine"</code>
+ * @since 2.0
+ */
+ static final String DELETE_LINE= "DeleteLine"; //$NON-NLS-1$
+
+ /**
+ * Name of the action to delete line to beginning.
+ * Value: <code>"DeleteLineToBeginning"</code>
+ * @since 2.0
+ */
+ static final String DELETE_LINE_TO_BEGINNING= "DeleteLineToBeginning"; //$NON-NLS-1$
+
+ /**
+ * Name of the action to delete line to end.
+ * Value: <code>"DeleteLineToEnd"</code>
+ * @since 2.0
+ */
+ static final String DELETE_LINE_TO_END= "DeleteLineToEnd"; //$NON-NLS-1$
+
+ /**
+ * Name of the action to set the mark.
+ * Value: <code>"SetMark"</code>
+ * @since 2.0
+ */
+ static final String SET_MARK= "SetMark"; //$NON-NLS-1$
+
+ /**
+ * Name of the action to set the mark.
+ * Value: <code>"ClearMark"</code>
+ * @since 2.0
+ */
+ static final String CLEAR_MARK= "ClearMark"; //$NON-NLS-1$
+
+ /**
+ * Name of the action to swap the mark with the cursor position.
+ * Value: <code>"SwapMark"</code>
+ * @since 2.0
+ */
+ static final String SWAP_MARK= "SwapMark"; //$NON-NLS-1$
+
+ /**
+ * Name of the action to jump to a certain text line.
+ * Value: <code>"GotoLine"</code>
+ */
+ static final String GOTO_LINE= "GotoLine"; //$NON-NLS-1$
+
+ /**
+ * Name of the action to find next.
+ * Value: <code>"FindNext"</code>
+ * @since 2.0
+ */
+ static final String FIND_NEXT= "FindNext"; //$NON-NLS-1$
+
+ /**
+ * Name of the action to find previous.
+ * Value: <code>"FindPrevious"</code>
+ * @since 2.0
+ */
+ static final String FIND_PREVIOUS= "FindPrevious"; //$NON-NLS-1$
+
+ /**
+ * Name of the action to incremental find.
+ * Value: <code>"FindIncremental"</code>
+ * @since 2.0
+ */
+ static final String FIND_INCREMENTAL= "FindIncremental"; //$NON-NLS-1$
+
+ /**
+ * Name of the action to convert line delimiters to Windows.
+ * Value: <code>"ConvertLineDelimitersToWindows"</code>
+ * @since 2.0
+ */
+ static final String CONVERT_LINE_DELIMITERS_TO_WINDOWS= "ConvertLineDelimitersToWindows"; //$NON-NLS-1$
+
+ /**
+ * Name of the action to convert line delimiters to UNIX.
+ * Value: <code>"ConvertLineDelimitersToUNIX"</code>
+ * @since 2.0
+ */
+ static final String CONVERT_LINE_DELIMITERS_TO_UNIX= "ConvertLineDelimitersToUNIX"; //$NON-NLS-1$
+
+ /**
+ * Name of the action to convert line delimiters to MAC.
+ * Value: <code>"ConvertLineDelimitersToMAC"</code>
+ * @since 2.0
+ */
+ static final String CONVERT_LINE_DELIMITERS_TO_MAC= "ConvertLineDelimitersToMAC"; //$NON-NLS-1$
+
+
+
+ /**
+ * Name of the ruler action performed when double clicking the editor's vertical ruler.
+ * Value: <code>"RulerDoubleClick"</code>
+ */
+ static final String RULER_DOUBLE_CLICK= "RulerDoubleClick"; //$NON-NLS-1$
+
+ /**
+ * Name of the ruler action performed when clicking the editor's vertical ruler.
+ * Value: <code>"RulerClick"</code>
+ * @since 2.0
+ */
+ static final String RULER_CLICK= "RulerClick"; //$NON-NLS-1$
+
+ /**
+ * Name of the ruler action to manage tasks.
+ * Value: <code>"ManageTasks"</code>
+ */
+ static final String RULER_MANAGE_TASKS= "ManageTasks"; //$NON-NLS-1$
+
+ /**
+ * Name of the ruler action to manage bookmarks.
+ * Value: <code>"ManageBookmarks"</code>
+ */
+ static final String RULER_MANAGE_BOOKMARKS= "ManageBookmarks"; //$NON-NLS-1$
+
+
+ /**
+ * Status line category "input position".
+ * Value: <code>"InputPosition"</code>
+ * @since 2.0
+ */
+ static final String STATUS_CATEGORY_INPUT_POSITION= "InputPosition"; //$NON-NLS-1$
+
+ /**
+ * Status line category "input mode".
+ * Value: <code>"InputMode"</code>
+ * @since 2.0
+ */
+ static final String STATUS_CATEGORY_INPUT_MODE= "InputMode"; //$NON-NLS-1$
+
+ /**
+ * Status line category "element state".
+ * Value: <code>"ElementState"</code>
+ * @since 2.0
+ */
+ static final String STATUS_CATEGORY_ELEMENT_STATE= "ElementState"; //$NON-NLS-1$
+} \ No newline at end of file
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ITextEditorActionDefinitionIds.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ITextEditorActionDefinitionIds.java
new file mode 100644
index 000000000..933c0975b
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ITextEditorActionDefinitionIds.java
@@ -0,0 +1,310 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+/**
+ * Defines the definitions ids for the text editor actions. These actions are
+ * navigation, selection, and modification actions.
+ * @since 2.0
+ */
+public interface ITextEditorActionDefinitionIds extends IWorkbenchActionDefinitionIds {
+
+ // edit
+
+ /**
+ * Action definition id of the edit delete line action.
+ * Value: <code>"org.eclipse.ui.edit.text.delete.line"</code>
+ */
+ public static final String DELETE_LINE= "org.eclipse.ui.edit.text.delete.line"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the edit delete line to beginning action.
+ * Value: <code>"org.eclipse.ui.edit.text.delete.line.to.beginning"</code>
+ */
+ public static final String DELETE_LINE_TO_BEGINNING= "org.eclipse.ui.edit.text.delete.line.to.beginning"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the edit delete line to end action.
+ * Value: <code>"org.eclipse.ui.edit.text.delete.line.to.end"</code>
+ */
+ public static final String DELETE_LINE_TO_END= "org.eclipse.ui.edit.text.delete.line.to.end"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the edit set mark action.
+ * Value: <code>"org.eclipse.ui.edit.text.set.mark"</code>
+ */
+ public static final String SET_MARK= "org.eclipse.ui.edit.text.set.mark"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the edit clear mark action.
+ * Value: <code>"org.eclipse.ui.edit.text.clear.mark"</code>
+ */
+ public static final String CLEAR_MARK= "org.eclipse.ui.edit.text.clear.mark"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the edit swap mark action.
+ * Value: <code>"org.eclipse.ui.edit.text.swap.mark"</code>
+ */
+ public static final String SWAP_MARK= "org.eclipse.ui.edit.text.swap.mark"; //$NON-NLS-1$
+
+
+ // navigation
+
+ /**
+ * Action definition id of the navigate goto previous line action.
+ * Value: <code>"org.eclipse.ui.edit.text.goto.lineUp"</code>
+ */
+ public static final String LINE_UP= "org.eclipse.ui.edit.text.goto.lineUp"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the navigate goto next line action.
+ * Value: <code>"org.eclipse.ui.edit.text.goto.lineDown"</code>
+ */
+ public static final String LINE_DOWN= "org.eclipse.ui.edit.text.goto.lineDown"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the navigate goto line start action.
+ * Value: <code>"org.eclipse.ui.edit.text.goto.lineStart"</code>
+ */
+ public static final String LINE_START= "org.eclipse.ui.edit.text.goto.lineStart"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the navigate goto line end action.
+ * Value: <code>"org.eclipse.ui.edit.text.goto.lineEnd"</code>
+ */
+ public static final String LINE_END= "org.eclipse.ui.edit.text.goto.lineEnd"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the navigate goto line action.
+ * Value: <code>"org.eclipse.ui.edit.text.goto.line"</code>
+ */
+ public static final String LINE_GOTO= "org.eclipse.ui.edit.text.goto.line"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the navigate goto previous column action.
+ * Value: <code>"org.eclipse.ui.edit.text.goto.columnPrevious"</code>
+ */
+ public static final String COLUMN_PREVIOUS= "org.eclipse.ui.edit.text.goto.columnPrevious"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the navigate goto next column action.
+ * Value: <code>"org.eclipse.ui.edit.text.goto.columnNext"</code>
+ */
+ public static final String COLUMN_NEXT= "org.eclipse.ui.edit.text.goto.columnNext"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the navigate goto previous page action.
+ * Value: <code>"org.eclipse.ui.edit.text.goto.pageUp"</code>
+ */
+ public static final String PAGE_UP= "org.eclipse.ui.edit.text.goto.pageUp"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the navigate goto next page action.
+ * Value: <code>"org.eclipse.ui.edit.text.goto.pageDown"</code>
+ */
+ public static final String PAGE_DOWN= "org.eclipse.ui.edit.text.goto.pageDown"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the navigate goto previous word action.
+ * Value: <code>"org.eclipse.ui.edit.text.goto.wordPrevious"</code>
+ */
+ public static final String WORD_PREVIOUS= "org.eclipse.ui.edit.text.goto.wordPrevious"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the navigate goto next word action.
+ * Value: <code>"org.eclipse.ui.edit.text.goto.wordNext"</code>
+ */
+ public static final String WORD_NEXT= "org.eclipse.ui.edit.text.goto.wordNext"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the navigate goto text start action.
+ * Value: <code>"org.eclipse.ui.edit.text.goto.textStart"</code>
+ */
+ public static final String TEXT_START= "org.eclipse.ui.edit.text.goto.textStart"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the navigate goto text end action.
+ * Value: <code>"org.eclipse.ui.edit.text.goto.textEnd"</code>
+ */
+ public static final String TEXT_END= "org.eclipse.ui.edit.text.goto.textEnd"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the navigate goto start of window action.
+ * Value: <code>"org.eclipse.ui.edit.text.goto.windowStart"</code>
+ */
+ public static final String WINDOW_START= "org.eclipse.ui.edit.text.goto.windowStart"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the navigate goto end of window action.
+ * Value: <code>"org.eclipse.ui.edit.text.goto.windowEnd"</code>
+ */
+ public static final String WINDOW_END= "org.eclipse.ui.edit.text.goto.windowEnd"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the navigate scroll line up action.
+ * Value: <code>"org.eclipse.ui.edit.text.scroll.lineUp"</code>
+ */
+ public static final String SCROLL_LINE_UP= "org.eclipse.ui.edit.text.scroll.lineUp"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the navigate scroll line down action.
+ * Value: <code>"org.eclipse.ui.edit.text.scroll.lineDown"</code>
+ */
+ public static final String SCROLL_LINE_DOWN= "org.eclipse.ui.edit.text.scroll.lineDown"; //$NON-NLS-1$
+
+
+ // selection
+
+ /**
+ * Action definition id of the select line up action.
+ * Value: <code>"org.eclipse.ui.edit.text.select.lineUp"</code>
+ */
+ public static final String SELECT_LINE_UP= "org.eclipse.ui.edit.text.select.lineUp"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the select line down action.
+ * Value: <code>"org.eclipse.ui.edit.text.select.lineDown"</code>
+ */
+ public static final String SELECT_LINE_DOWN= "org.eclipse.ui.edit.text.select.lineDown"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the select line start action.
+ * Value: <code>"org.eclipse.ui.edit.text.select.lineStart"</code>
+ */
+ public static final String SELECT_LINE_START= "org.eclipse.ui.edit.text.select.lineStart"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the select line end action.
+ * Value: <code>"org.eclipse.ui.edit.text.select.lineEnd"</code>
+ */
+ public static final String SELECT_LINE_END= "org.eclipse.ui.edit.text.select.lineEnd"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the select previous column action.
+ * Value: <code>"org.eclipse.ui.edit.text.select.columnPrevious"</code>
+ */
+ public static final String SELECT_COLUMN_PREVIOUS= "org.eclipse.ui.edit.text.select.columnPrevious"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the select next column action.
+ * Value: <code>"org.eclipse.ui.edit.text.select.columnNext"</code>
+ */
+ public static final String SELECT_COLUMN_NEXT= "org.eclipse.ui.edit.text.select.columnNext"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the select page up action.
+ * Value: <code>"org.eclipse.ui.edit.text.select.pageUp"</code>
+ */
+ public static final String SELECT_PAGE_UP= "org.eclipse.ui.edit.text.select.pageUp"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the select page down action.
+ * Value: <code>"org.eclipse.ui.edit.text.select.pageDown"</code>
+ */
+ public static final String SELECT_PAGE_DOWN= "org.eclipse.ui.edit.text.select.pageDown"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the select previous word action.
+ * Value: <code>"org.eclipse.ui.edit.text.select.wordPrevious"</code>
+ */
+ public static final String SELECT_WORD_PREVIOUS= "org.eclipse.ui.edit.text.select.wordPrevious"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the select next word action.
+ * Value: <code>"org.eclipse.ui.edit.text.select.wordNext"</code>
+ */
+ public static final String SELECT_WORD_NEXT= "org.eclipse.ui.edit.text.select.wordNext"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the select text start action.
+ * Value: <code>"org.eclipse.ui.edit.text.select.textStart"</code>
+ */
+ public static final String SELECT_TEXT_START= "org.eclipse.ui.edit.text.select.textStart"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the select text end action.
+ * Value: <code>"org.eclipse.ui.edit.text.select.textEnd"</code>
+ */
+ public static final String SELECT_TEXT_END= "org.eclipse.ui.edit.text.select.textEnd"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the select window start action.
+ * Value: <code>"org.eclipse.ui.edit.text.select.windowStart"</code>
+ */
+ public static final String SELECT_WINDOW_START= "org.eclipse.ui.edit.text.select.windowStart"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the select window end action.
+ * Value: <code>"org.eclipse.ui.edit.text.select.windowEnd"</code>
+ */
+ public static final String SELECT_WINDOW_END= "org.eclipse.ui.edit.text.select.windowEnd"; //$NON-NLS-1$
+
+
+ // modification
+
+ /**
+ * Action definition id of the edit delet previous character action.
+ * Value: <code>"org.eclipse.ui.edit.text.deletePrevious"</code>
+ */
+ public static final String DELETE_PREVIOUS= "org.eclipse.ui.edit.text.deletePrevious"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the edit delete next character action.
+ * Value: <code>"org.eclipse.ui.edit.text.deleteNext"</code>
+ */
+ public static final String DELETE_NEXT= "org.eclipse.ui.edit.text.deleteNext"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the edit shift right action.
+ * Value: <code>"org.eclipse.ui.edit.text.shiftRight"</code>
+ */
+ public static final String SHIFT_RIGHT= "org.eclipse.ui.edit.text.shiftRight"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the edit shift left action.
+ * Value: <code>"org.eclipse.ui.edit.text.shiftLeft"</code>
+ */
+ public static final String SHIFT_LEFT= "org.eclipse.ui.edit.text.shiftLeft"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the edit convert to window's line delimiter action.
+ * Value: <code>"org.eclipse.ui.edit.text.convert.lineDelimiters.toWindows"</code>
+ */
+ public static final String CONVERT_LINE_DELIMITERS_TO_WINDOWS= "org.eclipse.ui.edit.text.convert.lineDelimiters.toWindows"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the edit convert to unix' line delimiter action.
+ * Value: <code>"org.eclipse.ui.edit.text.convert.lineDelimiters.toUNIX"</code>
+ */
+ public static final String CONVERT_LINE_DELIMITERS_TO_UNIX= "org.eclipse.ui.edit.text.convert.lineDelimiters.toUNIX"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the edit convert to mac' line delimiter action.
+ * Value: <code>"org.eclipse.ui.edit.text.convert.lineDelimiters.toMac"</code>
+ */
+ public static final String CONVERT_LINE_DELIMITERS_TO_MAC= "org.eclipse.ui.edit.text.convert.lineDelimiters.toMac"; //$NON-NLS-1$
+
+
+ // miscellaneous
+
+ /**
+ * Action definition id of the toggle input mode action.
+ * Value: <code>"org.eclipse.ui.edit.text.toggleOverwrite"</code>
+ */
+ public static final String TOGGLE_OVERWRITE= "org.eclipse.ui.edit.text.toggleOverwrite"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the show ruler context menu action.
+ * Value: <code>"org.eclipse.ui.edit.text.showRulerContextMenu"</code>
+ */
+ public static final String SHOW_RULER_CONTEXT_MENU= "org.eclipse.ui.edit.text.showRulerContextMenu"; //$NON-NLS-1$
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ITextEditorExtension.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ITextEditorExtension.java
new file mode 100644
index 000000000..bce3995c3
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ITextEditorExtension.java
@@ -0,0 +1,64 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+
+import org.eclipse.jface.action.IMenuListener;
+
+
+/**
+ * Extension interface for <code>ITextEditor</code>. Adds the following functions:
+ * <ul>
+ * <li> status fields
+ * <li> read-only state of the editor's input
+ * <li> ruler context menu listeners.
+ * </ul>
+ *
+ * @since 2.0
+ */
+public interface ITextEditorExtension {
+
+ /**
+ * Informs the editor which status field is to be used when posting status
+ * information in the given category.
+ *
+ * @param field the status field to be used
+ * @param category the status information category
+ * @see ITextEditorActionConstants
+ */
+ void setStatusField(IStatusField field, String category);
+
+ /**
+ * Returns whether the editor's input is read-only. The semantics of
+ * this method is orthogonal to <code>isEditable</code> as it talks about the
+ * editor input, i.e. the domain element, and <b>not</b> about the editor
+ * document.
+ *
+ * @return <code>true</code> if the editor input is read-only
+ */
+ boolean isEditorInputReadOnly();
+
+ /**
+ * Adds a ruler context menu listener to the editor.
+ *
+ * @param listener the listener
+ */
+ void addRulerContextMenuListener(IMenuListener listener);
+
+ /**
+ * Removes a ruler context menu listener from the editor.
+ *
+ * @param listener the listener
+ */
+ void removeRulerContextMenuListener(IMenuListener listener);
+}
+
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IUpdate.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IUpdate.java
new file mode 100644
index 000000000..cda92839c
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IUpdate.java
@@ -0,0 +1,18 @@
+package org.eclipse.ui.texteditor;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+
+/**
+ * Indicates the support of an update method.
+ */
+public interface IUpdate {
+
+ /**
+ * Requests that this object update itself.
+ */
+ void update();
+} \ No newline at end of file
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IWorkbenchActionDefinitionIds.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IWorkbenchActionDefinitionIds.java
new file mode 100644
index 000000000..231fb4c38
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IWorkbenchActionDefinitionIds.java
@@ -0,0 +1,124 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+
+package org.eclipse.ui.texteditor;
+
+
+/**
+ * Defines the definitions ids for workbench actions.
+ * @since 2.0
+ */
+public interface IWorkbenchActionDefinitionIds {
+
+ // workbench file actions
+
+ /**
+ * Action definition id of the file print action.
+ * Value: <code>"org.eclipse.ui.file.print"</code>
+ */
+ public static final String PRINT= "org.eclipse.ui.file.print"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the file save action.
+ * Value: <code>"org.eclipse.file.save"</code>
+ */
+ public static final String SAVE= "org.eclipse.file.save"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the file revert action.
+ * Value: <code>"org.eclipse.ui.edit.revertToSaved"</code>
+ */
+ public static final String REVERT_TO_SAVED= "org.eclipse.ui.edit.revertToSaved"; //$NON-NLS-1$
+
+
+
+ // workbench edit actions
+
+ /**
+ * Action definition id of the edit cut action.
+ * Value: <code>"org.eclipse.ui.edit.cut"</code>
+ */
+ public static final String CUT= "org.eclipse.ui.edit.cut"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the edit copy action.
+ * Value: <code>"org.eclipse.ui.edit.copy"</code>
+ */
+ public static final String COPY= "org.eclipse.ui.edit.copy"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the edit past action.
+ * Value: <code>"org.eclipse.ui.edit.paste"</code>
+ */
+ public static final String PASTE= "org.eclipse.ui.edit.paste"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the edit undo action.
+ * Value: <code>"org.eclipse.ui.edit.undo"</code>
+ */
+ public static final String UNDO= "org.eclipse.ui.edit.undo"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the edit redo action.
+ * Value: <code>"org.eclipse.ui.edit.redo"</code>
+ */
+ public static final String REDO= "org.eclipse.ui.edit.redo"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the edit delete action.
+ * Value: <code>"org.eclipse.ui.edit.delete"</code>
+ */
+ public static final String DELETE= "org.eclipse.ui.edit.delete"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the edit select all action.
+ * Value: <code>"org.eclipse.ui.edit.selectAll"</code>
+ */
+ public static final String SELECT_ALL= "org.eclipse.ui.edit.selectAll"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the edit find/replace action.
+ * Value: <code>"org.eclipse.ui.edit.findReplace"</code>
+ */
+ public static final String FIND_REPLACE= "org.eclipse.ui.edit.findReplace"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the edit add bookmark action.
+ * Value: <code>"org.eclipse.ui.edit.addBookmark"</code>
+ */
+ public static final String ADD_BOOKMARK= "org.eclipse.ui.edit.addBookmark"; //$NON-NLS-1$
+
+ /**
+ * Action definition id of the edit add task action.
+ * Value: <code>"org.eclipse.ui.edit.addTask"</code>
+ */
+ public static final String ADD_TASK= "org.eclipse.ui.edit.addTask"; //$NON-NLS-1$
+
+
+ // future workbench edit actions
+
+ /**
+ * Action definition id of the edit find next action.
+ * Value: <code>"org.eclipse.ui.edit.findNext"</code>
+ */
+ public static final String FIND_NEXT= "org.eclipse.ui.edit.findNext"; //$NON-NLS-1$
+ /**
+ * Action definition id of the edit find previous action.
+ * Value: <code>"org.eclipse.ui.edit.findPrevious"</code>
+ */
+ public static final String FIND_PREVIOUS= "org.eclipse.ui.edit.findPrevious"; //$NON-NLS-1$
+ /**
+ * Action definition id of the edit incremental find action.
+ * Value: <code>"org.eclipse.ui.edit.findIncremental"</code>
+ */
+ public static final String FIND_INCREMENTAL= "org.eclipse.ui.edit.findIncremental"; //$NON-NLS-1$
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IncrementalFindAction.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IncrementalFindAction.java
new file mode 100644
index 000000000..354a65298
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IncrementalFindAction.java
@@ -0,0 +1,101 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+
+import java.util.ResourceBundle;
+
+import org.eclipse.jface.text.IFindReplaceTarget;
+import org.eclipse.jface.text.IFindReplaceTargetExtension;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+
+
+/**
+ * An action which enters the incremental find mode a la emacs.
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ * @since 2.0
+ */
+public class IncrementalFindAction extends ResourceAction implements IUpdate {
+
+ /** The action's target */
+ private IFindReplaceTarget fTarget;
+ /** The part the action is bound to */
+ private IWorkbenchPart fWorkbenchPart;
+ /** The workbench window */
+ private IWorkbenchWindow fWorkbenchWindow;
+
+ /**
+ * Creates a new incremental find action for the given text editor.
+ * The action configures its visual representation from the given
+ * resource bundle.
+ *
+ * @param bundle the resource bundle
+ * @param prefix a prefix to be prepended to the various resource keys
+ * (described in <code>ResourceAction</code> constructor), or
+ * <code>null</code> if none
+ * @param editor the text editor
+ * @see ResourceAction#ResourceAction
+ */
+ public IncrementalFindAction(ResourceBundle bundle, String prefix, IWorkbenchPart workbenchPart) {
+ super(bundle, prefix);
+ fWorkbenchPart= workbenchPart;
+ update();
+ }
+
+ /**
+ * Creates a new incremental find action for the given text editor.
+ * The action configures its visual representation from the given
+ * resource bundle.
+ *
+ * @param bundle the resource bundle
+ * @param prefix a prefix to be prepended to the various resource keys
+ * (described in <code>ResourceAction</code> constructor), or
+ * <code>null</code> if none
+ * @param workbenchWindow the workbench window
+ * @see ResourceAction#ResourceAction
+ *
+ * @deprecated use FindReplaceAction(ResourceBundle, String, IWorkbenchPart) instead
+ */
+ public IncrementalFindAction(ResourceBundle bundle, String prefix, IWorkbenchWindow workbenchWindow) {
+ super(bundle, prefix);
+ fWorkbenchWindow= workbenchWindow;
+ update();
+ }
+
+ /*
+ * @see IAction#run
+ */
+ public void run() {
+ if (fTarget != null && fTarget instanceof IFindReplaceTargetExtension)
+ ((IFindReplaceTargetExtension) fTarget).beginSession();
+ }
+
+ /*
+ * @see IUpdate#update()
+ */
+ public void update() {
+
+ if (fWorkbenchPart == null && fWorkbenchWindow != null)
+ fWorkbenchPart= fWorkbenchWindow.getPartService().getActivePart();
+
+ if (fWorkbenchPart != null)
+ fTarget= (IFindReplaceTarget) fWorkbenchPart.getAdapter(IncrementalFindTarget.class);
+ else
+ fTarget= null;
+
+ setEnabled(fTarget != null && fTarget.canPerformFind());
+ }
+
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IncrementalFindTarget.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IncrementalFindTarget.java
new file mode 100644
index 000000000..45ff4a807
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/IncrementalFindTarget.java
@@ -0,0 +1,577 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+import java.text.MessageFormat;
+import java.util.Stack;
+
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.jface.text.IFindReplaceTarget;
+import org.eclipse.jface.text.IFindReplaceTargetExtension;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextListener;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.ITextViewerExtension;
+import org.eclipse.jface.text.TextEvent;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.custom.VerifyKeyListener;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.VerifyEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Point;
+
+/**
+ * An incremental find target. Replace is always disabled.
+ * @since 2.0
+ */
+class IncrementalFindTarget implements IFindReplaceTarget, IFindReplaceTargetExtension, VerifyKeyListener, MouseListener, FocusListener, ITextListener {
+
+ /** The string representing rendered tab */
+ private final static String TAB= EditorMessages.getString("Editor.FindIncremental.render.tab"); //$NON-NLS-1$
+
+ /** The text viewer to operate on */
+ private final ITextViewer fTextViewer;
+ /** The status line manager for output */
+ private final IStatusLineManager fStatusLine;
+ /** The find replace target to delegate find requests */
+ private final IFindReplaceTarget fTarget;
+
+ /** The current find string */
+ private StringBuffer fFindString= new StringBuffer();
+ /** The position to start the find from */
+ private int fBasePosition;
+ /** The position of the first upper case character, -1 if none */
+ private int fCasePosition;
+ /** The position of the last successful find */
+ private int fCurrentIndex;
+ /** A flag indicating if last find was successful */
+ private boolean fFound;
+ /** A flag indicating listeners are installed. */
+ private boolean fInstalled;
+ /** The current find stack */
+ private Stack fSessionStack;
+ /** A constant representing a find-next operation */
+ private static final Object NEXT = new Object();
+ /** A constant representing a find-previous operation */
+ private static final Object PREVIOUS = new Object();
+ /** A constant representing adding a character to the find pattern */
+ private static final Object CHAR = new Object();
+ /** A constant representing a wrap operation */
+ private static final Object WRAPPED = new Object();
+
+ /**
+ * Creates an instance of an incremental find target.
+ *
+ * @param viewer the text viewer to operate on
+ * @param manager the status line manager for output
+ */
+ public IncrementalFindTarget(ITextViewer viewer, IStatusLineManager manager) {
+ fTextViewer= viewer;
+ fStatusLine= manager;
+ fTarget= viewer.getFindReplaceTarget();
+ }
+
+ /*
+ * @see IFindReplaceTarget#canPerformFind()
+ */
+ public boolean canPerformFind() {
+ return fTarget.canPerformFind();
+ }
+
+ /*
+ * @see IFindReplaceTarget#findAndSelect(int, String, boolean, boolean, boolean)
+ */
+ public int findAndSelect(int offset, String findString, boolean searchForward, boolean caseSensitive, boolean wholeWord) {
+ return fTarget.findAndSelect(offset, findString, searchForward, caseSensitive, wholeWord);
+ }
+
+ /*
+ * @see IFindReplaceTarget#getSelection()
+ */
+ public Point getSelection() {
+ return fTarget.getSelection();
+ }
+
+ /*
+ * @see IFindReplaceTarget#getSelectionText()
+ */
+ public String getSelectionText() {
+ return fTarget.getSelectionText();
+ }
+
+ /*
+ * @see IFindReplaceTarget#isEditable()
+ */
+ public boolean isEditable() {
+ return false;
+ }
+
+ /*
+ * @see IFindReplaceTarget#replaceSelection(String)
+ */
+ public void replaceSelection(String text) {
+ }
+
+ /*
+ * @see IFindReplaceTargetExtension#beginSession()
+ */
+ public void beginSession() {
+ fFindString.setLength(0);
+ fSessionStack = new Stack();
+ fCasePosition= -1;
+ fBasePosition= fTarget.getSelection().x;
+ fCurrentIndex= fBasePosition;
+ fFound= true;
+
+ install();
+ performFindNext(true, fBasePosition, false, false);
+ updateStatus(fFound);
+
+ if (fTarget instanceof IFindReplaceTargetExtension)
+ ((IFindReplaceTargetExtension) fTarget).beginSession();
+ }
+
+ /*
+ * @see IFindReplaceTargetExtension#endSession()
+ */
+ public void endSession() {
+ if (fTarget instanceof IFindReplaceTargetExtension)
+ ((IFindReplaceTargetExtension) fTarget).endSession();
+
+ // will uninstall itself
+ }
+
+ /*
+ * @see IFindReplaceTargetExtension#getScope()
+ */
+ public IRegion getScope() {
+ return null;
+ }
+
+ /*
+ * @see IFindReplaceTargetExtension#setGlobal(boolean)
+ */
+ public void setGlobal(boolean global) {
+ }
+
+ /*
+ * @see IFindReplaceTargetExtension#setScope(IRegion)
+ */
+ public void setScope(IRegion scope) {
+ }
+
+ /*
+ * @see IFindReplaceTargetExtension#setReplaceAllMode(boolean)
+ */
+ public void setReplaceAllMode(boolean replaceAll) {
+ }
+
+ /**
+ * Installs this target. I.e. adds all required listeners.
+ */
+ private void install() {
+ if (fInstalled)
+ return;
+
+ StyledText text= fTextViewer.getTextWidget();
+ if (text == null)
+ return;
+
+ text.addMouseListener(this);
+ fTextViewer.addTextListener(this);
+
+ if (fTextViewer instanceof ITextViewerExtension) {
+ ITextViewerExtension e= (ITextViewerExtension) fTextViewer;
+ e.prependVerifyKeyListener(this);
+ } else {
+ text.addVerifyKeyListener(this);
+ }
+
+ fInstalled= true;
+ }
+
+ /**
+ * Uninstalls itself. I.e. removes all listeners installed in <code>install</code>.
+ */
+ private void uninstall() {
+ fTextViewer.removeTextListener(this);
+
+ StyledText text= fTextViewer.getTextWidget();
+ text.removeMouseListener(this);
+
+ if (fTextViewer instanceof ITextViewerExtension) {
+ ITextViewerExtension e= (ITextViewerExtension) fTextViewer;
+ e.removeVerifyKeyListener(this);
+ } else {
+ text.removeVerifyKeyListener(this);
+ }
+
+ fInstalled= false;
+ }
+
+ /**
+ * Returns whether the find string can be found using the given options.
+ *
+ * @param forward the search direction
+ * @param position the start offset
+ * @param wrapSearch should the search wrap to start/end if end/start is reached
+ * @param takeBack is the find string shortend
+ * @return <code>true</code> if find string can be found using the options
+ */
+ private boolean performFindNext(boolean forward, int position, boolean wrapSearch, boolean takeBack) {
+ String string= fFindString.toString();
+
+ int index;
+ if (string.length() == 0) {
+
+ // workaround for empty selection in target
+ fTextViewer.setSelectedRange(fBasePosition + fTextViewer.getVisibleRegion().getOffset(), 0);
+ index= fBasePosition;
+
+ } else {
+
+ if (!forward)
+ position--;
+
+ index= findIndex(string, position, forward, fCasePosition != -1, wrapSearch, takeBack);
+ }
+
+ boolean found = (index != -1);
+ if (found) fCurrentIndex = index;
+
+ return found;
+ }
+
+ /**
+ * Updates the status line appropriate for the indicated success.
+ * @param found the success
+ */
+ private void updateStatus(boolean found) {
+ if (fSessionStack == null) return;
+
+ String string= fFindString.toString();
+ String prefix = ""; //$NON-NLS-1$
+ if (fSessionStack.search(WRAPPED) != -1) {
+ prefix = EditorMessages.getString("Editor.FindIncremental.wrapped"); //$NON-NLS-1$
+ }
+ if (!found) {
+ String pattern= EditorMessages.getString("Editor.FindIncremental.not_found.pattern"); //$NON-NLS-1$
+ statusError(MessageFormat.format(pattern, new Object[] { prefix, string }));
+
+ } else {
+ String pattern= EditorMessages.getString("Editor.FindIncremental.found.pattern"); //$NON-NLS-1$
+ statusMessage(MessageFormat.format(pattern, new Object[] { prefix, string }));
+ }
+ }
+
+ /**
+ * Retuns the offset at which the search string is found next using the given options
+ * @param findString the string to search for
+ * @param startPosition the start offset
+ * @param forward the search direction
+ * @param caseSensitive is the search case sensitive
+ * @param wrapSearch should the search wrap to start/end if end/start is reached
+ * @param takeBack is the find string shortend
+ * @return the offset of the next match or <code>-1</code>
+ */
+ private int findIndex(String findString, int startPosition, boolean forwardSearch, boolean caseSensitive, boolean wrapSearch, boolean takeBack) {
+
+ if (fTarget == null)
+ return -1;
+
+ int startIndex = (forwardSearch) ? startPosition : startPosition - 1;
+ int index= fTarget.findAndSelect(startIndex, findString, forwardSearch, caseSensitive, false);
+
+ if (index != -1) {
+ fFound = true;
+ return index;
+ }
+
+ if (fFound) {
+ // beep once
+ StyledText text= fTextViewer.getTextWidget();
+ if (!takeBack && text != null && !text.isDisposed())
+ text.getDisplay().beep();
+ }
+
+ if (!wrapSearch || (fFound && !takeBack)) {
+ fFound = false;
+ return index;
+ }
+
+ index = fTarget.findAndSelect(-1, findString, forwardSearch, caseSensitive, false);
+ fFound = (index != -1);
+ if (!takeBack && fFound) wrap();
+ return index;
+ }
+
+ /**
+ * Remembers wrapping in the session stack.
+ */
+ private void wrap() {
+ fSessionStack.push(WRAPPED);
+ }
+
+ /*
+ * @see VerifyKeyListener#verifyKey(VerifyEvent)
+ */
+ public void verifyKey(VerifyEvent event) {
+ if (!event.doit)
+ return;
+
+ if (event.character == 0) {
+
+ switch (event.keyCode) {
+
+ // ALT, CTRL, ARROW_LEFT, ARROW_RIGHT == leave
+ case SWT.ALT:
+ case SWT.CTRL:
+ case SWT.ARROW_LEFT:
+ case SWT.ARROW_RIGHT:
+ case SWT.HOME:
+ case SWT.END:
+ case SWT.PAGE_DOWN:
+ case SWT.PAGE_UP:
+ leave();
+ break;
+
+ // find next
+ case SWT.ARROW_DOWN:
+ if (performFindNext(true, fTarget.getSelection().x + fTarget.getSelection().y, true, false))
+ fSessionStack.push(NEXT);
+ event.doit= false;
+ break;
+
+ // find previous
+ case SWT.ARROW_UP:
+ if (performFindNext(false, fTarget.getSelection().x, true, false))
+ fSessionStack.push(PREVIOUS);
+
+ if (fCurrentIndex != -1 && fCurrentIndex < fBasePosition)
+ fBasePosition= fCurrentIndex;
+
+ event.doit= false;
+ break;
+ }
+
+ // event.character != 0
+ } else {
+
+ switch (event.character) {
+
+ // ESC, CR = quit
+ case 0x1B:
+ case 0x0D:
+ leave();
+ event.doit= false;
+ break;
+
+ // backspace and delete
+ case 0x08:
+ case 0x7F:
+ {
+ if (fSessionStack.empty()) {
+ StyledText text= fTextViewer.getTextWidget();
+ if (text != null && !text.isDisposed())
+ text.getDisplay().beep();
+ event.doit= false;
+ break;
+ }
+
+ Object last = popSessionStack();
+ while (!fSessionStack.empty() && fSessionStack.peek() == WRAPPED)
+ popSessionStack();
+
+ // Last event repeated a search
+ if (last == PREVIOUS) {
+ performFindNext(true, fTarget.getSelection().x + fTarget.getSelection().y, true, true);
+ } else if (last == NEXT) {
+ performFindNext(false, fTarget.getSelection().x, true, true);
+
+ if (fCurrentIndex != -1 && fCurrentIndex < fBasePosition)
+ fBasePosition= fCurrentIndex;
+ } else if (last == CHAR) {
+ // Last event added a character
+ performFindNext(true, fBasePosition, true, true);
+ }
+ event.doit= false;
+ }
+ break;
+
+ default:
+ if (event.stateMask == 0 || event.stateMask == SWT.SHIFT) {
+
+ pushChar(event.character);
+ performFindNext(true, fBasePosition, false, false);
+ event.doit= false;
+ }
+ break;
+ }
+ }
+ updateStatus(fFound);
+ }
+
+
+ /**
+ * Extends the incremental search by the given character.
+ * @param character the character to append to the searhc string
+ */
+ private void pushChar(char character) {
+ if (fCasePosition == -1 && Character.isUpperCase(character) && Character.toLowerCase(character) != character)
+ fCasePosition= fFindString.length();
+ fFindString.append(character);
+ fSessionStack.push(CHAR);
+ }
+
+ /**
+ * Pops the top element from the session stack.
+ * @return the top element from the session stack
+ */
+ private Object popSessionStack() {
+ Object o = fSessionStack.pop();
+ if (o == CHAR) {
+ int newLength = fFindString.length() -1;
+ fFindString.deleteCharAt(newLength);
+ if (fCasePosition == newLength)
+ fCasePosition= -1;
+ }
+ return o;
+ }
+
+ /**
+ * Leaves this incremental search session.
+ */
+ private void leave() {
+ statusClear();
+ uninstall();
+ fSessionStack = null;
+ }
+
+ /*
+ * @see ITextListener#textChanged(TextEvent)
+ */
+ public void textChanged(TextEvent event) {
+ leave();
+ }
+
+ /*
+ * @see MouseListener#mouseDoubleClick(MouseEvent)
+ */
+ public void mouseDoubleClick(MouseEvent e) {
+ leave();
+ }
+
+ /*
+ * @see MouseListener#mouseDown(MouseEvent)
+ */
+ public void mouseDown(MouseEvent e) {
+ leave();
+ }
+
+ /*
+ * @see MouseListener#mouseUp(MouseEvent)
+ */
+ public void mouseUp(MouseEvent e) {
+ leave();
+ }
+
+ /*
+ * @see FocusListener#focusGained(FocusEvent)
+ */
+ public void focusGained(FocusEvent e) {
+ leave();
+ }
+
+ /*
+ * @see FocusListener#focusLost(FocusEvent)
+ */
+ public void focusLost(FocusEvent e) {
+ leave();
+ }
+
+ /**
+ * Sets the given string as status message, clears the status error message.
+ * @param string the status message
+ */
+ private void statusMessage(String string) {
+ fStatusLine.setErrorMessage(""); //$NON-NLS-1$
+ fStatusLine.setMessage(escapeTabs(string));
+ }
+
+ /**
+ * Sets the status error message, clears the status message.
+ * @param string the status error message
+ */
+ private void statusError(String string) {
+ fStatusLine.setErrorMessage(escapeTabs(string));
+ fStatusLine.setMessage(""); //$NON-NLS-1$
+ }
+
+ /**
+ * Clears the status message and the status error message.
+ */
+ private void statusClear() {
+ fStatusLine.setErrorMessage(""); //$NON-NLS-1$
+ fStatusLine.setMessage(""); //$NON-NLS-1$
+ }
+
+ /**
+ * Translates all tab characters into a proper status line presentation.
+ * @param string the string in which to translate the tabs
+ * @return the given string with all tab characters replace with a proper status line presentation
+ */
+ private String escapeTabs(String string) {
+ StringBuffer buffer= new StringBuffer();
+
+ int begin= 0;
+ int end= string.indexOf('\t', begin);
+
+ while (end >= 0) {
+ buffer.append(string.substring(begin, end));
+ buffer.append(TAB);
+ begin= end + 1;
+ end= string.indexOf('\t', begin);
+ }
+ buffer.append(string.substring(begin));
+
+ return buffer.toString();
+ }
+
+ /*
+ * @see IFindReplaceTargetExtension#getLineSelection()
+ */
+ public Point getLineSelection() {
+ if (fTarget instanceof IFindReplaceTargetExtension)
+ return ((IFindReplaceTargetExtension) fTarget).getLineSelection();
+
+ return null; // XXX should not return null
+ }
+
+ /*
+ * @see IFindReplaceTargetExtension#setSelection(int, int)
+ */
+ public void setSelection(int offset, int length) {
+ if (fTarget instanceof IFindReplaceTargetExtension)
+ ((IFindReplaceTargetExtension) fTarget).setSelection(offset, length);
+ }
+
+ /*
+ * @see IFindReplaceTargetExtension#setScopeHighlightColor(Color)
+ */
+ public void setScopeHighlightColor(Color color) {
+ }
+
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/InfoForm.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/InfoForm.java
new file mode 100644
index 000000000..1f7362b49
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/InfoForm.java
@@ -0,0 +1,227 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+
+package org.eclipse.ui.texteditor;
+
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+
+
+/**
+ * A form consisting of a title, a banner, and a info text. Banner and info text are
+ * separated by a separator line. This form must be handled like a SWT widget.
+ * @since 2.0
+ */
+public class InfoForm {
+
+ /** The form's root widget */
+ private ScrolledComposite fScrolledComposite;
+ /** The background color */
+ private Color fBackgroundColor;
+ /** The foreground color */
+ private Color fForegroundColor;
+ /** The separator's color */
+ private Color fSeparatorColor;
+ /** The form header */
+ private Label fHeader;
+ /** The form banner */
+ private Label fBanner;
+ /** The form text */
+ private Label fText;
+ /** The preference change listener */
+ private IPropertyChangeListener fPropertyChangeListener;
+
+ /**
+ * Creates a new info form.
+ * @param parent the parent
+ */
+ public InfoForm(Composite parent) {
+
+ Display display= parent.getDisplay();
+ fBackgroundColor= display.getSystemColor(SWT.COLOR_LIST_BACKGROUND);
+ fForegroundColor= display.getSystemColor(SWT.COLOR_LIST_FOREGROUND);
+ fSeparatorColor= new Color(display, 152, 170, 203);
+
+ fPropertyChangeListener= new IPropertyChangeListener() {
+ public void propertyChange(PropertyChangeEvent event) {
+ handlePropertyChange(event);
+ }
+ };
+ JFaceResources.getFontRegistry().addListener(fPropertyChangeListener);
+
+ fScrolledComposite= new ScrolledComposite(parent, SWT.H_SCROLL | SWT.V_SCROLL);
+ fScrolledComposite.setAlwaysShowScrollBars(false);
+ fScrolledComposite.setExpandHorizontal(true);
+ fScrolledComposite.setExpandVertical(true);
+ fScrolledComposite.addDisposeListener(new DisposeListener() {
+ public void widgetDisposed(DisposeEvent e) {
+ JFaceResources.getFontRegistry().removeListener(fPropertyChangeListener);
+ fScrolledComposite= null;
+ fSeparatorColor.dispose();
+ fSeparatorColor= null;
+ fHeader= null;
+ fBanner= null;
+ fText= null;
+ }
+ });
+
+ Composite composite= createComposite(fScrolledComposite);
+ composite.setLayout(new GridLayout());
+
+ fHeader= createHeader(composite, null);
+ createLabel(composite, null);
+ createLabel(composite, null);
+
+ fBanner= createBanner(composite, null);
+
+ Composite separator= createCompositeSeparator(composite);
+ GridData data= new GridData(GridData.FILL_HORIZONTAL);
+ data.heightHint= 2;
+ separator.setLayoutData(data);
+
+ fText= createLabel(composite, null);
+ createLabel(composite, null);
+
+ fScrolledComposite.setContent(composite);
+ fScrolledComposite.setMinSize(composite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+
+ createActionControls(composite);
+ }
+
+ /**
+ * Hook method for creating an appropriate action control.
+ * @param parent the action control's parent control
+ */
+ protected void createActionControls(Composite parent) {
+ }
+
+ /**
+ * Returns the control of this form.
+ * @return the root control of this form
+ */
+ public Control getControl() {
+ return fScrolledComposite;
+ }
+
+ /**
+ * Sets the header text of this info form.
+ * @param header the header text
+ */
+ public void setHeaderText(String header) {
+ fHeader.setText(header);
+ }
+
+ /**
+ * Sets the banner text of this info form.
+ * @param banner the banner text
+ */
+ public void setBannerText(String banner) {
+ fBanner.setText(banner);
+ }
+
+ /**
+ * Sets the info of this info form
+ * @param info the info text
+ */
+ public void setInfo(String info) {
+ fText.setText(info);
+ }
+
+ /*
+ * @see IPropertyChangeListener#propertyChange(PropertyChangeEvent)
+ */
+ protected void handlePropertyChange(PropertyChangeEvent event) {
+
+ if (fHeader != null)
+ fHeader.setFont(JFaceResources.getHeaderFont());
+
+ if (fBanner != null)
+ fBanner.setFont(JFaceResources.getBannerFont());
+
+ Control control= fScrolledComposite.getContent();
+ fScrolledComposite.setMinSize(control.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+ fScrolledComposite.setContent(control);
+
+ fScrolledComposite.layout(true);
+ fScrolledComposite.redraw();
+ }
+
+ /*
+ * @see org.eclipse.update.ui.forms.internal.FormWidgetFactory#createComposite(Composite)
+ */
+ private Composite createComposite(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setBackground(fBackgroundColor);
+ return composite;
+ }
+
+ /*
+ * @see org.eclipse.update.ui.forms.internal.FormWidgetFactory#createCompositeSeparator(Composite)
+ */
+ private Composite createCompositeSeparator(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setBackground(fSeparatorColor);
+ return composite;
+ }
+
+ /*
+ * @see org.eclipse.update.ui.forms.internal.FormWidgetFactory#createLabel(Composite, String)
+ */
+ private Label createLabel(Composite parent, String text) {
+ Label label = new Label(parent, SWT.NONE);
+ if (text != null)
+ label.setText(text);
+ label.setBackground(fBackgroundColor);
+ label.setForeground(fForegroundColor);
+ return label;
+ }
+
+ /*
+ * @see org.eclipse.update.ui.forms.internal.FormWidgetFactory#createHeader(Composite, String)
+ */
+ private Label createHeader(Composite parent, String text) {
+ Label label = new Label(parent, SWT.NONE);
+ if (text != null)
+ label.setText(text);
+ label.setBackground(fBackgroundColor);
+ label.setForeground(fForegroundColor);
+ label.setFont(JFaceResources.getHeaderFont());
+ return label;
+ }
+
+ /*
+ * @see org.eclipse.update.ui.forms.internal.FormWidgetFactory#createBanner(Composite, String)
+ */
+ private Label createBanner(Composite parent, String text) {
+ Label label = new Label(parent, SWT.NONE);
+ if (text != null)
+ label.setText(text);
+ label.setBackground(fBackgroundColor);
+ label.setForeground(fForegroundColor);
+ label.setFont(JFaceResources.getBannerFont());
+ return label;
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkAction.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkAction.java
new file mode 100644
index 000000000..84d63b6fc
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkAction.java
@@ -0,0 +1,73 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+
+import java.util.ResourceBundle;
+
+import org.eclipse.jface.text.IMarkRegionTarget;
+
+/**
+ * An action to handle emacs-like marked regions.
+ * @since 2.0
+ */
+public class MarkAction extends TextEditorAction {
+
+ /** Sets the mark. */
+ public static final int SET_MARK= 0;
+ /** Clears the mark. */
+ public static final int CLEAR_MARK= 1;
+ /** Swaps the mark and the cursor position. */
+ public static final int SWAP_MARK= 2;
+
+ /** The mark action type. */
+ private final int fType;
+
+ /**
+ * Constructor for MarkAction.
+ *
+ * @param type the mark action type, must be one of
+ * <code>SET_MARK</code>, <code>CLEAR_MARK</code> or <code>SWAP_MARK</code>.
+ */
+ public MarkAction(ResourceBundle bundle, String prefix, ITextEditor editor, int type) {
+ super(bundle, prefix, editor);
+ fType= type;
+ }
+
+ /*
+ * @see IAction#run()
+ */
+ public void run() {
+
+ ITextEditor editor= getTextEditor();
+ if (editor == null)
+ return;
+
+ IMarkRegionTarget target= (IMarkRegionTarget) editor.getAdapter(IMarkRegionTarget.class);
+ if (target == null)
+ return;
+
+ switch (fType) {
+ case SET_MARK:
+ target.setMarkAtCursor(true);
+ break;
+
+ case CLEAR_MARK:
+ target.setMarkAtCursor(false);
+ break;
+
+ case SWAP_MARK:
+ target.swapMarkAndCursor();
+ break;
+ }
+ }
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkRegionTarget.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkRegionTarget.java
new file mode 100644
index 000000000..369f54184
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkRegionTarget.java
@@ -0,0 +1,107 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+
+import org.eclipse.swt.graphics.Point;
+
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.jface.text.IMarkRegionTarget;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.ITextViewerExtension;
+
+/**
+ * Default implementation of <code>IMarkRegionTarget</code> using <code>ITextViewer</code>
+ * and <code>IStatusLineManager</code>.
+ * @since 2.0
+ */
+public class MarkRegionTarget implements IMarkRegionTarget {
+
+ /** The text viewer. */
+ private final ITextViewer fViewer;
+ /** The status line. */
+ private final IStatusLineManager fStatusLine;
+
+ /**
+ * Creates a MarkRegionTaret.
+ *
+ * @param viewer the text viewer
+ * @param manager the status line manager
+ */
+ public MarkRegionTarget(ITextViewer viewer, IStatusLineManager manager) {
+ fViewer= viewer;
+ fStatusLine= manager;
+ }
+
+ /*
+ * @see IMarkregion#setMarkAtCursor(boolean)
+ */
+ public void setMarkAtCursor(boolean set) {
+
+ if (!(fViewer instanceof ITextViewerExtension))
+ return;
+
+ ITextViewerExtension viewerExtension= ((ITextViewerExtension) fViewer);
+
+ if (set) {
+ Point selection= fViewer.getSelectedRange();
+ viewerExtension.setMark(selection.x);
+
+ fStatusLine.setErrorMessage(""); //$NON-NLS-1$
+ fStatusLine.setMessage(EditorMessages.getString("Editor.mark.status.message.mark.set")); //$NON-NLS-1$
+
+ } else {
+ viewerExtension.setMark(-1);
+
+ fStatusLine.setErrorMessage(""); //$NON-NLS-1$
+ fStatusLine.setMessage(EditorMessages.getString("Editor.mark.status.message.mark.cleared")); //$NON-NLS-1$
+ }
+ }
+
+ /*
+ * @see IMarkregion#swapMarkAndCursor()
+ */
+ public void swapMarkAndCursor() {
+
+ if (!(fViewer instanceof ITextViewerExtension))
+ return;
+
+ ITextViewerExtension viewerExtension= ((ITextViewerExtension) fViewer);
+
+ int markPosition= viewerExtension.getMark();
+ if (markPosition == -1) {
+ fStatusLine.setErrorMessage("mark not set");
+ fStatusLine.setMessage(""); //$NON-NLS-1$
+ return;
+ }
+
+ IRegion region= fViewer.getVisibleRegion();
+ int offset= region.getOffset();
+ int length= region.getLength();
+
+ if (markPosition < offset || markPosition > offset + length) {
+ fStatusLine.setErrorMessage("mark not in visible region");
+ fStatusLine.setMessage(""); //$NON-NLS-1$
+ return;
+ }
+
+ Point selection= fViewer.getSelectedRange();
+ viewerExtension.setMark(selection.x);
+
+ fViewer.setSelectedRange(markPosition, 0);
+ fViewer.revealRange(markPosition, 0);
+
+ fStatusLine.setErrorMessage(""); //$NON-NLS-1$
+ fStatusLine.setMessage(EditorMessages.getString("Editor.mark.status.message.mark.swapped")); //$NON-NLS-1$
+ }
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkerAnnotation.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkerAnnotation.java
new file mode 100644
index 000000000..c531c2a39
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkerAnnotation.java
@@ -0,0 +1,262 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Display;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.text.source.Annotation;
+
+import org.eclipse.core.resources.IMarker;
+
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.model.IWorkbenchAdapter;
+
+
+/**
+ * Annotation representing a marker on a resource in the workspace.
+ * This class may be instantiated or be subclassed.
+ *
+ * @see IMarker
+ */
+public class MarkerAnnotation extends Annotation {
+
+ /**
+ * The layer in which markers representing problem are located.
+ * @since 2.0
+ */
+ public final static int PROBLEM_LAYER= 5;
+
+ /** Internal image registry */
+ private static Map fgImageRegistry;
+
+ /**
+ * Returns an image for the given display as specified by the given image descriptor.
+ * @param display the display
+ * @param descriptor the image descriptor
+ * @return an image for the display as specified by the descriptor
+ */
+ protected static Image getImage(Display display, ImageDescriptor descriptor) {
+ Map map= getImageRegistry(display);
+ Image image= (Image) map.get(descriptor);
+ if (image == null) {
+ image= descriptor.createImage();
+ map.put(descriptor, image);
+ }
+ return image;
+ }
+
+ /**
+ * Returns an image registry for the given display. If no such registry exists
+ * the resgitry is created.
+ * @param display the display
+ * @return the image registry for the given display
+ */
+ protected static Map getImageRegistry(Display display) {
+ if (fgImageRegistry == null) {
+ fgImageRegistry= new HashMap();
+ display.disposeExec(new Runnable() {
+ public void run() {
+ if (fgImageRegistry != null) {
+ Map map= fgImageRegistry;
+ fgImageRegistry= null;
+ Iterator e= map.values().iterator();
+ while (e.hasNext()) {
+ Image image= (Image) e.next();
+ if (!image.isDisposed())
+ image.dispose();
+ }
+ }
+ }
+ });
+ }
+ return fgImageRegistry;
+ }
+
+
+ /** The marker this annotation represents */
+ private IMarker fMarker;
+ /** The image, i.e., visual presentation of this annotation */
+ private Image fImage;
+ /** The image name */
+ private String fImageName;
+
+ /**
+ * Creates a new annotation for the given marker.
+ *
+ * @param marker the marker
+ */
+ public MarkerAnnotation(IMarker marker) {
+ fMarker= marker;
+ initialize();
+ }
+
+ /**
+ * Sets the marker image to the given image.
+ *
+ * @param image the new marker image
+ */
+ protected void setImage(Image image) {
+ fImage= image;
+ }
+
+ /**
+ * The <code>MarkerAnnotation</code> implementation of this
+ * <code>Object</code> method returns <code>true</code> iff the other
+ * object is also a <code>MarkerAnnotation</code> and the marker handles are
+ * equal.
+ */
+ public boolean equals(Object o) {
+ if (o != null && o.getClass() == getClass())
+ return fMarker.equals(((MarkerAnnotation) o).fMarker);
+ return false;
+ }
+
+ /*
+ * @see Object#hashCode
+ */
+ public int hashCode() {
+ return fMarker.hashCode();
+ }
+
+ /**
+ * Returns this annotation's underlying marker.
+ *
+ * @return the marker
+ */
+ public IMarker getMarker() {
+ return fMarker;
+ }
+
+ /**
+ * Initializes the annotation's icon representation and its drawing layer
+ * based upon the properties of the underlying marker.
+ */
+ protected void initialize() {
+
+ String name= null;
+ int layer= -1;
+
+ if (MarkerUtilities.isMarkerType(fMarker, IMarker.TASK)) {
+ name= ISharedImages.IMG_OBJS_TASK_TSK;
+ layer= 1;
+ } else if (MarkerUtilities.isMarkerType(fMarker, IMarker.BOOKMARK)) {
+ name= ISharedImages.IMG_OBJS_BKMRK_TSK;
+ layer= 2;
+ } else if (MarkerUtilities.isMarkerType(fMarker, IMarker.PROBLEM)) {
+ switch (fMarker.getAttribute(IMarker.SEVERITY, IMarker.SEVERITY_INFO)) {
+ case IMarker.SEVERITY_INFO:
+ name= ISharedImages.IMG_OBJS_INFO_TSK;
+ layer= 3;
+ break;
+ case IMarker.SEVERITY_WARNING:
+ layer= 3;
+ name= ISharedImages.IMG_OBJS_WARN_TSK;
+ break;
+ case IMarker.SEVERITY_ERROR:
+ layer= PROBLEM_LAYER;
+ name= ISharedImages.IMG_OBJS_ERROR_TSK;
+ break;
+ };
+ } else {
+ name= getUnknownImageName(fMarker);
+ layer= 1;
+ }
+
+ // setImage(getImage(name));
+ fImage= null;
+ fImageName= name;
+ setLayer(layer);
+ }
+
+ /*
+ * @see Annotation#paint
+ */
+ public void paint(GC gc, Canvas canvas, Rectangle r) {
+ Image image= getImage(canvas.getDisplay());
+ if (image != null) {
+ // http://dev.eclipse.org/bugs/show_bug.cgi?id=19184
+ drawImage(image, gc, canvas, r, SWT.CENTER, SWT.TOP);
+ }
+ }
+
+ /**
+ * Informs this annotation about changes applied to its underlying marker
+ * and adapts to those changes.
+ */
+ public void update() {
+ initialize();
+ }
+
+ /**
+ * Returns the name of an image used to visually represent markers of
+ * unknown type. This implementation returns <code>null</code>.
+ * Subclasses may replace this method.
+ *
+ * @param marker the marker of unkown type
+ * @return the name of an image for markers of unknown type.
+ */
+ protected String getUnknownImageName(IMarker marker) {
+ return null;
+ }
+
+ /**
+ * Returns the image of the given name. Subclasses may extend this method.
+ * If so, subclasses must assume responsibility for disposing the images
+ * they create.
+ *
+ * @param name the name of the requested image
+ * @return the image or <code>null</code> if there is no such image
+ */
+ protected Image getImage(String name) {
+ if (name != null)
+ return PlatformUI.getWorkbench().getSharedImages().getImage(name);
+ return null;
+ }
+
+
+ /**
+ * Returns an image for this annotation. It first consults the workbench adapter
+ * for this annotation's marker. If none is defined, it tries to find an image for
+ * the image name of this annotation.
+ *
+ * @param display the display for which the image is requested
+ * @return the image for this annotation
+ */
+ protected Image getImage(Display display) {
+ if (fImage == null) {
+
+ IWorkbenchAdapter adapter= (IWorkbenchAdapter) fMarker.getAdapter(IWorkbenchAdapter.class);
+ if (adapter != null) {
+ ImageDescriptor descriptor= adapter.getImageDescriptor(fMarker);
+ if (descriptor != null)
+ fImage= getImage(display, descriptor);
+ }
+
+ if (fImage == null)
+ fImage= getImage(fImageName);
+
+ }
+ return fImage;
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkerRulerAction.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkerRulerAction.java
new file mode 100644
index 000000000..a92c57bd3
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkerRulerAction.java
@@ -0,0 +1,417 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+import org.eclipse.swt.widgets.Shell;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRunnable;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.ILog;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.dialogs.IInputValidator;
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.Position;
+import org.eclipse.jface.text.source.IAnnotationModel;
+import org.eclipse.jface.text.source.IVerticalRuler;
+import org.eclipse.jface.text.source.IVerticalRulerInfo;
+import org.eclipse.jface.window.Window;
+
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.PlatformUI;
+
+
+
+/**
+ * A ruler action which can add and remove markers which have a visual
+ * representation in the ruler.
+ * <p>
+ * This class may be instantiated but is not intended for subclassing.
+ * </p>
+ */
+public class MarkerRulerAction extends ResourceAction implements IUpdate {
+
+ /** The vertical ruler info of the editor */
+ private IVerticalRulerInfo fRuler;
+ /** The associated editor */
+ private ITextEditor fTextEditor;
+ /** The of the marker to be created/removed */
+ private String fMarkerType;
+ /** The cached list of markers covering a particular vertical ruler position */
+ private List fMarkers;
+ /** The flag indicating whether user interaction is required. */
+ private boolean fAskForLabel;
+ /** The action's resource bundle */
+ private ResourceBundle fBundle;
+ /** The prefix used for resource bundle look ups */
+ private String fPrefix;
+ /** The cached action label when adding a marker */
+ private String fAddLabel;
+ /** The cached action label when removing a marker */
+ private String fRemoveLabel;
+
+
+ /**
+ * Creates a new action for the given ruler and editor. The action configures
+ * its visual representation from the given resource bundle.
+ *
+ * @param bundle the resource bundle
+ * @param prefix a prefix to be prepended to the various resource keys
+ * (described in <code>ResourceAction</code> constructor), or <code>null</code> if none
+ * @param editor the editor
+ * @param ruler the ruler
+ * @param markerType the type of marker
+ * @param askForLabel <code>true</code> if the user should be asked for a label when a new marker is created
+ * @see ResourceAction#ResourceAction
+ * @since 2.0
+ */
+ public MarkerRulerAction(ResourceBundle bundle, String prefix, ITextEditor editor, IVerticalRulerInfo ruler, String markerType, boolean askForLabel) {
+ super(bundle, prefix);
+ fRuler= ruler;
+ fTextEditor= editor;
+ fMarkerType= markerType;
+ fAskForLabel= askForLabel;
+
+ fBundle= bundle;
+ fPrefix= prefix;
+
+ fAddLabel= getString(bundle, prefix + "add.label", prefix + "add.label"); //$NON-NLS-2$ //$NON-NLS-1$
+ fRemoveLabel= getString(bundle, prefix + "remove.label", prefix + "remove.label"); //$NON-NLS-2$ //$NON-NLS-1$
+ }
+
+ /**
+ * @deprecated use <code>MarkerRulerAction(ResourceBundle, String, ITextEditor, IVerticalRulerInfo, String, boolean)</code> instead
+ */
+ public MarkerRulerAction(ResourceBundle bundle, String prefix, IVerticalRuler ruler, ITextEditor editor, String markerType, boolean askForLabel) {
+ this(bundle, prefix, editor, ruler, markerType, askForLabel);
+ }
+
+
+ /**
+ * Returns this action's editor.
+ *
+ * @return this action's editor
+ */
+ protected ITextEditor getTextEditor() {
+ return fTextEditor;
+ }
+
+ /**
+ * Returns this action's vertical ruler.
+ *
+ * @return this action's vertical ruler
+ * @deprecated use <code>getVerticalRulerInfo</code> instead
+ */
+ protected IVerticalRuler getVerticalRuler() {
+ if (fRuler instanceof IVerticalRuler)
+ return (IVerticalRuler) fRuler;
+ return null;
+ }
+
+ /**
+ * Returns this action's vertical ruler info.
+ *
+ * @return this action's vertical ruler info
+ * @since 2.0
+ */
+ protected IVerticalRulerInfo getVerticalRulerInfo() {
+ return fRuler;
+ }
+
+ /**
+ * Returns this action's resource bundle.
+ *
+ * @return this action's resource bundle
+ */
+ protected ResourceBundle getResourceBundle() {
+ return fBundle;
+ }
+
+ /**
+ * Returns this action's resource key prefix.
+ *
+ * @return this action's resource key prefix
+ */
+ protected String getResourceKeyPrefix() {
+ return fPrefix;
+ }
+
+ /*
+ * @see IUpdate#update()
+ */
+ public void update() {
+ fMarkers= getMarkers();
+ setText(fMarkers.isEmpty() ? fAddLabel : fRemoveLabel);
+ }
+
+ /*
+ * @see Action#run()
+ */
+ public void run() {
+ if (fMarkers.isEmpty())
+ addMarker();
+ else
+ removeMarkers(fMarkers);
+ }
+
+ /**
+ * Returns the resource for which to create the marker,
+ * or <code>null</code> if there is no applicable resource.
+ *
+ * @return the resource for which to create the marker or <code>null</code>
+ */
+ protected IResource getResource() {
+ IEditorInput input= fTextEditor.getEditorInput();
+
+ IResource resource= (IResource) input.getAdapter(IFile.class);
+
+ if (resource == null)
+ resource= (IResource) input.getAdapter(IResource.class);
+
+ return resource;
+ }
+
+ /**
+ * Returns the <code>AbstractMarkerAnnotationModel</code> of the editor's input.
+ *
+ * @return the marker annotation model
+ */
+ protected AbstractMarkerAnnotationModel getAnnotationModel() {
+ IDocumentProvider provider= fTextEditor.getDocumentProvider();
+ IAnnotationModel model= provider.getAnnotationModel(fTextEditor.getEditorInput());
+ if (model instanceof AbstractMarkerAnnotationModel)
+ return (AbstractMarkerAnnotationModel) model;
+ return null;
+ }
+
+ /**
+ * Returns the <code>IDocument</code> of the editor's input.
+ *
+ * @return the document of the editor's input
+ */
+ protected IDocument getDocument() {
+ IDocumentProvider provider= fTextEditor.getDocumentProvider();
+ return provider.getDocument(fTextEditor.getEditorInput());
+ }
+
+ /**
+ * Checks whether a position includes the ruler's line of activity.
+ *
+ * @param position the position to be checked
+ * @param document the document the position refers to
+ * @return <code>true</code> if the line is included by the given position
+ */
+ protected boolean includesRulerLine(Position position, IDocument document) {
+
+ if (position != null) {
+ try {
+ int markerLine= document.getLineOfOffset(position.getOffset());
+ int line= fRuler.getLineOfLastMouseButtonActivity();
+ if (line == markerLine)
+ return true;
+ // commented because of "1GEUOZ9: ITPJUI:ALL - Confusing UI for multiline Bookmarks and Tasks"
+ // return (markerLine <= line && line <= document.getLineOfOffset(position.getOffset() + position.getLength()));
+ } catch (BadLocationException x) {
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Handles core exceptions. This implementation logs the exceptions
+ * with the workbech plugin and shows an error dialog.
+ *
+ * @param exception the exception to be handled
+ * @param message the message to be logged with the given exception
+ */
+ protected void handleCoreException(CoreException exception, String message) {
+ ILog log= Platform.getPlugin(PlatformUI.PLUGIN_ID).getLog();
+
+ if (message != null)
+ log.log(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, message, null));
+
+ log.log(exception.getStatus());
+
+
+ Shell shell= getTextEditor().getSite().getShell();
+ String title= getString(fBundle, fPrefix + "error.dialog.title", fPrefix + "error.dialog.title"); //$NON-NLS-2$ //$NON-NLS-1$
+ String msg= getString(fBundle, fPrefix + "error.dialog.message", fPrefix + "error.dialog.message"); //$NON-NLS-2$ //$NON-NLS-1$
+
+ ErrorDialog.openError(shell, title, msg, exception.getStatus());
+ }
+
+ /**
+ * Returns all markers which include the ruler's line of activity.
+ *
+ * @return all markers which include the ruler's line of activity
+ */
+ protected List getMarkers() {
+
+ List markers= new ArrayList();
+
+ IResource resource= getResource();
+ IDocument document= getDocument();
+ AbstractMarkerAnnotationModel model= getAnnotationModel();
+
+ if (resource != null && model != null && resource.exists()) {
+ try {
+ IMarker[] allMarkers= resource.findMarkers(fMarkerType, true, IResource.DEPTH_ZERO);
+ if (allMarkers != null) {
+ for (int i= 0; i < allMarkers.length; i++) {
+ if (includesRulerLine(model.getMarkerPosition(allMarkers[i]), document)) {
+ markers.add(allMarkers[i]);
+ }
+ }
+ }
+ } catch (CoreException x) {
+ handleCoreException(x, EditorMessages.getString("MarkerRulerAction.getMarker")); //$NON-NLS-1$
+ }
+ }
+
+ return markers;
+ }
+
+ /**
+ * Creates a new marker according to the specification of this action and
+ * adds it to the marker resource.
+ */
+ protected void addMarker() {
+ IResource resource= getResource();
+ if (resource == null)
+ return;
+ Map attributes= getInitialAttributes();
+ if (fAskForLabel) {
+ if (!askForLabel(attributes))
+ return;
+ }
+
+ try {
+ MarkerUtilities.createMarker(resource, attributes, fMarkerType);
+ } catch (CoreException x) {
+ handleCoreException(x, EditorMessages.getString("MarkerRulerAction.addMarker")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Removes the given markers.
+ *
+ * @param markers the markers to be deleted
+ */
+ protected void removeMarkers(final List markers) {
+ try {
+ getResource().getWorkspace().run(new IWorkspaceRunnable() {
+ public void run(IProgressMonitor monitor) throws CoreException {
+ for (int i= 0; i < markers.size(); ++i) {
+ IMarker marker= (IMarker) markers.get(i);
+ marker.delete();
+ }
+ }
+ }, null);
+ } catch (CoreException x) {
+ handleCoreException(x, EditorMessages.getString("MarkerRulerAction.removeMarkers")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Asks the user for a marker label. Returns <code>true</code> if a label
+ * is entered, <code>false</code> if the user cancels the input dialog.
+ * Sets the value of the attribute <code>message</code> in the given
+ * map of attributes.
+ *
+ * @param attributes the map of attributes
+ * @return <code>true</code> if the map of attributes has successfuly been initialized
+ */
+ protected boolean askForLabel(Map attributes) {
+
+ Object o= attributes.get("message"); //$NON-NLS-1$
+ String proposal= (o instanceof String) ? (String) o : ""; //$NON-NLS-1$
+ if (proposal == null)
+ proposal= ""; //$NON-NLS-1$
+
+ String title= getString(fBundle, fPrefix + "add.dialog.title", fPrefix + "add.dialog.title"); //$NON-NLS-2$ //$NON-NLS-1$
+ String message= getString(fBundle, fPrefix + "add.dialog.message", fPrefix + "add.dialog.message"); //$NON-NLS-2$ //$NON-NLS-1$
+ IInputValidator inputValidator = new IInputValidator() {
+ public String isValid(String newText) {
+ return (newText == null || newText.length() == 0) ? " " : null; //$NON-NLS-1$
+ }
+ };
+ InputDialog dialog= new InputDialog(fTextEditor.getSite().getShell(), title, message, proposal, inputValidator);
+
+ String label= null;
+ if (dialog.open() != Window.CANCEL)
+ label= dialog.getValue();
+
+ if (label == null)
+ return false;
+
+ label= label.trim();
+ if (label.length() == 0)
+ return false;
+
+ MarkerUtilities.setMessage(attributes, label);
+ return true;
+ }
+
+ /**
+ * Returns the attributes with which a newly created marker will be
+ * initialized.
+ *
+ * @return the initial marker attributes
+ */
+ protected Map getInitialAttributes() {
+
+ Map attributes= new HashMap(11);
+
+ IDocumentProvider provider= fTextEditor.getDocumentProvider();
+ IDocument document= provider.getDocument(fTextEditor.getEditorInput());
+ int line= fRuler.getLineOfLastMouseButtonActivity();
+ int start= -1;
+ int end= -1;
+
+ try {
+
+ IRegion lineInformation= document.getLineInformation(line);
+ start= lineInformation.getOffset();
+ int length= lineInformation.getLength();
+
+ end= start + length;
+
+ } catch (BadLocationException x) {
+ }
+
+ // marker line numbers are 1-based
+ MarkerUtilities.setLineNumber(attributes, line + 1);
+ MarkerUtilities.setCharStart(attributes, start);
+ MarkerUtilities.setCharEnd(attributes, end);
+
+ return attributes;
+ }
+}
+
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkerRulerInfoAction.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkerRulerInfoAction.java
new file mode 100644
index 000000000..9a1900424
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkerRulerInfoAction.java
@@ -0,0 +1,31 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+
+import java.util.ResourceBundle;
+import org.eclipse.jface.text.source.IVerticalRulerInfo;
+
+
+/**
+ * @deprecated use <code>MarkerRulerAction</code> instead
+ * @since 2.0
+ */
+public class MarkerRulerInfoAction extends MarkerRulerAction {
+
+ /**
+ * @deprecated use super class instead
+ */
+ public MarkerRulerInfoAction(ResourceBundle bundle, String prefix, IVerticalRulerInfo ruler, ITextEditor editor, String markerType, boolean askForLabel) {
+ super(bundle, prefix, editor, ruler, markerType, askForLabel);
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkerUpdater.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkerUpdater.java
new file mode 100644
index 000000000..5a18799e1
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkerUpdater.java
@@ -0,0 +1,59 @@
+package org.eclipse.ui.texteditor;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.Position;
+
+import org.eclipse.core.resources.IMarker;
+
+/**
+ * Updates a marker's positional attributes which are start position, end position,
+ * and line number.
+ */
+class MarkerUpdater implements IMarkerUpdater {
+
+ private final static String[] ATTRIBUTES= {IMarker.CHAR_START, IMarker.CHAR_END, IMarker.LINE_NUMBER};
+
+ /*
+ * @see IMarkerUpdater#getAttribute()
+ */
+ public String[] getAttribute() {
+ return ATTRIBUTES;
+ }
+
+ /*
+ * @see IMarkerUpdater#getMarkerType()
+ */
+ public String getMarkerType() {
+ return null;
+ }
+
+ /*
+ * @see IMarkerUpdater#updateMarker(IMarker, IDocument, Position)
+ */
+ public boolean updateMarker(IMarker marker, IDocument document, Position position) {
+
+ if (position.isDeleted())
+ return false;
+
+ if (MarkerUtilities.getCharStart(marker) != -1 && MarkerUtilities.getCharEnd(marker) != -1) {
+ MarkerUtilities.setCharStart(marker, position.getOffset());
+ MarkerUtilities.setCharEnd(marker, position.getOffset() + position.getLength());
+ }
+ if (MarkerUtilities.getLineNumber(marker) != -1) {
+ try {
+ // marker line numbers are 1-based
+ MarkerUtilities.setLineNumber(marker, document.getLineOfOffset(position.getOffset()) + 1);
+ } catch (BadLocationException x) {
+ }
+ }
+
+ return true;
+ }
+
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkerUtilities.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkerUtilities.java
new file mode 100644
index 000000000..c67c7ee07
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/MarkerUtilities.java
@@ -0,0 +1,242 @@
+package org.eclipse.ui.texteditor;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+
+import java.util.Map;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRunnable;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Platform;
+
+import org.eclipse.ui.PlatformUI;
+
+
+
+/**
+ * Utility class for accessing marker attributes. The static methods provided
+ * on this class provide internal exception handling (unexpected
+ * <code>CoreException</code>s are logged to workbench).
+ * <p>
+ * This class provides static methods only; it is not intended to be
+ * instantiated or subclassed by clients.
+ * </p>
+ */
+public final class MarkerUtilities {
+
+ /**
+ * Don't allow instantiation.
+ */
+ private MarkerUtilities() {
+ }
+
+ /**
+ * Returns the ending character offset of the given marker.
+ *
+ * @param marker the marker
+ * @return the ending character offset, or <code>-1</code> if not set
+ * @see IMarker#CHAR_END
+ * @see IMarker#getAttribute(java.lang.String,int)
+ */
+ public static int getCharEnd(IMarker marker) {
+ return getIntAttribute(marker, IMarker.CHAR_END, -1);
+ }
+
+ /**
+ * Returns the starting character offset of the given marker.
+ *
+ * @param marker the marker
+ * @return the starting character offset, or <code>-1</code> if not set
+ * @see IMarker#CHAR_START
+ * @see IMarker#getAttribute(java.lang.String,int)
+ */
+ public static int getCharStart(IMarker marker) {
+ return getIntAttribute(marker, IMarker.CHAR_START, -1);
+ }
+
+ /**
+ * Returns the specified attribute of the given marker as an integer.
+ * Returns the given default if the attribute value is not an integer.
+ */
+ private static int getIntAttribute(IMarker marker, String attributeName, int defaultValue) {
+ return marker.getAttribute(attributeName, defaultValue);
+ }
+
+ /**
+ * Returns the line number of the given marker.
+ *
+ * @param marker the marker
+ * @return the line number, or <code>-1</code> if not set
+ * @see IMarker#LINE_NUMBER
+ * @see IMarker#getAttribute(java.lang.String,int)
+ */
+ public static int getLineNumber(IMarker marker) {
+ return getIntAttribute(marker, IMarker.LINE_NUMBER, -1);
+ }
+
+ /**
+ * Returns the priority of the given marker.
+ *
+ * @param marker the marker
+ * @return the priority, or <code>IMarker.PRIORITY_NORMAL</code> if not set
+ * @see IMarker#PRIORITY
+ * @see IMarker#PRIORITY_NORMAL
+ * @see IMarker#getAttribute(java.lang.String,int)
+ */
+ public static int getPriority(IMarker marker) {
+ return getIntAttribute(marker, IMarker.PRIORITY, IMarker.PRIORITY_NORMAL);
+ }
+
+ /**
+ * Handles a core exception which occurs when accessing marker attributes.
+ */
+ private static void handleCoreException(CoreException e) {
+ Platform.getPlugin(PlatformUI.PLUGIN_ID).getLog().log(e.getStatus());
+ }
+
+ /**
+ * Returns whether the given marker is of the given type (either directly or indirectly).
+ *
+ * @param marker the marker to be checked
+ * @param type the reference type
+ * @return <code>true</code>if maker is an instance of the reference type
+ */
+ public static boolean isMarkerType(IMarker marker, String type) {
+ try {
+ return marker.isSubtypeOf(type);
+ } catch (CoreException e) {
+ handleCoreException(e);
+ return false;
+ }
+ }
+
+ /**
+ * Sets the ending character offset of the given marker.
+ *
+ * @param marker the marker
+ * @param charEnd the ending character offset
+ * @see IMarker#CHAR_END
+ * @see IMarker#setAttribute(java.lang.String,int)
+ */
+ public static void setCharEnd(IMarker marker, int charEnd) {
+ setIntAttribute(marker, IMarker.CHAR_END, charEnd);
+ }
+
+ /**
+ * Sets the ending character offset in the given map using the standard
+ * marker attribute name as the key.
+ *
+ * @param map the map (key type: <code>String</code>, value type:
+ * <code>Object</code>)
+ * @param charEnd the ending character offset
+ * @see IMarker#CHAR_END
+ */
+ public static void setCharEnd(Map map, int charEnd) {
+ map.put(IMarker.CHAR_END, new Integer(charEnd));
+ }
+
+ /**
+ * Sets the starting character offset of the given marker.
+ *
+ * @param marker the marker
+ * @param charStart the starting character offset
+ * @see IMarker#CHAR_START
+ * @see IMarker#setAttribute(java.lang.String,int)
+ */
+ public static void setCharStart(IMarker marker, int charStart) {
+ setIntAttribute(marker, IMarker.CHAR_START, charStart);
+ }
+
+ /**
+ * Sets the starting character offset in the given map using the standard
+ * marker attribute name as the key.
+ *
+ * @param map the map (key type: <code>String</code>, value type:
+ * <code>Object</code>)
+ * @param charStart the starting character offset
+ * @see IMarker#CHAR_START
+ */
+ public static void setCharStart(Map map, int charStart) {
+ map.put(IMarker.CHAR_START, new Integer(charStart));
+ }
+
+ /**
+ * Sets the specified attribute of the given marker as an integer.
+ */
+ private static void setIntAttribute(IMarker marker, String attributeName, int value) {
+ try {
+ marker.setAttribute(attributeName, value);
+ } catch (CoreException e) {
+ handleCoreException(e);
+ }
+ }
+
+ /**
+ * Sets the line number of the given marker.
+ *
+ * @param marker the marker
+ * @param lineNum the line number
+ * @see IMarker#LINE_NUMBER
+ * @see IMarker#setAttribute(java.lang.String,int)
+ */
+ public static void setLineNumber(IMarker marker, int lineNum) {
+ setIntAttribute(marker, IMarker.LINE_NUMBER, lineNum);
+ }
+
+ /**
+ * Sets the line number in the given map using the standard marker attribute
+ * name as the key.
+ *
+ * @param map the map (key type: <code>String</code>, value type:
+ * <code>Object</code>)
+ * @param lineNum the line number
+ * @see IMarker#LINE_NUMBER
+ */
+ public static void setLineNumber(Map map, int lineNum) {
+ map.put(IMarker.LINE_NUMBER, new Integer(lineNum));
+ }
+
+ /**
+ * Sets the message in the given map using the standard marker attribute name
+ * as the key.
+ *
+ * @param map the map (key type: <code>String</code>, value type:
+ * <code>Object</code>)
+ * @param message the message
+ * @see IMarker#MESSAGE
+ */
+ public static void setMessage(Map map, String message) {
+ map.put(IMarker.MESSAGE, message);
+ }
+
+ /**
+ * Creates a marker on the given resource with the given type and attributes.
+ * <p>
+ * This method modifies the workspace (progress is not reported to the user).
+ * </p>
+ *
+ * @param resource the resource
+ * @param attributes the attribute map (key type: <code>String</code>,
+ * value type: <code>Object</code>)
+ * @param markerType the type of marker
+ * @exception CoreException if this method fails
+ * @see IResource#createMarker
+ */
+ public static void createMarker(final IResource resource, final Map attributes, final String markerType) throws CoreException {
+
+ IWorkspaceRunnable r= new IWorkspaceRunnable() {
+ public void run(IProgressMonitor monitor) throws CoreException {
+ IMarker marker= resource.createMarker(markerType);
+ marker.setAttributes(attributes);
+ }
+ };
+
+ resource.getWorkspace().run(r, null);
+ }
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/PropagatingFontFieldEditor.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/PropagatingFontFieldEditor.java
new file mode 100644
index 000000000..a9f76ce48
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/PropagatingFontFieldEditor.java
@@ -0,0 +1,23 @@
+package org.eclipse.ui.texteditor;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+
+import org.eclipse.swt.widgets.Composite;
+
+
+/**
+ * @deprecated use WorkbenchChainedTextFontFieldEditor
+ */
+public final class PropagatingFontFieldEditor extends WorkbenchChainedTextFontFieldEditor {
+
+ /**
+ * @deprecated use WorkbenchChainedTextFontFieldEditor
+ */
+ public PropagatingFontFieldEditor(String name, String labelText, Composite parent) {
+ super(name, labelText, parent);
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ResourceAction.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ResourceAction.java
new file mode 100644
index 000000000..f03712d7a
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ResourceAction.java
@@ -0,0 +1,101 @@
+package org.eclipse.ui.texteditor;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.resource.ImageDescriptor;
+
+import org.eclipse.ui.help.WorkbenchHelp;
+
+
+/**
+ * An action which configures its label, image, tooltip, and description from
+ * a resource bundle using known keys.
+ * <p>
+ * Clients may subclass this abstract class to define new kinds of actions. As
+ * with <code>Action</code>, subclasses must implement the
+ * <code>IAction.run</code> method to carry out the action's semantics.
+ * </p>
+ */
+public abstract class ResourceAction extends Action {
+
+ /**
+ * Retrieves and returns the value with the given key from the given resource
+ * bundle, or returns the given default value if there is no such resource.
+ * Convenience method for dealing gracefully with missing resources.
+ *
+ * @param bundle the resource bundle
+ * @param key the resource key
+ * @param defaultValue the default value, or <code>null</code>
+ * @return the resource value, or the given default value (which may be
+ * <code>null</code>)
+ */
+ protected static String getString(ResourceBundle bundle, String key, String defaultValue) {
+
+ String value= defaultValue;
+ try {
+ value= bundle.getString(key);
+ } catch (MissingResourceException x) {
+ }
+
+ return value;
+ }
+
+ /**
+ * Creates a new action that configures itself from the given resource
+ * bundle.
+ * <p>
+ * The following keys, prepended by the given option prefix,
+ * are used for retrieving resources from the given bundle:
+ * <ul>
+ * <li><code>"label"</code> - <code>setText</code></li>
+ * <li><code>"tooltip"</code> - <code>setToolTipText</code></li>
+ * <li><code>"image"</code> - <code>setImageDescriptor</code></li>
+ * <li><code>"description"</code> - <code>setDescription</code></li>
+ * </ul>
+ * </p>
+ *
+ * @param bundle the resource bundle
+ * @param prefix a prefix to be prepended to the various resource keys, or
+ * <code>null</code> if none
+ */
+ public ResourceAction(ResourceBundle bundle, String prefix) {
+ super();
+
+ String labelKey= "label"; //$NON-NLS-1$
+ String tooltipKey= "tooltip"; //$NON-NLS-1$
+ String imageKey= "image"; //$NON-NLS-1$
+ String descriptionKey= "description"; //$NON-NLS-1$
+
+ if (prefix != null && prefix.length() > 0) {
+ labelKey= prefix + labelKey;
+ tooltipKey= prefix + tooltipKey;
+ imageKey= prefix + imageKey;
+ descriptionKey= prefix + descriptionKey;
+ }
+
+ setText(getString(bundle, labelKey, labelKey));
+ setToolTipText(getString(bundle, tooltipKey, null));
+ setDescription(getString(bundle, descriptionKey, null));
+
+ String file= getString(bundle, imageKey, null);
+ if (file != null && file.trim().length() > 0)
+ setImageDescriptor(ImageDescriptor.createFromFile(getClass(), file));
+ }
+
+ /**
+ * Sets the action's help context id.
+ *
+ * @param contextId the help context id
+ */
+ public final void setHelpContextId(String contextId) {
+ WorkbenchHelp.setHelp(this, contextId);
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ResourceMarkerAnnotationModel.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ResourceMarkerAnnotationModel.java
new file mode 100644
index 000000000..a934e68af
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ResourceMarkerAnnotationModel.java
@@ -0,0 +1,171 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+
+import org.eclipse.jface.util.Assert;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IMarkerDelta;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceChangeEvent;
+import org.eclipse.core.resources.IResourceChangeListener;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.IResourceDeltaVisitor;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.IWorkspaceRunnable;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+
+
+/**
+ * A marker annotation model whose underlying source of markers is
+ * a resource in the workspace.
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ */
+public class ResourceMarkerAnnotationModel extends AbstractMarkerAnnotationModel {
+
+
+ /**
+ * Internal resource change listener.
+ */
+ class ResourceChangeListener implements IResourceChangeListener {
+ /*
+ * @see IResourceChangeListener#resourceChanged
+ */
+ public void resourceChanged(IResourceChangeEvent e) {
+ IResourceDelta delta= e.getDelta();
+ try {
+ if (delta != null)
+ delta.accept(fResourceDeltaVisitor);
+ } catch (CoreException x) {
+ handleCoreException(x, EditorMessages.getString("ResourceMarkerAnnotationModel.resourceChanged")); //$NON-NLS-1$
+ }
+ }
+ };
+
+ /**
+ * Internal resource delta visitor.
+ */
+ class ResourceDeltaVisitor implements IResourceDeltaVisitor {
+ /*
+ * @see IResourceDeltaVisitor#visit
+ */
+ public boolean visit(IResourceDelta delta) throws CoreException {
+ if (delta != null && fResource.equals(delta.getResource())) {
+ update(delta.getMarkerDeltas());
+ return false;
+ }
+ return true;
+ }
+ };
+
+ /** The workspace */
+ private IWorkspace fWorkspace;
+ /** The resource */
+ private IResource fResource;
+ /** The resource change listener */
+ private IResourceChangeListener fResourceChangeListener= new ResourceChangeListener();
+ /** The resource delta visitor */
+ private IResourceDeltaVisitor fResourceDeltaVisitor= new ResourceDeltaVisitor();
+
+
+ /**
+ * Creates a marker annotation model with the given resource as the source
+ * of the markers.
+ *
+ * @param resource the resource
+ */
+ public ResourceMarkerAnnotationModel(IResource resource) {
+ Assert.isNotNull(resource);
+ fResource= resource;
+ fWorkspace= resource.getWorkspace();
+ }
+
+ /*
+ * @see AnnotationModel#isAcceptable
+ */
+ protected boolean isAcceptable(IMarker marker) {
+ return marker != null && fResource.equals(marker.getResource());
+ }
+
+ /**
+ * Updates this model to the given marker deltas.
+ *
+ * @param markerDeltas the list of marker deltas
+ */
+ private void update(IMarkerDelta[] markerDeltas) {
+
+ if (markerDeltas.length == 0)
+ return;
+
+ for (int i= 0; i < markerDeltas.length; i++) {
+ IMarkerDelta delta= markerDeltas[i];
+ switch (delta.getKind()) {
+ case IResourceDelta.ADDED :
+ addMarkerAnnotation(delta.getMarker());
+ break;
+ case IResourceDelta.REMOVED :
+ removeMarkerAnnotation(delta.getMarker());
+ break;
+ case IResourceDelta.CHANGED :
+ modifyMarkerAnnotation(delta.getMarker());
+ break;
+ }
+ }
+
+ fireModelChanged();
+ }
+
+ /*
+ * @see AbstractMarkerAnnotationModel#listenToMarkerChanges(boolean)
+ */
+ protected void listenToMarkerChanges(boolean listen) {
+ if (listen)
+ fWorkspace.addResourceChangeListener(fResourceChangeListener);
+ else
+ fWorkspace.removeResourceChangeListener(fResourceChangeListener);
+ }
+
+ /*
+ * @see AbstractMarkerAnnotationModel#deleteMarkers(IMarker[])
+ */
+ protected void deleteMarkers(final IMarker[] markers) throws CoreException {
+ fWorkspace.run(new IWorkspaceRunnable() {
+ public void run(IProgressMonitor monitor) throws CoreException {
+ for (int i= 0; i < markers.length; ++i) {
+ markers[i].delete();
+ }
+ }
+ }, null);
+ }
+
+ /*
+ * @see AbstractMarkerAnnotationModel#retrieveMarkers()
+ */
+ protected IMarker[] retrieveMarkers() throws CoreException {
+ return fResource.findMarkers(IMarker.MARKER, true, IResource.DEPTH_ZERO);
+ }
+
+ /**
+ * Returns the resource serving as the source of markers for this annotation model.
+ *
+ * @return the resource serving as the source of markers for this annotation model
+ * @since 2.0
+ */
+ protected IResource getResource() {
+ return fResource;
+ }
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/RetargetTextEditorAction.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/RetargetTextEditorAction.java
new file mode 100644
index 000000000..b408da740
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/RetargetTextEditorAction.java
@@ -0,0 +1,149 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+
+package org.eclipse.ui.texteditor;
+
+
+import java.util.ResourceBundle;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+
+
+/**
+ * Action used by an editor action bar contributor to establish placeholders in
+ * menus or action bars which can be retargeted to dynamically changing actions,
+ * for example, those which come from the active editor. This action assumes that
+ * the "wrapped" action sends out property change events in response to state
+ * changes. It uses these change notification to adapt its enabling state and
+ * its visual presentation.
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ */
+public final class RetargetTextEditorAction extends ResourceAction {
+
+ /** The target action */
+ private IAction fAction;
+ /** The default label if there is no target action */
+ private String fDefaultText;
+ /** The listener to pick up changes of the target action */
+ private IPropertyChangeListener fListener= new IPropertyChangeListener() {
+ public void propertyChange(PropertyChangeEvent event) {
+ update(event);
+ }
+ };
+
+ /**
+ * Creates a new action. The action configures its initial visual
+ * representation from the given resource bundle. If this action's
+ * wrapped action is set to <code>null</code> it also uses the
+ * information in the resource bundle.
+ *
+ * @param bundle the resource bundle
+ * @param prefix a prefix to be prepended to the various resource keys
+ * (described in <code>ResourceAction</code> constructor), or
+ * <code>null</code> if none
+ * @see ResourceAction#ResourceAction
+ */
+ public RetargetTextEditorAction(ResourceBundle bundle, String prefix) {
+ super(bundle, prefix);
+ fDefaultText= getText();
+ }
+
+ /**
+ * Creates a new action. The action configures its initial visual
+ * representation from the given resource bundle. If this action's
+ * wrapped action is set to <code>null</code> it also uses the
+ * information in the resource bundle. The action gets the given
+ * action id.
+ *
+ * @param bundle the resource bundle
+ * @param prefix a prefix to be prepended to the various resource keys
+ * (described in <code>ResourceAction</code> constructor), or <code>null</code> if none
+ * @param actionId the action id
+ * @see ResourceAction#ResourceAction
+ * @since 2.0
+ */
+ public RetargetTextEditorAction(ResourceBundle bundle, String prefix, String actionId) {
+ super(bundle, prefix);
+ fDefaultText= getText();
+ setId(actionId);
+ }
+
+ /**
+ * Updates to the changes of the underlying action.
+ *
+ * @param event the change event describing the state change
+ */
+ private void update(PropertyChangeEvent event) {
+ if (ENABLED.equals(event.getProperty())) {
+ Boolean bool= (Boolean) event.getNewValue();
+ setEnabled(bool.booleanValue());
+ } else if (TEXT.equals(event.getProperty()))
+ setText((String) event.getNewValue());
+ else if (TOOL_TIP_TEXT.equals(event.getProperty()))
+ setToolTipText((String) event.getNewValue());
+ else if (CHECKED.equals(event.getProperty())) {
+ Boolean bool= (Boolean) event.getNewValue();
+ setChecked(bool.booleanValue());
+ }
+ }
+
+ /**
+ * Sets the underlying action.
+ *
+ * @param action the underlying action
+ */
+ public void setAction(IAction action) {
+
+ if (fAction != null) {
+ fAction.removePropertyChangeListener(fListener);
+ fAction= null;
+ }
+
+ fAction= action;
+
+ if (fAction == null) {
+
+ setEnabled(false);
+ setText(fDefaultText);
+ setToolTipText(""); //$NON-NLS-1$
+
+ } else {
+
+ setEnabled(fAction.isEnabled());
+ setText(fAction.getText());
+ setToolTipText(fAction.getToolTipText());
+ fAction.addPropertyChangeListener(fListener);
+ }
+ }
+
+ /*
+ * @see Action#run()
+ */
+ public void run() {
+ if (fAction != null)
+ fAction.run();
+ }
+
+ /*
+ * @see IAction#getActionDefinitionId()
+ * @since 2.0
+ */
+ public String getActionDefinitionId() {
+ if(fAction != null)
+ return fAction.getActionDefinitionId();
+ return null;
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/RevertToSavedAction.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/RevertToSavedAction.java
new file mode 100644
index 000000000..7fe34b01e
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/RevertToSavedAction.java
@@ -0,0 +1,50 @@
+package org.eclipse.ui.texteditor;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+
+import java.util.ResourceBundle;
+
+
+/**
+ * Action for abandoning changes made in the text editor since the last save
+ * operation. The action is initially associated with a text editor via the
+ * constructor, but that can be subsequently changed using <code>setEditor</code>.
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ */
+public class RevertToSavedAction extends TextEditorAction {
+
+ /**
+ * Creates a new action for the given text editor. The action configures its
+ * visual representation from the given resource bundle.
+ *
+ * @param bundle the resource bundle
+ * @param prefix a prefix to be prepended to the various resource keys
+ * (described in <code>ResourceAction</code> constructor), or
+ * <code>null</code> if none
+ * @param editor the text editor
+ * @see ResourceAction#ResourceAction
+ */
+ public RevertToSavedAction(ResourceBundle bundle, String prefix, ITextEditor editor) {
+ super(bundle, prefix, editor);
+ }
+
+ /*
+ * @see IAction#run
+ */
+ public void run() {
+ getTextEditor().doRevertToSaved();
+ }
+
+ /*
+ * @see TextEditorAction#update
+ */
+ public void update() {
+ setEnabled(getTextEditor().isDirty());
+ }
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/SaveAction.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/SaveAction.java
new file mode 100644
index 000000000..a4e71601c
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/SaveAction.java
@@ -0,0 +1,50 @@
+package org.eclipse.ui.texteditor;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+
+import java.util.ResourceBundle;
+
+
+/**
+ * Action for saving recent changes made in the text editor. The action is
+ * initially associated with a text editor via the constructor, but that can be
+ * subsequently changed using <code>setEditor</code>.
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ */
+public class SaveAction extends TextEditorAction {
+
+ /**
+ * Creates a new action for the given text editor. The action configures its
+ * visual representation from the given resource bundle.
+ *
+ * @param bundle the resource bundle
+ * @param prefix a prefix to be prepended to the various resource keys
+ * (described in <code>ResourceAction</code> constructor), or
+ * <code>null</code> if none
+ * @param editor the text editor
+ * @see ResourceAction#ResourceAction
+ */
+ public SaveAction(ResourceBundle bundle, String prefix, ITextEditor editor) {
+ super(bundle, prefix, editor);
+ }
+
+ /*
+ * @see IAction#run
+ */
+ public void run() {
+ getTextEditor().getSite().getPage().saveEditor(getTextEditor(), false);
+ }
+
+ /*
+ * @see TextEditorAction#update
+ */
+ public void update() {
+ setEnabled(getTextEditor().isDirty());
+ }
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ShiftAction.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ShiftAction.java
new file mode 100644
index 000000000..7a498afa7
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ShiftAction.java
@@ -0,0 +1,136 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+
+package org.eclipse.ui.texteditor;
+
+
+import java.util.ResourceBundle;
+
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+import org.eclipse.jface.text.ITextOperationTarget;
+
+import org.eclipse.ui.IWorkbenchPartSite;
+
+
+
+/**
+ * Action for shifting code to the right or left by one indentation level.
+ * @since 2.0
+ */
+public final class ShiftAction extends TextEditorAction implements IReadOnlyDependent {
+
+ /** The text operation code */
+ private int fOperationCode= -1;
+ /** The text operation target */
+ private ITextOperationTarget fOperationTarget;
+
+ /**
+ * Creates and initializes the action for the given text editor and operation
+ * code. The action configures its visual representation from the given resource
+ * bundle. The action works by asking the text editor at the time for its
+ * text operation target adapter (using
+ * <code>getAdapter(ITextOperationTarget.class)</code>. The action runs that
+ * operation with the given opcode.
+ *
+ * @param bundle the resource bundle
+ * @param prefix a prefix to be prepended to the various resource keys
+ * (described in <code>ResourceAction</code> constructor), or <code>null</code> if none
+ * @param editor the text editor
+ * @param operationCode the operation code
+ * @see ResourceAction#ResourceAction
+ */
+ public ShiftAction(ResourceBundle bundle, String prefix, ITextEditor editor, int operationCode) {
+ super(bundle, prefix, editor);
+ fOperationCode= operationCode;
+ update();
+ }
+
+ /**
+ * The <code>TextOperationAction</code> implementation of this
+ * <code>IAction</code> method runs the operation with the current
+ * operation code.
+ */
+ public void run() {
+ if (fOperationCode != -1 && fOperationTarget != null) {
+
+ ITextEditor editor= getTextEditor();
+ if (editor != null) {
+
+ Display display= null;
+
+ IWorkbenchPartSite site= editor.getSite();
+ Shell shell= site.getShell();
+ if (shell != null && !shell.isDisposed())
+ display= shell.getDisplay();
+
+ BusyIndicator.showWhile(display, new Runnable() {
+ public void run() {
+ fOperationTarget.doOperation(fOperationCode);
+ }
+ });
+ }
+ }
+ }
+
+ /*
+ * @see IUpdate#update()
+ */
+ public void update() {
+
+ ITextEditor editor= getTextEditor();
+ if (editor instanceof ITextEditorExtension) {
+ ITextEditorExtension extension= (ITextEditorExtension) editor;
+ if (extension.isEditorInputReadOnly()) {
+ setEnabled(false);
+ return;
+ }
+ }
+
+ if (fOperationTarget == null && editor!= null && fOperationCode != -1)
+ fOperationTarget= (ITextOperationTarget) editor.getAdapter(ITextOperationTarget.class);
+
+ boolean isEnabled= (fOperationTarget != null && fOperationTarget.canDoOperation(fOperationCode));
+ setEnabled(isEnabled);
+ }
+
+ /*
+ * @see TextEditorAction#setEditor(ITextEditor)
+ */
+ public void setEditor(ITextEditor editor) {
+ super.setEditor(editor);
+ fOperationTarget= null;
+ }
+
+ /*
+ * @see IReadOnlyDependent#isEnabled(boolean)
+ */
+ public boolean isEnabled(boolean isWritable) {
+
+ if (!isWritable)
+ return false;
+
+ /*
+ * Note that this implementation still honors the result returned by canDoOperation.
+ * I.e. if the viewer is set to read-only, this method still returns false.
+ * It covers the case in which the viewer is also writable.
+ *
+ */
+ ITextEditor editor= getTextEditor();
+ if (fOperationTarget == null && editor!= null && fOperationCode != -1)
+ fOperationTarget= (ITextOperationTarget) editor.getAdapter(ITextOperationTarget.class);
+
+ return (fOperationTarget != null && fOperationTarget.canDoOperation(fOperationCode));
+ }
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/StatusLineContributionItem.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/StatusLineContributionItem.java
new file mode 100644
index 000000000..62e8db950
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/StatusLineContributionItem.java
@@ -0,0 +1,114 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+
+package org.eclipse.ui.texteditor;
+
+
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CLabel;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+
+import org.eclipse.jface.action.ContributionItem;
+
+
+/**
+ * Contribution item for the status line.
+ * @since 2.0
+ */
+public class StatusLineContributionItem extends ContributionItem implements IStatusField {
+
+ /**
+ * Specific label for the status line.
+ */
+ static class StatusLineLabel extends CLabel {
+
+ /** Left and right margin used in CLabel */
+ private static int INDENT= 3;
+ /** Precomputed label size */
+ private Point fFixedSize;
+
+ /**
+ * Creates a new status line label.
+ * @param parent parent control
+ * @param style the swt style bits
+ */
+ public StatusLineLabel(Composite parent, int style) {
+ super(parent, style);
+
+ GC gc= new GC(parent);
+ gc.setFont(parent.getFont());
+ Point extent= gc.textExtent("MMMMMMMMM"); //$NON-NLS-1$
+ gc.dispose();
+
+ fFixedSize= new Point(extent.x + INDENT * 2, 10);
+ }
+
+ /*
+ * @see Control#computeSize(int, int, boolean)
+ */
+ public Point computeSize(int wHint, int hHint, boolean changed) {
+ return fFixedSize;
+ }
+ };
+
+ /** The label text */
+ private String fText;
+ /** The label image */
+ private Image fImage;
+ /** The status line label widget */
+ private StatusLineLabel fLabel;
+
+ /**
+ * Creates a new item with the given id.
+ *
+ * @param id the item's id
+ */
+ public StatusLineContributionItem(String id) {
+ super(id);
+ }
+
+ /*
+ * @see IStatusField#setText
+ */
+ public void setText(String text) {
+ fText= text;
+ if (fLabel != null && !fLabel.isDisposed()) {
+ fLabel.setText(fText);
+ }
+ }
+
+ /*
+ * @see IStatusField#setImage(Image)
+ */
+ public void setImage(Image image) {
+ fImage= image;
+ if (fLabel != null && !fLabel.isDisposed()) {
+ fLabel.setImage(fImage);
+ }
+ }
+
+ /*
+ * @see IContributionItem#fill(Composite)
+ */
+ public void fill(Composite parent) {
+ fLabel= new StatusLineLabel(parent, SWT.SHADOW_IN);
+ fLabel.setData(this);
+
+ if (fText != null)
+ fLabel.setText(fText);
+ }
+}
+
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/StatusTextEditor.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/StatusTextEditor.java
new file mode 100644
index 000000000..034ee969d
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/StatusTextEditor.java
@@ -0,0 +1,196 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.custom.StackLayout;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+
+import org.eclipse.ui.IEditorInput;
+
+
+/**
+ * Capable of handling input elements that have an associated status with them.
+ * @since 2.0
+ */
+public class StatusTextEditor extends AbstractTextEditor {
+
+ /** The root composite of this editor */
+ private Composite fParent;
+ /** The layout used to manage the regular and the status page */
+ private StackLayout fStackLayout;
+ /** The root composite for the regular page */
+ private Composite fDefaultComposite;
+ /** The status page */
+ private Control fStatusControl;
+
+ /*
+ * @see IWorkbenchPart#createPartControl(Composite)
+ */
+ public void createPartControl(Composite parent) {
+
+ fParent= new Composite(parent, SWT.NONE);
+ fStackLayout= new StackLayout();
+ fParent.setLayout(fStackLayout);
+
+ fDefaultComposite= new Composite(fParent, SWT.NONE);
+ fDefaultComposite.setLayout(new FillLayout());
+ super.createPartControl(fDefaultComposite);
+
+ updatePartControl(getEditorInput());
+ }
+
+ /**
+ * Checks if the status of the given input is OK. If not the
+ * status control is shown rather than the default control.
+ *
+ * @param input the input whose status is checked
+ */
+ public void updatePartControl(IEditorInput input) {
+
+ if (fStatusControl != null) {
+ fStatusControl.dispose();
+ fStatusControl= null;
+ }
+
+ Control front= null;
+ if (fParent != null && input != null) {
+ if (getDocumentProvider() instanceof IDocumentProviderExtension) {
+ IDocumentProviderExtension extension= (IDocumentProviderExtension) getDocumentProvider();
+ IStatus status= extension.getStatus(input);
+ if (status.isOK()) {
+ front= fDefaultComposite;
+ } else {
+ fStatusControl= createStatusControl(fParent, status);
+ front= fStatusControl;
+ }
+ }
+ }
+
+ if (fStackLayout.topControl != front) {
+ fStackLayout.topControl= front;
+ fParent.layout();
+ updateStatusFields();
+ }
+ }
+
+ /**
+ * Creates the status control for the given status. May be overridden by subclasses.
+ *
+ * @param parent the parent control
+ * @param status the status
+ */
+ protected Control createStatusControl(Composite parent, IStatus status) {
+ InfoForm infoForm= new InfoForm(parent);
+ infoForm.setHeaderText(getStatusHeader(status));
+ infoForm.setBannerText(getStatusBanner(status));
+ infoForm.setInfo(getStatusMessage(status));
+ return infoForm.getControl();
+ }
+
+ /**
+ * Returns a header for the given status
+ *
+ * @param status the status whose message is returned
+ * @return a header for the given status
+ */
+ protected String getStatusHeader(IStatus status) {
+ return ""; //$NON-NLS-1$
+ }
+
+ /**
+ * Returns a banner for the given status.
+ *
+ * @param status the status whose message is returned
+ * @return a banner for the given status
+ */
+ protected String getStatusBanner(IStatus status) {
+ return ""; //$NON-NLS-1$
+ }
+
+ /**
+ * Returns a message for the given status.
+ *
+ * @param status the status whose message is returned
+ * @return a message for the given status
+ */
+ protected String getStatusMessage(IStatus status) {
+ return status.getMessage();
+ }
+
+ /*
+ * @see AbstractTextEditor#updateStatusField(String)
+ */
+ protected void updateStatusField(String category) {
+ IDocumentProvider provider= getDocumentProvider();
+ if (provider instanceof IDocumentProviderExtension) {
+ IDocumentProviderExtension extension= (IDocumentProviderExtension) provider;
+ IStatus status= extension.getStatus(getEditorInput());
+ if (status != null && !status.isOK()) {
+ IStatusField field= getStatusField(category);
+ if (field != null) {
+ field.setText(fErrorLabel);
+ return;
+ }
+ }
+ }
+
+ super.updateStatusField(category);
+ }
+
+ /*
+ * @see AbstractTextEditor#doSetInput(IEditorInput)
+ */
+ protected void doSetInput(IEditorInput input) throws CoreException {
+ super.doSetInput(input);
+ if (fParent != null && !fParent.isDisposed())
+ updatePartControl(getEditorInput());
+ }
+
+ /*
+ * @see ITextEditor#doRevertToSaved()
+ */
+ public void doRevertToSaved() {
+ // http://dev.eclipse.org/bugs/show_bug.cgi?id=19014
+ super.doRevertToSaved();
+ if (fParent != null && !fParent.isDisposed())
+ updatePartControl(getEditorInput());
+ }
+
+ /*
+ * @see AbstractTextEditor#sanityCheckState(IEditorInput)
+ */
+ protected void sanityCheckState(IEditorInput input) {
+ // http://dev.eclipse.org/bugs/show_bug.cgi?id=19014
+ super.sanityCheckState(input);
+ if (fParent != null && !fParent.isDisposed())
+ updatePartControl(getEditorInput());
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/TextEditorAction.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/TextEditorAction.java
new file mode 100644
index 000000000..09e8db7fa
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/TextEditorAction.java
@@ -0,0 +1,66 @@
+package org.eclipse.ui.texteditor;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import java.util.ResourceBundle;
+
+/**
+ * Sekelleton of a standard text editor action. The action is
+ * initially associated with a text editor via the constructor,
+ * but can subsequently be changed using <code>setEditor</code>.
+ * Subclasses must implement the <code>run</code> method and if
+ * required override the <code>update</code> method.
+ * </p>
+ */
+public abstract class TextEditorAction extends ResourceAction implements IUpdate {
+
+ /** The action's editor */
+ private ITextEditor fTextEditor;
+
+ /**
+ * Creates and initializes the action for the given text editor. The action
+ * configures its visual representation from the given resource bundle.
+ *
+ * @param bundle the resource bundle
+ * @param prefix a prefix to be prepended to the various resource keys
+ * (described in <code>ResourceAction</code> constructor), or
+ * <code>null</code> if none
+ * @param editor the text editor
+ * @see ResourceAction#ResourceAction
+ */
+ protected TextEditorAction(ResourceBundle bundle, String prefix, ITextEditor editor) {
+ super(bundle, prefix);
+ setEditor(editor);
+ update();
+ }
+
+ /**
+ * Returns the action's text editor.
+ *
+ * @return the action's text editor
+ */
+ protected ITextEditor getTextEditor() {
+ return fTextEditor;
+ }
+
+ /**
+ * Retargets this action to the given editor.
+ *
+ * @param editor the new editor, or <code>null</code> if none
+ */
+ public void setEditor(ITextEditor editor) {
+ fTextEditor= editor;
+ }
+
+ /**
+ * Always enables this action if it is connected to a text editor.
+ * If the asocciated editor is <code>null</code>, the action is disabled.
+ * Subclasses may override.
+ */
+ public void update() {
+ setEnabled(getTextEditor() != null);
+ }
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/TextNavigationAction.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/TextNavigationAction.java
new file mode 100644
index 000000000..499f53702
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/TextNavigationAction.java
@@ -0,0 +1,258 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+
+package org.eclipse.ui.texteditor;
+
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuCreator;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.events.HelpListener;
+import org.eclipse.swt.widgets.Event;
+
+
+/**
+ * An <code>IAction</code> wrapper for text widget navigational and selection actions.
+ * @since 2.0
+ */
+public class TextNavigationAction implements IAction {
+
+ /** The text widget */
+ private StyledText fTextWidget;
+ /** The styled text action id */
+ private int fAction;
+ /** The action's action id */
+ private String fActionId;
+ /** This action's action definition id */
+ private String fActionDefinitionId;
+
+
+ /**
+ * Creates a new <code>TextNavigationAction</code>.
+ * @param textWidget the text widget
+ * @param action the styled text widget action
+ */
+ public TextNavigationAction(StyledText textWidget, int action) {
+ fTextWidget= textWidget;
+ fAction= action;
+ }
+
+ /*
+ * @see IAction#run()
+ */
+ public void run() {
+ fTextWidget.invokeAction(fAction);
+ }
+
+ /*
+ * @see IAction#runWithEvent(Event)
+ */
+ public void runWithEvent(Event event) {
+ run();
+ }
+
+ /*
+ * @see IAction#setActionDefinitionId(String)
+ */
+ public void setActionDefinitionId(String id) {
+ fActionDefinitionId= id;
+ }
+
+ /*
+ * @see IAction#getActionDefinitionId()
+ */
+ public String getActionDefinitionId() {
+ return fActionDefinitionId;
+ }
+
+ /*
+ * @see IAction#setId(String)
+ */
+ public void setId(String id) {
+ fActionId= id;
+ }
+
+ /*
+ * @see IAction#getId()
+ */
+ public String getId() {
+ return fActionId;
+ }
+
+
+// ----------------------------------------------------------------------------------------------------------------------------------
+// All the subsequent methods are just empty method bodies.
+
+ /*
+ * @see IAction#addPropertyChangeListener(IPropertyChangeListener)
+ */
+ public void addPropertyChangeListener(IPropertyChangeListener listener) {
+ }
+
+ /*
+ * @see IAction#getAccelerator()
+ */
+ public int getAccelerator() {
+ return 0;
+ }
+
+ /*
+ * @see IAction#getDescription()
+ */
+ public String getDescription() {
+ return null;
+ }
+
+ /*
+ * @see IAction#getDisabledImageDescriptor()
+ */
+ public ImageDescriptor getDisabledImageDescriptor() {
+ return null;
+ }
+
+ /*
+ * @see IAction#getHelpListener()
+ */
+ public HelpListener getHelpListener() {
+ return null;
+ }
+
+ /*
+ * @see IAction#getHoverImageDescriptor()
+ */
+ public ImageDescriptor getHoverImageDescriptor() {
+ return null;
+ }
+
+ /*
+ * @see IAction#getImageDescriptor()
+ */
+ public ImageDescriptor getImageDescriptor() {
+ return null;
+ }
+
+ /*
+ * @see IAction#getMenuCreator()
+ */
+ public IMenuCreator getMenuCreator() {
+ return null;
+ }
+
+ /*
+ * @see IAction#getStyle()
+ */
+ public int getStyle() {
+ return 0;
+ }
+
+ /*
+ * @see IAction#getText()
+ */
+ public String getText() {
+ return null;
+ }
+
+ /*
+ * @see IAction#getToolTipText()
+ */
+ public String getToolTipText() {
+ return null;
+ }
+
+ /*
+ * @see IAction#isChecked()
+ */
+ public boolean isChecked() {
+ return false;
+ }
+
+ /*
+ * @see IAction#isEnabled()
+ */
+ public boolean isEnabled() {
+ return true;
+ }
+
+ /*
+ * @see IAction#removePropertyChangeListener(IPropertyChangeListener)
+ */
+ public void removePropertyChangeListener(IPropertyChangeListener listener) {
+ }
+
+ /*
+ * @see IAction#setAccelerator(int)
+ */
+ public void setAccelerator(int keycode) {
+ }
+
+ /*
+ * @see IAction#setChecked(boolean)
+ */
+ public void setChecked(boolean checked) {
+ }
+
+ /*
+ * @see IAction#setDescription(String)
+ */
+ public void setDescription(String text) {
+ }
+
+ /*
+ * @see IAction#setDisabledImageDescriptor(ImageDescriptor)
+ */
+ public void setDisabledImageDescriptor(ImageDescriptor newImage) {
+ }
+
+ /*
+ * @see IAction#setEnabled(boolean)
+ */
+ public void setEnabled(boolean enabled) {
+ }
+
+ /*
+ * @see IAction#setHelpListener(HelpListener)
+ */
+ public void setHelpListener(HelpListener listener) {
+ }
+
+ /*
+ * @see IAction#setHoverImageDescriptor(ImageDescriptor)
+ */
+ public void setHoverImageDescriptor(ImageDescriptor newImage) {
+ }
+
+ /*
+ * @see IAction#setImageDescriptor(ImageDescriptor)
+ */
+ public void setImageDescriptor(ImageDescriptor newImage) {
+ }
+
+ /*
+ * @see IAction#setMenuCreator(IMenuCreator)
+ */
+ public void setMenuCreator(IMenuCreator creator) {
+ }
+
+ /*
+ * @see IAction#setText(String)
+ */
+ public void setText(String text) {
+ }
+
+ /*
+ * @see IAction#setToolTipText(String)
+ */
+ public void setToolTipText(String text) {
+ }
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/TextOperationAction.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/TextOperationAction.java
new file mode 100644
index 000000000..462f123ab
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/TextOperationAction.java
@@ -0,0 +1,157 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+
+package org.eclipse.ui.texteditor;
+
+
+import java.util.ResourceBundle;
+
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+import org.eclipse.jface.text.ITextOperationTarget;
+
+import org.eclipse.ui.IWorkbenchPartSite;
+
+
+/**
+ * An action which gets a text operation target from its text editor.
+ * <p>
+ * The action is initially associated with a text editor via the constructor,
+ * but can subsequently be changed using <code>setEditor</code>.
+ * </p>
+ * <p>
+ * If this class is used as is, it works by asking the text editor for its
+ * text operation target adapter (using <code>getAdapter(ITextOperationTarget.class)</code>.
+ * The action runs this operation with the pre-configured opcode.
+ * </p>
+ */
+public final class TextOperationAction extends TextEditorAction {
+
+ /** The text operation code */
+ private int fOperationCode= -1;
+ /** The text operation target */
+ private ITextOperationTarget fOperationTarget;
+ /**
+ * Indicates whether this action can be executed on read only editors
+ * @since 2.0
+ */
+ private boolean fRunsOnReadOnly= false;
+
+ /**
+ * Creates and initializes the action for the given text editor and operation
+ * code. The action configures its visual representation from the given resource
+ * bundle. The action works by asking the text editor at the time for its
+ * text operation target adapter (using
+ * <code>getAdapter(ITextOperationTarget.class)</code>. The action runs that
+ * operation with the given opcode.
+ *
+ * @param bundle the resource bundle
+ * @param prefix a prefix to be prepended to the various resource keys
+ * (described in <code>ResourceAction</code> constructor), or
+ * <code>null</code> if none
+ * @param editor the text editor
+ * @param operationCode the operation code
+ * @see ResourceAction#ResourceAction
+ */
+ public TextOperationAction(ResourceBundle bundle, String prefix, ITextEditor editor, int operationCode) {
+ super(bundle, prefix, editor);
+ fOperationCode= operationCode;
+ update();
+ }
+
+ /**
+ * Creates and initializes the action for the given text editor and operation
+ * code. The action configures its visual representation from the given resource
+ * bundle. The action works by asking the text editor at the time for its
+ * text operation target adapter (using
+ * <code>getAdapter(ITextOperationTarget.class)</code>. The action runs that
+ * operation with the given opcode.
+ *
+ * @param bundle the resource bundle
+ * @param prefix a prefix to be prepended to the various resource keys
+ * (described in <code>ResourceAction</code> constructor), or
+ * <code>null</code> if none
+ * @param editor the text editor
+ * @param operationCode the operation code
+ * @param runsOnReadOnly <code>true</code> if action can be executed on read-only files
+ *
+ * @see ResourceAction#ResourceAction
+ * @since 2.0
+ */
+ public TextOperationAction(ResourceBundle bundle, String prefix, ITextEditor editor, int operationCode, boolean runsOnReadOnly) {
+ super(bundle, prefix, editor);
+ fOperationCode= operationCode;
+ fRunsOnReadOnly= runsOnReadOnly;
+ update();
+ }
+
+ /**
+ * The <code>TextOperationAction</code> implementation of this
+ * <code>IAction</code> method runs the operation with the current
+ * operation code.
+ */
+ public void run() {
+ if (fOperationCode != -1 && fOperationTarget != null) {
+
+ ITextEditor editor= getTextEditor();
+ if (editor != null) {
+
+ Display display= null;
+
+ IWorkbenchPartSite site= editor.getSite();
+ Shell shell= site.getShell();
+ if (shell != null && !shell.isDisposed())
+ display= shell.getDisplay();
+
+ BusyIndicator.showWhile(display, new Runnable() {
+ public void run() {
+ fOperationTarget.doOperation(fOperationCode);
+ }
+ });
+ }
+ }
+ }
+
+ /**
+ * The <code>TextOperationAction</code> implementation of this
+ * <code>IUpdate</code> method discovers the operation through the current
+ * editor's <code>ITextOperationTarget</code> adapter, and sets the
+ * enabled state accordingly.
+ */
+ public void update() {
+
+ ITextEditor editor= getTextEditor();
+ if (editor instanceof ITextEditorExtension) {
+ ITextEditorExtension extension= (ITextEditorExtension) editor;
+ if (extension.isEditorInputReadOnly() && !fRunsOnReadOnly) {
+ setEnabled(false);
+ return;
+ }
+ }
+
+ if (fOperationTarget == null && editor!= null && fOperationCode != -1)
+ fOperationTarget= (ITextOperationTarget) editor.getAdapter(ITextOperationTarget.class);
+
+ boolean isEnabled= (fOperationTarget != null && fOperationTarget.canDoOperation(fOperationCode));
+ setEnabled(isEnabled);
+ }
+
+ /*
+ * @see TextEditorAction#setEditor(ITextEditor)
+ */
+ public void setEditor(ITextEditor editor) {
+ super.setEditor(editor);
+ fOperationTarget= null;
+ }
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/TextSelectionNavigationLocation.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/TextSelectionNavigationLocation.java
new file mode 100644
index 000000000..bb4c6795d
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/TextSelectionNavigationLocation.java
@@ -0,0 +1,238 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+package org.eclipse.ui.texteditor;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.BadPositionCategoryException;
+import org.eclipse.jface.text.DefaultPositionUpdater;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IPositionUpdater;
+import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.text.Position;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.NavigationLocation;
+import org.eclipse.ui.internal.IWorkbenchConstants;
+
+
+/**
+ * 2.1 - WORK_IN_PROGRESS do not use.
+ */
+public class TextSelectionNavigationLocation extends NavigationLocation {
+
+
+ private final static String DELETED= "deleted";
+ private final static String NOT_DELETED= "not_deleted";
+
+ private final static String CATEGORY= "__navigation_" + TextSelectionNavigationLocation.class.hashCode();
+ private static IPositionUpdater fgPositionUpdater= new DefaultPositionUpdater(CATEGORY);
+
+ private Position fPosition;
+ private IDocument fDocument;
+ private Position fSavedPosition;
+
+
+ public TextSelectionNavigationLocation(ITextEditor part) {
+
+ super(part);
+
+ ISelection s= part.getSelectionProvider().getSelection();
+ ITextSelection selection= (ITextSelection) s;
+ IDocument document= getDocument(part);
+
+ Position position= new Position(selection.getOffset(), selection.getLength());
+ if (installOnDocument(document, position)) {
+ fDocument= document;
+ fPosition= position;
+
+ if (!part.isDirty())
+ fSavedPosition= new Position(fPosition.offset, fPosition.length);
+ }
+ }
+
+ private IDocument getDocument(ITextEditor part) {
+ IDocumentProvider provider= part.getDocumentProvider();
+ return provider.getDocument(part.getEditorInput());
+ }
+
+ private boolean installOnDocument(IDocument document, Position position) {
+
+ if (document != null && position != null) {
+
+ if (!document.containsPositionCategory(CATEGORY)) {
+ document.addPositionCategory(CATEGORY);
+ document.addPositionUpdater(fgPositionUpdater);
+ }
+
+ try {
+ document.addPosition(CATEGORY, position);
+ return true;
+ } catch (BadLocationException e) {
+ } catch (BadPositionCategoryException e) {
+ }
+ }
+
+ return false;
+ }
+
+ private boolean uninstallFromDocument(IDocument document, Position position) {
+
+ if (document != null && position != null) {
+ try {
+
+ document.removePosition(CATEGORY, position);
+
+ Position[] category= document.getPositions(CATEGORY);
+ if (category == null || category.length == 0) {
+ document.removePositionCategory(CATEGORY);
+ document.removePositionUpdater(fgPositionUpdater);
+ }
+ return true;
+
+ } catch (BadPositionCategoryException e) {
+ }
+ }
+
+ return false;
+ }
+
+ public String toString() {
+ return "Selection<" + fPosition + ">";
+ }
+
+ public boolean equalsLocationOf(IEditorPart part) {
+
+ if (fPosition == null)
+ return true;
+
+ if (fPosition.isDeleted)
+ return false;
+
+ ISelectionProvider provider= part.getSite().getSelectionProvider();
+ ISelection selection= provider.getSelection();
+ if (selection instanceof ITextSelection) {
+ ITextSelection textSelection= (ITextSelection) selection;
+ if (textSelection.getOffset() == fPosition.offset && textSelection.getLength() == fPosition.length) {
+ String text= textSelection.getText();
+ if (text != null) {
+ try {
+ return text.equals(fDocument.get(fPosition.offset, fPosition.length));
+ } catch (BadLocationException e) {
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public void dispose() {
+ uninstallFromDocument(fDocument, fPosition);
+ fDocument= null;
+ fPosition= null;
+ fSavedPosition= null;
+ super.dispose();
+ }
+
+ public void clearState() {
+ fDocument= null;
+ fPosition= null;
+ fSavedPosition= null;
+ super.clearState();
+ }
+
+ public boolean mergeInto(NavigationLocation location) {
+
+ if (location == null)
+ return false;
+
+ if (getClass() != location.getClass())
+ return false;
+
+ TextSelectionNavigationLocation s= (TextSelectionNavigationLocation) location;
+
+ if (fPosition == null || fPosition.isDeleted)
+ return true;
+
+ if (s.fPosition == null || s.fPosition.isDeleted) {
+ uninstallFromDocument(fDocument, fPosition);
+ s.fDocument= fDocument;
+ s. fPosition= fPosition;
+ s.fSavedPosition= fSavedPosition;
+ return true;
+ }
+
+ return s.fDocument == fDocument && s.fPosition.equals(fPosition);
+ }
+
+ public void restore() {
+ if (fPosition == null || fPosition.isDeleted)
+ return;
+
+ if (getEditorPart() instanceof ITextEditor) {
+ ITextEditor editor= (ITextEditor) getEditorPart();
+ editor.selectAndReveal(fPosition.offset, fPosition.length);
+ }
+ }
+
+ public void restoreState(IMemento memento) {
+
+ IEditorPart part= getEditorPart();
+ if (part instanceof ITextEditor) {
+
+ // restore
+ fDocument= getDocument((ITextEditor) part);
+
+ Integer offset= memento.getInteger(IWorkbenchConstants.TAG_X);
+ Integer length= memento.getInteger(IWorkbenchConstants.TAG_Y);
+ String deleted= memento.getString(IWorkbenchConstants.TAG_INFO);
+
+ if (offset != null && length != null) {
+ fPosition= new Position(offset.intValue(), length.intValue());
+ if (deleted != null)
+ fPosition.isDeleted= DELETED.equals(deleted) ? true : false;
+ }
+
+ // activate
+ if (installOnDocument(fDocument, fPosition) && !part.isDirty())
+ fSavedPosition= new Position(fPosition.offset, fPosition.length);
+ }
+ }
+
+ public void saveState(IMemento memento) {
+
+ // save
+ if (fSavedPosition != null) {
+ memento.putInteger(IWorkbenchConstants.TAG_X, fSavedPosition.offset);
+ memento.putInteger(IWorkbenchConstants.TAG_Y, fSavedPosition.length);
+ memento.putString(IWorkbenchConstants.TAG_INFO, (fSavedPosition.isDeleted ? DELETED : NOT_DELETED));
+ }
+
+ // deactivate
+ uninstallFromDocument(fDocument, fPosition);
+ }
+
+ public void partSaved(IEditorPart part) {
+
+ if (fPosition == null)
+ return;
+
+ if (fSavedPosition == null)
+ fSavedPosition= new Position(0, 0);
+
+ fSavedPosition.offset= fPosition.offset;
+ fSavedPosition.length= fPosition.length;
+ fSavedPosition.isDeleted= fPosition.isDeleted;
+ }
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/TextUtilities.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/TextUtilities.java
new file mode 100644
index 000000000..89651ab3f
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/TextUtilities.java
@@ -0,0 +1,109 @@
+package org.eclipse.ui.texteditor;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+
+/**
+ * Collection of text functions.
+ */
+class TextUtilities {
+
+ /*
+ * 1GF86V3: ITPUI:WINNT - Internal errors using Find/Replace Dialog
+ * Copied from JFace text
+ */
+
+
+ public final static String[] fgDelimiters= new String[] { "\n", "\r", "\r\n" }; //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$
+
+
+ /**
+ * Determines which one of fgDelimiters appears first in the list. If none of them the
+ * hint is returned.
+ */
+ public static String determineLineDelimiter(String text, String hint) {
+ try {
+ int[] info= indexOf(fgDelimiters, text, 0);
+ return fgDelimiters[info[1]];
+ } catch (ArrayIndexOutOfBoundsException x) {
+ }
+ return hint;
+ }
+
+ /**
+ * Returns the position in the string greater than offset
+ * of the longest matching search string.
+ */
+ public static int[] indexOf(String[] searchStrings, String text, int offset) {
+
+ int[] result= { -1, -1 };
+
+ for (int i= 0; i < searchStrings.length; i++) {
+ int index= text.indexOf(searchStrings[i], offset);
+ if (index >= 0) {
+
+ if (result[0] == -1) {
+ result[0]= index;
+ result[1]= i;
+ } else if (index < result[0]) {
+ result[0]= index;
+ result[1]= i;
+ } else if (index == result[0] && searchStrings[i].length() > searchStrings[result[1]].length()) {
+ result[0]= index;
+ result[1]= i;
+ }
+ }
+ }
+
+ return result;
+
+ }
+
+ /**
+ * Returns the longest search string with which the given text ends.
+ */
+ public static int endsWith(String[] searchStrings, String text) {
+
+ int index= -1;
+
+ for (int i= 0; i < searchStrings.length; i++) {
+ if (text.endsWith(searchStrings[i])) {
+ if (index == -1 || searchStrings[i].length() > searchStrings[index].length())
+ index= i;
+ }
+ }
+
+ return index;
+ }
+
+ /**
+ * Returns the longest search string with which the given text starts.
+ */
+ public static int startsWith(String[] searchStrings, String text) {
+
+ int index= -1;
+
+ for (int i= 0; i < searchStrings.length; i++) {
+ if (text.startsWith(searchStrings[i])) {
+ if (index == -1 || searchStrings[i].length() > searchStrings[index].length())
+ index= i;
+ }
+ }
+
+ return index;
+ }
+
+ /**
+ * Returns whether the text equals one of the given compare strings.
+ */
+ public static int equals(String[] compareStrings, String text) {
+ for (int i= 0; i < compareStrings.length; i++) {
+ if (text.equals(compareStrings[i]))
+ return i;
+ }
+ return -1;
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/WorkbenchChainedTextFontFieldEditor.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/WorkbenchChainedTextFontFieldEditor.java
new file mode 100644
index 000000000..f1eafb1c8
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/WorkbenchChainedTextFontFieldEditor.java
@@ -0,0 +1,70 @@
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ IBM Corporation - Initial implementation
+**********************************************************************/
+
+
+package org.eclipse.ui.texteditor;
+
+
+import org.eclipse.swt.widgets.Composite;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Plugin;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.text.PropagatingFontFieldEditor;
+
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+
+/**
+ * This font field editor implements chaining between the workbench's preference
+ * store and a given target preference store. Any time the workbench's preference
+ * for the text font changes, the change is propagated to the target store.
+ * Propagation means that the actual text font stored in the workbench store is set as
+ * default text font in the target store. If the target store does not contain a value
+ * rather than the default text font, the new default text font is immediately effective.
+ *
+ * @see org.eclipse.jface.preference.FontFieldEditor
+ * @since 2.0
+ */
+public class WorkbenchChainedTextFontFieldEditor extends PropagatingFontFieldEditor {
+
+ /**
+ * Creates a new font field editor with the given parameters.
+ *
+ * @param name the editor's name
+ * @param labelText the text shown as editor description
+ * @param parent the editor's parent widget
+ */
+ public WorkbenchChainedTextFontFieldEditor(String name, String labelText, Composite parent) {
+ super(name, labelText, parent, EditorMessages.getString("WorkbenchChainedTextFontFieldEditor.defaultWorkbenchTextFont")); //$NON-NLS-1$
+ }
+
+ /**
+ * Starts the propagation of the text font preference set in the workbench
+ * to given target preference store using the given preference key.
+ *
+ * @param target the target preference store
+ * @param targetKey the key to be used in the target preference store
+ */
+ public static void startPropagate(IPreferenceStore target, String targetKey) {
+ Plugin plugin= Platform.getPlugin(PlatformUI.PLUGIN_ID);
+ if (plugin instanceof AbstractUIPlugin) {
+ AbstractUIPlugin uiPlugin= (AbstractUIPlugin) plugin;
+ IPreferenceStore store= uiPlugin.getPreferenceStore();
+ if (store != null)
+ PropagatingFontFieldEditor.startPropagate(store, JFaceResources.TEXT_FONT, target, targetKey);
+ }
+ }
+}
+
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/package.html b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/package.html
new file mode 100644
index 000000000..0ebf7f2db
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/package.html
@@ -0,0 +1,30 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="Author" content="IBM">
+ <meta name="GENERATOR" content="Mozilla/4.51 [en] (WinNT; I) [Netscape]">
+ <title>Package-level Javadoc</title>
+</head>
+<body>
+Provides a framework for text editors obeying to the
+desktop rules.
+<h2>
+Package Specification</h2>
+<tt>ITextEditor</tt> extends <tt>IEditorPart</tt> with text editor specific
+functionality. Text editors use source viewers (<tt>ISourceViewer</tt>)
+for displaying and editing the given editor input. In order to translate
+the editor input into a document and vice versa (e.g., for saving a change),
+a text editor uses document providers (<tt>IDocumentProvider</tt>). A document
+provider is responsible not just for providing the document for a given
+editor input but for the complete translation between the domain model
+and the editor's internal document-based model. Document provider can be
+shared between editors.
+<br>The package provides a default implementation of <tt>ITextEditor</tt>
+(<tt>AbstractTextEditor</tt>). This default implementation also covers
+the editor's complete action management and activation. The package contains
+a number of configurable and predefined actions. <tt>AbstractMarkerAnnotationModel</tt>
+establishs a link between text annotations (<tt>Annotation</tt>) and desktop
+markers (<tt>IMarker</tt>).
+</body>
+</html>

Back to the top