/*******************************************************************************
* 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;
}
}