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 java.util.ArrayList;
15 import java.util.List;
17 import net.sourceforge.phpdt.internal.ui.actions.CompositeActionGroup;
18 import net.sourceforge.phpdt.internal.ui.text.HTMLTextPresenter;
19 import net.sourceforge.phpdt.internal.ui.text.PHPPairMatcher;
20 import net.sourceforge.phpdt.internal.ui.viewsupport.IViewPartInputProvider;
21 import net.sourceforge.phpdt.ui.PreferenceConstants;
22 import net.sourceforge.phpdt.ui.actions.GenerateActionGroup;
23 import net.sourceforge.phpdt.ui.actions.GotoMatchingBracketAction;
24 import net.sourceforge.phpdt.ui.text.IColorManager;
25 import net.sourceforge.phpdt.ui.text.JavaTextTools;
26 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
27 import net.sourceforge.phpeclipse.phpeditor.php.IPHPPartitionScannerConstants;
29 import org.eclipse.core.resources.IResource;
30 import org.eclipse.core.runtime.CoreException;
31 import org.eclipse.core.runtime.IProgressMonitor;
32 import org.eclipse.jface.action.Action;
33 import org.eclipse.jface.action.IAction;
34 import org.eclipse.jface.action.MenuManager;
35 import org.eclipse.jface.preference.IPreferenceStore;
36 import org.eclipse.jface.preference.PreferenceConverter;
37 import org.eclipse.jface.text.BadLocationException;
38 import org.eclipse.jface.text.DefaultInformationControl;
39 import org.eclipse.jface.text.IDocument;
40 import org.eclipse.jface.text.IInformationControl;
41 import org.eclipse.jface.text.IInformationControlCreator;
42 import org.eclipse.jface.text.IRegion;
43 import org.eclipse.jface.text.ITextHover;
44 import org.eclipse.jface.text.ITextOperationTarget;
45 import org.eclipse.jface.text.ITextViewer;
46 import org.eclipse.jface.text.ITextViewerExtension2;
47 import org.eclipse.jface.text.ITextViewerExtension3;
48 import org.eclipse.jface.text.ITypedRegion;
49 import org.eclipse.jface.text.Region;
50 import org.eclipse.jface.text.information.InformationPresenter;
51 import org.eclipse.jface.text.source.AnnotationRulerColumn;
52 import org.eclipse.jface.text.source.CompositeRuler;
53 import org.eclipse.jface.text.source.ISourceViewer;
54 import org.eclipse.jface.text.source.IVerticalRuler;
55 import org.eclipse.jface.text.source.IVerticalRulerColumn;
56 import org.eclipse.jface.text.source.LineNumberRulerColumn;
57 import org.eclipse.jface.text.source.SourceViewerConfiguration;
58 import org.eclipse.jface.util.PropertyChangeEvent;
59 import org.eclipse.swt.SWT;
60 import org.eclipse.swt.custom.BidiSegmentEvent;
61 import org.eclipse.swt.custom.BidiSegmentListener;
62 import org.eclipse.swt.custom.StyledText;
63 import org.eclipse.swt.graphics.Point;
64 import org.eclipse.swt.graphics.RGB;
65 import org.eclipse.swt.widgets.Composite;
66 import org.eclipse.swt.widgets.Shell;
67 import org.eclipse.ui.IEditorInput;
68 import org.eclipse.ui.actions.ActionContext;
69 import org.eclipse.ui.actions.ActionGroup;
70 import org.eclipse.ui.texteditor.ContentAssistAction;
71 import org.eclipse.ui.texteditor.DefaultRangeIndicator;
72 import org.eclipse.ui.texteditor.IDocumentProvider;
73 import org.eclipse.ui.texteditor.IEditorStatusLine;
74 import org.eclipse.ui.texteditor.ITextEditorActionConstants;
75 import org.eclipse.ui.texteditor.StatusTextEditor;
76 import org.eclipse.ui.texteditor.TextOperationAction;
77 import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
79 * PHP specific text editor.
81 public class PHPEditor extends StatusTextEditor implements IViewPartInputProvider { // extends TextEditor {
83 /** Preference key for showing the line number ruler */
84 private final static String LINE_NUMBER_RULER = PreferenceConstants.EDITOR_LINE_NUMBER_RULER;
85 /** Preference key for the foreground color of the line numbers */
86 private final static String LINE_NUMBER_COLOR = PreferenceConstants.EDITOR_LINE_NUMBER_RULER_COLOR;
87 /** Preference key for the link color */
88 private final static String LINK_COLOR = PreferenceConstants.EDITOR_LINK_COLOR;
90 // protected PHPActionGroup fActionGroups;
91 /** The outline page */
92 private AbstractContentOutlinePage fOutlinePage;
94 // protected PHPSyntaxParserThread fValidationThread = null;
96 // private IPreferenceStore fPHPPrefStore;
98 /** The editor's bracket matcher */
99 private PHPPairMatcher fBracketMatcher;
100 /** The line number ruler column */
101 private LineNumberRulerColumn fLineNumberRulerColumn;
103 protected CompositeActionGroup fActionGroups;
104 /** The standard action groups added to the menu */
105 private GenerateActionGroup fGenerateActionGroup;
106 private CompositeActionGroup fContextMenuGroup;
108 /** The information presenter. */
109 private InformationPresenter fInformationPresenter;
112 * Default constructor.
116 JavaTextTools textTools = PHPeclipsePlugin.getDefault().getJavaTextTools();
117 setSourceViewerConfiguration(new PHPSourceViewerConfiguration(textTools, this));
118 setRangeIndicator(new DefaultRangeIndicator());
119 setPreferenceStore(PHPeclipsePlugin.getDefault().getPreferenceStore());
121 // if (PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_SYNC_OUTLINE_ON_CURSOR_MOVE))
122 // fUpdater= new OutlinePageSelectionUpdater();
128 // * @see IMember#getCompilationUnit()
130 // public ICompilationUnit getCompilationUnit() {
134 // * @see org.phpeclipse.phpdt.internal.compiler.env.ICompilationUnit#getContents()
136 // public char[] getContents() {
137 // IDocument doc = this.getDocumentProvider().getDocument(this.getEditorInput());
139 // return doc.get().toCharArray();
143 * Update the hovering behavior depending on the preferences.
145 private void updateHoverBehavior() {
146 SourceViewerConfiguration configuration = getSourceViewerConfiguration();
147 String[] types = configuration.getConfiguredContentTypes(getSourceViewer());
149 for (int i = 0; i < types.length; i++) {
153 int[] stateMasks = configuration.getConfiguredTextHoverStateMasks(getSourceViewer(), t);
155 ISourceViewer sourceViewer = getSourceViewer();
156 if (sourceViewer instanceof ITextViewerExtension2) {
157 if (stateMasks != null) {
158 for (int j = 0; j < stateMasks.length; j++) {
159 int stateMask = stateMasks[j];
160 ITextHover textHover = configuration.getTextHover(sourceViewer, t, stateMask);
161 ((ITextViewerExtension2) sourceViewer).setTextHover(textHover, t, stateMask);
164 ITextHover textHover = configuration.getTextHover(sourceViewer, t);
165 ((ITextViewerExtension2) sourceViewer).setTextHover(textHover, t, ITextViewerExtension2.DEFAULT_HOVER_STATE_MASK);
168 sourceViewer.setTextHover(configuration.getTextHover(sourceViewer, t), t);
173 * @see net.sourceforge.phpdt.internal.ui.viewsupport.IViewPartInputProvider#getViewPartInput()
175 public Object getViewPartInput() {
176 return getEditorInput().getAdapter(IResource.class);
180 * @see org.eclipse.ui.IWorkbenchPart#createPartControl(org.eclipse.swt.
183 public void createPartControl(Composite parent) {
184 super.createPartControl(parent);
186 IInformationControlCreator informationControlCreator = new IInformationControlCreator() {
187 public IInformationControl createInformationControl(Shell parent) {
188 boolean cutDown = false;
189 int style = cutDown ? SWT.NONE : (SWT.V_SCROLL | SWT.H_SCROLL);
190 return new DefaultInformationControl(parent, SWT.RESIZE, style, new HTMLTextPresenter(cutDown));
194 fInformationPresenter = new InformationPresenter(informationControlCreator);
195 fInformationPresenter.setSizeConstraints(60, 10, true, true);
196 fInformationPresenter.install(getSourceViewer());
200 * Returns this document's complete text.
202 * @return the document's complete text
204 public String get() {
205 IDocument doc = this.getDocumentProvider().getDocument(this.getEditorInput());
210 * Returns the standard action group of this editor.
212 protected ActionGroup getActionGroup() {
213 return fActionGroups;
216 public AbstractContentOutlinePage getfOutlinePage() {
220 /** The <code>PHPEditor</code> implementation of this
221 * <code>AbstractTextEditor</code> method extend the
222 * actions to add those specific to the receiver
224 protected void createActions() {
225 super.createActions();
229 // "ContentAssistProposal",
230 // new TextOperationAction(
231 // PHPEditorMessages.getResourceBundle(),
232 // "ContentAssistProposal.",
234 // ISourceViewer.CONTENTASSIST_PROPOSALS));
235 action = new ContentAssistAction(PHPEditorMessages.getResourceBundle(), "ContentAssistProposal.", this); //$NON-NLS-1$
236 action.setActionDefinitionId(PHPEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS);
237 setAction("ContentAssistProposal", action); //$NON-NLS-1$
241 new TextOperationAction(
242 PHPEditorMessages.getResourceBundle(),
245 ISourceViewer.CONTENTASSIST_CONTEXT_INFORMATION));
247 action = new TextOperationAction(PHPEditorMessages.getResourceBundle(), "Comment.", this, ITextOperationTarget.PREFIX);
248 action.setActionDefinitionId(PHPEditorActionDefinitionIds.COMMENT);
249 setAction("Comment", action);
251 action = new TextOperationAction(PHPEditorMessages.getResourceBundle(), "Uncomment.", this, ITextOperationTarget.STRIP_PREFIX);
252 action.setActionDefinitionId(PHPEditorActionDefinitionIds.UNCOMMENT);
253 setAction("Uncomment", action);
255 action = new TextOperationAction(PHPEditorMessages.getResourceBundle(), "Format.", this, ISourceViewer.FORMAT); //$NON-NLS-1$
256 action.setActionDefinitionId(PHPEditorActionDefinitionIds.FORMAT);
257 setAction("Format", action); //$NON-NLS-1$
259 markAsStateDependentAction("ContentAssistProposal", true); //$NON-NLS-1$
260 markAsStateDependentAction("Comment", true); //$NON-NLS-1$
261 markAsStateDependentAction("Uncomment", true); //$NON-NLS-1$
262 markAsStateDependentAction("Format", true); //$NON-NLS-1$
264 action = new GotoMatchingBracketAction(this);
265 action.setActionDefinitionId(PHPEditorActionDefinitionIds.GOTO_MATCHING_BRACKET);
266 setAction(GotoMatchingBracketAction.GOTO_MATCHING_BRACKET, action);
268 fGenerateActionGroup = new GenerateActionGroup(this, ITextEditorActionConstants.GROUP_EDIT);
270 fActionGroups = new CompositeActionGroup(new ActionGroup[] { fGenerateActionGroup });
272 // We have to keep the context menu group separate to have better control over positioning
273 fContextMenuGroup = new CompositeActionGroup(new ActionGroup[] { fGenerateActionGroup });
275 // new LocalHistoryActionGroup(this, ITextEditorActionConstants.GROUP_EDIT)});
277 // if (fValidationThread == null) {
278 // fValidationThread =
279 // new PHPSyntaxParserThread(this, getSourceViewer());
282 // fValidationThread.start();
285 // fValidationThread.setText(getSourceViewer().getTextWidget().getText());
288 /** The <code>PHPEditor</code> implementation of this
289 * <code>AbstractTextEditor</code> method performs any extra
290 * disposal actions required by the php editor.
292 public void dispose() {
293 // PHPEditorEnvironment.disconnect(this);
294 if (fOutlinePage != null)
295 fOutlinePage.setInput(null);
297 if (fActionGroups != null)
298 fActionGroups.dispose();
303 /** The <code>PHPEditor</code> implementation of this
304 * <code>AbstractTextEditor</code> method performs any extra
305 * revert behavior required by the php editor.
307 public void doRevertToSaved() {
308 super.doRevertToSaved();
309 if (fOutlinePage != null)
310 fOutlinePage.update();
313 /** The <code>PHPEditor</code> implementation of this
314 * <code>AbstractTextEditor</code> method performs any extra
315 * save behavior required by the php editor.
317 public void doSave(IProgressMonitor monitor) {
318 super.doSave(monitor);
319 // compile or not, according to the user preferences
320 IPreferenceStore store = getPreferenceStore(); // fPHPPrefStore;
321 if (store.getBoolean(PHPeclipsePlugin.PHP_PARSE_ON_SAVE)) {
322 IAction a = PHPParserAction.getInstance();
326 // if (SWT.getPlatform().equals("win32")) {
327 // IAction a = ShowExternalPreviewAction.getInstance();
331 if (fOutlinePage != null)
332 fOutlinePage.update();
335 /** The <code>PHPEditor</code> implementation of this
336 * <code>AbstractTextEditor</code> method performs any extra
337 * save as behavior required by the php editor.
339 public void doSaveAs() {
341 if (fOutlinePage != null)
342 fOutlinePage.update();
345 /** The <code>PHPEditor</code> implementation of this
346 * <code>AbstractTextEditor</code> method performs sets the
347 * input of the outline page after AbstractTextEditor has set input.
349 protected void doSetInput(IEditorInput input) throws CoreException {
350 super.doSetInput(input);
351 if (fOutlinePage != null)
352 fOutlinePage.setInput(input);
356 * @see org.phpeclipse.phpdt.internal.ui.viewsupport.IViewPartInputProvider#getViewPartInput()
358 // public Object getViewPartInput() {
359 // return getEditorInput().getAdapter(IFile.class);
362 /** The <code>PHPEditor</code> implementation of this
363 * <code>AbstractTextEditor</code> method adds any
364 * PHPEditor specific entries.
366 public void editorContextMenuAboutToShow(MenuManager menu) {
367 super.editorContextMenuAboutToShow(menu);
369 addAction(menu, ITextEditorActionConstants.GROUP_EDIT, "Format"); //$NON-NLS-1$
371 ActionContext context = new ActionContext(getSelectionProvider().getSelection());
372 fContextMenuGroup.setContext(context);
373 fContextMenuGroup.fillContextMenu(menu);
374 fContextMenuGroup.setContext(null);
377 protected void updateStateDependentActions() {
378 super.updateStateDependentActions();
379 fGenerateActionGroup.editorStateChanged();
382 /** The <code>PHPEditor</code> implementation of this
383 * <code>AbstractTextEditor</code> method performs gets
384 * the java content outline page if request is for a an
387 public Object getAdapter(Class required) {
388 if (IContentOutlinePage.class.equals(required)) {
389 if (fOutlinePage == null) {
390 fOutlinePage = new PHPContentOutlinePage(getDocumentProvider(), this);
391 if (getEditorInput() != null)
392 fOutlinePage.setInput(getEditorInput());
396 return super.getAdapter(required);
399 // public void openContextHelp() {
400 // IDocument doc = this.getDocumentProvider().getDocument(this.getEditorInput());
401 // ITextSelection selection = (ITextSelection) this.getSelectionProvider().getSelection();
402 // int pos = selection.getOffset();
403 // String word = getFunctionName(doc, pos);
404 // openContextHelp(word);
407 // private void openContextHelp(String word) {
411 // public static void open(String word) {
412 // IHelp help = WorkbenchHelp.getHelpSupport();
413 // if (help != null) {
414 // IHelpResource helpResource = new PHPFunctionHelpResource(word);
415 // WorkbenchHelp.getHelpSupport().displayHelpResource(helpResource);
417 // // showMessage(shell, dialogTitle, ActionMessages.getString("Open help not available"), false); //$NON-NLS-1$
421 // private String getFunctionName(IDocument doc, int pos) {
422 // Point word = PHPWordExtractor.findWord(doc, pos);
423 // if (word != null) {
425 // return doc.get(word.x, word.y).replace('_', '-');
426 // } catch (BadLocationException e) {
433 * @see AbstractTextEditor#handlePreferenceStoreChanged(PropertyChangeEvent)
435 protected void handlePreferenceStoreChanged(PropertyChangeEvent event) {
439 ISourceViewer sourceViewer = getSourceViewer();
440 if (sourceViewer == null)
443 String property = event.getProperty();
445 if (PreferenceConstants.EDITOR_TAB_WIDTH.equals(property)) {
446 Object value = event.getNewValue();
447 if (value instanceof Integer) {
448 sourceViewer.getTextWidget().setTabs(((Integer) value).intValue());
449 } else if (value instanceof String) {
450 sourceViewer.getTextWidget().setTabs(Integer.parseInt((String) value));
455 if (LINE_NUMBER_RULER.equals(property)) {
456 if (isLineNumberRulerVisible())
457 showLineNumberRuler();
459 hideLineNumberRuler();
463 if (fLineNumberRulerColumn != null
464 && (LINE_NUMBER_COLOR.equals(property)
465 || PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT.equals(property)
466 || PREFERENCE_COLOR_BACKGROUND.equals(property))) {
468 initializeLineNumberRulerColumn(fLineNumberRulerColumn);
471 if (isJavaEditorHoverProperty(property)) {
472 updateHoverBehavior();
476 super.handlePreferenceStoreChanged(event);
481 // * @see AbstractTextEditor#handlePreferenceStoreChanged(PropertyChangeEvent)
483 // protected void handlePreferenceStoreChanged(PropertyChangeEvent event) {
487 // ISourceViewer sourceViewer = getSourceViewer();
488 // if (sourceViewer == null)
491 // String property = event.getProperty();
493 // // if (JavaSourceViewerConfiguration.PREFERENCE_TAB_WIDTH.equals(property)) {
494 // // Object value= event.getNewValue();
495 // // if (value instanceof Integer) {
496 // // sourceViewer.getTextWidget().setTabs(((Integer) value).intValue());
497 // // } else if (value instanceof String) {
498 // // sourceViewer.getTextWidget().setTabs(Integer.parseInt((String) value));
503 // if (IPreferenceConstants.LINE_NUMBER_RULER.equals(property)) {
504 // if (isLineNumberRulerVisible())
505 // showLineNumberRuler();
507 // hideLineNumberRuler();
511 // if (fLineNumberRulerColumn != null
512 // && (IPreferenceConstants.LINE_NUMBER_COLOR.equals(property)
513 // || PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT.equals(property)
514 // || PREFERENCE_COLOR_BACKGROUND.equals(property))) {
516 // initializeLineNumberRulerColumn(fLineNumberRulerColumn);
520 // super.handlePreferenceStoreChanged(event);
524 private boolean isJavaEditorHoverProperty(String property) {
525 return PreferenceConstants.EDITOR_DEFAULT_HOVER.equals(property)
526 || PreferenceConstants.EDITOR_NONE_HOVER.equals(property)
527 || PreferenceConstants.EDITOR_CTRL_HOVER.equals(property)
528 || PreferenceConstants.EDITOR_SHIFT_HOVER.equals(property)
529 || PreferenceConstants.EDITOR_CTRL_ALT_HOVER.equals(property)
530 || PreferenceConstants.EDITOR_CTRL_SHIFT_HOVER.equals(property)
531 || PreferenceConstants.EDITOR_CTRL_ALT_SHIFT_HOVER.equals(property)
532 || PreferenceConstants.EDITOR_ALT_SHIFT_HOVER.equals(property);
536 * Shows the line number ruler column.
538 private void showLineNumberRuler() {
539 IVerticalRuler v = getVerticalRuler();
540 if (v instanceof CompositeRuler) {
541 CompositeRuler c = (CompositeRuler) v;
542 c.addDecorator(1, createLineNumberRulerColumn());
547 * Return whether the line number ruler column should be
548 * visible according to the preference store settings.
549 * @return <code>true</code> if the line numbers should be visible
551 private boolean isLineNumberRulerVisible() {
552 IPreferenceStore store = getPreferenceStore();
553 return store.getBoolean(LINE_NUMBER_RULER);
556 * Hides the line number ruler column.
558 private void hideLineNumberRuler() {
559 IVerticalRuler v = getVerticalRuler();
560 if (v instanceof CompositeRuler) {
561 CompositeRuler c = (CompositeRuler) v;
563 c.removeDecorator(1);
564 } catch (Throwable e) {
570 * Initializes the given line number ruler column from the preference store.
571 * @param rulerColumn the ruler column to be initialized
573 protected void initializeLineNumberRulerColumn(LineNumberRulerColumn rulerColumn) {
574 JavaTextTools textTools = PHPeclipsePlugin.getDefault().getJavaTextTools();
575 IColorManager manager = textTools.getColorManager();
577 IPreferenceStore store = getPreferenceStore();
582 if (store.contains(LINE_NUMBER_COLOR)) {
583 if (store.isDefault(LINE_NUMBER_COLOR))
584 rgb = PreferenceConverter.getDefaultColor(store, LINE_NUMBER_COLOR);
586 rgb = PreferenceConverter.getColor(store, LINE_NUMBER_COLOR);
588 rulerColumn.setForeground(manager.getColor(rgb));
592 if (!store.getBoolean(PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT)) {
593 if (store.contains(PREFERENCE_COLOR_BACKGROUND)) {
594 if (store.isDefault(PREFERENCE_COLOR_BACKGROUND))
595 rgb = PreferenceConverter.getDefaultColor(store, PREFERENCE_COLOR_BACKGROUND);
597 rgb = PreferenceConverter.getColor(store, PREFERENCE_COLOR_BACKGROUND);
600 rulerColumn.setBackground(manager.getColor(rgb));
605 * Creates a new line number ruler column that is appropriately initialized.
607 protected IVerticalRulerColumn createLineNumberRulerColumn() {
608 fLineNumberRulerColumn = new LineNumberRulerColumn();
609 initializeLineNumberRulerColumn(fLineNumberRulerColumn);
610 return fLineNumberRulerColumn;
614 * @see AbstractTextEditor#createVerticalRuler()
616 protected IVerticalRuler createVerticalRuler() {
617 CompositeRuler ruler = new CompositeRuler();
618 ruler.addDecorator(0, new AnnotationRulerColumn(VERTICAL_RULER_WIDTH));
619 if (isLineNumberRulerVisible())
620 ruler.addDecorator(1, createLineNumberRulerColumn());
625 * Method declared on TextEditor
627 protected void initializeEditor() {
628 IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
629 // PHPEditorEnvironment.connect(this);
631 // store.addPropertyChangeListener(new IPropertyChangeListener() {
632 // public void propertyChange(PropertyChangeEvent event) {
633 // PHPCodeScanner scanner = PHPEditorEnvironment.getPHPCodeScanner();
634 // if (scanner != null) {
635 // scanner.updateToken(PHPEditorEnvironment.getPHPColorProvider());
637 // if (getSourceViewer() != null) {
638 // getSourceViewer().invalidateTextPresentation();
641 // String property = event.getProperty();
642 // if (IPreferenceConstants.LINE_NUMBER_RULER.equals(property)) {
643 // if (isLineNumberRulerVisible())
644 // showLineNumberRuler();
646 // hideLineNumberRuler();
653 private static IRegion getSignedSelection(ITextViewer viewer) {
655 StyledText text = viewer.getTextWidget();
656 int caretOffset = text.getCaretOffset();
657 Point selection = text.getSelection();
661 if (caretOffset == selection.x) {
662 offset = selection.y;
663 length = selection.x - selection.y;
667 offset = selection.x;
668 length = selection.y - selection.x;
671 return new Region(offset, length);
674 private final static char[] BRACKETS = { '{', '}', '(', ')', '[', ']' };
676 private static boolean isBracket(char character) {
677 for (int i = 0; i != BRACKETS.length; ++i)
678 if (character == BRACKETS[i])
683 private static boolean isSurroundedByBrackets(IDocument document, int offset) {
684 if (offset == 0 || offset == document.getLength())
688 return isBracket(document.getChar(offset - 1)) && isBracket(document.getChar(offset));
690 } catch (BadLocationException e) {
695 * Jumps to the matching bracket.
697 public void gotoMatchingBracket() {
699 if (fBracketMatcher == null)
700 fBracketMatcher = new PHPPairMatcher(BRACKETS);
702 ISourceViewer sourceViewer = getSourceViewer();
703 IDocument document = sourceViewer.getDocument();
704 if (document == null)
707 IRegion selection = getSignedSelection(sourceViewer);
709 int selectionLength = Math.abs(selection.getLength());
710 if (selectionLength > 1) {
711 setStatusLineErrorMessage(PHPEditorMessages.getString("GotoMatchingBracket.error.invalidSelection")); //$NON-NLS-1$
712 sourceViewer.getTextWidget().getDisplay().beep();
717 int sourceCaretOffset = selection.getOffset() + selection.getLength();
718 if (isSurroundedByBrackets(document, sourceCaretOffset))
719 sourceCaretOffset -= selection.getLength();
721 IRegion region = fBracketMatcher.match(document, sourceCaretOffset);
722 if (region == null) {
723 setStatusLineErrorMessage(PHPEditorMessages.getString("GotoMatchingBracket.error.noMatchingBracket")); //$NON-NLS-1$
724 sourceViewer.getTextWidget().getDisplay().beep();
728 int offset = region.getOffset();
729 int length = region.getLength();
734 int anchor = fBracketMatcher.getAnchor();
735 int targetOffset = (PHPPairMatcher.RIGHT == anchor) ? offset : offset + length - 1;
737 boolean visible = false;
738 if (sourceViewer instanceof ITextViewerExtension3) {
739 ITextViewerExtension3 extension = (ITextViewerExtension3) sourceViewer;
740 visible = (extension.modelOffset2WidgetOffset(targetOffset) > -1);
742 IRegion visibleRegion = sourceViewer.getVisibleRegion();
743 visible = (targetOffset >= visibleRegion.getOffset() && targetOffset < visibleRegion.getOffset() + visibleRegion.getLength());
747 setStatusLineErrorMessage(PHPEditorMessages.getString("GotoMatchingBracket.error.bracketOutsideSelectedElement")); //$NON-NLS-1$
748 sourceViewer.getTextWidget().getDisplay().beep();
752 if (selection.getLength() < 0)
753 targetOffset -= selection.getLength();
755 sourceViewer.setSelectedRange(targetOffset, selection.getLength());
756 sourceViewer.revealRange(targetOffset, selection.getLength());
759 * Ses the given message as error message to this editor's status line.
760 * @param msg message to be set
762 protected void setStatusLineErrorMessage(String msg) {
763 IEditorStatusLine statusLine = (IEditorStatusLine) getAdapter(IEditorStatusLine.class);
764 if (statusLine != null)
765 statusLine.setMessage(true, msg, null);
769 * Returns a segmentation of the line of the given document appropriate for bidi rendering.
770 * The default implementation returns only the string literals of a php code line as segments.
772 * @param document the document
773 * @param lineOffset the offset of the line
774 * @return the line's bidi segmentation
775 * @throws BadLocationException in case lineOffset is not valid in document
777 public static int[] getBidiLineSegments(IDocument document, int lineOffset) throws BadLocationException {
779 IRegion line = document.getLineInformationOfOffset(lineOffset);
780 ITypedRegion[] linePartitioning = document.computePartitioning(lineOffset, line.getLength());
782 List segmentation = new ArrayList();
783 for (int i = 0; i < linePartitioning.length; i++) {
784 if (IPHPPartitionScannerConstants.PHP_STRING.equals(linePartitioning[i].getType()))
785 segmentation.add(linePartitioning[i]);
788 if (segmentation.size() == 0)
791 int size = segmentation.size();
792 int[] segments = new int[size * 2 + 1];
795 for (int i = 0; i < size; i++) {
796 ITypedRegion segment = (ITypedRegion) segmentation.get(i);
801 int offset = segment.getOffset() - lineOffset;
802 if (offset > segments[j - 1])
803 segments[j++] = offset;
805 if (offset + segment.getLength() >= line.getLength())
808 segments[j++] = offset + segment.getLength();
811 if (j < segments.length) {
812 int[] result = new int[j];
813 System.arraycopy(segments, 0, result, 0, j);
820 * Returns a segmentation of the given line appropriate for bidi rendering. The default
821 * implementation returns only the string literals of a php code line as segments.
823 * @param lineOffset the offset of the line
824 * @param line the content of the line
825 * @return the line's bidi segmentation
827 protected int[] getBidiLineSegments(int lineOffset, String line) {
828 IDocumentProvider provider = getDocumentProvider();
829 if (provider != null && line != null && line.length() > 0) {
830 IDocument document = provider.getDocument(getEditorInput());
831 if (document != null)
833 return getBidiLineSegments(document, lineOffset);
834 } catch (BadLocationException x) {
842 * @see AbstractTextEditor#createSourceViewer(Composite, IVerticalRuler, int)
844 protected final ISourceViewer createSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
845 ISourceViewer viewer = createJavaSourceViewer(parent, ruler, styles);
846 StyledText text = viewer.getTextWidget();
847 text.addBidiSegmentListener(new BidiSegmentListener() {
848 public void lineGetSegments(BidiSegmentEvent event) {
849 event.segments = getBidiLineSegments(event.lineOffset, event.lineText);
852 // JavaUIHelp.setHelp(this, text, IJavaHelpContextIds.JAVA_EDITOR);
857 * @see AbstractTextEditor#createSourceViewer(Composite, IVerticalRuler, int)
859 protected ISourceViewer createJavaSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
860 return super.createSourceViewer(parent, ruler, styles);
864 * @see AbstractTextEditor#affectsTextPresentation(PropertyChangeEvent)
866 protected boolean affectsTextPresentation(PropertyChangeEvent event) {
867 JavaTextTools textTools = PHPeclipsePlugin.getDefault().getJavaTextTools();
868 return textTools.affectsBehavior(event);