X-Git-Url: http://git.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditor.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditor.java index 86ca2c9..fc5da20 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditor.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditor.java @@ -11,13 +11,22 @@ Contributors: IBM Corporation - Initial implementation Klaus Hartlage - www.eclipseproject.de **********************************************************************/ +import java.util.ArrayList; +import java.util.List; + 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.PreferenceConstants; import net.sourceforge.phpdt.ui.actions.GenerateActionGroup; -import net.sourceforge.phpeclipse.IPreferenceConstants; +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.PHPCodeScanner; -import net.sourceforge.phpeclipse.phpeditor.util.PHPColorProvider; +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.jface.action.Action; @@ -25,489 +34,874 @@ import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.MenuManager; 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.IDocument; +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.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.Region; +import org.eclipse.jface.text.information.InformationPresenter; import org.eclipse.jface.text.source.AnnotationRulerColumn; import org.eclipse.jface.text.source.CompositeRuler; import org.eclipse.jface.text.source.ISourceViewer; 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.util.IPropertyChangeListener; +import org.eclipse.jface.text.source.SourceViewerConfiguration; import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.BidiSegmentEvent; +import org.eclipse.swt.custom.BidiSegmentListener; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.actions.ActionContext; import org.eclipse.ui.actions.ActionGroup; -import org.eclipse.ui.editors.text.TextEditor; import org.eclipse.ui.texteditor.ContentAssistAction; import org.eclipse.ui.texteditor.DefaultRangeIndicator; +import org.eclipse.ui.texteditor.IDocumentProvider; +import org.eclipse.ui.texteditor.IEditorStatusLine; import org.eclipse.ui.texteditor.ITextEditorActionConstants; +import org.eclipse.ui.texteditor.StatusTextEditor; import org.eclipse.ui.texteditor.TextOperationAction; import org.eclipse.ui.views.contentoutline.IContentOutlinePage; /** * PHP specific text editor. */ -public class PHPEditor extends TextEditor { - - // protected PHPActionGroup fActionGroups; - /** The outline page */ - private PHPContentOutlinePage fOutlinePage; - private IPreferenceStore phpPrefStore; - - /** The line number ruler column */ - private LineNumberRulerColumn fLineNumberRulerColumn; - - protected CompositeActionGroup fActionGroups; - /** The standard action groups added to the menu */ - private GenerateActionGroup fGenerateActionGroup; - private CompositeActionGroup fContextMenuGroup; - /** - * Default constructor. - */ - public PHPEditor() { - super(); - setRulerContextMenuId("#PHPRulerContext"); //$NON-NLS-1$ - } -// -// /** -// * @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(); -// } - - /** - * 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 PHPContentOutlinePage 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(); - - Action action; - // setAction( - // "ContentAssistProposal", - // new TextOperationAction( - // PHPEditorMessages.getResourceBundle(), - // "ContentAssistProposal.", - // this, - // ISourceViewer.CONTENTASSIST_PROPOSALS)); - action = new ContentAssistAction(PHPEditorMessages.getResourceBundle(), "ContentAssistProposal.", this); //$NON-NLS-1$ - action.setActionDefinitionId( - PHPEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS); - setAction("ContentAssistProposal", action); //$NON-NLS-1$ - - // System.out.println(action.getId()); - // System.out.println(action.getActionDefinitionId()); - - setAction( - "ContentAssistTip", - new TextOperationAction( - PHPEditorMessages.getResourceBundle(), - "ContentAssistTip.", - this, - ISourceViewer.CONTENTASSIST_CONTEXT_INFORMATION)); - - action = - new TextOperationAction( - PHPEditorMessages.getResourceBundle(), - "Comment.", - this, - ITextOperationTarget.PREFIX); - action.setActionDefinitionId(PHPEditorActionDefinitionIds.COMMENT); - setAction("Comment", action); - - // System.out.println(action.getId()); - // System.out.println(action.getActionDefinitionId()); - - action = - new TextOperationAction( - PHPEditorMessages.getResourceBundle(), - "Uncomment.", - this, - ITextOperationTarget.STRIP_PREFIX); - action.setActionDefinitionId(PHPEditorActionDefinitionIds.UNCOMMENT); - setAction("Uncomment", action); - - // System.out.println(action.getId()); - // System.out.println(action.getActionDefinitionId()); - - // fActionGroups = new PHPActionGroup(this, ITextEditorActionConstants.GROUP_EDIT); - - markAsStateDependentAction("Comment", true); //$NON-NLS-1$ - markAsStateDependentAction("Uncomment", true); //$NON-NLS-1$ - - 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)}); - } - - /** 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(); - - 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 = phpPrefStore; - if (store.getBoolean(PHPeclipsePlugin.PHP_PARSE_ON_SAVE)) { - IAction a = PHPParserAction.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(); - } - - /** The PHPEditor implementation of this - * AbstractTextEditor method performs sets the - * input of the outline page after AbstractTextEditor has set input. - */ - public void doSetInput(IEditorInput input) throws CoreException { - super.doSetInput(input); - if (fOutlinePage != null) - fOutlinePage.setInput(input); - } - - /** The PHPEditor implementation of this - * AbstractTextEditor method adds any - * PHPEditor specific entries. - */ - public void editorContextMenuAboutToShow(MenuManager menu) { - super.editorContextMenuAboutToShow(menu); - // addAction(menu, "ContentAssistProposal"); //$NON-NLS-1$ - // addAction(menu, "ContentAssistTip"); //$NON-NLS-1$ - - // fActionGroups.fillContextMenu(menu); - - ActionContext context = - new ActionContext(getSelectionProvider().getSelection()); - fContextMenuGroup.setContext(context); - fContextMenuGroup.fillContextMenu(menu); - fContextMenuGroup.setContext(null); - } - - 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; - } - return super.getAdapter(required); - } - - // 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 (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); - } - } - /** - * 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 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 phpPrefStore.getBoolean(IPreferenceConstants.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= JavaPlugin.getDefault().getJavaTextTools(); - PHPColorProvider manager = PHPEditorEnvironment.getPHPColorProvider(); - - if (phpPrefStore != null) { - - RGB rgb = null; - // foreground color - if (phpPrefStore - .contains(IPreferenceConstants.LINE_NUMBER_COLOR)) { - if (phpPrefStore - .isDefault(IPreferenceConstants.LINE_NUMBER_COLOR)) - rgb = - PreferenceConverter.getDefaultColor( - phpPrefStore, - IPreferenceConstants.LINE_NUMBER_COLOR); - else - rgb = - PreferenceConverter.getColor( - phpPrefStore, - IPreferenceConstants.LINE_NUMBER_COLOR); - } - rulerColumn.setForeground(manager.getColor(rgb)); - - rgb = null; - // background color - if (!phpPrefStore - .getBoolean( - IPreferenceConstants - .PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT)) { - if (phpPrefStore - .contains( - IPreferenceConstants.PREFERENCE_COLOR_BACKGROUND)) { - if (phpPrefStore - .isDefault( - IPreferenceConstants.PREFERENCE_COLOR_BACKGROUND)) - rgb = - PreferenceConverter.getDefaultColor( - phpPrefStore, - IPreferenceConstants - .PREFERENCE_COLOR_BACKGROUND); - else - rgb = - PreferenceConverter.getColor( - phpPrefStore, - IPreferenceConstants - .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; - } - - /* (non-Javadoc) - * Method declared on AbstractTextEditor - */ - protected void initializeEditor() { - PHPEditorEnvironment.connect(this); - - setSourceViewerConfiguration(new PHPSourceViewerConfiguration()); - setRangeIndicator(new DefaultRangeIndicator()); - setEditorContextMenuId("#PHPEditorContext"); //$NON-NLS-1$ - setRulerContextMenuId("#PHPRulerContext"); //$NON-NLS-1$ - // setDocumentProvider(PHPeclipsePlugin.getCompilationUnitDocumentProvider()); - phpPrefStore = PHPeclipsePlugin.getDefault().getPreferenceStore(); - - phpPrefStore.addPropertyChangeListener(new IPropertyChangeListener() { - public void propertyChange(PropertyChangeEvent event) { - PHPCodeScanner scanner = - PHPEditorEnvironment.getPHPCodeScanner(); - if (scanner != null) { - scanner.updateToken( - PHPEditorEnvironment.getPHPColorProvider()); - } - if (getSourceViewer() != null) { - getSourceViewer().invalidateTextPresentation(); - } - - String property = event.getProperty(); - if (IPreferenceConstants.LINE_NUMBER_RULER.equals(property)) { - if (isLineNumberRulerVisible()) - showLineNumberRuler(); - else - hideLineNumberRuler(); - return; - } - } - }); - } +public class PHPEditor + extends StatusTextEditor + implements IViewPartInputProvider { // extends TextEditor { + + /** 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 PHPContentOutlinePage fOutlinePage; + + // protected PHPSyntaxParserThread fValidationThread = null; + + // private IPreferenceStore fPHPPrefStore; + + /** The editor's bracket matcher */ + private PHPPairMatcher fBracketMatcher; + /** The line number ruler column */ + private LineNumberRulerColumn fLineNumberRulerColumn; + + protected CompositeActionGroup fActionGroups; + /** The standard action groups added to the menu */ + private GenerateActionGroup fGenerateActionGroup; + private CompositeActionGroup fContextMenuGroup; + + /** The information presenter. */ + private InformationPresenter fInformationPresenter; + + /** + * Default constructor. + */ + public PHPEditor() { + super(); + JavaTextTools textTools = PHPeclipsePlugin.getDefault().getJavaTextTools(); + setSourceViewerConfiguration( + new PHPSourceViewerConfiguration(textTools, this)); + setRangeIndicator(new DefaultRangeIndicator()); + setPreferenceStore(PHPeclipsePlugin.getDefault().getPreferenceStore()); + + // if (PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_SYNC_OUTLINE_ON_CURSOR_MOVE)) + // fUpdater= new OutlinePageSelectionUpdater(); + + initializeEditor(); + } + // + // /** + // * @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(); + // } + + /* + * 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); + + 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 PHPContentOutlinePage 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(); + + Action action; + // setAction( + // "ContentAssistProposal", + // new TextOperationAction( + // PHPEditorMessages.getResourceBundle(), + // "ContentAssistProposal.", + // this, + // ISourceViewer.CONTENTASSIST_PROPOSALS)); + action = new ContentAssistAction(PHPEditorMessages.getResourceBundle(), "ContentAssistProposal.", this); //$NON-NLS-1$ + action.setActionDefinitionId( + PHPEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS); + setAction("ContentAssistProposal", action); //$NON-NLS-1$ + + setAction( + "ContentAssistTip", + new TextOperationAction( + PHPEditorMessages.getResourceBundle(), + "ContentAssistTip.", + this, + ISourceViewer.CONTENTASSIST_CONTEXT_INFORMATION)); + + action = + new TextOperationAction( + PHPEditorMessages.getResourceBundle(), + "Comment.", + this, + ITextOperationTarget.PREFIX); + action.setActionDefinitionId(PHPEditorActionDefinitionIds.COMMENT); + setAction("Comment", action); + + action = + new TextOperationAction( + PHPEditorMessages.getResourceBundle(), + "Uncomment.", + this, + ITextOperationTarget.STRIP_PREFIX); + action.setActionDefinitionId(PHPEditorActionDefinitionIds.UNCOMMENT); + setAction("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("ContentAssistProposal", true); //$NON-NLS-1$ + markAsStateDependentAction("Comment", true); //$NON-NLS-1$ + markAsStateDependentAction("Uncomment", true); //$NON-NLS-1$ + markAsStateDependentAction("Format", true); //$NON-NLS-1$ + + 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(); + + 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(); // fPHPPrefStore; + if (store.getBoolean(PHPeclipsePlugin.PHP_PARSE_ON_SAVE)) { + IAction a = PHPParserAction.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(); + } + + /** 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 (fOutlinePage != null) + fOutlinePage.setInput(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); + + addAction(menu, ITextEditorActionConstants.GROUP_EDIT, "Format"); //$NON-NLS-1$ + + ActionContext context = + new ActionContext(getSelectionProvider().getSelection()); + fContextMenuGroup.setContext(context); + fContextMenuGroup.fillContextMenu(menu); + fContextMenuGroup.setContext(null); + } + + 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; + } + return super.getAdapter(required); + } + + // 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 (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 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; + } + + /* (non-Javadoc) + * Method declared on TextEditor + */ + protected void initializeEditor() { + IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore(); + PHPEditorEnvironment.connect(this); + + // store.addPropertyChangeListener(new IPropertyChangeListener() { + // public void propertyChange(PropertyChangeEvent event) { + // PHPCodeScanner scanner = PHPEditorEnvironment.getPHPCodeScanner(); + // if (scanner != null) { + // scanner.updateToken(PHPEditorEnvironment.getPHPColorProvider()); + // } + // if (getSourceViewer() != null) { + // getSourceViewer().invalidateTextPresentation(); + // } + // + // String property = event.getProperty(); + // if (IPreferenceConstants.LINE_NUMBER_RULER.equals(property)) { + // if (isLineNumberRulerVisible()) + // showLineNumberRuler(); + // else + // hideLineNumberRuler(); + // return; + // } + // } + // }); + } + + 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); + } + + 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; + } + } + /** + * Jumps to the matching bracket. + */ + public void gotoMatchingBracket() { + + if (fBracketMatcher == null) + fBracketMatcher = new PHPPairMatcher(BRACKETS); + + 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; + } + + /* + * @see AbstractTextEditor#createSourceViewer(Composite, IVerticalRuler, int) + */ + protected ISourceViewer createJavaSourceViewer( + Composite parent, + IVerticalRuler ruler, + int styles) { + return super.createSourceViewer(parent, ruler, styles); + } }