package net.sourceforge.phpeclipse.phpeditor; /********************************************************************** Copyright (c) 2000, 2002 IBM Corp. and others. All rights reserved. This program and the accompanying materials are made available under the terms of the Common Public License v1.0 which accompanies this distribution, and is available at http://www.eclipse.org/legal/cpl-v10.html Contributors: IBM Corporation - Initial implementation Klaus Hartlage - www.eclipseproject.de **********************************************************************/ import java.util.ArrayList; import java.util.List; import java.util.ResourceBundle; import java.util.StringTokenizer; import net.sourceforge.phpdt.internal.ui.actions.CompositeActionGroup; import net.sourceforge.phpdt.internal.ui.text.HTMLTextPresenter; import net.sourceforge.phpdt.internal.ui.text.PHPPairMatcher; import net.sourceforge.phpdt.internal.ui.viewsupport.IViewPartInputProvider; import net.sourceforge.phpdt.ui.IContextMenuConstants; import net.sourceforge.phpdt.ui.PreferenceConstants; import net.sourceforge.phpdt.ui.actions.GenerateActionGroup; import net.sourceforge.phpdt.ui.actions.GotoMatchingBracketAction; import net.sourceforge.phpdt.ui.text.IColorManager; import net.sourceforge.phpdt.ui.text.JavaTextTools; import net.sourceforge.phpeclipse.PHPeclipsePlugin; import net.sourceforge.phpeclipse.phpeditor.php.IPHPPartitionScannerConstants; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Preferences; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.GroupMarker; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.preference.PreferenceConverter; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.DefaultInformationControl; import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentListener; import org.eclipse.jface.text.IInformationControl; import org.eclipse.jface.text.IInformationControlCreator; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextHover; import org.eclipse.jface.text.ITextInputListener; import org.eclipse.jface.text.ITextOperationTarget; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.ITextViewerExtension2; import org.eclipse.jface.text.ITextViewerExtension3; import org.eclipse.jface.text.ITypedRegion; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.information.IInformationProvider; import org.eclipse.jface.text.information.InformationPresenter; import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.AnnotationRulerColumn; import org.eclipse.jface.text.source.CompositeRuler; import org.eclipse.jface.text.source.IAnnotationAccess; import org.eclipse.jface.text.source.IOverviewRuler; import org.eclipse.jface.text.source.ISharedTextColors; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.text.source.ISourceViewerExtension; import org.eclipse.jface.text.source.IVerticalRuler; import org.eclipse.jface.text.source.IVerticalRulerColumn; import org.eclipse.jface.text.source.LineNumberRulerColumn; import org.eclipse.jface.text.source.OverviewRuler; import org.eclipse.jface.text.source.SourceViewer; import org.eclipse.jface.text.source.SourceViewerConfiguration; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.BidiSegmentEvent; import org.eclipse.swt.custom.BidiSegmentListener; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.MouseMoveListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Cursor; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IPartService; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.actions.ActionContext; import org.eclipse.ui.actions.ActionGroup; import org.eclipse.ui.editors.text.DefaultEncodingSupport; import org.eclipse.ui.editors.text.IEncodingSupport; import org.eclipse.ui.texteditor.AddTaskAction; import org.eclipse.ui.texteditor.ContentAssistAction; import org.eclipse.ui.texteditor.DefaultRangeIndicator; import org.eclipse.ui.texteditor.IAbstractTextEditorHelpContextIds; import org.eclipse.ui.texteditor.IDocumentProvider; import org.eclipse.ui.texteditor.IEditorStatusLine; import org.eclipse.ui.texteditor.ITextEditorActionConstants; import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; import org.eclipse.ui.texteditor.ResourceAction; import org.eclipse.ui.texteditor.SourceViewerDecorationSupport; import org.eclipse.ui.texteditor.StatusTextEditor; import org.eclipse.ui.texteditor.TextEditorAction; import org.eclipse.ui.texteditor.TextOperationAction; import org.eclipse.ui.views.contentoutline.IContentOutlinePage; /** * PHP specific text editor. */ public abstract class PHPEditor extends StatusTextEditor implements IViewPartInputProvider { // extends TextEditor { class SelectionChangedListener implements ISelectionChangedListener { public void selectionChanged(SelectionChangedEvent event) { doSelectionChanged(event); } }; /* * Link mode. */ class MouseClickListener implements KeyListener, MouseListener, MouseMoveListener, FocusListener, PaintListener, IPropertyChangeListener, IDocumentListener, ITextInputListener { /** The session is active. */ private boolean fActive; /** The currently active style range. */ private IRegion fActiveRegion; /** The currently active style range as position. */ private Position fRememberedPosition; /** The hand cursor. */ private Cursor fCursor; /** The link color. */ private Color fColor; /** The key modifier mask. */ private int fKeyModifierMask; public void deactivate() { deactivate(false); } public void deactivate(boolean redrawAll) { if (!fActive) return; repairRepresentation(redrawAll); fActive = false; } public void install() { ISourceViewer sourceViewer = getSourceViewer(); if (sourceViewer == null) return; StyledText text = sourceViewer.getTextWidget(); if (text == null || text.isDisposed()) return; updateColor(sourceViewer); sourceViewer.addTextInputListener(this); IDocument document = sourceViewer.getDocument(); if (document != null) document.addDocumentListener(this); text.addKeyListener(this); text.addMouseListener(this); text.addMouseMoveListener(this); text.addFocusListener(this); text.addPaintListener(this); updateKeyModifierMask(); IPreferenceStore preferenceStore = getPreferenceStore(); preferenceStore.addPropertyChangeListener(this); } private void updateKeyModifierMask() { String modifiers = getPreferenceStore().getString(BROWSER_LIKE_LINKS_KEY_MODIFIER); fKeyModifierMask = computeStateMask(modifiers); if (fKeyModifierMask == -1) { // Fallback to stored state mask fKeyModifierMask = getPreferenceStore().getInt(BROWSER_LIKE_LINKS_KEY_MODIFIER_MASK); }; } private int computeStateMask(String modifiers) { if (modifiers == null) return -1; if (modifiers.length() == 0) return SWT.NONE; int stateMask = 0; StringTokenizer modifierTokenizer = new StringTokenizer(modifiers, ",;.:+-* "); //$NON-NLS-1$ while (modifierTokenizer.hasMoreTokens()) { int modifier = EditorUtility.findLocalizedModifier(modifierTokenizer.nextToken()); if (modifier == 0 || (stateMask & modifier) == modifier) return -1; stateMask = stateMask | modifier; } return stateMask; } public void uninstall() { if (fColor != null) { fColor.dispose(); fColor = null; } if (fCursor != null) { fCursor.dispose(); fCursor = null; } ISourceViewer sourceViewer = getSourceViewer(); if (sourceViewer == null) return; sourceViewer.removeTextInputListener(this); IDocument document = sourceViewer.getDocument(); if (document != null) document.removeDocumentListener(this); IPreferenceStore preferenceStore = getPreferenceStore(); if (preferenceStore != null) preferenceStore.removePropertyChangeListener(this); StyledText text = sourceViewer.getTextWidget(); if (text == null || text.isDisposed()) return; text.removeKeyListener(this); text.removeMouseListener(this); text.removeMouseMoveListener(this); text.removeFocusListener(this); text.removePaintListener(this); } /* * @see IPropertyChangeListener#propertyChange(PropertyChangeEvent) */ public void propertyChange(PropertyChangeEvent event) { if (event.getProperty().equals(PHPEditor.LINK_COLOR)) { ISourceViewer viewer = getSourceViewer(); if (viewer != null) updateColor(viewer); } else if (event.getProperty().equals(BROWSER_LIKE_LINKS_KEY_MODIFIER)) { updateKeyModifierMask(); } } private void updateColor(ISourceViewer viewer) { if (fColor != null) fColor.dispose(); StyledText text = viewer.getTextWidget(); if (text == null || text.isDisposed()) return; Display display = text.getDisplay(); fColor = createColor(getPreferenceStore(), PHPEditor.LINK_COLOR, display); } /** * Creates a color from the information stored in the given preference store. * Returns null if there is no such information available. */ private Color createColor(IPreferenceStore store, String key, Display display) { RGB rgb = null; if (store.contains(key)) { if (store.isDefault(key)) rgb = PreferenceConverter.getDefaultColor(store, key); else rgb = PreferenceConverter.getColor(store, key); if (rgb != null) return new Color(display, rgb); } return null; } private void repairRepresentation() { repairRepresentation(false); } private void repairRepresentation(boolean redrawAll) { if (fActiveRegion == null) return; ISourceViewer viewer = getSourceViewer(); if (viewer != null) { resetCursor(viewer); int offset = fActiveRegion.getOffset(); int length = fActiveRegion.getLength(); // remove style if (!redrawAll && viewer instanceof ITextViewerExtension2) ((ITextViewerExtension2) viewer).invalidateTextPresentation(offset, length); else viewer.invalidateTextPresentation(); // remove underline if (viewer instanceof ITextViewerExtension3) { ITextViewerExtension3 extension = (ITextViewerExtension3) viewer; offset = extension.modelOffset2WidgetOffset(offset); } else { offset -= viewer.getVisibleRegion().getOffset(); } StyledText text = viewer.getTextWidget(); try { text.redrawRange(offset, length, true); } catch (IllegalArgumentException x) { PHPeclipsePlugin.log(x); } } fActiveRegion = null; } // will eventually be replaced by a method provided by jdt.core private IRegion selectWord(IDocument document, int anchor) { try { int offset = anchor; char c; while (offset >= 0) { c = document.getChar(offset); if (!Character.isJavaIdentifierPart(c)) break; --offset; } int start = offset; offset = anchor; int length = document.getLength(); while (offset < length) { c = document.getChar(offset); if (!Character.isJavaIdentifierPart(c)) break; ++offset; } int end = offset; if (start == end) return new Region(start, 0); else return new Region(start + 1, end - start - 1); } catch (BadLocationException x) { return null; } } IRegion getCurrentTextRegion(ISourceViewer viewer) { int offset = getCurrentTextOffset(viewer); if (offset == -1) return null; return null; // IJavaElement input= SelectionConverter.getInput(PHPEditor.this); // if (input == null) // return null; // // try { // // IJavaElement[] elements= null; // synchronized (input) { // elements= ((ICodeAssist) input).codeSelect(offset, 0); // } // // if (elements == null || elements.length == 0) // return null; // // return selectWord(viewer.getDocument(), offset); // // } catch (JavaModelException e) { // return null; // } } private int getCurrentTextOffset(ISourceViewer viewer) { try { StyledText text = viewer.getTextWidget(); if (text == null || text.isDisposed()) return -1; Display display = text.getDisplay(); Point absolutePosition = display.getCursorLocation(); Point relativePosition = text.toControl(absolutePosition); int widgetOffset = text.getOffsetAtLocation(relativePosition); if (viewer instanceof ITextViewerExtension3) { ITextViewerExtension3 extension = (ITextViewerExtension3) viewer; return extension.widgetOffset2ModelOffset(widgetOffset); } else { return widgetOffset + viewer.getVisibleRegion().getOffset(); } } catch (IllegalArgumentException e) { return -1; } } private void highlightRegion(ISourceViewer viewer, IRegion region) { if (region.equals(fActiveRegion)) return; repairRepresentation(); StyledText text = viewer.getTextWidget(); if (text == null || text.isDisposed()) return; // highlight region int offset = 0; int length = 0; if (viewer instanceof ITextViewerExtension3) { ITextViewerExtension3 extension = (ITextViewerExtension3) viewer; IRegion widgetRange = extension.modelRange2WidgetRange(region); if (widgetRange == null) return; offset = widgetRange.getOffset(); length = widgetRange.getLength(); } else { offset = region.getOffset() - viewer.getVisibleRegion().getOffset(); length = region.getLength(); } StyleRange oldStyleRange = text.getStyleRangeAtOffset(offset); Color foregroundColor = fColor; Color backgroundColor = oldStyleRange == null ? text.getBackground() : oldStyleRange.background; StyleRange styleRange = new StyleRange(offset, length, foregroundColor, backgroundColor); text.setStyleRange(styleRange); // underline text.redrawRange(offset, length, true); fActiveRegion = region; } private void activateCursor(ISourceViewer viewer) { StyledText text = viewer.getTextWidget(); if (text == null || text.isDisposed()) return; Display display = text.getDisplay(); if (fCursor == null) fCursor = new Cursor(display, SWT.CURSOR_HAND); text.setCursor(fCursor); } private void resetCursor(ISourceViewer viewer) { StyledText text = viewer.getTextWidget(); if (text != null && !text.isDisposed()) text.setCursor(null); if (fCursor != null) { fCursor.dispose(); fCursor = null; } } /* * @see org.eclipse.swt.events.KeyListener#keyPressed(org.eclipse.swt.events.KeyEvent) */ public void keyPressed(KeyEvent event) { if (fActive) { deactivate(); return; } if (event.keyCode != fKeyModifierMask) { deactivate(); return; } fActive = true; // removed for #25871 // // ISourceViewer viewer= getSourceViewer(); // if (viewer == null) // return; // // IRegion region= getCurrentTextRegion(viewer); // if (region == null) // return; // // highlightRegion(viewer, region); // activateCursor(viewer); } /* * @see org.eclipse.swt.events.KeyListener#keyReleased(org.eclipse.swt.events.KeyEvent) */ public void keyReleased(KeyEvent event) { if (!fActive) return; deactivate(); } /* * @see org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent) */ public void mouseDoubleClick(MouseEvent e) { } /* * @see org.eclipse.swt.events.MouseListener#mouseDown(org.eclipse.swt.events.MouseEvent) */ public void mouseDown(MouseEvent event) { if (!fActive) return; if (event.stateMask != fKeyModifierMask) { deactivate(); return; } if (event.button != 1) { deactivate(); return; } } /* * @see org.eclipse.swt.events.MouseListener#mouseUp(org.eclipse.swt.events.MouseEvent) */ public void mouseUp(MouseEvent e) { if (!fActive) return; if (e.button != 1) { deactivate(); return; } boolean wasActive = fCursor != null; deactivate(); if (wasActive) { IAction action = getAction("OpenEditor"); //$NON-NLS-1$ if (action != null) action.run(); } } /* * @see org.eclipse.swt.events.MouseMoveListener#mouseMove(org.eclipse.swt.events.MouseEvent) */ public void mouseMove(MouseEvent event) { if (event.widget instanceof Control && !((Control) event.widget).isFocusControl()) { deactivate(); return; } if (!fActive) { if (event.stateMask != fKeyModifierMask) return; // modifier was already pressed fActive = true; } ISourceViewer viewer = getSourceViewer(); if (viewer == null) { deactivate(); return; } StyledText text = viewer.getTextWidget(); if (text == null || text.isDisposed()) { deactivate(); return; } if ((event.stateMask & SWT.BUTTON1) != 0 && text.getSelectionCount() != 0) { deactivate(); return; } IRegion region = getCurrentTextRegion(viewer); if (region == null || region.getLength() == 0) { repairRepresentation(); return; } highlightRegion(viewer, region); activateCursor(viewer); } /* * @see org.eclipse.swt.events.FocusListener#focusGained(org.eclipse.swt.events.FocusEvent) */ public void focusGained(FocusEvent e) { } /* * @see org.eclipse.swt.events.FocusListener#focusLost(org.eclipse.swt.events.FocusEvent) */ public void focusLost(FocusEvent event) { deactivate(); } /* * @see org.eclipse.jface.text.IDocumentListener#documentAboutToBeChanged(org.eclipse.jface.text.DocumentEvent) */ public void documentAboutToBeChanged(DocumentEvent event) { if (fActive && fActiveRegion != null) { fRememberedPosition = new Position(fActiveRegion.getOffset(), fActiveRegion.getLength()); try { event.getDocument().addPosition(fRememberedPosition); } catch (BadLocationException x) { fRememberedPosition = null; } } } /* * @see org.eclipse.jface.text.IDocumentListener#documentChanged(org.eclipse.jface.text.DocumentEvent) */ public void documentChanged(DocumentEvent event) { if (fRememberedPosition != null && !fRememberedPosition.isDeleted()) { event.getDocument().removePosition(fRememberedPosition); fActiveRegion = new Region(fRememberedPosition.getOffset(), fRememberedPosition.getLength()); } fRememberedPosition = null; ISourceViewer viewer = getSourceViewer(); if (viewer != null) { StyledText widget = viewer.getTextWidget(); if (widget != null && !widget.isDisposed()) { widget.getDisplay().asyncExec(new Runnable() { public void run() { deactivate(); } }); } } } /* * @see org.eclipse.jface.text.ITextInputListener#inputDocumentAboutToBeChanged(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument) */ public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) { if (oldInput == null) return; deactivate(); oldInput.removeDocumentListener(this); } /* * @see org.eclipse.jface.text.ITextInputListener#inputDocumentChanged(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument) */ public void inputDocumentChanged(IDocument oldInput, IDocument newInput) { if (newInput == null) return; newInput.addDocumentListener(this); } /* * @see PaintListener#paintControl(PaintEvent) */ public void paintControl(PaintEvent event) { if (fActiveRegion == null) return; ISourceViewer viewer = getSourceViewer(); if (viewer == null) return; StyledText text = viewer.getTextWidget(); if (text == null || text.isDisposed()) return; int offset = 0; int length = 0; if (viewer instanceof ITextViewerExtension3) { ITextViewerExtension3 extension = (ITextViewerExtension3) viewer; IRegion widgetRange = extension.modelRange2WidgetRange(new Region(offset, length)); if (widgetRange == null) return; offset = widgetRange.getOffset(); length = widgetRange.getLength(); } else { IRegion region = viewer.getVisibleRegion(); if (!includes(region, fActiveRegion)) return; offset = fActiveRegion.getOffset() - region.getOffset(); length = fActiveRegion.getLength(); } // support for bidi Point minLocation = getMinimumLocation(text, offset, length); Point maxLocation = getMaximumLocation(text, offset, length); int x1 = minLocation.x; int x2 = minLocation.x + maxLocation.x - minLocation.x - 1; int y = minLocation.y + text.getLineHeight() - 1; GC gc = event.gc; if (fColor != null && !fColor.isDisposed()) gc.setForeground(fColor); gc.drawLine(x1, y, x2, y); } private boolean includes(IRegion region, IRegion position) { return position.getOffset() >= region.getOffset() && position.getOffset() + position.getLength() <= region.getOffset() + region.getLength(); } private Point getMinimumLocation(StyledText text, int offset, int length) { Point minLocation = new Point(Integer.MAX_VALUE, Integer.MAX_VALUE); for (int i = 0; i <= length; i++) { Point location = text.getLocationAtOffset(offset + i); if (location.x < minLocation.x) minLocation.x = location.x; if (location.y < minLocation.y) minLocation.y = location.y; } return minLocation; } private Point getMaximumLocation(StyledText text, int offset, int length) { Point maxLocation = new Point(Integer.MIN_VALUE, Integer.MIN_VALUE); for (int i = 0; i <= length; i++) { Point location = text.getLocationAtOffset(offset + i); if (location.x > maxLocation.x) maxLocation.x = location.x; if (location.y > maxLocation.y) maxLocation.y = location.y; } return maxLocation; } }; /** * This action dispatches into two behaviours: If there is no current text * hover, the javadoc is displayed using information presenter. If there is * a current text hover, it is converted into a information presenter in * order to make it sticky. */ class InformationDispatchAction extends TextEditorAction { /** The wrapped text operation action. */ private final TextOperationAction fTextOperationAction; /** * Creates a dispatch action. */ public InformationDispatchAction(ResourceBundle resourceBundle, String prefix, final TextOperationAction textOperationAction) { super(resourceBundle, prefix, PHPEditor.this); if (textOperationAction == null) throw new IllegalArgumentException(); fTextOperationAction = textOperationAction; } /* * @see org.eclipse.jface.action.IAction#run() */ public void run() { ISourceViewer sourceViewer = getSourceViewer(); if (sourceViewer == null) { fTextOperationAction.run(); return; } if (!(sourceViewer instanceof ITextViewerExtension2)) { fTextOperationAction.run(); return; } ITextViewerExtension2 textViewerExtension2 = (ITextViewerExtension2) sourceViewer; // does a text hover exist? ITextHover textHover = textViewerExtension2.getCurrentTextHover(); if (textHover == null) { fTextOperationAction.run(); return; } Point hoverEventLocation = textViewerExtension2.getHoverEventLocation(); int offset = computeOffsetAtLocation(sourceViewer, hoverEventLocation.x, hoverEventLocation.y); if (offset == -1) { fTextOperationAction.run(); return; } try { // get the text hover content IDocument document = sourceViewer.getDocument(); String contentType = document.getContentType(offset); final IRegion hoverRegion = textHover.getHoverRegion(sourceViewer, offset); if (hoverRegion == null) return; final String hoverInfo = textHover.getHoverInfo(sourceViewer, hoverRegion); // with information provider IInformationProvider informationProvider = new IInformationProvider() { /* * @see org.eclipse.jface.text.information.IInformationProvider#getSubject(org.eclipse.jface.text.ITextViewer, int) */ public IRegion getSubject(ITextViewer textViewer, int offset) { return hoverRegion; } /* * @see org.eclipse.jface.text.information.IInformationProvider#getInformation(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion) */ public String getInformation(ITextViewer textViewer, IRegion subject) { return hoverInfo; } }; fInformationPresenter.setOffset(offset); fInformationPresenter.setInformationProvider(informationProvider, contentType); fInformationPresenter.showInformation(); } catch (BadLocationException e) { } } // modified version from TextViewer private int computeOffsetAtLocation(ITextViewer textViewer, int x, int y) { StyledText styledText = textViewer.getTextWidget(); IDocument document = textViewer.getDocument(); if (document == null) return -1; try { int widgetLocation = styledText.getOffsetAtLocation(new Point(x, y)); if (textViewer instanceof ITextViewerExtension3) { ITextViewerExtension3 extension = (ITextViewerExtension3) textViewer; return extension.widgetOffset2ModelOffset(widgetLocation); } else { IRegion visibleRegion = textViewer.getVisibleRegion(); return widgetLocation + visibleRegion.getOffset(); } } catch (IllegalArgumentException e) { return -1; } } }; static protected class AnnotationAccess implements IAnnotationAccess { /* * @see org.eclipse.jface.text.source.IAnnotationAccess#getType(org.eclipse.jface.text.source.Annotation) */ public Object getType(Annotation annotation) { if (annotation instanceof IJavaAnnotation) { IJavaAnnotation javaAnnotation = (IJavaAnnotation) annotation; if (javaAnnotation.isRelevant()) return javaAnnotation.getAnnotationType(); } return null; } /* * @see org.eclipse.jface.text.source.IAnnotationAccess#isMultiLine(org.eclipse.jface.text.source.Annotation) */ public boolean isMultiLine(Annotation annotation) { return true; } /* * @see org.eclipse.jface.text.source.IAnnotationAccess#isTemporary(org.eclipse.jface.text.source.Annotation) */ public boolean isTemporary(Annotation annotation) { if (annotation instanceof IJavaAnnotation) { IJavaAnnotation javaAnnotation = (IJavaAnnotation) annotation; if (javaAnnotation.isRelevant()) return javaAnnotation.isTemporary(); } return false; } }; private class PropertyChangeListener implements org.eclipse.core.runtime.Preferences.IPropertyChangeListener { /* * @see IPropertyChangeListener#propertyChange(PropertyChangeEvent) */ public void propertyChange(org.eclipse.core.runtime.Preferences.PropertyChangeEvent event) { handlePreferencePropertyChanged(event); } }; /** Preference key for showing the line number ruler */ private final static String LINE_NUMBER_RULER = PreferenceConstants.EDITOR_LINE_NUMBER_RULER; /** Preference key for the foreground color of the line numbers */ private final static String LINE_NUMBER_COLOR = PreferenceConstants.EDITOR_LINE_NUMBER_RULER_COLOR; /** Preference key for the link color */ private final static String LINK_COLOR = PreferenceConstants.EDITOR_LINK_COLOR; // protected PHPActionGroup fActionGroups; /** The outline page */ private AbstractContentOutlinePage fOutlinePage; // protected PHPSyntaxParserThread fValidationThread = null; // private IPreferenceStore fPHPPrefStore; /** The selection changed listener */ protected ISelectionChangedListener fSelectionChangedListener = new SelectionChangedListener(); /** The editor's bracket matcher */ private PHPPairMatcher fBracketMatcher = new PHPPairMatcher(BRACKETS); /** The line number ruler column */ private LineNumberRulerColumn fLineNumberRulerColumn; /** This editor's encoding support */ private DefaultEncodingSupport fEncodingSupport; /** The mouse listener */ private MouseClickListener fMouseListener; protected CompositeActionGroup fActionGroups; /** The standard action groups added to the menu */ protected GenerateActionGroup fGenerateActionGroup; protected CompositeActionGroup fContextMenuGroup; /** The information presenter. */ private InformationPresenter fInformationPresenter; /** The annotation access */ protected IAnnotationAccess fAnnotationAccess = new AnnotationAccess(); /** The overview ruler */ protected OverviewRuler isOverviewRulerVisible; /** The source viewer decoration support */ protected SourceViewerDecorationSupport fSourceViewerDecorationSupport; /** The overview ruler */ protected OverviewRuler fOverviewRuler; /** The preference property change listener for java core. */ private org.eclipse.core.runtime.Preferences.IPropertyChangeListener fPropertyChangeListener = new PropertyChangeListener(); /** * Default constructor. */ public PHPEditor() { super(); JavaTextTools textTools = PHPeclipsePlugin.getDefault().getJavaTextTools(); setSourceViewerConfiguration(new PHPSourceViewerConfiguration(textTools, this)); setRangeIndicator(new DefaultRangeIndicator()); setPreferenceStore(PHPeclipsePlugin.getDefault().getPreferenceStore()); // don't activate this scope without synchronizing plugin.xml !!! // setKeyBindingScopes(new String[] { "net.sourceforge.phpdt.ui.phpEditorScope" }); //$NON-NLS-1$ // if (PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_SYNC_OUTLINE_ON_CURSOR_MOVE)) // fUpdater= new OutlinePageSelectionUpdater(); } // // /** // * @see IMember#getCompilationUnit() // */ // public ICompilationUnit getCompilationUnit() { // return this; // } // /** // * @see org.phpeclipse.phpdt.internal.compiler.env.ICompilationUnit#getContents() // */ // public char[] getContents() { // IDocument doc = this.getDocumentProvider().getDocument(this.getEditorInput()); // // return doc.get().toCharArray(); // } /* * @see org.eclipse.ui.texteditor.AbstractTextEditor#updatePropertyDependentActions() */ protected void updatePropertyDependentActions() { super.updatePropertyDependentActions(); if (fEncodingSupport != null) fEncodingSupport.reset(); } /* * Update the hovering behavior depending on the preferences. */ private void updateHoverBehavior() { SourceViewerConfiguration configuration = getSourceViewerConfiguration(); String[] types = configuration.getConfiguredContentTypes(getSourceViewer()); for (int i = 0; i < types.length; i++) { String t = types[i]; int[] stateMasks = configuration.getConfiguredTextHoverStateMasks(getSourceViewer(), t); ISourceViewer sourceViewer = getSourceViewer(); if (sourceViewer instanceof ITextViewerExtension2) { if (stateMasks != null) { for (int j = 0; j < stateMasks.length; j++) { int stateMask = stateMasks[j]; ITextHover textHover = configuration.getTextHover(sourceViewer, t, stateMask); ((ITextViewerExtension2) sourceViewer).setTextHover(textHover, t, stateMask); } } else { ITextHover textHover = configuration.getTextHover(sourceViewer, t); ((ITextViewerExtension2) sourceViewer).setTextHover(textHover, t, ITextViewerExtension2.DEFAULT_HOVER_STATE_MASK); } } else sourceViewer.setTextHover(configuration.getTextHover(sourceViewer, t), t); } } /* * @see net.sourceforge.phpdt.internal.ui.viewsupport.IViewPartInputProvider#getViewPartInput() */ public Object getViewPartInput() { return getEditorInput().getAdapter(IResource.class); } /* * @see org.eclipse.ui.IWorkbenchPart#createPartControl(org.eclipse.swt. * widgets.Composite) */ public void createPartControl(Composite parent) { super.createPartControl(parent); fSourceViewerDecorationSupport.install(getPreferenceStore()); Preferences preferences = PHPeclipsePlugin.getDefault().getPluginPreferences(); preferences.addPropertyChangeListener(fPropertyChangeListener); IInformationControlCreator informationControlCreator = new IInformationControlCreator() { public IInformationControl createInformationControl(Shell parent) { boolean cutDown = false; int style = cutDown ? SWT.NONE : (SWT.V_SCROLL | SWT.H_SCROLL); return new DefaultInformationControl(parent, SWT.RESIZE, style, new HTMLTextPresenter(cutDown)); } }; fInformationPresenter = new InformationPresenter(informationControlCreator); fInformationPresenter.setSizeConstraints(60, 10, true, true); fInformationPresenter.install(getSourceViewer()); } /** * Returns this document's complete text. * * @return the document's complete text */ public String get() { IDocument doc = this.getDocumentProvider().getDocument(this.getEditorInput()); return doc.get(); } /** * Returns the standard action group of this editor. */ protected ActionGroup getActionGroup() { return fActionGroups; } public AbstractContentOutlinePage getfOutlinePage() { return fOutlinePage; } /** The PHPEditor implementation of this * AbstractTextEditor method extend the * actions to add those specific to the receiver */ protected void createActions() { super.createActions(); ResourceAction resAction = new AddTaskAction(PHPEditorMessages.getResourceBundle(), "AddTask.", this); //$NON-NLS-1$ resAction.setHelpContextId(IAbstractTextEditorHelpContextIds.ADD_TASK_ACTION); resAction.setActionDefinitionId(ITextEditorActionDefinitionIds.ADD_TASK); setAction(ITextEditorActionConstants.ADD_TASK, resAction); resAction = new TextOperationAction(PHPEditorMessages.getResourceBundle(), "ShowJavaDoc.", this, ISourceViewer.INFORMATION, true); //$NON-NLS-1$ resAction = new InformationDispatchAction(PHPEditorMessages.getResourceBundle(), "ShowJavaDoc.", (TextOperationAction) resAction); //$NON-NLS-1$ resAction.setActionDefinitionId(PHPEditorActionDefinitionIds.SHOW_JAVADOC); setAction("ShowJavaDoc", resAction); //$NON-NLS-1$ // WorkbenchHelp.setHelp(resAction, IJavaHelpContextIds.SHOW_JAVADOC_ACTION); Action action; setAction( "ContentAssistTip", new TextOperationAction( PHPEditorMessages.getResourceBundle(), "ContentAssistTip.", this, ISourceViewer.CONTENTASSIST_CONTEXT_INFORMATION)); action = new ContentAssistAction(PHPEditorMessages.getResourceBundle(), "ContentAssistProposal.", this); //$NON-NLS-1$ action.setActionDefinitionId(PHPEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS); setAction("ContentAssistProposal", action); //$NON-NLS-1$ markAsStateDependentAction("ContentAssistProposal", true); //$NON-NLS-1$ // WorkbenchHelp.setHelp(action, IJavaHelpContextIds.CONTENT_ASSIST_ACTION); fEncodingSupport = new DefaultEncodingSupport(); fEncodingSupport.initialize(this); action = new TextOperationAction(PHPEditorMessages.getResourceBundle(), "Comment.", this, ITextOperationTarget.PREFIX); //$NON-NLS-1$ action.setActionDefinitionId(PHPEditorActionDefinitionIds.COMMENT); setAction("Comment", action); //$NON-NLS-1$ markAsStateDependentAction("Comment", true); //$NON-NLS-1$ // WorkbenchHelp.setHelp(action, IJavaHelpContextIds.COMMENT_ACTION); action = new TextOperationAction(PHPEditorMessages.getResourceBundle(), "Uncomment.", this, ITextOperationTarget.STRIP_PREFIX); //$NON-NLS-1$ action.setActionDefinitionId(PHPEditorActionDefinitionIds.UNCOMMENT); setAction("Uncomment", action); //$NON-NLS-1$ markAsStateDependentAction("Uncomment", true); //$NON-NLS-1$ // WorkbenchHelp.setHelp(action, IJavaHelpContextIds.UNCOMMENT_ACTION); action = new TextOperationAction(PHPEditorMessages.getResourceBundle(), "Format.", this, ISourceViewer.FORMAT); //$NON-NLS-1$ action.setActionDefinitionId(PHPEditorActionDefinitionIds.FORMAT); setAction("Format", action); //$NON-NLS-1$ markAsStateDependentAction("Format", true); //$NON-NLS-1$ markAsSelectionDependentAction("Format", true); //$NON-NLS-1$ // WorkbenchHelp.setHelp(action, IJavaHelpContextIds.FORMAT_ACTION); action = new GotoMatchingBracketAction(this); action.setActionDefinitionId(PHPEditorActionDefinitionIds.GOTO_MATCHING_BRACKET); setAction(GotoMatchingBracketAction.GOTO_MATCHING_BRACKET, action); fGenerateActionGroup = new GenerateActionGroup(this, ITextEditorActionConstants.GROUP_EDIT); fActionGroups = new CompositeActionGroup(new ActionGroup[] { fGenerateActionGroup }); // We have to keep the context menu group separate to have better control over positioning fContextMenuGroup = new CompositeActionGroup(new ActionGroup[] { fGenerateActionGroup }); // rg, // new LocalHistoryActionGroup(this, ITextEditorActionConstants.GROUP_EDIT)}); // if (fValidationThread == null) { // fValidationThread = // new PHPSyntaxParserThread(this, getSourceViewer()); // //Thread defaults // // fValidationThread.start(); // } // // fValidationThread.setText(getSourceViewer().getTextWidget().getText()); } /** The PHPEditor implementation of this * AbstractTextEditor method performs any extra * disposal actions required by the php editor. */ public void dispose() { // PHPEditorEnvironment.disconnect(this); if (fOutlinePage != null) fOutlinePage.setInput(null); if (fActionGroups != null) fActionGroups.dispose(); if (isBrowserLikeLinks()) disableBrowserLikeLinks(); if (fEncodingSupport != null) { fEncodingSupport.dispose(); fEncodingSupport = null; } if (fPropertyChangeListener != null) { Preferences preferences = PHPeclipsePlugin.getDefault().getPluginPreferences(); preferences.removePropertyChangeListener(fPropertyChangeListener); fPropertyChangeListener = null; } if (fSourceViewerDecorationSupport != null) { fSourceViewerDecorationSupport.dispose(); fSourceViewerDecorationSupport = null; } if (fBracketMatcher != null) { fBracketMatcher.dispose(); fBracketMatcher = null; } super.dispose(); } /** The PHPEditor implementation of this * AbstractTextEditor method performs any extra * revert behavior required by the php editor. */ public void doRevertToSaved() { super.doRevertToSaved(); if (fOutlinePage != null) fOutlinePage.update(); } /** The PHPEditor implementation of this * AbstractTextEditor method performs any extra * save behavior required by the php editor. */ public void doSave(IProgressMonitor monitor) { super.doSave(monitor); // compile or not, according to the user preferences // IPreferenceStore store = getPreferenceStore(); // the parse on save was changed to the eclipse "builders" concept // if (store.getBoolean(PHPeclipsePlugin.PHP_PARSE_ON_SAVE)) { // IAction a = PHPParserAction.getInstance(); // if (a != null) // a.run(); // } // if (SWT.getPlatform().equals("win32")) { // IAction a = ShowExternalPreviewAction.getInstance(); // if (a != null) // a.run(); // } if (fOutlinePage != null) fOutlinePage.update(); } /** The PHPEditor implementation of this * AbstractTextEditor method performs any extra * save as behavior required by the php editor. */ public void doSaveAs() { super.doSaveAs(); if (fOutlinePage != null) fOutlinePage.update(); } /* * @see StatusTextEditor#getStatusHeader(IStatus) */ protected String getStatusHeader(IStatus status) { if (fEncodingSupport != null) { String message = fEncodingSupport.getStatusHeader(status); if (message != null) return message; } return super.getStatusHeader(status); } /* * @see StatusTextEditor#getStatusBanner(IStatus) */ protected String getStatusBanner(IStatus status) { if (fEncodingSupport != null) { String message = fEncodingSupport.getStatusBanner(status); if (message != null) return message; } return super.getStatusBanner(status); } /* * @see StatusTextEditor#getStatusMessage(IStatus) */ protected String getStatusMessage(IStatus status) { if (fEncodingSupport != null) { String message = fEncodingSupport.getStatusMessage(status); if (message != null) return message; } return super.getStatusMessage(status); } /** The PHPEditor implementation of this * AbstractTextEditor method performs sets the * input of the outline page after AbstractTextEditor has set input. */ protected void doSetInput(IEditorInput input) throws CoreException { super.doSetInput(input); if (fEncodingSupport != null) fEncodingSupport.reset(); if (fOutlinePage != null) fOutlinePage.setInput(input); // setOutlinePageInput(fOutlinePage, input); } /* * @see org.phpeclipse.phpdt.internal.ui.viewsupport.IViewPartInputProvider#getViewPartInput() */ // public Object getViewPartInput() { // return getEditorInput().getAdapter(IFile.class); // } /** The PHPEditor implementation of this * AbstractTextEditor method adds any * PHPEditor specific entries. */ public void editorContextMenuAboutToShow(MenuManager menu) { super.editorContextMenuAboutToShow(menu); menu.appendToGroup(ITextEditorActionConstants.GROUP_UNDO, new Separator(IContextMenuConstants.GROUP_OPEN)); menu.insertAfter(IContextMenuConstants.GROUP_OPEN, new GroupMarker(IContextMenuConstants.GROUP_SHOW)); ActionContext context = new ActionContext(getSelectionProvider().getSelection()); fContextMenuGroup.setContext(context); fContextMenuGroup.fillContextMenu(menu); fContextMenuGroup.setContext(null); // addAction(menu, ITextEditorActionConstants.GROUP_EDIT, "Format"); //$NON-NLS-1$ // // ActionContext context = // new ActionContext(getSelectionProvider().getSelection()); // fContextMenuGroup.setContext(context); // fContextMenuGroup.fillContextMenu(menu); // fContextMenuGroup.setContext(null); } /** * Creates the outline page used with this editor. */ protected AbstractContentOutlinePage createOutlinePage() { AbstractContentOutlinePage page = new PHPContentOutlinePage(getDocumentProvider(), this); page.addSelectionChangedListener(fSelectionChangedListener); // setOutlinePageInput(page, getEditorInput()); if (getEditorInput() != null) fOutlinePage.setInput(getEditorInput()); return page; } /** * Informs the editor that its outliner has been closed. */ public void outlinePageClosed() { if (fOutlinePage != null) { fOutlinePage.removeSelectionChangedListener(fSelectionChangedListener); fOutlinePage = null; resetHighlightRange(); } } protected void updateStateDependentActions() { super.updateStateDependentActions(); fGenerateActionGroup.editorStateChanged(); } /** The PHPEditor implementation of this * AbstractTextEditor method performs gets * the java content outline page if request is for a an * outline page. */ public Object getAdapter(Class required) { if (IContentOutlinePage.class.equals(required)) { if (fOutlinePage == null) { fOutlinePage = new PHPContentOutlinePage(getDocumentProvider(), this); if (getEditorInput() != null) fOutlinePage.setInput(getEditorInput()); } return fOutlinePage; } if (IEncodingSupport.class.equals(required)) return fEncodingSupport; return super.getAdapter(required); } protected void doSelectionChanged(SelectionChangedEvent event) { // ISourceReference reference= null; // // ISelection selection= event.getSelection(); // Iterator iter= ((IStructuredSelection) selection).iterator(); // while (iter.hasNext()) { // Object o= iter.next(); // if (o instanceof ISourceReference) { // reference= (ISourceReference) o; // break; // } // } if (!isActivePart() && PHPeclipsePlugin.getActivePage() != null) PHPeclipsePlugin.getActivePage().bringToTop(this); // try { // editingScriptStarted(); // setSelection(reference, !isActivePart()); // } finally { // editingScriptEnded(); // } } protected boolean isActivePart() { IWorkbenchWindow window = getSite().getWorkbenchWindow(); IPartService service = window.getPartService(); IWorkbenchPart part = service.getActivePart(); return part != null && part.equals(this); } // public void openContextHelp() { // IDocument doc = this.getDocumentProvider().getDocument(this.getEditorInput()); // ITextSelection selection = (ITextSelection) this.getSelectionProvider().getSelection(); // int pos = selection.getOffset(); // String word = getFunctionName(doc, pos); // openContextHelp(word); // } // // private void openContextHelp(String word) { // open(word); // } // // public static void open(String word) { // IHelp help = WorkbenchHelp.getHelpSupport(); // if (help != null) { // IHelpResource helpResource = new PHPFunctionHelpResource(word); // WorkbenchHelp.getHelpSupport().displayHelpResource(helpResource); // } else { // // showMessage(shell, dialogTitle, ActionMessages.getString("Open help not available"), false); //$NON-NLS-1$ // } // } // private String getFunctionName(IDocument doc, int pos) { // Point word = PHPWordExtractor.findWord(doc, pos); // if (word != null) { // try { // return doc.get(word.x, word.y).replace('_', '-'); // } catch (BadLocationException e) { // } // } // return ""; // } /* * @see AbstractTextEditor#handlePreferenceStoreChanged(PropertyChangeEvent) */ protected void handlePreferenceStoreChanged(PropertyChangeEvent event) { try { ISourceViewer sourceViewer = getSourceViewer(); if (sourceViewer == null) return; String property = event.getProperty(); if (PreferenceConstants.EDITOR_TAB_WIDTH.equals(property)) { Object value = event.getNewValue(); if (value instanceof Integer) { sourceViewer.getTextWidget().setTabs(((Integer) value).intValue()); } else if (value instanceof String) { sourceViewer.getTextWidget().setTabs(Integer.parseInt((String) value)); } return; } if (OVERVIEW_RULER.equals(property)) { if (isOverviewRulerVisible()) showOverviewRuler(); else hideOverviewRuler(); return; } if (LINE_NUMBER_RULER.equals(property)) { if (isLineNumberRulerVisible()) showLineNumberRuler(); else hideLineNumberRuler(); return; } if (fLineNumberRulerColumn != null && (LINE_NUMBER_COLOR.equals(property) || PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT.equals(property) || PREFERENCE_COLOR_BACKGROUND.equals(property))) { initializeLineNumberRulerColumn(fLineNumberRulerColumn); } if (isJavaEditorHoverProperty(property)) { updateHoverBehavior(); } } finally { super.handlePreferenceStoreChanged(event); } } // /* // * @see AbstractTextEditor#handlePreferenceStoreChanged(PropertyChangeEvent) // */ // protected void handlePreferenceStoreChanged(PropertyChangeEvent event) { // // try { // // ISourceViewer sourceViewer = getSourceViewer(); // if (sourceViewer == null) // return; // // String property = event.getProperty(); // // // if (JavaSourceViewerConfiguration.PREFERENCE_TAB_WIDTH.equals(property)) { // // Object value= event.getNewValue(); // // if (value instanceof Integer) { // // sourceViewer.getTextWidget().setTabs(((Integer) value).intValue()); // // } else if (value instanceof String) { // // sourceViewer.getTextWidget().setTabs(Integer.parseInt((String) value)); // // } // // return; // // } // // if (IPreferenceConstants.LINE_NUMBER_RULER.equals(property)) { // if (isLineNumberRulerVisible()) // showLineNumberRuler(); // else // hideLineNumberRuler(); // return; // } // // if (fLineNumberRulerColumn != null // && (IPreferenceConstants.LINE_NUMBER_COLOR.equals(property) // || PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT.equals(property) // || PREFERENCE_COLOR_BACKGROUND.equals(property))) { // // initializeLineNumberRulerColumn(fLineNumberRulerColumn); // } // // } finally { // super.handlePreferenceStoreChanged(event); // } // } private boolean isJavaEditorHoverProperty(String property) { return PreferenceConstants.EDITOR_DEFAULT_HOVER.equals(property) || PreferenceConstants.EDITOR_NONE_HOVER.equals(property) || PreferenceConstants.EDITOR_CTRL_HOVER.equals(property) || PreferenceConstants.EDITOR_SHIFT_HOVER.equals(property) || PreferenceConstants.EDITOR_CTRL_ALT_HOVER.equals(property) || PreferenceConstants.EDITOR_CTRL_SHIFT_HOVER.equals(property) || PreferenceConstants.EDITOR_CTRL_ALT_SHIFT_HOVER.equals(property) || PreferenceConstants.EDITOR_ALT_SHIFT_HOVER.equals(property); } /** * Shows the line number ruler column. */ private void showLineNumberRuler() { IVerticalRuler v = getVerticalRuler(); if (v instanceof CompositeRuler) { CompositeRuler c = (CompositeRuler) v; c.addDecorator(1, createLineNumberRulerColumn()); } } /** * Return whether the browser like links should be enabled * according to the preference store settings. * @return true if the browser like links should be enabled */ private boolean isBrowserLikeLinks() { IPreferenceStore store = getPreferenceStore(); return store.getBoolean(BROWSER_LIKE_LINKS); } /** * Enables browser like links. */ private void enableBrowserLikeLinks() { if (fMouseListener == null) { fMouseListener = new MouseClickListener(); fMouseListener.install(); } } /** * Disables browser like links. */ private void disableBrowserLikeLinks() { if (fMouseListener != null) { fMouseListener.uninstall(); fMouseListener = null; } } /** * Handles a property change event describing a change * of the java core's preferences and updates the preference * related editor properties. * * @param event the property change event */ protected void handlePreferencePropertyChanged(org.eclipse.core.runtime.Preferences.PropertyChangeEvent event) { // if (COMPILER_TASK_TAGS.equals(event.getProperty())) { // ISourceViewer sourceViewer= getSourceViewer(); // if (sourceViewer != null && affectsTextPresentation(new PropertyChangeEvent(event.getSource(), event.getProperty(), event.getOldValue(), event.getNewValue()))) // sourceViewer.invalidateTextPresentation(); // } } /** * Return whether the line number ruler column should be * visible according to the preference store settings. * @return true if the line numbers should be visible */ private boolean isLineNumberRulerVisible() { IPreferenceStore store = getPreferenceStore(); return store.getBoolean(LINE_NUMBER_RULER); } /** * Hides the line number ruler column. */ private void hideLineNumberRuler() { IVerticalRuler v = getVerticalRuler(); if (v instanceof CompositeRuler) { CompositeRuler c = (CompositeRuler) v; try { c.removeDecorator(1); } catch (Throwable e) { } } } /** * Initializes the given line number ruler column from the preference store. * @param rulerColumn the ruler column to be initialized */ protected void initializeLineNumberRulerColumn(LineNumberRulerColumn rulerColumn) { JavaTextTools textTools = PHPeclipsePlugin.getDefault().getJavaTextTools(); IColorManager manager = textTools.getColorManager(); IPreferenceStore store = getPreferenceStore(); if (store != null) { RGB rgb = null; // foreground color if (store.contains(LINE_NUMBER_COLOR)) { if (store.isDefault(LINE_NUMBER_COLOR)) rgb = PreferenceConverter.getDefaultColor(store, LINE_NUMBER_COLOR); else rgb = PreferenceConverter.getColor(store, LINE_NUMBER_COLOR); } rulerColumn.setForeground(manager.getColor(rgb)); rgb = null; // background color if (!store.getBoolean(PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT)) { if (store.contains(PREFERENCE_COLOR_BACKGROUND)) { if (store.isDefault(PREFERENCE_COLOR_BACKGROUND)) rgb = PreferenceConverter.getDefaultColor(store, PREFERENCE_COLOR_BACKGROUND); else rgb = PreferenceConverter.getColor(store, PREFERENCE_COLOR_BACKGROUND); } } rulerColumn.setBackground(manager.getColor(rgb)); } } /** * Creates a new line number ruler column that is appropriately initialized. */ protected IVerticalRulerColumn createLineNumberRulerColumn() { fLineNumberRulerColumn = new LineNumberRulerColumn(); initializeLineNumberRulerColumn(fLineNumberRulerColumn); return fLineNumberRulerColumn; } /* * @see AbstractTextEditor#createVerticalRuler() */ protected IVerticalRuler createVerticalRuler() { CompositeRuler ruler = new CompositeRuler(); ruler.addDecorator(0, new AnnotationRulerColumn(VERTICAL_RULER_WIDTH)); if (isLineNumberRulerVisible()) ruler.addDecorator(1, createLineNumberRulerColumn()); return ruler; } private static IRegion getSignedSelection(ITextViewer viewer) { StyledText text = viewer.getTextWidget(); int caretOffset = text.getCaretOffset(); Point selection = text.getSelection(); // caret left int offset, length; if (caretOffset == selection.x) { offset = selection.y; length = selection.x - selection.y; // caret right } else { offset = selection.x; length = selection.y - selection.x; } return new Region(offset, length); } /** Preference key for matching brackets */ protected final static String MATCHING_BRACKETS = PreferenceConstants.EDITOR_MATCHING_BRACKETS; /** Preference key for matching brackets color */ protected final static String MATCHING_BRACKETS_COLOR = PreferenceConstants.EDITOR_MATCHING_BRACKETS_COLOR; /** Preference key for highlighting current line */ protected final static String CURRENT_LINE = PreferenceConstants.EDITOR_CURRENT_LINE; /** Preference key for highlight color of current line */ protected final static String CURRENT_LINE_COLOR = PreferenceConstants.EDITOR_CURRENT_LINE_COLOR; /** Preference key for showing print marging ruler */ protected final static String PRINT_MARGIN = PreferenceConstants.EDITOR_PRINT_MARGIN; /** Preference key for print margin ruler color */ protected final static String PRINT_MARGIN_COLOR = PreferenceConstants.EDITOR_PRINT_MARGIN_COLOR; /** Preference key for print margin ruler column */ protected final static String PRINT_MARGIN_COLUMN = PreferenceConstants.EDITOR_PRINT_MARGIN_COLUMN; /** Preference key for error indication */ protected final static String ERROR_INDICATION = PreferenceConstants.EDITOR_PROBLEM_INDICATION; /** Preference key for error color */ protected final static String ERROR_INDICATION_COLOR = PreferenceConstants.EDITOR_PROBLEM_INDICATION_COLOR; /** Preference key for warning indication */ protected final static String WARNING_INDICATION = PreferenceConstants.EDITOR_WARNING_INDICATION; /** Preference key for warning color */ protected final static String WARNING_INDICATION_COLOR = PreferenceConstants.EDITOR_WARNING_INDICATION_COLOR; /** Preference key for task indication */ protected final static String TASK_INDICATION = PreferenceConstants.EDITOR_TASK_INDICATION; /** Preference key for task color */ protected final static String TASK_INDICATION_COLOR = PreferenceConstants.EDITOR_TASK_INDICATION_COLOR; /** Preference key for bookmark indication */ protected final static String BOOKMARK_INDICATION = PreferenceConstants.EDITOR_BOOKMARK_INDICATION; /** Preference key for bookmark color */ protected final static String BOOKMARK_INDICATION_COLOR = PreferenceConstants.EDITOR_BOOKMARK_INDICATION_COLOR; /** Preference key for search result indication */ protected final static String SEARCH_RESULT_INDICATION = PreferenceConstants.EDITOR_SEARCH_RESULT_INDICATION; /** Preference key for search result color */ protected final static String SEARCH_RESULT_INDICATION_COLOR = PreferenceConstants.EDITOR_SEARCH_RESULT_INDICATION_COLOR; /** Preference key for unknown annotation indication */ protected final static String UNKNOWN_INDICATION = PreferenceConstants.EDITOR_UNKNOWN_INDICATION; /** Preference key for unknown annotation color */ protected final static String UNKNOWN_INDICATION_COLOR = PreferenceConstants.EDITOR_UNKNOWN_INDICATION_COLOR; /** Preference key for shwoing the overview ruler */ protected final static String OVERVIEW_RULER = PreferenceConstants.EDITOR_OVERVIEW_RULER; /** Preference key for error indication in overview ruler */ protected final static String ERROR_INDICATION_IN_OVERVIEW_RULER = PreferenceConstants.EDITOR_ERROR_INDICATION_IN_OVERVIEW_RULER; /** Preference key for warning indication in overview ruler */ protected final static String WARNING_INDICATION_IN_OVERVIEW_RULER = PreferenceConstants.EDITOR_WARNING_INDICATION_IN_OVERVIEW_RULER; /** Preference key for task indication in overview ruler */ protected final static String TASK_INDICATION_IN_OVERVIEW_RULER = PreferenceConstants.EDITOR_TASK_INDICATION_IN_OVERVIEW_RULER; /** Preference key for bookmark indication in overview ruler */ protected final static String BOOKMARK_INDICATION_IN_OVERVIEW_RULER = PreferenceConstants.EDITOR_BOOKMARK_INDICATION_IN_OVERVIEW_RULER; /** Preference key for search result indication in overview ruler */ protected final static String SEARCH_RESULT_INDICATION_IN_OVERVIEW_RULER = PreferenceConstants.EDITOR_SEARCH_RESULT_INDICATION_IN_OVERVIEW_RULER; /** Preference key for unknown annotation indication in overview ruler */ protected final static String UNKNOWN_INDICATION_IN_OVERVIEW_RULER = PreferenceConstants.EDITOR_UNKNOWN_INDICATION_IN_OVERVIEW_RULER; // /** Preference key for compiler task tags */ // private final static String COMPILER_TASK_TAGS= JavaCore.COMPILER_TASK_TAGS; /** Preference key for browser like links */ private final static String BROWSER_LIKE_LINKS = PreferenceConstants.EDITOR_BROWSER_LIKE_LINKS; /** Preference key for key modifier of browser like links */ private final static String BROWSER_LIKE_LINKS_KEY_MODIFIER = PreferenceConstants.EDITOR_BROWSER_LIKE_LINKS_KEY_MODIFIER; /** * Preference key for key modifier mask of browser like links. * The value is only used if the value of EDITOR_BROWSER_LIKE_LINKS * cannot be resolved to valid SWT modifier bits. * * @since 2.1.1 */ private final static String BROWSER_LIKE_LINKS_KEY_MODIFIER_MASK = PreferenceConstants.EDITOR_BROWSER_LIKE_LINKS_KEY_MODIFIER_MASK; private final static char[] BRACKETS = { '{', '}', '(', ')', '[', ']' }; private static boolean isBracket(char character) { for (int i = 0; i != BRACKETS.length; ++i) if (character == BRACKETS[i]) return true; return false; } private static boolean isSurroundedByBrackets(IDocument document, int offset) { if (offset == 0 || offset == document.getLength()) return false; try { return isBracket(document.getChar(offset - 1)) && isBracket(document.getChar(offset)); } catch (BadLocationException e) { return false; } } protected void configureSourceViewerDecorationSupport() { fSourceViewerDecorationSupport.setCharacterPairMatcher(fBracketMatcher); fSourceViewerDecorationSupport.setAnnotationPainterPreferenceKeys( AnnotationType.UNKNOWN, UNKNOWN_INDICATION_COLOR, UNKNOWN_INDICATION, UNKNOWN_INDICATION_IN_OVERVIEW_RULER, 0); fSourceViewerDecorationSupport.setAnnotationPainterPreferenceKeys( AnnotationType.BOOKMARK, BOOKMARK_INDICATION_COLOR, BOOKMARK_INDICATION, BOOKMARK_INDICATION_IN_OVERVIEW_RULER, 1); fSourceViewerDecorationSupport.setAnnotationPainterPreferenceKeys( AnnotationType.TASK, TASK_INDICATION_COLOR, TASK_INDICATION, TASK_INDICATION_IN_OVERVIEW_RULER, 2); fSourceViewerDecorationSupport.setAnnotationPainterPreferenceKeys( AnnotationType.SEARCH, SEARCH_RESULT_INDICATION_COLOR, SEARCH_RESULT_INDICATION, SEARCH_RESULT_INDICATION_IN_OVERVIEW_RULER, 3); fSourceViewerDecorationSupport.setAnnotationPainterPreferenceKeys( AnnotationType.WARNING, WARNING_INDICATION_COLOR, WARNING_INDICATION, WARNING_INDICATION_IN_OVERVIEW_RULER, 4); fSourceViewerDecorationSupport.setAnnotationPainterPreferenceKeys( AnnotationType.ERROR, ERROR_INDICATION_COLOR, ERROR_INDICATION, ERROR_INDICATION_IN_OVERVIEW_RULER, 5); fSourceViewerDecorationSupport.setCursorLinePainterPreferenceKeys(CURRENT_LINE, CURRENT_LINE_COLOR); fSourceViewerDecorationSupport.setMarginPainterPreferenceKeys(PRINT_MARGIN, PRINT_MARGIN_COLOR, PRINT_MARGIN_COLUMN); fSourceViewerDecorationSupport.setMatchingCharacterPainterPreferenceKeys(MATCHING_BRACKETS, MATCHING_BRACKETS_COLOR); fSourceViewerDecorationSupport.setSymbolicFontName(getFontPropertyPreferenceKey()); } /** * Jumps to the matching bracket. */ public void gotoMatchingBracket() { ISourceViewer sourceViewer = getSourceViewer(); IDocument document = sourceViewer.getDocument(); if (document == null) return; IRegion selection = getSignedSelection(sourceViewer); int selectionLength = Math.abs(selection.getLength()); if (selectionLength > 1) { setStatusLineErrorMessage(PHPEditorMessages.getString("GotoMatchingBracket.error.invalidSelection")); //$NON-NLS-1$ sourceViewer.getTextWidget().getDisplay().beep(); return; } // #26314 int sourceCaretOffset = selection.getOffset() + selection.getLength(); if (isSurroundedByBrackets(document, sourceCaretOffset)) sourceCaretOffset -= selection.getLength(); IRegion region = fBracketMatcher.match(document, sourceCaretOffset); if (region == null) { setStatusLineErrorMessage(PHPEditorMessages.getString("GotoMatchingBracket.error.noMatchingBracket")); //$NON-NLS-1$ sourceViewer.getTextWidget().getDisplay().beep(); return; } int offset = region.getOffset(); int length = region.getLength(); if (length < 1) return; int anchor = fBracketMatcher.getAnchor(); int targetOffset = (PHPPairMatcher.RIGHT == anchor) ? offset : offset + length - 1; boolean visible = false; if (sourceViewer instanceof ITextViewerExtension3) { ITextViewerExtension3 extension = (ITextViewerExtension3) sourceViewer; visible = (extension.modelOffset2WidgetOffset(targetOffset) > -1); } else { IRegion visibleRegion = sourceViewer.getVisibleRegion(); visible = (targetOffset >= visibleRegion.getOffset() && targetOffset < visibleRegion.getOffset() + visibleRegion.getLength()); } if (!visible) { setStatusLineErrorMessage(PHPEditorMessages.getString("GotoMatchingBracket.error.bracketOutsideSelectedElement")); //$NON-NLS-1$ sourceViewer.getTextWidget().getDisplay().beep(); return; } if (selection.getLength() < 0) targetOffset -= selection.getLength(); sourceViewer.setSelectedRange(targetOffset, selection.getLength()); sourceViewer.revealRange(targetOffset, selection.getLength()); } /** * Ses the given message as error message to this editor's status line. * @param msg message to be set */ protected void setStatusLineErrorMessage(String msg) { IEditorStatusLine statusLine = (IEditorStatusLine) getAdapter(IEditorStatusLine.class); if (statusLine != null) statusLine.setMessage(true, msg, null); } /** * Returns a segmentation of the line of the given document appropriate for bidi rendering. * The default implementation returns only the string literals of a php code line as segments. * * @param document the document * @param lineOffset the offset of the line * @return the line's bidi segmentation * @throws BadLocationException in case lineOffset is not valid in document */ public static int[] getBidiLineSegments(IDocument document, int lineOffset) throws BadLocationException { IRegion line = document.getLineInformationOfOffset(lineOffset); ITypedRegion[] linePartitioning = document.computePartitioning(lineOffset, line.getLength()); List segmentation = new ArrayList(); for (int i = 0; i < linePartitioning.length; i++) { if (IPHPPartitionScannerConstants.PHP_STRING.equals(linePartitioning[i].getType())) segmentation.add(linePartitioning[i]); } if (segmentation.size() == 0) return null; int size = segmentation.size(); int[] segments = new int[size * 2 + 1]; int j = 0; for (int i = 0; i < size; i++) { ITypedRegion segment = (ITypedRegion) segmentation.get(i); if (i == 0) segments[j++] = 0; int offset = segment.getOffset() - lineOffset; if (offset > segments[j - 1]) segments[j++] = offset; if (offset + segment.getLength() >= line.getLength()) break; segments[j++] = offset + segment.getLength(); } if (j < segments.length) { int[] result = new int[j]; System.arraycopy(segments, 0, result, 0, j); segments = result; } return segments; } /** * Returns a segmentation of the given line appropriate for bidi rendering. The default * implementation returns only the string literals of a php code line as segments. * * @param lineOffset the offset of the line * @param line the content of the line * @return the line's bidi segmentation */ protected int[] getBidiLineSegments(int lineOffset, String line) { IDocumentProvider provider = getDocumentProvider(); if (provider != null && line != null && line.length() > 0) { IDocument document = provider.getDocument(getEditorInput()); if (document != null) try { return getBidiLineSegments(document, lineOffset); } catch (BadLocationException x) { // ignore } } return null; } /* * @see AbstractTextEditor#createSourceViewer(Composite, IVerticalRuler, int) */ // protected final ISourceViewer createSourceViewer( // Composite parent, // IVerticalRuler ruler, // int styles) { // ISourceViewer viewer = createJavaSourceViewer(parent, ruler, styles); // StyledText text = viewer.getTextWidget(); // text.addBidiSegmentListener(new BidiSegmentListener() { // public void lineGetSegments(BidiSegmentEvent event) { // event.segments = getBidiLineSegments(event.lineOffset, event.lineText); // } // }); // // JavaUIHelp.setHelp(this, text, IJavaHelpContextIds.JAVA_EDITOR); // return viewer; // } protected final ISourceViewer createSourceViewer(Composite parent, IVerticalRuler verticalRuler, int styles) { ISharedTextColors sharedColors = PHPeclipsePlugin.getDefault().getJavaTextTools().getColorManager(); fOverviewRuler = new OverviewRuler(fAnnotationAccess, VERTICAL_RULER_WIDTH, sharedColors); fOverviewRuler.addHeaderAnnotationType(AnnotationType.WARNING); fOverviewRuler.addHeaderAnnotationType(AnnotationType.ERROR); ISourceViewer viewer = createJavaSourceViewer(parent, verticalRuler, fOverviewRuler, isOverviewRulerVisible(), styles); StyledText text = viewer.getTextWidget(); text.addBidiSegmentListener(new BidiSegmentListener() { public void lineGetSegments(BidiSegmentEvent event) { event.segments = getBidiLineSegments(event.lineOffset, event.lineText); } }); // JavaUIHelp.setHelp(this, text, IJavaHelpContextIds.JAVA_EDITOR); fSourceViewerDecorationSupport = new SourceViewerDecorationSupport(viewer, fOverviewRuler, fAnnotationAccess, sharedColors); configureSourceViewerDecorationSupport(); return viewer; } protected void showOverviewRuler() { if (fOverviewRuler != null) { if (getSourceViewer() instanceof ISourceViewerExtension) { ((ISourceViewerExtension) getSourceViewer()).showAnnotationsOverview(true); fSourceViewerDecorationSupport.updateOverviewDecorations(); } } } protected void hideOverviewRuler() { if (getSourceViewer() instanceof ISourceViewerExtension) { fSourceViewerDecorationSupport.hideAnnotationOverview(); ((ISourceViewerExtension) getSourceViewer()).showAnnotationsOverview(false); } } protected boolean isOverviewRulerVisible() { IPreferenceStore store = getPreferenceStore(); return store.getBoolean(OVERVIEW_RULER); } /* * @see AbstractTextEditor#createSourceViewer(Composite, IVerticalRuler, int) */ protected ISourceViewer createJavaSourceViewer( Composite parent, IVerticalRuler ruler, IOverviewRuler overviewRuler, boolean isOverviewRulerVisible, int styles) { return new SourceViewer(parent, ruler, overviewRuler, isOverviewRulerVisible(), styles); // return super.createSourceViewer(parent, ruler, styles); } /* * @see AbstractTextEditor#affectsTextPresentation(PropertyChangeEvent) */ protected boolean affectsTextPresentation(PropertyChangeEvent event) { JavaTextTools textTools = PHPeclipsePlugin.getDefault().getJavaTextTools(); return textTools.affectsBehavior(event); } }