1 package net.sourceforge.phpeclipse.phpeditor;
3 /**********************************************************************
4 Copyright (c) 2000, 2002 IBM Corp. and others.
5 All rights reserved. This program and the accompanying materials
6 are made available under the terms of the Common Public License v1.0
7 which accompanies this distribution, and is available at
8 http://www.eclipse.org/legal/cpl-v10.html
11 IBM Corporation - Initial implementation
12 Klaus Hartlage - www.eclipseproject.de
13 **********************************************************************/
14 import net.sourceforge.phpdt.internal.ui.actions.CompositeActionGroup;
15 import net.sourceforge.phpdt.internal.ui.text.PHPPairMatcher;
16 import net.sourceforge.phpdt.ui.actions.GenerateActionGroup;
17 import net.sourceforge.phpdt.ui.actions.GotoMatchingBracketAction;
18 import net.sourceforge.phpeclipse.IPreferenceConstants;
19 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
20 import net.sourceforge.phpeclipse.phpeditor.php.PHPCodeScanner;
21 import net.sourceforge.phpeclipse.phpeditor.util.PHPColorProvider;
23 import org.eclipse.core.runtime.CoreException;
24 import org.eclipse.core.runtime.IProgressMonitor;
25 import org.eclipse.jface.action.Action;
26 import org.eclipse.jface.action.IAction;
27 import org.eclipse.jface.action.MenuManager;
28 import org.eclipse.jface.preference.IPreferenceStore;
29 import org.eclipse.jface.preference.PreferenceConverter;
30 import org.eclipse.jface.text.BadLocationException;
31 import org.eclipse.jface.text.IDocument;
32 import org.eclipse.jface.text.IRegion;
33 import org.eclipse.jface.text.ITextOperationTarget;
34 import org.eclipse.jface.text.ITextViewer;
35 import org.eclipse.jface.text.ITextViewerExtension3;
36 import org.eclipse.jface.text.Region;
37 import org.eclipse.jface.text.source.AnnotationRulerColumn;
38 import org.eclipse.jface.text.source.CompositeRuler;
39 import org.eclipse.jface.text.source.ISourceViewer;
40 import org.eclipse.jface.text.source.IVerticalRuler;
41 import org.eclipse.jface.text.source.IVerticalRulerColumn;
42 import org.eclipse.jface.text.source.LineNumberRulerColumn;
43 import org.eclipse.jface.util.IPropertyChangeListener;
44 import org.eclipse.jface.util.PropertyChangeEvent;
45 import org.eclipse.swt.custom.StyledText;
46 import org.eclipse.swt.graphics.Point;
47 import org.eclipse.swt.graphics.RGB;
48 import org.eclipse.ui.IEditorInput;
49 import org.eclipse.ui.actions.ActionContext;
50 import org.eclipse.ui.actions.ActionGroup;
51 import org.eclipse.ui.editors.text.TextEditor;
52 import org.eclipse.ui.texteditor.ContentAssistAction;
53 import org.eclipse.ui.texteditor.DefaultRangeIndicator;
54 import org.eclipse.ui.texteditor.IEditorStatusLine;
55 import org.eclipse.ui.texteditor.ITextEditorActionConstants;
56 import org.eclipse.ui.texteditor.TextOperationAction;
57 import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
59 * PHP specific text editor.
61 public class PHPEditor extends TextEditor {
62 // extends StatusTextEditor implements IViewPartInputProvider { // extends TextEditor {
64 // protected PHPActionGroup fActionGroups;
65 /** The outline page */
66 private PHPContentOutlinePage fOutlinePage;
67 private IPreferenceStore phpPrefStore;
69 /** The editor's bracket matcher */
70 private PHPPairMatcher fBracketMatcher;
71 /** The line number ruler column */
72 private LineNumberRulerColumn fLineNumberRulerColumn;
74 protected CompositeActionGroup fActionGroups;
75 /** The standard action groups added to the menu */
76 private GenerateActionGroup fGenerateActionGroup;
77 private CompositeActionGroup fContextMenuGroup;
79 * Default constructor.
83 setEditorContextMenuId("#PHPEditorContext"); //$NON-NLS-1$
84 setRulerContextMenuId("#PHPRulerContext"); //$NON-NLS-1$
88 // * @see IMember#getCompilationUnit()
90 // public ICompilationUnit getCompilationUnit() {
94 // * @see org.phpeclipse.phpdt.internal.compiler.env.ICompilationUnit#getContents()
96 // public char[] getContents() {
97 // IDocument doc = this.getDocumentProvider().getDocument(this.getEditorInput());
99 // return doc.get().toCharArray();
103 * Returns this document's complete text.
105 * @return the document's complete text
107 public String get() {
109 this.getDocumentProvider().getDocument(this.getEditorInput());
114 * Returns the standard action group of this editor.
116 protected ActionGroup getActionGroup() {
117 return fActionGroups;
120 public PHPContentOutlinePage getfOutlinePage() {
124 /** The <code>PHPEditor</code> implementation of this
125 * <code>AbstractTextEditor</code> method extend the
126 * actions to add those specific to the receiver
128 protected void createActions() {
129 super.createActions();
133 // "ContentAssistProposal",
134 // new TextOperationAction(
135 // PHPEditorMessages.getResourceBundle(),
136 // "ContentAssistProposal.",
138 // ISourceViewer.CONTENTASSIST_PROPOSALS));
139 action = new ContentAssistAction(PHPEditorMessages.getResourceBundle(), "ContentAssistProposal.", this); //$NON-NLS-1$
140 action.setActionDefinitionId(
141 PHPEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS);
142 setAction("ContentAssistProposal", action); //$NON-NLS-1$
146 new TextOperationAction(
147 PHPEditorMessages.getResourceBundle(),
150 ISourceViewer.CONTENTASSIST_CONTEXT_INFORMATION));
153 new TextOperationAction(
154 PHPEditorMessages.getResourceBundle(),
157 ITextOperationTarget.PREFIX);
158 action.setActionDefinitionId(PHPEditorActionDefinitionIds.COMMENT);
159 setAction("Comment", action);
162 new TextOperationAction(
163 PHPEditorMessages.getResourceBundle(),
166 ITextOperationTarget.STRIP_PREFIX);
167 action.setActionDefinitionId(PHPEditorActionDefinitionIds.UNCOMMENT);
168 setAction("Uncomment", action);
170 action = new TextOperationAction(PHPEditorMessages.getResourceBundle(), "Format.", this, ISourceViewer.FORMAT); //$NON-NLS-1$
171 action.setActionDefinitionId(PHPEditorActionDefinitionIds.FORMAT);
172 setAction("Format", action); //$NON-NLS-1$
174 markAsStateDependentAction("ContentAssistProposal", true); //$NON-NLS-1$
175 markAsStateDependentAction("Comment", true); //$NON-NLS-1$
176 markAsStateDependentAction("Uncomment", true); //$NON-NLS-1$
177 markAsStateDependentAction("Format", true); //$NON-NLS-1$
179 action = new GotoMatchingBracketAction(this);
180 action.setActionDefinitionId(
181 PHPEditorActionDefinitionIds.GOTO_MATCHING_BRACKET);
182 setAction(GotoMatchingBracketAction.GOTO_MATCHING_BRACKET, action);
184 fGenerateActionGroup =
185 new GenerateActionGroup(this, ITextEditorActionConstants.GROUP_EDIT);
188 new CompositeActionGroup(new ActionGroup[] { fGenerateActionGroup });
190 // We have to keep the context menu group separate to have better control over positioning
192 new CompositeActionGroup(new ActionGroup[] { fGenerateActionGroup });
194 // new LocalHistoryActionGroup(this, ITextEditorActionConstants.GROUP_EDIT)});
197 /** The <code>PHPEditor</code> implementation of this
198 * <code>AbstractTextEditor</code> method performs any extra
199 * disposal actions required by the php editor.
201 public void dispose() {
202 PHPEditorEnvironment.disconnect(this);
203 if (fOutlinePage != null)
204 fOutlinePage.setInput(null);
206 if (fActionGroups != null)
207 fActionGroups.dispose();
212 /** The <code>PHPEditor</code> implementation of this
213 * <code>AbstractTextEditor</code> method performs any extra
214 * revert behavior required by the php editor.
216 public void doRevertToSaved() {
217 super.doRevertToSaved();
218 if (fOutlinePage != null)
219 fOutlinePage.update();
222 /** The <code>PHPEditor</code> implementation of this
223 * <code>AbstractTextEditor</code> method performs any extra
224 * save behavior required by the php editor.
226 public void doSave(IProgressMonitor monitor) {
227 super.doSave(monitor);
228 // compile or not, according to the user preferences
229 IPreferenceStore store = phpPrefStore;
230 if (store.getBoolean(PHPeclipsePlugin.PHP_PARSE_ON_SAVE)) {
231 IAction a = PHPParserAction.getInstance();
235 if (fOutlinePage != null)
236 fOutlinePage.update();
239 /** The <code>PHPEditor</code> implementation of this
240 * <code>AbstractTextEditor</code> method performs any extra
241 * save as behavior required by the php editor.
243 public void doSaveAs() {
245 if (fOutlinePage != null)
246 fOutlinePage.update();
249 /** The <code>PHPEditor</code> implementation of this
250 * <code>AbstractTextEditor</code> method performs sets the
251 * input of the outline page after AbstractTextEditor has set input.
253 public void doSetInput(IEditorInput input) throws CoreException {
254 super.doSetInput(input);
255 if (fOutlinePage != null)
256 fOutlinePage.setInput(input);
260 * @see org.phpeclipse.phpdt.internal.ui.viewsupport.IViewPartInputProvider#getViewPartInput()
262 // public Object getViewPartInput() {
263 // return getEditorInput().getAdapter(IFile.class);
266 /** The <code>PHPEditor</code> implementation of this
267 * <code>AbstractTextEditor</code> method adds any
268 * PHPEditor specific entries.
270 public void editorContextMenuAboutToShow(MenuManager menu) {
271 super.editorContextMenuAboutToShow(menu);
273 addAction(menu, ITextEditorActionConstants.GROUP_EDIT, "Format"); //$NON-NLS-1$
275 ActionContext context =
276 new ActionContext(getSelectionProvider().getSelection());
277 fContextMenuGroup.setContext(context);
278 fContextMenuGroup.fillContextMenu(menu);
279 fContextMenuGroup.setContext(null);
282 protected void updateStateDependentActions() {
283 super.updateStateDependentActions();
284 fGenerateActionGroup.editorStateChanged();
287 /** The <code>PHPEditor</code> implementation of this
288 * <code>AbstractTextEditor</code> method performs gets
289 * the java content outline page if request is for a an
292 public Object getAdapter(Class required) {
293 if (IContentOutlinePage.class.equals(required)) {
294 if (fOutlinePage == null) {
295 fOutlinePage = new PHPContentOutlinePage(getDocumentProvider(), this);
296 if (getEditorInput() != null)
297 fOutlinePage.setInput(getEditorInput());
301 return super.getAdapter(required);
304 // public void openContextHelp() {
305 // IDocument doc = this.getDocumentProvider().getDocument(this.getEditorInput());
306 // ITextSelection selection = (ITextSelection) this.getSelectionProvider().getSelection();
307 // int pos = selection.getOffset();
308 // String word = getFunctionName(doc, pos);
309 // openContextHelp(word);
312 // private void openContextHelp(String word) {
316 // public static void open(String word) {
317 // IHelp help = WorkbenchHelp.getHelpSupport();
318 // if (help != null) {
319 // IHelpResource helpResource = new PHPFunctionHelpResource(word);
320 // WorkbenchHelp.getHelpSupport().displayHelpResource(helpResource);
322 // // showMessage(shell, dialogTitle, ActionMessages.getString("Open help not available"), false); //$NON-NLS-1$
326 // private String getFunctionName(IDocument doc, int pos) {
327 // Point word = PHPWordExtractor.findWord(doc, pos);
328 // if (word != null) {
330 // return doc.get(word.x, word.y).replace('_', '-');
331 // } catch (BadLocationException e) {
338 * @see AbstractTextEditor#handlePreferenceStoreChanged(PropertyChangeEvent)
340 protected void handlePreferenceStoreChanged(PropertyChangeEvent event) {
344 ISourceViewer sourceViewer = getSourceViewer();
345 if (sourceViewer == null)
348 String property = event.getProperty();
350 // if (JavaSourceViewerConfiguration.PREFERENCE_TAB_WIDTH.equals(property)) {
351 // Object value= event.getNewValue();
352 // if (value instanceof Integer) {
353 // sourceViewer.getTextWidget().setTabs(((Integer) value).intValue());
354 // } else if (value instanceof String) {
355 // sourceViewer.getTextWidget().setTabs(Integer.parseInt((String) value));
360 if (IPreferenceConstants.LINE_NUMBER_RULER.equals(property)) {
361 if (isLineNumberRulerVisible())
362 showLineNumberRuler();
364 hideLineNumberRuler();
368 if (fLineNumberRulerColumn != null
369 && (IPreferenceConstants.LINE_NUMBER_COLOR.equals(property)
370 || PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT.equals(property)
371 || PREFERENCE_COLOR_BACKGROUND.equals(property))) {
373 initializeLineNumberRulerColumn(fLineNumberRulerColumn);
377 super.handlePreferenceStoreChanged(event);
381 * Shows the line number ruler column.
383 private void showLineNumberRuler() {
384 IVerticalRuler v = getVerticalRuler();
385 if (v instanceof CompositeRuler) {
386 CompositeRuler c = (CompositeRuler) v;
387 c.addDecorator(1, createLineNumberRulerColumn());
392 * Return whether the line number ruler column should be
393 * visible according to the preference store settings.
394 * @return <code>true</code> if the line numbers should be visible
396 private boolean isLineNumberRulerVisible() {
397 // IPreferenceStore store= getPreferenceStore();
398 return phpPrefStore.getBoolean(IPreferenceConstants.LINE_NUMBER_RULER);
401 * Hides the line number ruler column.
403 private void hideLineNumberRuler() {
404 IVerticalRuler v = getVerticalRuler();
405 if (v instanceof CompositeRuler) {
406 CompositeRuler c = (CompositeRuler) v;
408 c.removeDecorator(1);
409 } catch (Throwable e) {
415 * Initializes the given line number ruler column from the preference store.
416 * @param rulerColumn the ruler column to be initialized
418 protected void initializeLineNumberRulerColumn(LineNumberRulerColumn rulerColumn) {
419 // JavaTextTools textTools= JavaPlugin.getDefault().getJavaTextTools();
420 PHPColorProvider manager = PHPEditorEnvironment.getPHPColorProvider();
422 if (phpPrefStore != null) {
426 if (phpPrefStore.contains(IPreferenceConstants.LINE_NUMBER_COLOR)) {
427 if (phpPrefStore.isDefault(IPreferenceConstants.LINE_NUMBER_COLOR))
429 PreferenceConverter.getDefaultColor(
431 IPreferenceConstants.LINE_NUMBER_COLOR);
434 PreferenceConverter.getColor(
436 IPreferenceConstants.LINE_NUMBER_COLOR);
438 rulerColumn.setForeground(manager.getColor(rgb));
444 IPreferenceConstants.PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT)) {
446 .contains(IPreferenceConstants.PREFERENCE_COLOR_BACKGROUND)) {
448 .isDefault(IPreferenceConstants.PREFERENCE_COLOR_BACKGROUND))
450 PreferenceConverter.getDefaultColor(
452 IPreferenceConstants.PREFERENCE_COLOR_BACKGROUND);
455 PreferenceConverter.getColor(
457 IPreferenceConstants.PREFERENCE_COLOR_BACKGROUND);
459 rulerColumn.setBackground(manager.getColor(rgb));
466 * Creates a new line number ruler column that is appropriately initialized.
468 protected IVerticalRulerColumn createLineNumberRulerColumn() {
469 fLineNumberRulerColumn = new LineNumberRulerColumn();
470 initializeLineNumberRulerColumn(fLineNumberRulerColumn);
471 return fLineNumberRulerColumn;
475 * @see AbstractTextEditor#createVerticalRuler()
477 protected IVerticalRuler createVerticalRuler() {
478 CompositeRuler ruler = new CompositeRuler();
479 ruler.addDecorator(0, new AnnotationRulerColumn(VERTICAL_RULER_WIDTH));
480 if (isLineNumberRulerVisible())
481 ruler.addDecorator(1, createLineNumberRulerColumn());
486 * Method declared on TextEditor
488 protected void initializeEditor() {
489 PHPEditorEnvironment.connect(this);
491 setSourceViewerConfiguration(new PHPSourceViewerConfiguration(this));
492 setRangeIndicator(new DefaultRangeIndicator());
493 setEditorContextMenuId("#PHPEditorContext"); //$NON-NLS-1$
494 setRulerContextMenuId("#PHPRulerContext"); //$NON-NLS-1$
495 // setDocumentProvider(PHPeclipsePlugin.getCompilationUnitDocumentProvider());
496 phpPrefStore = PHPeclipsePlugin.getDefault().getPreferenceStore();
498 phpPrefStore.addPropertyChangeListener(new IPropertyChangeListener() {
499 public void propertyChange(PropertyChangeEvent event) {
500 PHPCodeScanner scanner = PHPEditorEnvironment.getPHPCodeScanner();
501 if (scanner != null) {
502 scanner.updateToken(PHPEditorEnvironment.getPHPColorProvider());
504 if (getSourceViewer() != null) {
505 getSourceViewer().invalidateTextPresentation();
508 String property = event.getProperty();
509 if (IPreferenceConstants.LINE_NUMBER_RULER.equals(property)) {
510 if (isLineNumberRulerVisible())
511 showLineNumberRuler();
513 hideLineNumberRuler();
520 private static IRegion getSignedSelection(ITextViewer viewer) {
522 StyledText text = viewer.getTextWidget();
523 int caretOffset = text.getCaretOffset();
524 Point selection = text.getSelection();
528 if (caretOffset == selection.x) {
529 offset = selection.y;
530 length = selection.x - selection.y;
534 offset = selection.x;
535 length = selection.y - selection.x;
538 return new Region(offset, length);
541 private final static char[] BRACKETS = { '{', '}', '(', ')', '[', ']' };
543 private static boolean isBracket(char character) {
544 for (int i = 0; i != BRACKETS.length; ++i)
545 if (character == BRACKETS[i])
550 private static boolean isSurroundedByBrackets(
553 if (offset == 0 || offset == document.getLength())
557 return isBracket(document.getChar(offset - 1))
558 && isBracket(document.getChar(offset));
560 } catch (BadLocationException e) {
565 * Jumps to the matching bracket.
567 public void gotoMatchingBracket() {
569 if (fBracketMatcher == null)
570 fBracketMatcher = new PHPPairMatcher(BRACKETS);
572 ISourceViewer sourceViewer = getSourceViewer();
573 IDocument document = sourceViewer.getDocument();
574 if (document == null)
577 IRegion selection = getSignedSelection(sourceViewer);
579 int selectionLength = Math.abs(selection.getLength());
580 if (selectionLength > 1) {
581 setStatusLineErrorMessage(PHPEditorMessages.getString("GotoMatchingBracket.error.invalidSelection")); //$NON-NLS-1$
582 sourceViewer.getTextWidget().getDisplay().beep();
587 int sourceCaretOffset = selection.getOffset() + selection.getLength();
588 if (isSurroundedByBrackets(document, sourceCaretOffset))
589 sourceCaretOffset -= selection.getLength();
591 IRegion region = fBracketMatcher.match(document, sourceCaretOffset);
592 if (region == null) {
593 setStatusLineErrorMessage(PHPEditorMessages.getString("GotoMatchingBracket.error.noMatchingBracket")); //$NON-NLS-1$
594 sourceViewer.getTextWidget().getDisplay().beep();
598 int offset = region.getOffset();
599 int length = region.getLength();
604 int anchor = fBracketMatcher.getAnchor();
606 (PHPPairMatcher.RIGHT == anchor) ? offset : offset + length - 1;
608 boolean visible = false;
609 if (sourceViewer instanceof ITextViewerExtension3) {
610 ITextViewerExtension3 extension = (ITextViewerExtension3) sourceViewer;
611 visible = (extension.modelOffset2WidgetOffset(targetOffset) > -1);
613 IRegion visibleRegion = sourceViewer.getVisibleRegion();
615 (targetOffset >= visibleRegion.getOffset()
616 && targetOffset < visibleRegion.getOffset() + visibleRegion.getLength());
620 setStatusLineErrorMessage(PHPEditorMessages.getString("GotoMatchingBracket.error.bracketOutsideSelectedElement")); //$NON-NLS-1$
621 sourceViewer.getTextWidget().getDisplay().beep();
625 if (selection.getLength() < 0)
626 targetOffset -= selection.getLength();
628 sourceViewer.setSelectedRange(targetOffset, selection.getLength());
629 sourceViewer.revealRange(targetOffset, selection.getLength());
632 * Ses the given message as error message to this editor's status line.
633 * @param msg message to be set
635 protected void setStatusLineErrorMessage(String msg) {
636 IEditorStatusLine statusLine =
637 (IEditorStatusLine) getAdapter(IEditorStatusLine.class);
638 if (statusLine != null)
639 statusLine.setMessage(true, msg, null);