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;
81 import org.eclipse.update.internal.ui.UpdatePerspective;
82 import org.eclipse.update.internal.ui.UpdateUIPlugin;
83 import org.eclipse.update.internal.ui.views.IEmbeddedWebBrowser;
85 * PHP specific text editor.
87 public class PHPEditor extends StatusTextEditor implements IViewPartInputProvider { // extends TextEditor {
89 /** Preference key for showing the line number ruler */
90 private final static String LINE_NUMBER_RULER = PreferenceConstants.EDITOR_LINE_NUMBER_RULER;
91 /** Preference key for the foreground color of the line numbers */
92 private final static String LINE_NUMBER_COLOR = PreferenceConstants.EDITOR_LINE_NUMBER_RULER_COLOR;
93 /** Preference key for the link color */
94 private final static String LINK_COLOR = PreferenceConstants.EDITOR_LINK_COLOR;
96 // protected PHPActionGroup fActionGroups;
97 /** The outline page */
98 private PHPContentOutlinePage fOutlinePage;
100 // protected PHPSyntaxParserThread fValidationThread = null;
102 // private IPreferenceStore fPHPPrefStore;
104 /** The editor's bracket matcher */
105 private PHPPairMatcher fBracketMatcher;
106 /** The line number ruler column */
107 private LineNumberRulerColumn fLineNumberRulerColumn;
109 protected CompositeActionGroup fActionGroups;
110 /** The standard action groups added to the menu */
111 private GenerateActionGroup fGenerateActionGroup;
112 private CompositeActionGroup fContextMenuGroup;
114 /** The information presenter. */
115 private InformationPresenter fInformationPresenter;
118 * Default constructor.
122 JavaTextTools textTools = PHPeclipsePlugin.getDefault().getJavaTextTools();
123 setSourceViewerConfiguration(new PHPSourceViewerConfiguration(textTools, this));
124 setRangeIndicator(new DefaultRangeIndicator());
125 setPreferenceStore(PHPeclipsePlugin.getDefault().getPreferenceStore());
127 // if (PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_SYNC_OUTLINE_ON_CURSOR_MOVE))
128 // fUpdater= new OutlinePageSelectionUpdater();
134 // * @see IMember#getCompilationUnit()
136 // public ICompilationUnit getCompilationUnit() {
140 // * @see org.phpeclipse.phpdt.internal.compiler.env.ICompilationUnit#getContents()
142 // public char[] getContents() {
143 // IDocument doc = this.getDocumentProvider().getDocument(this.getEditorInput());
145 // return doc.get().toCharArray();
149 * Update the hovering behavior depending on the preferences.
151 private void updateHoverBehavior() {
152 SourceViewerConfiguration configuration = getSourceViewerConfiguration();
153 String[] types = configuration.getConfiguredContentTypes(getSourceViewer());
155 for (int i = 0; i < types.length; i++) {
159 int[] stateMasks = configuration.getConfiguredTextHoverStateMasks(getSourceViewer(), t);
161 ISourceViewer sourceViewer = getSourceViewer();
162 if (sourceViewer instanceof ITextViewerExtension2) {
163 if (stateMasks != null) {
164 for (int j = 0; j < stateMasks.length; j++) {
165 int stateMask = stateMasks[j];
166 ITextHover textHover = configuration.getTextHover(sourceViewer, t, stateMask);
167 ((ITextViewerExtension2) sourceViewer).setTextHover(textHover, t, stateMask);
170 ITextHover textHover = configuration.getTextHover(sourceViewer, t);
171 ((ITextViewerExtension2) sourceViewer).setTextHover(textHover, t, ITextViewerExtension2.DEFAULT_HOVER_STATE_MASK);
174 sourceViewer.setTextHover(configuration.getTextHover(sourceViewer, t), t);
179 * @see net.sourceforge.phpdt.internal.ui.viewsupport.IViewPartInputProvider#getViewPartInput()
181 public Object getViewPartInput() {
182 return getEditorInput().getAdapter(IResource.class);
186 * @see org.eclipse.ui.IWorkbenchPart#createPartControl(org.eclipse.swt.
189 public void createPartControl(Composite parent) {
190 super.createPartControl(parent);
192 IInformationControlCreator informationControlCreator = new IInformationControlCreator() {
193 public IInformationControl createInformationControl(Shell parent) {
194 boolean cutDown = false;
195 int style = cutDown ? SWT.NONE : (SWT.V_SCROLL | SWT.H_SCROLL);
196 return new DefaultInformationControl(parent, SWT.RESIZE, style, new HTMLTextPresenter(cutDown));
200 fInformationPresenter = new InformationPresenter(informationControlCreator);
201 fInformationPresenter.setSizeConstraints(60, 10, true, true);
202 fInformationPresenter.install(getSourceViewer());
206 * Returns this document's complete text.
208 * @return the document's complete text
210 public String get() {
211 IDocument doc = this.getDocumentProvider().getDocument(this.getEditorInput());
216 * Returns the standard action group of this editor.
218 protected ActionGroup getActionGroup() {
219 return fActionGroups;
222 public PHPContentOutlinePage getfOutlinePage() {
226 /** The <code>PHPEditor</code> implementation of this
227 * <code>AbstractTextEditor</code> method extend the
228 * actions to add those specific to the receiver
230 protected void createActions() {
231 super.createActions();
235 // "ContentAssistProposal",
236 // new TextOperationAction(
237 // PHPEditorMessages.getResourceBundle(),
238 // "ContentAssistProposal.",
240 // ISourceViewer.CONTENTASSIST_PROPOSALS));
241 action = new ContentAssistAction(PHPEditorMessages.getResourceBundle(), "ContentAssistProposal.", this); //$NON-NLS-1$
242 action.setActionDefinitionId(PHPEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS);
243 setAction("ContentAssistProposal", action); //$NON-NLS-1$
247 new TextOperationAction(
248 PHPEditorMessages.getResourceBundle(),
251 ISourceViewer.CONTENTASSIST_CONTEXT_INFORMATION));
253 action = new TextOperationAction(PHPEditorMessages.getResourceBundle(), "Comment.", this, ITextOperationTarget.PREFIX);
254 action.setActionDefinitionId(PHPEditorActionDefinitionIds.COMMENT);
255 setAction("Comment", action);
257 action = new TextOperationAction(PHPEditorMessages.getResourceBundle(), "Uncomment.", this, ITextOperationTarget.STRIP_PREFIX);
258 action.setActionDefinitionId(PHPEditorActionDefinitionIds.UNCOMMENT);
259 setAction("Uncomment", action);
261 action = new TextOperationAction(PHPEditorMessages.getResourceBundle(), "Format.", this, ISourceViewer.FORMAT); //$NON-NLS-1$
262 action.setActionDefinitionId(PHPEditorActionDefinitionIds.FORMAT);
263 setAction("Format", action); //$NON-NLS-1$
265 markAsStateDependentAction("ContentAssistProposal", true); //$NON-NLS-1$
266 markAsStateDependentAction("Comment", true); //$NON-NLS-1$
267 markAsStateDependentAction("Uncomment", true); //$NON-NLS-1$
268 markAsStateDependentAction("Format", true); //$NON-NLS-1$
270 action = new GotoMatchingBracketAction(this);
271 action.setActionDefinitionId(PHPEditorActionDefinitionIds.GOTO_MATCHING_BRACKET);
272 setAction(GotoMatchingBracketAction.GOTO_MATCHING_BRACKET, action);
274 fGenerateActionGroup = new GenerateActionGroup(this, ITextEditorActionConstants.GROUP_EDIT);
276 fActionGroups = new CompositeActionGroup(new ActionGroup[] { fGenerateActionGroup });
278 // We have to keep the context menu group separate to have better control over positioning
279 fContextMenuGroup = new CompositeActionGroup(new ActionGroup[] { fGenerateActionGroup });
281 // new LocalHistoryActionGroup(this, ITextEditorActionConstants.GROUP_EDIT)});
283 // if (fValidationThread == null) {
284 // fValidationThread =
285 // new PHPSyntaxParserThread(this, getSourceViewer());
288 // fValidationThread.start();
291 // fValidationThread.setText(getSourceViewer().getTextWidget().getText());
294 /** The <code>PHPEditor</code> implementation of this
295 * <code>AbstractTextEditor</code> method performs any extra
296 * disposal actions required by the php editor.
298 public void dispose() {
299 // PHPEditorEnvironment.disconnect(this);
300 if (fOutlinePage != null)
301 fOutlinePage.setInput(null);
303 if (fActionGroups != null)
304 fActionGroups.dispose();
309 /** The <code>PHPEditor</code> implementation of this
310 * <code>AbstractTextEditor</code> method performs any extra
311 * revert behavior required by the php editor.
313 public void doRevertToSaved() {
314 super.doRevertToSaved();
315 if (fOutlinePage != null)
316 fOutlinePage.update();
319 /** The <code>PHPEditor</code> implementation of this
320 * <code>AbstractTextEditor</code> method performs any extra
321 * save behavior required by the php editor.
323 public void doSave(IProgressMonitor monitor) {
324 super.doSave(monitor);
325 // compile or not, according to the user preferences
326 IPreferenceStore store = getPreferenceStore(); // fPHPPrefStore;
327 if (store.getBoolean(PHPeclipsePlugin.PHP_PARSE_ON_SAVE)) {
328 IAction a = PHPParserAction.getInstance();
332 // if (SWT.getPlatform().equals("win32")) {
333 // IAction a = ShowExternalPreviewAction.getInstance();
337 if (fOutlinePage != null)
338 fOutlinePage.update();
341 /** The <code>PHPEditor</code> implementation of this
342 * <code>AbstractTextEditor</code> method performs any extra
343 * save as behavior required by the php editor.
345 public void doSaveAs() {
347 if (fOutlinePage != null)
348 fOutlinePage.update();
351 /** The <code>PHPEditor</code> implementation of this
352 * <code>AbstractTextEditor</code> method performs sets the
353 * input of the outline page after AbstractTextEditor has set input.
355 protected void doSetInput(IEditorInput input) throws CoreException {
356 super.doSetInput(input);
357 if (fOutlinePage != null)
358 fOutlinePage.setInput(input);
362 * @see org.phpeclipse.phpdt.internal.ui.viewsupport.IViewPartInputProvider#getViewPartInput()
364 // public Object getViewPartInput() {
365 // return getEditorInput().getAdapter(IFile.class);
368 /** The <code>PHPEditor</code> implementation of this
369 * <code>AbstractTextEditor</code> method adds any
370 * PHPEditor specific entries.
372 public void editorContextMenuAboutToShow(MenuManager menu) {
373 super.editorContextMenuAboutToShow(menu);
375 addAction(menu, ITextEditorActionConstants.GROUP_EDIT, "Format"); //$NON-NLS-1$
377 ActionContext context = new ActionContext(getSelectionProvider().getSelection());
378 fContextMenuGroup.setContext(context);
379 fContextMenuGroup.fillContextMenu(menu);
380 fContextMenuGroup.setContext(null);
383 protected void updateStateDependentActions() {
384 super.updateStateDependentActions();
385 fGenerateActionGroup.editorStateChanged();
388 /** The <code>PHPEditor</code> implementation of this
389 * <code>AbstractTextEditor</code> method performs gets
390 * the java content outline page if request is for a an
393 public Object getAdapter(Class required) {
394 if (IContentOutlinePage.class.equals(required)) {
395 if (fOutlinePage == null) {
396 fOutlinePage = new PHPContentOutlinePage(getDocumentProvider(), this);
397 if (getEditorInput() != null)
398 fOutlinePage.setInput(getEditorInput());
402 return super.getAdapter(required);
405 // public void openContextHelp() {
406 // IDocument doc = this.getDocumentProvider().getDocument(this.getEditorInput());
407 // ITextSelection selection = (ITextSelection) this.getSelectionProvider().getSelection();
408 // int pos = selection.getOffset();
409 // String word = getFunctionName(doc, pos);
410 // openContextHelp(word);
413 // private void openContextHelp(String word) {
417 // public static void open(String word) {
418 // IHelp help = WorkbenchHelp.getHelpSupport();
419 // if (help != null) {
420 // IHelpResource helpResource = new PHPFunctionHelpResource(word);
421 // WorkbenchHelp.getHelpSupport().displayHelpResource(helpResource);
423 // // showMessage(shell, dialogTitle, ActionMessages.getString("Open help not available"), false); //$NON-NLS-1$
427 // private String getFunctionName(IDocument doc, int pos) {
428 // Point word = PHPWordExtractor.findWord(doc, pos);
429 // if (word != null) {
431 // return doc.get(word.x, word.y).replace('_', '-');
432 // } catch (BadLocationException e) {
439 * @see AbstractTextEditor#handlePreferenceStoreChanged(PropertyChangeEvent)
441 protected void handlePreferenceStoreChanged(PropertyChangeEvent event) {
445 ISourceViewer sourceViewer = getSourceViewer();
446 if (sourceViewer == null)
449 String property = event.getProperty();
451 if (PreferenceConstants.EDITOR_TAB_WIDTH.equals(property)) {
452 Object value = event.getNewValue();
453 if (value instanceof Integer) {
454 sourceViewer.getTextWidget().setTabs(((Integer) value).intValue());
455 } else if (value instanceof String) {
456 sourceViewer.getTextWidget().setTabs(Integer.parseInt((String) value));
461 if (LINE_NUMBER_RULER.equals(property)) {
462 if (isLineNumberRulerVisible())
463 showLineNumberRuler();
465 hideLineNumberRuler();
469 if (fLineNumberRulerColumn != null
470 && (LINE_NUMBER_COLOR.equals(property)
471 || PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT.equals(property)
472 || PREFERENCE_COLOR_BACKGROUND.equals(property))) {
474 initializeLineNumberRulerColumn(fLineNumberRulerColumn);
477 if (isJavaEditorHoverProperty(property)) {
478 updateHoverBehavior();
482 super.handlePreferenceStoreChanged(event);
487 // * @see AbstractTextEditor#handlePreferenceStoreChanged(PropertyChangeEvent)
489 // protected void handlePreferenceStoreChanged(PropertyChangeEvent event) {
493 // ISourceViewer sourceViewer = getSourceViewer();
494 // if (sourceViewer == null)
497 // String property = event.getProperty();
499 // // if (JavaSourceViewerConfiguration.PREFERENCE_TAB_WIDTH.equals(property)) {
500 // // Object value= event.getNewValue();
501 // // if (value instanceof Integer) {
502 // // sourceViewer.getTextWidget().setTabs(((Integer) value).intValue());
503 // // } else if (value instanceof String) {
504 // // sourceViewer.getTextWidget().setTabs(Integer.parseInt((String) value));
509 // if (IPreferenceConstants.LINE_NUMBER_RULER.equals(property)) {
510 // if (isLineNumberRulerVisible())
511 // showLineNumberRuler();
513 // hideLineNumberRuler();
517 // if (fLineNumberRulerColumn != null
518 // && (IPreferenceConstants.LINE_NUMBER_COLOR.equals(property)
519 // || PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT.equals(property)
520 // || PREFERENCE_COLOR_BACKGROUND.equals(property))) {
522 // initializeLineNumberRulerColumn(fLineNumberRulerColumn);
526 // super.handlePreferenceStoreChanged(event);
530 private boolean isJavaEditorHoverProperty(String property) {
531 return PreferenceConstants.EDITOR_DEFAULT_HOVER.equals(property)
532 || PreferenceConstants.EDITOR_NONE_HOVER.equals(property)
533 || PreferenceConstants.EDITOR_CTRL_HOVER.equals(property)
534 || PreferenceConstants.EDITOR_SHIFT_HOVER.equals(property)
535 || PreferenceConstants.EDITOR_CTRL_ALT_HOVER.equals(property)
536 || PreferenceConstants.EDITOR_CTRL_SHIFT_HOVER.equals(property)
537 || PreferenceConstants.EDITOR_CTRL_ALT_SHIFT_HOVER.equals(property)
538 || PreferenceConstants.EDITOR_ALT_SHIFT_HOVER.equals(property);
542 * Shows the line number ruler column.
544 private void showLineNumberRuler() {
545 IVerticalRuler v = getVerticalRuler();
546 if (v instanceof CompositeRuler) {
547 CompositeRuler c = (CompositeRuler) v;
548 c.addDecorator(1, createLineNumberRulerColumn());
553 * Return whether the line number ruler column should be
554 * visible according to the preference store settings.
555 * @return <code>true</code> if the line numbers should be visible
557 private boolean isLineNumberRulerVisible() {
558 IPreferenceStore store = getPreferenceStore();
559 return store.getBoolean(LINE_NUMBER_RULER);
562 * Hides the line number ruler column.
564 private void hideLineNumberRuler() {
565 IVerticalRuler v = getVerticalRuler();
566 if (v instanceof CompositeRuler) {
567 CompositeRuler c = (CompositeRuler) v;
569 c.removeDecorator(1);
570 } catch (Throwable e) {
576 * Initializes the given line number ruler column from the preference store.
577 * @param rulerColumn the ruler column to be initialized
579 protected void initializeLineNumberRulerColumn(LineNumberRulerColumn rulerColumn) {
580 JavaTextTools textTools = PHPeclipsePlugin.getDefault().getJavaTextTools();
581 IColorManager manager = textTools.getColorManager();
583 IPreferenceStore store = getPreferenceStore();
588 if (store.contains(LINE_NUMBER_COLOR)) {
589 if (store.isDefault(LINE_NUMBER_COLOR))
590 rgb = PreferenceConverter.getDefaultColor(store, LINE_NUMBER_COLOR);
592 rgb = PreferenceConverter.getColor(store, LINE_NUMBER_COLOR);
594 rulerColumn.setForeground(manager.getColor(rgb));
598 if (!store.getBoolean(PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT)) {
599 if (store.contains(PREFERENCE_COLOR_BACKGROUND)) {
600 if (store.isDefault(PREFERENCE_COLOR_BACKGROUND))
601 rgb = PreferenceConverter.getDefaultColor(store, PREFERENCE_COLOR_BACKGROUND);
603 rgb = PreferenceConverter.getColor(store, PREFERENCE_COLOR_BACKGROUND);
606 rulerColumn.setBackground(manager.getColor(rgb));
611 * Creates a new line number ruler column that is appropriately initialized.
613 protected IVerticalRulerColumn createLineNumberRulerColumn() {
614 fLineNumberRulerColumn = new LineNumberRulerColumn();
615 initializeLineNumberRulerColumn(fLineNumberRulerColumn);
616 return fLineNumberRulerColumn;
620 * @see AbstractTextEditor#createVerticalRuler()
622 protected IVerticalRuler createVerticalRuler() {
623 CompositeRuler ruler = new CompositeRuler();
624 ruler.addDecorator(0, new AnnotationRulerColumn(VERTICAL_RULER_WIDTH));
625 if (isLineNumberRulerVisible())
626 ruler.addDecorator(1, createLineNumberRulerColumn());
631 * Method declared on TextEditor
633 protected void initializeEditor() {
634 IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
635 // PHPEditorEnvironment.connect(this);
637 // store.addPropertyChangeListener(new IPropertyChangeListener() {
638 // public void propertyChange(PropertyChangeEvent event) {
639 // PHPCodeScanner scanner = PHPEditorEnvironment.getPHPCodeScanner();
640 // if (scanner != null) {
641 // scanner.updateToken(PHPEditorEnvironment.getPHPColorProvider());
643 // if (getSourceViewer() != null) {
644 // getSourceViewer().invalidateTextPresentation();
647 // String property = event.getProperty();
648 // if (IPreferenceConstants.LINE_NUMBER_RULER.equals(property)) {
649 // if (isLineNumberRulerVisible())
650 // showLineNumberRuler();
652 // hideLineNumberRuler();
659 private static IRegion getSignedSelection(ITextViewer viewer) {
661 StyledText text = viewer.getTextWidget();
662 int caretOffset = text.getCaretOffset();
663 Point selection = text.getSelection();
667 if (caretOffset == selection.x) {
668 offset = selection.y;
669 length = selection.x - selection.y;
673 offset = selection.x;
674 length = selection.y - selection.x;
677 return new Region(offset, length);
680 private final static char[] BRACKETS = { '{', '}', '(', ')', '[', ']' };
682 private static boolean isBracket(char character) {
683 for (int i = 0; i != BRACKETS.length; ++i)
684 if (character == BRACKETS[i])
689 private static boolean isSurroundedByBrackets(IDocument document, int offset) {
690 if (offset == 0 || offset == document.getLength())
694 return isBracket(document.getChar(offset - 1)) && isBracket(document.getChar(offset));
696 } catch (BadLocationException e) {
701 * Jumps to the matching bracket.
703 public void gotoMatchingBracket() {
705 if (fBracketMatcher == null)
706 fBracketMatcher = new PHPPairMatcher(BRACKETS);
708 ISourceViewer sourceViewer = getSourceViewer();
709 IDocument document = sourceViewer.getDocument();
710 if (document == null)
713 IRegion selection = getSignedSelection(sourceViewer);
715 int selectionLength = Math.abs(selection.getLength());
716 if (selectionLength > 1) {
717 setStatusLineErrorMessage(PHPEditorMessages.getString("GotoMatchingBracket.error.invalidSelection")); //$NON-NLS-1$
718 sourceViewer.getTextWidget().getDisplay().beep();
723 int sourceCaretOffset = selection.getOffset() + selection.getLength();
724 if (isSurroundedByBrackets(document, sourceCaretOffset))
725 sourceCaretOffset -= selection.getLength();
727 IRegion region = fBracketMatcher.match(document, sourceCaretOffset);
728 if (region == null) {
729 setStatusLineErrorMessage(PHPEditorMessages.getString("GotoMatchingBracket.error.noMatchingBracket")); //$NON-NLS-1$
730 sourceViewer.getTextWidget().getDisplay().beep();
734 int offset = region.getOffset();
735 int length = region.getLength();
740 int anchor = fBracketMatcher.getAnchor();
741 int targetOffset = (PHPPairMatcher.RIGHT == anchor) ? offset : offset + length - 1;
743 boolean visible = false;
744 if (sourceViewer instanceof ITextViewerExtension3) {
745 ITextViewerExtension3 extension = (ITextViewerExtension3) sourceViewer;
746 visible = (extension.modelOffset2WidgetOffset(targetOffset) > -1);
748 IRegion visibleRegion = sourceViewer.getVisibleRegion();
749 visible = (targetOffset >= visibleRegion.getOffset() && targetOffset < visibleRegion.getOffset() + visibleRegion.getLength());
753 setStatusLineErrorMessage(PHPEditorMessages.getString("GotoMatchingBracket.error.bracketOutsideSelectedElement")); //$NON-NLS-1$
754 sourceViewer.getTextWidget().getDisplay().beep();
758 if (selection.getLength() < 0)
759 targetOffset -= selection.getLength();
761 sourceViewer.setSelectedRange(targetOffset, selection.getLength());
762 sourceViewer.revealRange(targetOffset, selection.getLength());
765 * Ses the given message as error message to this editor's status line.
766 * @param msg message to be set
768 protected void setStatusLineErrorMessage(String msg) {
769 IEditorStatusLine statusLine = (IEditorStatusLine) getAdapter(IEditorStatusLine.class);
770 if (statusLine != null)
771 statusLine.setMessage(true, msg, null);
775 * Returns a segmentation of the line of the given document appropriate for bidi rendering.
776 * The default implementation returns only the string literals of a php code line as segments.
778 * @param document the document
779 * @param lineOffset the offset of the line
780 * @return the line's bidi segmentation
781 * @throws BadLocationException in case lineOffset is not valid in document
783 public static int[] getBidiLineSegments(IDocument document, int lineOffset) throws BadLocationException {
785 IRegion line = document.getLineInformationOfOffset(lineOffset);
786 ITypedRegion[] linePartitioning = document.computePartitioning(lineOffset, line.getLength());
788 List segmentation = new ArrayList();
789 for (int i = 0; i < linePartitioning.length; i++) {
790 if (IPHPPartitionScannerConstants.PHP_STRING.equals(linePartitioning[i].getType()))
791 segmentation.add(linePartitioning[i]);
794 if (segmentation.size() == 0)
797 int size = segmentation.size();
798 int[] segments = new int[size * 2 + 1];
801 for (int i = 0; i < size; i++) {
802 ITypedRegion segment = (ITypedRegion) segmentation.get(i);
807 int offset = segment.getOffset() - lineOffset;
808 if (offset > segments[j - 1])
809 segments[j++] = offset;
811 if (offset + segment.getLength() >= line.getLength())
814 segments[j++] = offset + segment.getLength();
817 if (j < segments.length) {
818 int[] result = new int[j];
819 System.arraycopy(segments, 0, result, 0, j);
826 * Returns a segmentation of the given line appropriate for bidi rendering. The default
827 * implementation returns only the string literals of a php code line as segments.
829 * @param lineOffset the offset of the line
830 * @param line the content of the line
831 * @return the line's bidi segmentation
833 protected int[] getBidiLineSegments(int lineOffset, String line) {
834 IDocumentProvider provider = getDocumentProvider();
835 if (provider != null && line != null && line.length() > 0) {
836 IDocument document = provider.getDocument(getEditorInput());
837 if (document != null)
839 return getBidiLineSegments(document, lineOffset);
840 } catch (BadLocationException x) {
848 * @see AbstractTextEditor#createSourceViewer(Composite, IVerticalRuler, int)
850 protected final ISourceViewer createSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
851 ISourceViewer viewer = createJavaSourceViewer(parent, ruler, styles);
852 StyledText text = viewer.getTextWidget();
853 text.addBidiSegmentListener(new BidiSegmentListener() {
854 public void lineGetSegments(BidiSegmentEvent event) {
855 event.segments = getBidiLineSegments(event.lineOffset, event.lineText);
858 // JavaUIHelp.setHelp(this, text, IJavaHelpContextIds.JAVA_EDITOR);
863 * @see AbstractTextEditor#createSourceViewer(Composite, IVerticalRuler, int)
865 protected ISourceViewer createJavaSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
866 return super.createSourceViewer(parent, ruler, styles);
870 * @see AbstractTextEditor#affectsTextPresentation(PropertyChangeEvent)
872 protected boolean affectsTextPresentation(PropertyChangeEvent event) {
873 JavaTextTools textTools = PHPeclipsePlugin.getDefault().getJavaTextTools();
874 return textTools.affectsBehavior(event);