// Copyright (c) 2006 by Leif Frenzel <himself@leiffrenzel.de> // All rights reserved. package net.sf.eclipsefp.haskell.ui.internal.editors.cabal; import java.util.Iterator; import net.sf.eclipsefp.haskell.core.cabalmodel.PackageDescription; import net.sf.eclipsefp.haskell.core.cabalmodel.PackageDescriptionStanza; import net.sf.eclipsefp.haskell.ui.HaskellUIPlugin; import net.sf.eclipsefp.haskell.ui.editor.actions.IEditorActionDefinitionIds; import net.sf.eclipsefp.haskell.ui.internal.editors.cabal.outline.CabalOutlinePage; import net.sf.eclipsefp.haskell.ui.internal.editors.haskell.HaskellEditor; import net.sf.eclipsefp.haskell.ui.internal.editors.haskell.QuickFixAction; import net.sf.eclipsefp.haskell.ui.internal.editors.text.HaskellViewer; import net.sf.eclipsefp.haskell.ui.internal.resolve.SelectAnnotationForQuickFix; import net.sf.eclipsefp.haskell.ui.internal.util.UITexts; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.text.source.IVerticalRuler; import org.eclipse.jface.text.source.IVerticalRulerInfo; import org.eclipse.jface.text.source.SourceViewer; import org.eclipse.jface.text.source.projection.ProjectionSupport; import org.eclipse.jface.text.source.projection.ProjectionViewer; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.contexts.IContextService; import org.eclipse.ui.editors.text.TextEditor; import org.eclipse.ui.texteditor.ITextEditorActionConstants; import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; import org.eclipse.ui.texteditor.MarkerAnnotation; import org.eclipse.ui.views.contentoutline.IContentOutlinePage; /** <p>an editor for Cabal package description files.</p> * * <p>Note: this class is declared in <code>plugin.xml</code>.</p> * * @author Leif Frenzel */ public class CabalEditor extends TextEditor { private CabalOutlinePage outlinePage; private ProjectionSupport projectionSupport; private final CabalFormEditor formEditor; /** The key binding context active while the Cabal editor is active */ private static final String CONTEXT_ID = CabalEditor.class.getName() + ".context"; //$NON-NLS-1$ public CabalEditor(final CabalFormEditor formEditor) { this.formEditor=formEditor; setSourceViewerConfiguration( new CabalConfiguration( formEditor ) ); } IDocument getDocument() { IDocument result = null; if( getSourceViewer() != null ) { result = getSourceViewer().getDocument(); } return result; } public void setPackageDescription( final PackageDescription packageDescription ) { if( outlinePage != null ) { outlinePage.setPackageDescription( packageDescription ); } } public void selectAndReveal( final Object element ) { if( element instanceof PackageDescriptionStanza ) { PackageDescriptionStanza stanza = (PackageDescriptionStanza) element; IDocument doc = getSourceViewer().getDocument(); try { int offset = doc.getLineOffset( stanza.getStartLine() ); int end = doc.getLength(); try { end = doc.getLineOffset( stanza.getEndLine()-1 ) + doc.getLineLength( stanza.getEndLine()-1 ); } catch( final BadLocationException badlox ) { // ignore } int length = end - offset; selectAndReveal( offset, length ); } catch( final BadLocationException badlox ) { // ignore } } } // interface methods of TextEditor ////////////////////////////////// @Override protected ISourceViewer createSourceViewer( final Composite parent, final IVerticalRuler ruler, final int styles ) { fOverviewRuler = createOverviewRuler( getSharedColors() ); ISourceViewer viewer = new HaskellViewer( parent, ruler, fOverviewRuler, true, styles ); // ensure decoration support has been created and configured: getSourceViewerDecorationSupport( viewer ); return viewer; } @Override public void createPartControl( final Composite parent ) { super.createPartControl( parent ); ProjectionViewer pv = ( ProjectionViewer )getSourceViewer(); projectionSupport = new ProjectionSupport( pv, getAnnotationAccess(), getSharedColors() ); projectionSupport.install(); projectionSupport.addSummarizableAnnotationType("org.eclipse.ui.workbench.texteditor.error"); //$NON-NLS-1$ projectionSupport.addSummarizableAnnotationType("org.eclipse.ui.workbench.texteditor.warning"); //$NON-NLS-1$ pv.doOperation( ProjectionViewer.TOGGLE ); activateContext(); } private void activateContext() { IContextService contextService = ( IContextService )getSite().getService( IContextService.class ); contextService.activateContext( CONTEXT_ID ); } @Override protected void createActions() { super.createActions(); HaskellViewer.createTextOpAction(this, "ContentAssist.", "ContentAssistProposal", ISourceViewer.CONTENTASSIST_PROPOSALS, ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS ); // comment/uncomment HaskellViewer.createTextOpAction(this, HaskellEditor.LINE_COMMENT_ACTION, HaskellEditor.commentResourcePrefix, HaskellViewer.TOGGLE_COMMENT, IEditorActionDefinitionIds.COMMENT ); // HaskellEditor.createTextOpAction(this, HaskellEditor.LINE_UNCOMMENT_ACTION, HaskellEditor.uncommentResourcePrefix, ITextOperationTarget.STRIP_PREFIX, // IEditorActionDefinitionIds.UNCOMMENT ); addRulerContextMenuListener( new IMenuListener() { @Override public void menuAboutToShow( final IMenuManager manager ) { IVerticalRulerInfo service= (IVerticalRulerInfo)getAdapter(IVerticalRulerInfo.class); if (service!=null){ int line=service.getLineOfLastMouseButtonActivity(); for (Iterator<?> it=getSourceViewer().getAnnotationModel().getAnnotationIterator();it.hasNext();){ Annotation ann = (Annotation) it.next(); if (ann instanceof MarkerAnnotation){ Position p=getSourceViewer().getAnnotationModel().getPosition( ann ); try { if (p!=null && getDocument().getLineOfOffset(p.getOffset())==line){ if (((ProjectionViewer)getSourceViewer()).getQuickAssistAssistant().canFix( ann )){ IAction action=new SelectAnnotationForQuickFix( CabalEditor.this , (SourceViewer)getSourceViewer(), (MarkerAnnotation)ann ); manager.add( action ); //return; } } } catch (BadLocationException ble){ // ignore } } } } } }); QuickFixAction action = new QuickFixAction(HaskellUIPlugin.getDefault().getResourceBundle(), "RulerQuickFixAction", this, getVerticalRuler()); //$NON-NLS-1$ setAction(ITextEditorActionConstants.RULER_CLICK, action); } @Override protected void initializeEditor() { super.initializeEditor(); } @Override public void editorContextMenuAboutToShow( final IMenuManager menu ) { super.editorContextMenuAboutToShow( menu ); if( isEditable() ) { IMenuManager mmSource = new MenuManager( UITexts.editor_actions_source, "source" ); //$NON-NLS-1$ menu.prependToGroup( ITextEditorActionConstants.GROUP_EDIT, mmSource ); mmSource.add( new Separator( "comments" ) ); //$NON-NLS-1$ addAction( mmSource, "comments", HaskellEditor.LINE_COMMENT_ACTION ); //$NON-NLS-1$ addAction( mmSource, "comments", HaskellEditor.LINE_UNCOMMENT_ACTION ); //$NON-NLS-1$ } } // interface methods of IAdaptable ////////////////////////////////// @Override public Object getAdapter( @SuppressWarnings("rawtypes") final Class adapterType ) { Object result = null; if( IContentOutlinePage.class.equals( adapterType ) ) { if( outlinePage == null ) { outlinePage = new CabalOutlinePage( this, formEditor.getPackageDescription() ); } result = outlinePage; } else if( projectionSupport != null ) { Object adapter = projectionSupport.getAdapter( getSourceViewer(), adapterType ); if( adapter != null ) { result = adapter; } } if( result == null ) { result = super.getAdapter( adapterType ); } return result; } }