2 * Copyright (c) 2004 Christopher Lenz and others
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * Christopher Lenz - initial API and implementation
11 * $Id: StructuredTextEditor.java,v 1.1 2004-09-02 18:26:30 jsurfer Exp $
14 package net.sourceforge.phpeclipse.ui.editor;
16 import net.sourceforge.phpeclipse.core.model.ISourceModel;
17 import net.sourceforge.phpeclipse.core.model.ISourceReference;
18 import net.sourceforge.phpeclipse.ui.text.IReconcilingParticipant;
19 import net.sourceforge.phpeclipse.ui.views.outline.ModelBasedOutlinePage;
21 import org.eclipse.jface.preference.IPreferenceStore;
22 import org.eclipse.jface.text.IRegion;
23 import org.eclipse.jface.text.source.ISourceViewer;
24 import org.eclipse.jface.viewers.ISelectionChangedListener;
25 import org.eclipse.jface.viewers.IStructuredSelection;
26 import org.eclipse.jface.viewers.SelectionChangedEvent;
27 import org.eclipse.swt.custom.StyledText;
28 import org.eclipse.swt.widgets.Shell;
29 import org.eclipse.ui.editors.text.TextEditor;
30 import org.eclipse.ui.texteditor.IUpdate;
31 import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
34 * Abstract base class for editors that keep a source model synchronized with
35 * the textual contants being edited.
37 public abstract class StructuredTextEditor extends TextEditor
38 implements IReconcilingParticipant {
40 // Inner Classes -----------------------------------------------------------
43 * Listens to changes to the selection in the outline page, and changes the
44 * selection and highlight range in the editor accordingly.
46 private class OutlineSelectionChangedListener
47 implements ISelectionChangedListener {
50 * @see ISelectionChangedListener#selectionChanged(SelectionChangedEvent)
52 public void selectionChanged(SelectionChangedEvent event) {
53 IStructuredSelection selection =
54 (IStructuredSelection) event.getSelection();
55 if (selection.isEmpty()) {
56 resetHighlightRange();
58 ISourceReference element = (ISourceReference)
59 selection.getFirstElement();
60 highlightElement(element, true);
66 // Instance Variables ------------------------------------------------------
69 * The associated outline page.
71 private IContentOutlinePage outlinePage;
74 * Listens to changes in the outline page's selection to update the editor
75 * selection and highlight range.
77 private ISelectionChangedListener outlinePageSelectionListener;
79 // TextEditor Implementation -----------------------------------------------
82 * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
84 public Object getAdapter(Class adapter) {
85 if (adapter.equals(IContentOutlinePage.class)) {
86 if (outlinePage == null) {
87 outlinePage = createOutlinePage();
88 outlinePageSelectionListener =
89 new OutlineSelectionChangedListener();
90 outlinePage.addSelectionChangedListener(
91 outlinePageSelectionListener);
95 return super.getAdapter(adapter);
99 * @see org.eclipse.ui.texteditor.AbstractTextEditor#handleCursorPositionChanged()
101 protected void handleCursorPositionChanged() {
102 super.handleCursorPositionChanged();
103 highlightElement(computeHighlightRangeSourceReference(), false);
104 synchronizeOutlinePageSelection();
107 // IReconcilingParticipant Implementation ----------------------------------
110 * @see IReconcilingParticipant#reconciled()
112 public void reconciled() {
113 Shell shell = getSite().getShell();
114 if ((shell != null) && !shell.isDisposed()) {
115 shell.getDisplay().asyncExec(new Runnable() {
117 if (outlinePage instanceof IUpdate) {
118 ((IUpdate) outlinePage).update();
120 synchronizeOutlinePageSelection();
126 // Public Methods ----------------------------------------------------------
129 * Computes and returns the source reference that includes the caret and
130 * serves as provider for the outline page selection and the editor range
133 * @return the computed source reference
135 public ISourceReference computeHighlightRangeSourceReference() {
136 ISourceViewer sourceViewer = getSourceViewer();
137 if (sourceViewer == null) {
140 StyledText styledText = sourceViewer.getTextWidget();
141 if ((styledText == null) || styledText.isDisposed()) {
144 int offset = sourceViewer.getVisibleRegion().getOffset();
145 int caret = offset + styledText.getCaretOffset();
147 return getElementAt(caret);
151 * Returns the source model element at the specified offset.
153 * @param offset the offset into the document
154 * @return the element at the given offset, or <tt>null</tt> if no model is
155 * available or there is no element at the offset
157 public ISourceReference getElementAt(int offset) {
158 ISourceReference retVal = null;
159 ISourceModel model = getSourceModel();
161 ISourceReference elements[] = model.getElements();
162 retVal = getElementAt(model, elements, offset);
168 * Returns the structure source model corresponding to the document
169 * currently being edited.
171 * Concrete implementations must implement this method to return the model
172 * appropriate to the content being edited.
174 * @return the source model
176 public abstract ISourceModel getSourceModel();
179 * Informs the editor that its outliner has been closed.
181 * TODO There must be a more elegant way to get notified when the outline
182 * page was closed. Otherwise move this method into an interface
184 public void outlinePageClosed() {
185 if (outlinePage != null) {
186 outlinePage.removeSelectionChangedListener(
187 outlinePageSelectionListener);
189 resetHighlightRange();
194 * Synchronizes the outliner selection with the given element position in
197 * @param element the java element to select
199 public void synchronizeOutlinePage(ISourceReference element) {
200 if (outlinePage != null) {
201 outlinePage.removeSelectionChangedListener(
202 outlinePageSelectionListener);
203 if (outlinePage instanceof ModelBasedOutlinePage) {
204 ((ModelBasedOutlinePage) outlinePage).select(element);
206 outlinePage.addSelectionChangedListener(
207 outlinePageSelectionListener);
212 * Synchronizes the outliner selection with the currently highlighted source
215 public void synchronizeOutlinePage() {
216 ISourceReference element = computeHighlightRangeSourceReference();
217 synchronizeOutlinePage(element);
220 // Protected Methods -------------------------------------------------------
222 protected abstract IContentOutlinePage createOutlinePage();
225 * Highlights the given element.
227 * @param element the element that should be highlighted
228 * @param moveCursor whether the cursor should be moved to the element
230 protected final void highlightElement(ISourceReference element,
231 boolean moveCursor) {
232 if (element != null) {
233 IRegion highlightRegion = element.getSourceRegion();
234 setHighlightRange(highlightRegion.getOffset(),
235 highlightRegion.getLength(), moveCursor);
237 resetHighlightRange();
242 * Returns whether the outline page is currently linked with the editor,
243 * meaning that its selection should automatically be updated to reflect the
244 * current cursor position.
246 * @return <tt>true</tt> if the outline page is linked with the editor,
247 * <tt>false</tt> otherwise
249 protected abstract boolean isOutlineLinkedWithEditor();
251 // Private Methods ---------------------------------------------------------
254 * Recursively searches the specified list of elements managed by the given
255 * model for the element that covers the specified offfset with minimal
258 * @param model the source model
259 * @param elements the current list of elements
260 * @param offset the offset into the document
261 * @return the model element at the specified offset, or <tt>null</tt> if
262 * no element could be found
264 private static ISourceReference getElementAt(
265 ISourceModel model, ISourceReference elements[], int offset) {
266 ISourceReference retVal = null;
267 for (int i = 0; i < elements.length; i++) {
268 ISourceReference element = elements[i];
269 IRegion region = element.getSourceRegion();
270 if ((offset > region.getOffset())
271 && (offset < (region.getOffset() + region.getLength()))) {
272 ISourceReference[] children = model.getChildren(element);
273 if (children.length > 0) {
274 retVal = getElementAt(model, children, offset);
275 if (retVal != null) {
279 if (retVal == null) {
287 private void synchronizeOutlinePageSelection() {
288 IPreferenceStore store = getPreferenceStore();
290 boolean linkWithEditor = isOutlineLinkedWithEditor();
291 if (linkWithEditor) {
292 synchronizeOutlinePage(computeHighlightRangeSourceReference());