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.IViewPart;
69 import org.eclipse.ui.IWorkbenchPage;
70 import org.eclipse.ui.PartInitException;
71 import org.eclipse.ui.actions.ActionContext;
72 import org.eclipse.ui.actions.ActionGroup;
73 import org.eclipse.ui.texteditor.ContentAssistAction;
74 import org.eclipse.ui.texteditor.DefaultRangeIndicator;
75 import org.eclipse.ui.texteditor.IDocumentProvider;
76 import org.eclipse.ui.texteditor.IEditorStatusLine;
77 import org.eclipse.ui.texteditor.ITextEditorActionConstants;
78 import org.eclipse.ui.texteditor.StatusTextEditor;
79 import org.eclipse.ui.texteditor.TextOperationAction;
80 import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
82 * PHP specific text editor.
84 public class PHPEditor extends StatusTextEditor implements IViewPartInputProvider { // extends TextEditor {
86 /** Preference key for showing the line number ruler */
87 private final static String LINE_NUMBER_RULER = PreferenceConstants.EDITOR_LINE_NUMBER_RULER;
88 /** Preference key for the foreground color of the line numbers */
89 private final static String LINE_NUMBER_COLOR = PreferenceConstants.EDITOR_LINE_NUMBER_RULER_COLOR;
90 /** Preference key for the link color */
91 private final static String LINK_COLOR = PreferenceConstants.EDITOR_LINK_COLOR;
93 // protected PHPActionGroup fActionGroups;
94 /** The outline page */
95 private PHPContentOutlinePage fOutlinePage;
97 // protected PHPSyntaxParserThread fValidationThread = null;
99 // private IPreferenceStore fPHPPrefStore;
101 /** The editor's bracket matcher */
102 private PHPPairMatcher fBracketMatcher;
103 /** The line number ruler column */
104 private LineNumberRulerColumn fLineNumberRulerColumn;
106 protected CompositeActionGroup fActionGroups;
107 /** The standard action groups added to the menu */
108 private GenerateActionGroup fGenerateActionGroup;
109 private CompositeActionGroup fContextMenuGroup;
111 /** The information presenter. */
112 private InformationPresenter fInformationPresenter;
115 * Default constructor.
119 JavaTextTools textTools = PHPeclipsePlugin.getDefault().getJavaTextTools();
120 setSourceViewerConfiguration(new PHPSourceViewerConfiguration(textTools, this));
121 setRangeIndicator(new DefaultRangeIndicator());
122 setPreferenceStore(PHPeclipsePlugin.getDefault().getPreferenceStore());
124 // if (PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_SYNC_OUTLINE_ON_CURSOR_MOVE))
125 // fUpdater= new OutlinePageSelectionUpdater();
131 // * @see IMember#getCompilationUnit()
133 // public ICompilationUnit getCompilationUnit() {
137 // * @see org.phpeclipse.phpdt.internal.compiler.env.ICompilationUnit#getContents()
139 // public char[] getContents() {
140 // IDocument doc = this.getDocumentProvider().getDocument(this.getEditorInput());
142 // return doc.get().toCharArray();
146 * Update the hovering behavior depending on the preferences.
148 private void updateHoverBehavior() {
149 SourceViewerConfiguration configuration = getSourceViewerConfiguration();
150 String[] types = configuration.getConfiguredContentTypes(getSourceViewer());
152 for (int i = 0; i < types.length; i++) {
156 int[] stateMasks = configuration.getConfiguredTextHoverStateMasks(getSourceViewer(), t);
158 ISourceViewer sourceViewer = getSourceViewer();
159 if (sourceViewer instanceof ITextViewerExtension2) {
160 if (stateMasks != null) {
161 for (int j = 0; j < stateMasks.length; j++) {
162 int stateMask = stateMasks[j];
163 ITextHover textHover = configuration.getTextHover(sourceViewer, t, stateMask);
164 ((ITextViewerExtension2) sourceViewer).setTextHover(textHover, t, stateMask);
167 ITextHover textHover = configuration.getTextHover(sourceViewer, t);
168 ((ITextViewerExtension2) sourceViewer).setTextHover(textHover, t, ITextViewerExtension2.DEFAULT_HOVER_STATE_MASK);
171 sourceViewer.setTextHover(configuration.getTextHover(sourceViewer, t), t);
176 * @see net.sourceforge.phpdt.internal.ui.viewsupport.IViewPartInputProvider#getViewPartInput()
178 public Object getViewPartInput() {
179 return getEditorInput().getAdapter(IResource.class);
183 * @see org.eclipse.ui.IWorkbenchPart#createPartControl(org.eclipse.swt.
186 public void createPartControl(Composite parent) {
187 super.createPartControl(parent);
189 IInformationControlCreator informationControlCreator = new IInformationControlCreator() {
190 public IInformationControl createInformationControl(Shell parent) {
191 boolean cutDown = false;
192 int style = cutDown ? SWT.NONE : (SWT.V_SCROLL | SWT.H_SCROLL);
193 return new DefaultInformationControl(parent, SWT.RESIZE, style, new HTMLTextPresenter(cutDown));
197 fInformationPresenter = new InformationPresenter(informationControlCreator);
198 fInformationPresenter.setSizeConstraints(60, 10, true, true);
199 fInformationPresenter.install(getSourceViewer());
203 * Returns this document's complete text.
205 * @return the document's complete text
207 public String get() {
208 IDocument doc = this.getDocumentProvider().getDocument(this.getEditorInput());
213 * Returns the standard action group of this editor.
215 protected ActionGroup getActionGroup() {
216 return fActionGroups;
219 public PHPContentOutlinePage getfOutlinePage() {
223 /** The <code>PHPEditor</code> implementation of this
224 * <code>AbstractTextEditor</code> method extend the
225 * actions to add those specific to the receiver
227 protected void createActions() {
228 super.createActions();
232 // "ContentAssistProposal",
233 // new TextOperationAction(
234 // PHPEditorMessages.getResourceBundle(),
235 // "ContentAssistProposal.",
237 // ISourceViewer.CONTENTASSIST_PROPOSALS));
238 action = new ContentAssistAction(PHPEditorMessages.getResourceBundle(), "ContentAssistProposal.", this); //$NON-NLS-1$
239 action.setActionDefinitionId(PHPEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS);
240 setAction("ContentAssistProposal", action); //$NON-NLS-1$
244 new TextOperationAction(
245 PHPEditorMessages.getResourceBundle(),
248 ISourceViewer.CONTENTASSIST_CONTEXT_INFORMATION));
250 action = new TextOperationAction(PHPEditorMessages.getResourceBundle(), "Comment.", this, ITextOperationTarget.PREFIX);
251 action.setActionDefinitionId(PHPEditorActionDefinitionIds.COMMENT);
252 setAction("Comment", action);
254 action = new TextOperationAction(PHPEditorMessages.getResourceBundle(), "Uncomment.", this, ITextOperationTarget.STRIP_PREFIX);
255 action.setActionDefinitionId(PHPEditorActionDefinitionIds.UNCOMMENT);
256 setAction("Uncomment", action);
258 action = new TextOperationAction(PHPEditorMessages.getResourceBundle(), "Format.", this, ISourceViewer.FORMAT); //$NON-NLS-1$
259 action.setActionDefinitionId(PHPEditorActionDefinitionIds.FORMAT);
260 setAction("Format", action); //$NON-NLS-1$
262 markAsStateDependentAction("ContentAssistProposal", true); //$NON-NLS-1$
263 markAsStateDependentAction("Comment", true); //$NON-NLS-1$
264 markAsStateDependentAction("Uncomment", true); //$NON-NLS-1$
265 markAsStateDependentAction("Format", true); //$NON-NLS-1$
267 action = new GotoMatchingBracketAction(this);
268 action.setActionDefinitionId(PHPEditorActionDefinitionIds.GOTO_MATCHING_BRACKET);
269 setAction(GotoMatchingBracketAction.GOTO_MATCHING_BRACKET, action);
271 fGenerateActionGroup = new GenerateActionGroup(this, ITextEditorActionConstants.GROUP_EDIT);
273 fActionGroups = new CompositeActionGroup(new ActionGroup[] { fGenerateActionGroup });
275 // We have to keep the context menu group separate to have better control over positioning
276 fContextMenuGroup = new CompositeActionGroup(new ActionGroup[] { fGenerateActionGroup });
278 // new LocalHistoryActionGroup(this, ITextEditorActionConstants.GROUP_EDIT)});
280 // if (fValidationThread == null) {
281 // fValidationThread =
282 // new PHPSyntaxParserThread(this, getSourceViewer());
285 // fValidationThread.start();
288 // fValidationThread.setText(getSourceViewer().getTextWidget().getText());
291 /** The <code>PHPEditor</code> implementation of this
292 * <code>AbstractTextEditor</code> method performs any extra
293 * disposal actions required by the php editor.
295 public void dispose() {
296 // PHPEditorEnvironment.disconnect(this);
297 if (fOutlinePage != null)
298 fOutlinePage.setInput(null);
300 if (fActionGroups != null)
301 fActionGroups.dispose();
306 /** The <code>PHPEditor</code> implementation of this
307 * <code>AbstractTextEditor</code> method performs any extra
308 * revert behavior required by the php editor.
310 public void doRevertToSaved() {
311 super.doRevertToSaved();
312 if (fOutlinePage != null)
313 fOutlinePage.update();
316 /** The <code>PHPEditor</code> implementation of this
317 * <code>AbstractTextEditor</code> method performs any extra
318 * save behavior required by the php editor.
320 public void doSave(IProgressMonitor monitor) {
321 super.doSave(monitor);
322 // compile or not, according to the user preferences
323 IPreferenceStore store = getPreferenceStore(); // fPHPPrefStore;
324 if (store.getBoolean(PHPeclipsePlugin.PHP_PARSE_ON_SAVE)) {
325 IAction a = PHPParserAction.getInstance();
329 // if (SWT.getPlatform().equals("win32")) {
330 // IAction a = ShowExternalPreviewAction.getInstance();
334 if (fOutlinePage != null)
335 fOutlinePage.update();
338 /** The <code>PHPEditor</code> implementation of this
339 * <code>AbstractTextEditor</code> method performs any extra
340 * save as behavior required by the php editor.
342 public void doSaveAs() {
344 if (fOutlinePage != null)
345 fOutlinePage.update();
348 /** The <code>PHPEditor</code> implementation of this
349 * <code>AbstractTextEditor</code> method performs sets the
350 * input of the outline page after AbstractTextEditor has set input.
352 protected void doSetInput(IEditorInput input) throws CoreException {
353 super.doSetInput(input);
354 if (fOutlinePage != null)
355 fOutlinePage.setInput(input);
359 * @see org.phpeclipse.phpdt.internal.ui.viewsupport.IViewPartInputProvider#getViewPartInput()
361 // public Object getViewPartInput() {
362 // return getEditorInput().getAdapter(IFile.class);
365 /** The <code>PHPEditor</code> implementation of this
366 * <code>AbstractTextEditor</code> method adds any
367 * PHPEditor specific entries.
369 public void editorContextMenuAboutToShow(MenuManager menu) {
370 super.editorContextMenuAboutToShow(menu);
372 addAction(menu, ITextEditorActionConstants.GROUP_EDIT, "Format"); //$NON-NLS-1$
374 ActionContext context = new ActionContext(getSelectionProvider().getSelection());
375 fContextMenuGroup.setContext(context);
376 fContextMenuGroup.fillContextMenu(menu);
377 fContextMenuGroup.setContext(null);
380 protected void updateStateDependentActions() {
381 super.updateStateDependentActions();
382 fGenerateActionGroup.editorStateChanged();
385 /** The <code>PHPEditor</code> implementation of this
386 * <code>AbstractTextEditor</code> method performs gets
387 * the java content outline page if request is for a an
390 public Object getAdapter(Class required) {
391 if (IContentOutlinePage.class.equals(required)) {
392 if (fOutlinePage == null) {
393 fOutlinePage = new PHPContentOutlinePage(getDocumentProvider(), this);
394 if (getEditorInput() != null)
395 fOutlinePage.setInput(getEditorInput());
399 return super.getAdapter(required);
402 // public void openContextHelp() {
403 // IDocument doc = this.getDocumentProvider().getDocument(this.getEditorInput());
404 // ITextSelection selection = (ITextSelection) this.getSelectionProvider().getSelection();
405 // int pos = selection.getOffset();
406 // String word = getFunctionName(doc, pos);
407 // openContextHelp(word);
410 // private void openContextHelp(String word) {
414 // public static void open(String word) {
415 // IHelp help = WorkbenchHelp.getHelpSupport();
416 // if (help != null) {
417 // IHelpResource helpResource = new PHPFunctionHelpResource(word);
418 // WorkbenchHelp.getHelpSupport().displayHelpResource(helpResource);
420 // // showMessage(shell, dialogTitle, ActionMessages.getString("Open help not available"), false); //$NON-NLS-1$
424 // private String getFunctionName(IDocument doc, int pos) {
425 // Point word = PHPWordExtractor.findWord(doc, pos);
426 // if (word != null) {
428 // return doc.get(word.x, word.y).replace('_', '-');
429 // } catch (BadLocationException e) {
436 * @see AbstractTextEditor#handlePreferenceStoreChanged(PropertyChangeEvent)
438 protected void handlePreferenceStoreChanged(PropertyChangeEvent event) {
442 ISourceViewer sourceViewer = getSourceViewer();
443 if (sourceViewer == null)
446 String property = event.getProperty();
448 if (PreferenceConstants.EDITOR_TAB_WIDTH.equals(property)) {
449 Object value = event.getNewValue();
450 if (value instanceof Integer) {
451 sourceViewer.getTextWidget().setTabs(((Integer) value).intValue());
452 } else if (value instanceof String) {
453 sourceViewer.getTextWidget().setTabs(Integer.parseInt((String) value));
458 if (LINE_NUMBER_RULER.equals(property)) {
459 if (isLineNumberRulerVisible())
460 showLineNumberRuler();
462 hideLineNumberRuler();
466 if (fLineNumberRulerColumn != null
467 && (LINE_NUMBER_COLOR.equals(property)
468 || PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT.equals(property)
469 || PREFERENCE_COLOR_BACKGROUND.equals(property))) {
471 initializeLineNumberRulerColumn(fLineNumberRulerColumn);
474 if (isJavaEditorHoverProperty(property)) {
475 updateHoverBehavior();
479 super.handlePreferenceStoreChanged(event);
484 // * @see AbstractTextEditor#handlePreferenceStoreChanged(PropertyChangeEvent)
486 // protected void handlePreferenceStoreChanged(PropertyChangeEvent event) {
490 // ISourceViewer sourceViewer = getSourceViewer();
491 // if (sourceViewer == null)
494 // String property = event.getProperty();
496 // // if (JavaSourceViewerConfiguration.PREFERENCE_TAB_WIDTH.equals(property)) {
497 // // Object value= event.getNewValue();
498 // // if (value instanceof Integer) {
499 // // sourceViewer.getTextWidget().setTabs(((Integer) value).intValue());
500 // // } else if (value instanceof String) {
501 // // sourceViewer.getTextWidget().setTabs(Integer.parseInt((String) value));
506 // if (IPreferenceConstants.LINE_NUMBER_RULER.equals(property)) {
507 // if (isLineNumberRulerVisible())
508 // showLineNumberRuler();
510 // hideLineNumberRuler();
514 // if (fLineNumberRulerColumn != null
515 // && (IPreferenceConstants.LINE_NUMBER_COLOR.equals(property)
516 // || PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT.equals(property)
517 // || PREFERENCE_COLOR_BACKGROUND.equals(property))) {
519 // initializeLineNumberRulerColumn(fLineNumberRulerColumn);
523 // super.handlePreferenceStoreChanged(event);
527 private boolean isJavaEditorHoverProperty(String property) {
528 return PreferenceConstants.EDITOR_DEFAULT_HOVER.equals(property)
529 || PreferenceConstants.EDITOR_NONE_HOVER.equals(property)
530 || PreferenceConstants.EDITOR_CTRL_HOVER.equals(property)
531 || PreferenceConstants.EDITOR_SHIFT_HOVER.equals(property)
532 || PreferenceConstants.EDITOR_CTRL_ALT_HOVER.equals(property)
533 || PreferenceConstants.EDITOR_CTRL_SHIFT_HOVER.equals(property)
534 || PreferenceConstants.EDITOR_CTRL_ALT_SHIFT_HOVER.equals(property)
535 || PreferenceConstants.EDITOR_ALT_SHIFT_HOVER.equals(property);
539 * Shows the line number ruler column.
541 private void showLineNumberRuler() {
542 IVerticalRuler v = getVerticalRuler();
543 if (v instanceof CompositeRuler) {
544 CompositeRuler c = (CompositeRuler) v;
545 c.addDecorator(1, createLineNumberRulerColumn());
550 * Return whether the line number ruler column should be
551 * visible according to the preference store settings.
552 * @return <code>true</code> if the line numbers should be visible
554 private boolean isLineNumberRulerVisible() {
555 IPreferenceStore store = getPreferenceStore();
556 return store.getBoolean(LINE_NUMBER_RULER);
559 * Hides the line number ruler column.
561 private void hideLineNumberRuler() {
562 IVerticalRuler v = getVerticalRuler();
563 if (v instanceof CompositeRuler) {
564 CompositeRuler c = (CompositeRuler) v;
566 c.removeDecorator(1);
567 } catch (Throwable e) {
573 * Initializes the given line number ruler column from the preference store.
574 * @param rulerColumn the ruler column to be initialized
576 protected void initializeLineNumberRulerColumn(LineNumberRulerColumn rulerColumn) {
577 JavaTextTools textTools = PHPeclipsePlugin.getDefault().getJavaTextTools();
578 IColorManager manager = textTools.getColorManager();
580 IPreferenceStore store = getPreferenceStore();
585 if (store.contains(LINE_NUMBER_COLOR)) {
586 if (store.isDefault(LINE_NUMBER_COLOR))
587 rgb = PreferenceConverter.getDefaultColor(store, LINE_NUMBER_COLOR);
589 rgb = PreferenceConverter.getColor(store, LINE_NUMBER_COLOR);
591 rulerColumn.setForeground(manager.getColor(rgb));
595 if (!store.getBoolean(PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT)) {
596 if (store.contains(PREFERENCE_COLOR_BACKGROUND)) {
597 if (store.isDefault(PREFERENCE_COLOR_BACKGROUND))
598 rgb = PreferenceConverter.getDefaultColor(store, PREFERENCE_COLOR_BACKGROUND);
600 rgb = PreferenceConverter.getColor(store, PREFERENCE_COLOR_BACKGROUND);
603 rulerColumn.setBackground(manager.getColor(rgb));
608 * Creates a new line number ruler column that is appropriately initialized.
610 protected IVerticalRulerColumn createLineNumberRulerColumn() {
611 fLineNumberRulerColumn = new LineNumberRulerColumn();
612 initializeLineNumberRulerColumn(fLineNumberRulerColumn);
613 return fLineNumberRulerColumn;
617 * @see AbstractTextEditor#createVerticalRuler()
619 protected IVerticalRuler createVerticalRuler() {
620 CompositeRuler ruler = new CompositeRuler();
621 ruler.addDecorator(0, new AnnotationRulerColumn(VERTICAL_RULER_WIDTH));
622 if (isLineNumberRulerVisible())
623 ruler.addDecorator(1, createLineNumberRulerColumn());
628 * Method declared on TextEditor
630 protected void initializeEditor() {
631 IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
632 // PHPEditorEnvironment.connect(this);
634 // store.addPropertyChangeListener(new IPropertyChangeListener() {
635 // public void propertyChange(PropertyChangeEvent event) {
636 // PHPCodeScanner scanner = PHPEditorEnvironment.getPHPCodeScanner();
637 // if (scanner != null) {
638 // scanner.updateToken(PHPEditorEnvironment.getPHPColorProvider());
640 // if (getSourceViewer() != null) {
641 // getSourceViewer().invalidateTextPresentation();
644 // String property = event.getProperty();
645 // if (IPreferenceConstants.LINE_NUMBER_RULER.equals(property)) {
646 // if (isLineNumberRulerVisible())
647 // showLineNumberRuler();
649 // hideLineNumberRuler();
656 private static IRegion getSignedSelection(ITextViewer viewer) {
658 StyledText text = viewer.getTextWidget();
659 int caretOffset = text.getCaretOffset();
660 Point selection = text.getSelection();
664 if (caretOffset == selection.x) {
665 offset = selection.y;
666 length = selection.x - selection.y;
670 offset = selection.x;
671 length = selection.y - selection.x;
674 return new Region(offset, length);
677 private final static char[] BRACKETS = { '{', '}', '(', ')', '[', ']' };
679 private static boolean isBracket(char character) {
680 for (int i = 0; i != BRACKETS.length; ++i)
681 if (character == BRACKETS[i])
686 private static boolean isSurroundedByBrackets(IDocument document, int offset) {
687 if (offset == 0 || offset == document.getLength())
691 return isBracket(document.getChar(offset - 1)) && isBracket(document.getChar(offset));
693 } catch (BadLocationException e) {
698 * Jumps to the matching bracket.
700 public void gotoMatchingBracket() {
702 if (fBracketMatcher == null)
703 fBracketMatcher = new PHPPairMatcher(BRACKETS);
705 ISourceViewer sourceViewer = getSourceViewer();
706 IDocument document = sourceViewer.getDocument();
707 if (document == null)
710 IRegion selection = getSignedSelection(sourceViewer);
712 int selectionLength = Math.abs(selection.getLength());
713 if (selectionLength > 1) {
714 setStatusLineErrorMessage(PHPEditorMessages.getString("GotoMatchingBracket.error.invalidSelection")); //$NON-NLS-1$
715 sourceViewer.getTextWidget().getDisplay().beep();
720 int sourceCaretOffset = selection.getOffset() + selection.getLength();
721 if (isSurroundedByBrackets(document, sourceCaretOffset))
722 sourceCaretOffset -= selection.getLength();
724 IRegion region = fBracketMatcher.match(document, sourceCaretOffset);
725 if (region == null) {
726 setStatusLineErrorMessage(PHPEditorMessages.getString("GotoMatchingBracket.error.noMatchingBracket")); //$NON-NLS-1$
727 sourceViewer.getTextWidget().getDisplay().beep();
731 int offset = region.getOffset();
732 int length = region.getLength();
737 int anchor = fBracketMatcher.getAnchor();
738 int targetOffset = (PHPPairMatcher.RIGHT == anchor) ? offset : offset + length - 1;
740 boolean visible = false;
741 if (sourceViewer instanceof ITextViewerExtension3) {
742 ITextViewerExtension3 extension = (ITextViewerExtension3) sourceViewer;
743 visible = (extension.modelOffset2WidgetOffset(targetOffset) > -1);
745 IRegion visibleRegion = sourceViewer.getVisibleRegion();
746 visible = (targetOffset >= visibleRegion.getOffset() && targetOffset < visibleRegion.getOffset() + visibleRegion.getLength());
750 setStatusLineErrorMessage(PHPEditorMessages.getString("GotoMatchingBracket.error.bracketOutsideSelectedElement")); //$NON-NLS-1$
751 sourceViewer.getTextWidget().getDisplay().beep();
755 if (selection.getLength() < 0)
756 targetOffset -= selection.getLength();
758 sourceViewer.setSelectedRange(targetOffset, selection.getLength());
759 sourceViewer.revealRange(targetOffset, selection.getLength());
762 * Ses the given message as error message to this editor's status line.
763 * @param msg message to be set
765 protected void setStatusLineErrorMessage(String msg) {
766 IEditorStatusLine statusLine = (IEditorStatusLine) getAdapter(IEditorStatusLine.class);
767 if (statusLine != null)
768 statusLine.setMessage(true, msg, null);
772 * Returns a segmentation of the line of the given document appropriate for bidi rendering.
773 * The default implementation returns only the string literals of a php code line as segments.
775 * @param document the document
776 * @param lineOffset the offset of the line
777 * @return the line's bidi segmentation
778 * @throws BadLocationException in case lineOffset is not valid in document
780 public static int[] getBidiLineSegments(IDocument document, int lineOffset) throws BadLocationException {
782 IRegion line = document.getLineInformationOfOffset(lineOffset);
783 ITypedRegion[] linePartitioning = document.computePartitioning(lineOffset, line.getLength());
785 List segmentation = new ArrayList();
786 for (int i = 0; i < linePartitioning.length; i++) {
787 if (IPHPPartitionScannerConstants.PHP_STRING.equals(linePartitioning[i].getType()))
788 segmentation.add(linePartitioning[i]);
791 if (segmentation.size() == 0)
794 int size = segmentation.size();
795 int[] segments = new int[size * 2 + 1];
798 for (int i = 0; i < size; i++) {
799 ITypedRegion segment = (ITypedRegion) segmentation.get(i);
804 int offset = segment.getOffset() - lineOffset;
805 if (offset > segments[j - 1])
806 segments[j++] = offset;
808 if (offset + segment.getLength() >= line.getLength())
811 segments[j++] = offset + segment.getLength();
814 if (j < segments.length) {
815 int[] result = new int[j];
816 System.arraycopy(segments, 0, result, 0, j);
823 * Returns a segmentation of the given line appropriate for bidi rendering. The default
824 * implementation returns only the string literals of a php code line as segments.
826 * @param lineOffset the offset of the line
827 * @param line the content of the line
828 * @return the line's bidi segmentation
830 protected int[] getBidiLineSegments(int lineOffset, String line) {
831 IDocumentProvider provider = getDocumentProvider();
832 if (provider != null && line != null && line.length() > 0) {
833 IDocument document = provider.getDocument(getEditorInput());
834 if (document != null)
836 return getBidiLineSegments(document, lineOffset);
837 } catch (BadLocationException x) {
845 * @see AbstractTextEditor#createSourceViewer(Composite, IVerticalRuler, int)
847 protected final ISourceViewer createSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
848 ISourceViewer viewer = createJavaSourceViewer(parent, ruler, styles);
849 StyledText text = viewer.getTextWidget();
850 text.addBidiSegmentListener(new BidiSegmentListener() {
851 public void lineGetSegments(BidiSegmentEvent event) {
852 event.segments = getBidiLineSegments(event.lineOffset, event.lineText);
855 // JavaUIHelp.setHelp(this, text, IJavaHelpContextIds.JAVA_EDITOR);
860 * @see AbstractTextEditor#createSourceViewer(Composite, IVerticalRuler, int)
862 protected ISourceViewer createJavaSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
863 return super.createSourceViewer(parent, ruler, styles);
867 * @see AbstractTextEditor#affectsTextPresentation(PropertyChangeEvent)
869 protected boolean affectsTextPresentation(PropertyChangeEvent event) {
870 JavaTextTools textTools = PHPeclipsePlugin.getDefault().getJavaTextTools();
871 return textTools.affectsBehavior(event);