/******************************************************************************* * Copyright (c) 2008 ARM Limited and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * ARM Limited - Initial API and implementation *******************************************************************************/ package org.eclipse.cdt.debug.internal.ui.disassembly.viewer; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.eclipse.cdt.debug.internal.ui.IInternalCDebugUIConstants; import org.eclipse.core.runtime.Assert; 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.preference.IPreferenceStore; import org.eclipse.jface.resource.JFaceResources; 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.IVerticalRuler; import org.eclipse.jface.text.source.IVerticalRulerColumn; import org.eclipse.jface.text.source.OverviewRuler; import org.eclipse.jface.text.source.SourceViewerConfiguration; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Menu; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.editors.text.EditorsUI; import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants; import org.eclipse.ui.texteditor.AnnotationPreference; import org.eclipse.ui.texteditor.DefaultMarkerAnnotationAccess; import org.eclipse.ui.texteditor.DefaultRangeIndicator; import org.eclipse.ui.texteditor.ITextEditorActionConstants; import org.eclipse.ui.texteditor.IUpdate; import org.eclipse.ui.texteditor.MarkerAnnotationPreferences; import org.eclipse.ui.texteditor.SourceViewerDecorationSupport; public class DisassemblyPane implements IPropertyChangeListener { private final static int VERTICAL_RULER_WIDTH = 12; private final static String CURRENT_LINE = AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE; private final static String CURRENT_LINE_COLOR = AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE_COLOR; private Composite fControl; private VirtualSourceViewer fViewer; private IVerticalRuler fVerticalRuler; private IOverviewRuler fOverviewRuler; private SourceViewerDecorationSupport fSourceViewerDecorationSupport; private IAnnotationAccess fAnnotationAccess; private MarkerAnnotationPreferences fAnnotationPreferences; private String fViewContextMenuId; private String fRulerContextMenuId; private MenuManager fTextMenuManager; private MenuManager fRulerMenuManager; private Menu fRulerContextMenu; private Menu fTextContextMenu; private IMenuListener fMenuListener; private MouseListener fMouseListener; private Map<String, IAction> fActions = new HashMap<String, IAction>( 10 ); public DisassemblyPane( String contextMenuId, String rulerMenuId ) { fAnnotationPreferences = new MarkerAnnotationPreferences(); setViewContextMenuId( contextMenuId ); setRulerContextMenuId( rulerMenuId ); } public void create( Composite parent ) { Composite composite = new Composite( parent, SWT.NONE ); composite.setLayout( new GridLayout() ); GridData data = new GridData( SWT.FILL, SWT.FILL, true, true ); composite.setLayoutData( data ); fVerticalRuler = createCompositeRuler(); fOverviewRuler = createOverviewRuler( getSharedColors() ); createActions(); fViewer = createViewer( composite, fVerticalRuler, fOverviewRuler ); fControl = composite; createViewContextMenu(); createRulerContextMenu(); if ( fSourceViewerDecorationSupport != null ) { fSourceViewerDecorationSupport.install( getEditorPreferenceStore() ); } } public Control getControl() { return fControl; } public VirtualSourceViewer getViewer() { return fViewer; } public void dispose() { getEditorPreferenceStore().removePropertyChangeListener( this ); JFaceResources.getFontRegistry().removeListener( this ); JFaceResources.getColorRegistry().removeListener( this ); if ( fSourceViewerDecorationSupport != null ) { fSourceViewerDecorationSupport.dispose(); fSourceViewerDecorationSupport = null; } if ( fActions != null ) { fActions.clear(); fActions = null; } } protected void createActions() { } public void setAction( String actionID, IAction action ) { Assert.isNotNull( actionID ); if ( action == null ) { fActions.remove( actionID ); } else { fActions.put( actionID, action ); } } public IAction getAction( String actionID ) { Assert.isNotNull( actionID ); return fActions.get( actionID ); } protected void rulerContextMenuAboutToShow( IMenuManager menu ) { menu.add( new Separator( ITextEditorActionConstants.GROUP_REST ) ); menu.add( new Separator( IWorkbenchActionConstants.MB_ADDITIONS ) ); addAction( menu, IInternalCDebugUIConstants.ACTION_TOGGLE_BREAKPOINT ); addAction( menu, IInternalCDebugUIConstants.ACTION_ENABLE_DISABLE_BREAKPOINT ); addAction( menu, IInternalCDebugUIConstants.ACTION_BREAKPOINT_PROPERTIES ); } protected void viewContextMenuAboutToShow( IMenuManager menu ) { menu.add( new Separator( ITextEditorActionConstants.GROUP_REST ) ); menu.add( new Separator( IWorkbenchActionConstants.MB_ADDITIONS ) ); } protected void addAction( IMenuManager menu, String group, String actionId ) { IAction action = getAction( actionId ); if ( action != null ) { if ( action instanceof IUpdate ) ((IUpdate)action).update(); IMenuManager subMenu = menu.findMenuUsingPath( group ); if ( subMenu != null ) subMenu.add( action ); else menu.appendToGroup( group, action ); } } protected void addAction( IMenuManager menu, String actionId ) { IAction action = getAction( actionId ); if ( action != null ) { if ( action instanceof IUpdate ) ((IUpdate)action).update(); menu.add( action ); } } protected final IMenuListener getContextMenuListener() { if ( fMenuListener == null ) { fMenuListener = new IMenuListener() { public void menuAboutToShow( IMenuManager menu ) { String id = menu.getId(); if ( getRulerContextMenuId().equals( id ) ) { // setFocus(); rulerContextMenuAboutToShow( menu ); } else if ( getViewContextMenuId().equals( id ) ) { // setFocus(); viewContextMenuAboutToShow( menu ); } } }; } return fMenuListener; } protected final MouseListener getRulerMouseListener() { if ( fMouseListener == null ) { fMouseListener = new MouseListener() { private boolean fDoubleClicked = false; private void triggerAction( String actionID ) { IAction action = getAction( actionID ); if ( action != null ) { if ( action instanceof IUpdate ) ((IUpdate)action).update(); if ( action.isEnabled() ) action.run(); } } public void mouseUp( MouseEvent e ) { // setFocus(); if ( 1 == e.button && !fDoubleClicked ) triggerAction( ITextEditorActionConstants.RULER_CLICK ); fDoubleClicked = false; } public void mouseDoubleClick( MouseEvent e ) { if ( 1 == e.button ) { fDoubleClicked = true; triggerAction( IInternalCDebugUIConstants.ACTION_TOGGLE_BREAKPOINT ); } } public void mouseDown( MouseEvent e ) { StyledText text = getViewer().getTextWidget(); if ( text != null && !text.isDisposed() ) { Display display = text.getDisplay(); Point location = display.getCursorLocation(); getRulerContextMenu().setLocation( location.x, location.y ); } } }; } return fMouseListener; } private Menu getTextContextMenu() { return this.fTextContextMenu; } private void setTextContextMenu( Menu textContextMenu ) { this.fTextContextMenu = textContextMenu; } protected Menu getRulerContextMenu() { return this.fRulerContextMenu; } private void setRulerContextMenu( Menu rulerContextMenu ) { this.fRulerContextMenu = rulerContextMenu; } public String getRulerContextMenuId() { return fRulerContextMenuId; } private void setRulerContextMenuId( String rulerContextMenuId ) { Assert.isNotNull( rulerContextMenuId ); fRulerContextMenuId = rulerContextMenuId; } public String getViewContextMenuId() { return fViewContextMenuId; } private void setViewContextMenuId( String viewContextMenuId ) { Assert.isNotNull( viewContextMenuId ); fViewContextMenuId = viewContextMenuId; } private void createViewContextMenu() { String id = getViewContextMenuId(); fTextMenuManager = new MenuManager( id, id ); fTextMenuManager.setRemoveAllWhenShown( true ); fTextMenuManager.addMenuListener( getContextMenuListener() ); StyledText styledText = getViewer().getTextWidget(); setTextContextMenu( fTextMenuManager.createContextMenu( styledText ) ); styledText.setMenu( getTextContextMenu() ); } private void createRulerContextMenu() { String id = getRulerContextMenuId(); fRulerMenuManager = new MenuManager( id, id ); fRulerMenuManager.setRemoveAllWhenShown( true ); fRulerMenuManager.addMenuListener( getContextMenuListener() ); Control rulerControl = fVerticalRuler.getControl(); setRulerContextMenu( fRulerMenuManager.createContextMenu( rulerControl ) ); rulerControl.setMenu( getRulerContextMenu() ); rulerControl.addMouseListener( getRulerMouseListener() ); } protected SourceViewerDecorationSupport getSourceViewerDecorationSupport( ISourceViewer viewer ) { if ( fSourceViewerDecorationSupport == null ) { fSourceViewerDecorationSupport = new SourceViewerDecorationSupport( viewer, getOverviewRuler(), getAnnotationAccess(), getSharedColors() ); configureSourceViewerDecorationSupport( fSourceViewerDecorationSupport ); } return fSourceViewerDecorationSupport; } protected VirtualSourceViewer createViewer( Composite parent, IVerticalRuler vertRuler, IOverviewRuler ovRuler ) { int styles = SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION; VirtualSourceViewer viewer = new VirtualSourceViewer( parent, fVerticalRuler, fOverviewRuler, true, styles ); viewer.getControl().setLayoutData( parent.getLayoutData() ); viewer.setEditable( false ); viewer.getTextWidget().setFont( JFaceResources.getFont( IInternalCDebugUIConstants.DISASSEMBLY_FONT ) ); viewer.setRangeIndicator( new DefaultRangeIndicator() ); getSourceViewerDecorationSupport( viewer ); viewer.configure( new SourceViewerConfiguration() ); JFaceResources.getFontRegistry().addListener( this ); JFaceResources.getColorRegistry().addListener( this ); getEditorPreferenceStore().addPropertyChangeListener( this ); return viewer; } private IAnnotationAccess createAnnotationAccess() { return new DefaultMarkerAnnotationAccess(); } private void configureSourceViewerDecorationSupport( SourceViewerDecorationSupport support ) { for( Object pref : fAnnotationPreferences.getAnnotationPreferences() ) { support.setAnnotationPreference( (AnnotationPreference)pref ); } support.setCursorLinePainterPreferenceKeys( CURRENT_LINE, CURRENT_LINE_COLOR ); } private IAnnotationAccess getAnnotationAccess() { if ( fAnnotationAccess == null ) fAnnotationAccess = createAnnotationAccess(); return fAnnotationAccess; } private ISharedTextColors getSharedColors() { return EditorsUI.getSharedTextColors(); } @SuppressWarnings("unchecked") protected IVerticalRuler createCompositeRuler() { CompositeRuler ruler = new CompositeRuler(); ruler.addDecorator( 0, new AnnotationRulerColumn( VERTICAL_RULER_WIDTH, getAnnotationAccess() ) ); for( Iterator iter = ruler.getDecoratorIterator(); iter.hasNext(); ) { IVerticalRulerColumn col = (IVerticalRulerColumn)iter.next(); if ( col instanceof AnnotationRulerColumn ) { AnnotationRulerColumn column = (AnnotationRulerColumn)col; for( Iterator iter2 = fAnnotationPreferences.getAnnotationPreferences().iterator(); iter2.hasNext(); ) { AnnotationPreference preference = (AnnotationPreference)iter2.next(); column.addAnnotationType( preference.getAnnotationType() ); } column.addAnnotationType( Annotation.TYPE_UNKNOWN ); break; } } return ruler; } private IOverviewRuler createOverviewRuler( ISharedTextColors sharedColors ) { IOverviewRuler ruler = new OverviewRuler( getAnnotationAccess(), VERTICAL_RULER_WIDTH, sharedColors ); for( Object o : fAnnotationPreferences.getAnnotationPreferences() ) { AnnotationPreference preference = (AnnotationPreference)o; if ( preference.contributesToHeader() ) ruler.addHeaderAnnotationType( preference.getAnnotationType() ); } return ruler; } private IOverviewRuler getOverviewRuler() { if ( fOverviewRuler == null ) fOverviewRuler = createOverviewRuler( getSharedColors() ); return fOverviewRuler; } /* (non-Javadoc) * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent) */ public void propertyChange( PropertyChangeEvent event ) { // TODO Auto-generated method stub } private IPreferenceStore getEditorPreferenceStore() { return EditorsUI.getPreferenceStore(); } public MenuManager getTextMenuManager() { return fTextMenuManager; } public MenuManager getRulerMenuManager() { return fRulerMenuManager; } public IVerticalRuler getVerticalRuler() { return fVerticalRuler; } }