2 * Copyright (c) 2003-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: CssEditor.java,v 1.1 2004-09-02 18:11:50 jsurfer Exp $
14 package net.sourceforge.phpeclipse.css.ui.internal.editor;
16 import net.sourceforge.phpeclipse.core.model.ISourceReference;
17 import net.sourceforge.phpeclipse.css.core.model.IAtRule;
18 import net.sourceforge.phpeclipse.css.core.model.IRule;
19 import net.sourceforge.phpeclipse.css.core.model.IStyleRule;
20 import net.sourceforge.phpeclipse.css.core.model.IStyleSheet;
21 import net.sourceforge.phpeclipse.css.ui.CssUI;
22 import net.sourceforge.phpeclipse.css.ui.internal.CssDocumentProvider;
23 import net.sourceforge.phpeclipse.css.ui.internal.CssUIMessages;
24 import net.sourceforge.phpeclipse.css.ui.internal.CssUIPreferences;
25 import net.sourceforge.phpeclipse.css.ui.internal.ICssUIHelpContextIds;
26 import net.sourceforge.phpeclipse.css.ui.internal.outline.CssOutlinePage;
27 import net.sourceforge.phpeclipse.css.ui.internal.text.CssPairMatcher;
28 import net.sourceforge.phpeclipse.css.ui.internal.text.CssSourceViewerConfiguration;
29 import net.sourceforge.phpeclipse.css.ui.internal.text.IReconcilingParticipant;
31 import org.eclipse.jface.action.IAction;
32 import org.eclipse.jface.preference.IPreferenceStore;
33 import org.eclipse.jface.text.IRegion;
34 import org.eclipse.jface.text.source.ISourceViewer;
35 import org.eclipse.jface.util.PropertyChangeEvent;
36 import org.eclipse.jface.viewers.ISelectionChangedListener;
37 import org.eclipse.jface.viewers.IStructuredSelection;
38 import org.eclipse.jface.viewers.SelectionChangedEvent;
39 import org.eclipse.swt.custom.StyledText;
40 import org.eclipse.swt.widgets.Shell;
41 import org.eclipse.ui.editors.text.TextEditor;
42 import org.eclipse.ui.texteditor.ContentAssistAction;
43 import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
44 import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;
45 import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
48 * Implementation of a CSS editor based on the text editor infrastructure
49 * provided by the platform.
51 * TODO Reacting to every caret move seems rather expensive. Ideally, we'd
52 * collect the caret position changes and react after a specific delay.
54 public class CssEditor extends TextEditor implements IReconcilingParticipant {
56 // Inner Classes -----------------------------------------------------------
59 * Listens to changes to the selection in the outline page, and changes the
60 * selection and highlight range in the editor accordingly.
62 private class OutlineSelectionChangedListener
63 implements ISelectionChangedListener {
66 * @see ISelectionChangedListener#selectionChanged(SelectionChangedEvent)
68 public void selectionChanged(SelectionChangedEvent event) {
69 IStructuredSelection selection =
70 (IStructuredSelection) event.getSelection();
71 if (selection.isEmpty()) {
72 resetHighlightRange();
74 ISourceReference element =
75 (ISourceReference) selection.getFirstElement();
76 highlightElement(element, true);
78 IRegion selectedRegion = null;
79 if (element instanceof IAtRule) {
80 IAtRule atRule = (IAtRule) element;
81 selectedRegion = atRule.getValue().getSourceRegion();
82 } else if (element instanceof IStyleRule) {
83 IStyleRule styleRule = (IStyleRule) element;
84 selectedRegion = styleRule.getSelector().getSourceRegion();
87 if (selectedRegion != null) {
88 selectAndReveal(selectedRegion.getOffset(),
89 selectedRegion.getLength());
95 // Constants ---------------------------------------------------------------
98 * Alias for the preference constant <code>OUTLINE_LINK_WITH_EDITOR</code>.
100 private static final String LINK_WITH_OUTLINE =
101 CssUIPreferences.OUTLINE_LINK_WITH_EDITOR;
103 // Instance Variables ------------------------------------------------------
106 * The associated outline page.
108 CssOutlinePage outlinePage;
111 * Listens to changes in the outline page's selection to update the editor
112 * selection and highlight range.
114 private ISelectionChangedListener outlineSelectionChangedListener;
116 // Constructors ------------------------------------------------------------
119 * Default constructor.
122 setSourceViewerConfiguration(
123 new CssSourceViewerConfiguration(
124 CssUI.getDefault().getTextTools(),
125 getPreferenceStore(), this));
128 // AbstractTextEditor Implementation ---------------------------------------
131 * @see org.eclipse.ui.texteditor.AbstractTextEditor#affectsTextPresentation(PropertyChangeEvent)
133 protected boolean affectsTextPresentation(PropertyChangeEvent event) {
134 String p = event.getProperty();
135 if (CssUIPreferences.EDITOR_DEFAULT_COLOR.equals(p) ||
136 CssUIPreferences.EDITOR_DEFAULT_BOLD.equals(p) ||
137 CssUIPreferences.EDITOR_COMMENT_COLOR.equals(p) ||
138 CssUIPreferences.EDITOR_COMMENT_BOLD.equals(p) ||
139 CssUIPreferences.EDITOR_STRING_COLOR.equals(p) ||
140 CssUIPreferences.EDITOR_STRING_BOLD.equals(p) ||
141 CssUIPreferences.EDITOR_PROPERTY_COLOR.equals(p) ||
142 CssUIPreferences.EDITOR_PROPERTY_BOLD.equals(p) ||
143 CssUIPreferences.EDITOR_AT_KEYWORD_COLOR.equals(p) ||
144 CssUIPreferences.EDITOR_AT_KEYWORD_BOLD.equals(p) ||
145 CssUIPreferences.EDITOR_PSEUDO_CLASS_COLOR.equals(p) ||
146 CssUIPreferences.EDITOR_PSEUDO_CLASS_BOLD.equals(p)
151 return super.affectsTextPresentation(event);
155 * @see org.eclipse.ui.texteditor.AbstractTextEditor#createActions()
157 protected void createActions() {
158 super.createActions();
162 action = new ContentAssistAction(
163 CssUIMessages.getResourceBundle(),
164 "CssEditor.contentAssist.", this); //$NON-NLS-1$
165 action.setActionDefinitionId(
166 ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS);
167 setAction(ICssEditorActionConstants.CONTENT_ASSIST, action);
169 action = new CommentAction(
170 CssUIMessages.getResourceBundle(),
171 "CssEditor.comment.", this); //$NON-NLS-1$
172 action.setActionDefinitionId(ICssEditorActionDefinitionIds.COMMENT);
173 setAction(ICssEditorActionConstants.COMMENT, action);
174 markAsStateDependentAction(ICssEditorActionConstants.COMMENT, true);
175 markAsSelectionDependentAction(ICssEditorActionConstants.COMMENT, true);
177 action = new UncommentAction(
178 CssUIMessages.getResourceBundle(),
179 "CssEditor.uncomment.", this); //$NON-NLS-1$
180 action.setActionDefinitionId(ICssEditorActionDefinitionIds.UNCOMMENT);
181 setAction(ICssEditorActionConstants.UNCOMMENT, action);
182 markAsStateDependentAction(ICssEditorActionConstants.UNCOMMENT, true);
183 markAsSelectionDependentAction(ICssEditorActionConstants.UNCOMMENT,
188 * @see org.eclipse.ui.texteditor.ExtendedTextEditor#configureSourceViewerDecorationSupport(SourceViewerDecorationSupport)
190 protected void configureSourceViewerDecorationSupport(
191 SourceViewerDecorationSupport support
193 super.configureSourceViewerDecorationSupport(support);
195 support.setCharacterPairMatcher(new CssPairMatcher());
196 support.setMatchingCharacterPainterPreferenceKeys(
197 CssUIPreferences.EDITOR_MATCHING_BRACKETS,
198 CssUIPreferences.EDITOR_MATCHING_BRACKETS_COLOR);
199 support.setSymbolicFontName(getFontPropertyPreferenceKey());
203 * @see org.eclipse.ui.texteditor.AbstractTextEditor#getAdapter(Class)
205 public Object getAdapter(Class adapter) {
206 if (IContentOutlinePage.class.equals(adapter)) {
207 if (outlinePage == null) {
208 outlinePage = new CssOutlinePage(this);
209 outlineSelectionChangedListener =
210 new OutlineSelectionChangedListener();
211 outlinePage.addSelectionChangedListener(
212 outlineSelectionChangedListener);
218 return super.getAdapter(adapter);
222 * @see org.eclipse.ui.texteditor.AbstractTextEditor#handleCursorPositionChanged()
224 protected void handleCursorPositionChanged() {
225 super.handleCursorPositionChanged();
227 highlightElement(computeHighlightRangeSourceReference(), false);
228 synchronizeOutlinePageSelection();
232 * @see org.eclipse.ui.texteditor.ExtendedTextEditor#initializeEditor()
234 protected void initializeEditor() {
235 super.initializeEditor();
237 setHelpContextId(ICssUIHelpContextIds.EDITOR);
238 setPreferenceStore(CssUI.getDefault().getPreferenceStore());
239 configureInsertMode(SMART_INSERT, true);
240 setInsertMode(SMART_INSERT);
243 // IReconcilingParticipant Implementation ----------------------------------
246 * @see IReconcilingParticipant#reconciled()
248 public void reconciled() {
249 Shell shell = getSite().getShell();
250 if ((shell != null) && !shell.isDisposed()) {
251 shell.getDisplay().asyncExec(new Runnable() {
253 if (outlinePage != null) {
254 outlinePage.update();
256 synchronizeOutlinePageSelection();
262 // Public Methods ----------------------------------------------------------
265 * Computes and returns the source reference that includes the caret and
266 * serves as provider for the outline page selection and the editor range
269 * @return the computed source reference
271 public ISourceReference computeHighlightRangeSourceReference() {
272 ISourceViewer sourceViewer = getSourceViewer();
273 if (sourceViewer == null) {
277 StyledText styledText = sourceViewer.getTextWidget();
278 if ((styledText == null) || styledText.isDisposed()) {
282 int offset = sourceViewer.getVisibleRegion().getOffset();
283 int caret = offset + styledText.getCaretOffset();
285 return getRuleAt(caret);
289 * Informs the editor that its outliner has been closed.
291 * TODO There must be a more elegant way to get notified when the outline
292 * page was closed. Otherwise move this method into an interface
294 public void outlinePageClosed() {
295 if (outlinePage != null) {
296 outlinePage.removeSelectionChangedListener(
297 outlineSelectionChangedListener);
299 resetHighlightRange();
304 * Synchronizes the outliner selection with the given element position in
307 * @param element the java element to select
309 public void synchronizeOutlinePage(ISourceReference element) {
310 if (outlinePage != null) {
311 outlinePage.removeSelectionChangedListener(
312 outlineSelectionChangedListener);
313 outlinePage.select(element);
314 outlinePage.addSelectionChangedListener(
315 outlineSelectionChangedListener);
320 * Synchronizes the outliner selection with the currently highlighted source
323 public void synchronizeOutlinePage() {
324 ISourceReference element = computeHighlightRangeSourceReference();
325 synchronizeOutlinePage(element);
328 // Private Methods ---------------------------------------------------------
330 private IRule getRuleAt(int offset) {
331 IStyleSheet styleSheet = getStyleSheet();
332 if (styleSheet == null) {
336 return styleSheet.getRuleAt(offset);
339 private IStyleSheet getStyleSheet() {
340 if (getDocumentProvider() instanceof CssDocumentProvider) {
341 CssDocumentProvider p = (CssDocumentProvider) getDocumentProvider();
342 return p.getStyleSheet(getEditorInput());
348 void highlightElement(ISourceReference element, boolean moveCursor) {
349 if (element != null) {
350 IRegion highlightRegion = element.getSourceRegion();
351 setHighlightRange(highlightRegion.getOffset(),
352 highlightRegion.getLength(), moveCursor);
354 resetHighlightRange();
358 void synchronizeOutlinePageSelection() {
359 IPreferenceStore store = getPreferenceStore();
361 boolean linkWithEditor = store.getBoolean(LINK_WITH_OUTLINE);
362 if (linkWithEditor) {
363 synchronizeOutlinePage(computeHighlightRangeSourceReference());