/* * Copyright (c) 2010-2012 Research In Motion Limited. All rights reserved. * * This program and the accompanying materials are made available * under the terms of the Eclipse Public License, Version 1.0, * which accompanies this distribution and is available at * * http://www.eclipse.org/legal/epl-v10.html * */ package net.rim.ejde.internal.ui.views; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import net.rim.ejde.internal.core.ContextManager; import net.rim.ejde.internal.ui.CompositeFactory; import net.rim.ejde.internal.util.DebugUtils; import net.rim.ejde.internal.util.Messages; import net.rim.ide.core.VarContentsHelper.MenuAction; import org.apache.log4j.Logger; import org.eclipse.core.runtime.CoreException; import org.eclipse.debug.core.DebugEvent; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.IDebugEventSetListener; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchesListener2; import org.eclipse.jface.action.IContributionItem; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.ui.part.ViewPart; /** * This class is the basic view class of the debugger views (profiler, memory states, objects etc.) All other debugger views are * supposed to extend from this class. */ abstract public class BasicDebugView extends ViewPart implements IDebugEventSetListener, ILaunchesListener2 { private static final Logger log = Logger.getLogger( BasicDebugView.class ); // bit mask for tool bar buttons final public static int REFRESH_BUTTON = 0x0001; final public static int SAVE_BUTTON = 0x0002; final public static int CLEAR_BUTTON = 0x0004; final public static int OPTIONS_BUTTON = 0x0008; final public static int COMPARE_BUTTON = 0x0010; final public static int SNAPSHOT_BUTTON = 0x0020; final public static int GARBAGE_COLLECTION_BUTTON = 0x0040; final public static int FILTER_BUTTON = 0x0080; final public static int FORWARD_BUTTON = 0x0100; final public static int BACKWARD_BUTTON = 0x0200; final public static int RETURN_TO_START_BUTTON = 0x0400; final public static int RETURN_TO_END_BUTTON = 0x0800; final public static int SAVE_TO_XML = 0x2000; final public static int SAVE_RAW_TO_XML = 0x4000; final public static int OPEN_PROFILEVIS = 0x8000; final static String HPROF_EXTENSION = "hprof"; //$NON-NLS-1$ private int _buttons; private boolean _isSuspended; protected List< Object > _toolbarActionList; protected List< MenuAction > _menuActionList; private boolean _hasData; private boolean _hasSnapShot; private Label _messageLabel; /** * Constructs an instance of this view. * * @param buttons * bit mask to indicate what buttons will be created on the tool bar of this view. */ public BasicDebugView( int buttons ) { _buttons = buttons; _toolbarActionList = new ArrayList< Object >(); DebugPlugin.getDefault().addDebugEventListener( this ); DebugPlugin.getDefault().getLaunchManager().addLaunchListener( this ); } /** * Creates the UI of this view. This method only creates tool bar buttons on the view, and is supposed to be overridden by its * subclasses to create other UI parts. * * Caution: super#createPartControl(Composite parent) must be called in the beginning of the overridden method in subclasses. */ public void createPartControl( Composite parent ) { createToolbarButtons(); // debugger may be suspended before this view is created setSuspended( ContextManager.PLUGIN.isSuspended() ); // initialize buttons updateToolbar(); parent.setLayout( new GridLayout( 1, false ) ); // create message labels createMessageComposite( parent ); // create table Composite tableComposite = CompositeFactory.gridComposite( parent, 1 ); tableComposite.setLayoutData( new GridData( GridData.FILL_BOTH ) ); // create the table view part createTableViewPart( tableComposite ); } abstract public void createTableViewPart( Composite parent ); public void setMessage( final String errorMessage, final boolean error ) { Display.getDefault().syncExec( new Runnable() { @Override public void run() { if( _messageLabel != null ) { if( error ) { _messageLabel.setForeground( Display.getCurrent().getSystemColor( SWT.COLOR_RED ) ); } else { _messageLabel.setForeground( Display.getCurrent().getSystemColor( SWT.COLOR_BLACK ) ); } _messageLabel.setText( errorMessage ); } } } ); } public void cleanMessage() { Display.getDefault().syncExec( new Runnable() { @Override public void run() { if( _messageLabel != null ) { _messageLabel.setText( "" ); } } } ); } private void createMessageComposite( Composite parent ) { Composite composite = CompositeFactory.gridComposite( parent, 1 ); // message label _messageLabel = new Label( composite, SWT.NONE ); _messageLabel.setLayoutData( new GridData( GridData.FILL_HORIZONTAL ) ); } protected void setHasData( boolean hasData ) { _hasData = hasData; } protected void setHasSnapshot( boolean hasSnapshot ) { _hasSnapShot = hasSnapshot; } protected boolean hasData() { return _hasData; } protected boolean hasSnapshot() { return _hasSnapShot; } /** * Creates the Image instance indicated by <code>imageId</code>. * * @param imageId * <code>int</code> number which indicates the image to be created. * @return Image instance or <code>null</code> if some exception occurs. */ static protected Image createImage( int imageId ) { Image image = null; ImageDescriptor descriptor = null; switch( imageId ) { case REFRESH_BUTTON: { descriptor = ContextManager.imageDescriptorFromPlugin( ContextManager.PLUGIN_ID, "icons/obj16/refresh_enabled.gif" ); break; } case SAVE_BUTTON: { descriptor = ContextManager.imageDescriptorFromPlugin( ContextManager.PLUGIN_ID, "icons/obj16/save_edit_enabled.gif" ); break; } case CLEAR_BUTTON: { descriptor = ContextManager.imageDescriptorFromPlugin( ContextManager.PLUGIN_ID, "icons/obj16/clear.gif" ); break; } case OPTIONS_BUTTON: { descriptor = ContextManager.imageDescriptorFromPlugin( ContextManager.PLUGIN_ID, "icons/obj16/options.gif" ); break; } case COMPARE_BUTTON: { descriptor = ContextManager.imageDescriptorFromPlugin( ContextManager.PLUGIN_ID, "icons/obj16/compare.gif" ); break; } case SNAPSHOT_BUTTON: { descriptor = ContextManager.imageDescriptorFromPlugin( ContextManager.PLUGIN_ID, "icons/obj16/snapshot.gif" ); break; } case GARBAGE_COLLECTION_BUTTON: { descriptor = ContextManager.imageDescriptorFromPlugin( ContextManager.PLUGIN_ID, "icons/obj16/recycle.gif" ); break; } case FILTER_BUTTON: { descriptor = ContextManager.imageDescriptorFromPlugin( ContextManager.PLUGIN_ID, "icons/obj16/filter.gif" ); break; } case FORWARD_BUTTON: { descriptor = ContextManager.imageDescriptorFromPlugin( ContextManager.PLUGIN_ID, "icons/obj16/forward_nav.gif" ); break; } case BACKWARD_BUTTON: { descriptor = ContextManager.imageDescriptorFromPlugin( ContextManager.PLUGIN_ID, "icons/obj16/backward_nav.gif" ); break; } case RETURN_TO_START_BUTTON: { descriptor = ContextManager.imageDescriptorFromPlugin( ContextManager.PLUGIN_ID, "icons/obj16/return_to_start.gif" ); break; } case RETURN_TO_END_BUTTON: { descriptor = ContextManager.imageDescriptorFromPlugin( ContextManager.PLUGIN_ID, "icons/obj16/return_to_end.gif" ); break; } case SAVE_TO_XML: { descriptor = ContextManager.imageDescriptorFromPlugin( ContextManager.PLUGIN_ID, "icons/obj16/save_edit_enabled.gif" ); break; } case SAVE_RAW_TO_XML: { descriptor = ContextManager.imageDescriptorFromPlugin( ContextManager.PLUGIN_ID, "icons/obj16/save_edit_enabled.gif" ); break; } case OPEN_PROFILEVIS: { descriptor = ContextManager.imageDescriptorFromPlugin( ContextManager.PLUGIN_ID, "icons/obj16/openfile.gif" ); break; } } if( descriptor != null ) { image = descriptor.createImage(); } return image; } /** * Disposes created image instances. */ public void dispose() { super.dispose(); log.trace( "Disposing the debug view and removing the debug listener" ); // fixed IDP350529, remove this object from the listener lists DebugPlugin.getDefault().removeDebugEventListener( this ); DebugPlugin.getDefault().getLaunchManager().removeLaunchListener( this ); // dispose all created actions for( Iterator iterator = _toolbarActionList.iterator(); iterator.hasNext(); ) { Object obj = iterator.next(); if( obj instanceof BasicAction ) { BasicAction action = (BasicAction) obj; action.dispose(); } else if( obj instanceof Separator ) { Separator separator = (Separator) obj; separator.dispose(); } } } /** * Creates a tool bar Action instance indicated by <code>action</code>. * * @param action * the action to be created. */ private void createToolbarAction( int action ) { String text; String hint; switch( action ) { case REFRESH_BUTTON: { // create fresh action text = Messages.BasicView_REFRESH_ACTION_TITLE; hint = Messages.BasicView_REFRESH_ACTION_HINT; break; } case SAVE_BUTTON: { // create save action text = Messages.BasicView_SAVE_ACTION_TITLE; hint = Messages.BasicView_SAVE_ACTION_HINT; break; } case CLEAR_BUTTON: { // create clear action text = Messages.BasicView_CLEAR_ACTION_TITLE; hint = Messages.BasicView_CLEAR_ACTION_HINT; break; } case OPTIONS_BUTTON: { // create options action text = Messages.BasicView_OPTIONS_ACTION_TITLE; hint = Messages.BasicView_OPTIONS_ACTION_HINT; break; } case COMPARE_BUTTON: { // create compare action text = Messages.BasicView_COMPARE_ACTION_TITLE; hint = Messages.BasicView_COMPARE_ACTION_HINT; break; } case SNAPSHOT_BUTTON: { // create snapshot action text = Messages.BasicView_SNAPSHOT_ACTION_TITLE; hint = Messages.BasicView_SNAPSHOT_ACTION_HINT; break; } case GARBAGE_COLLECTION_BUTTON: { // create garbage collection action text = Messages.BasicView_GC_ACTION_TITLE; hint = Messages.BasicView_GC_ACTION_HINT; break; } case FILTER_BUTTON: { // create filter action text = Messages.BasicView_FILTER_ACTION_TITLE; hint = Messages.BasicView_FILTER_ACTION_HINT; break; } case FORWARD_BUTTON: { // create forward action text = Messages.BasicView_FORWARD_ACTION_TITLE; hint = Messages.BasicView_FORWARD_ACTION_HINT; break; } case BACKWARD_BUTTON: { // create backward action text = Messages.BasicView_BACKWARD_ACTION_TITLE; hint = Messages.BasicView_BACKWARD_ACTION_HINT; break; } case RETURN_TO_START_BUTTON: { // create "return to start" action text = Messages.BasicView_RETURN_TO_START_ACTION_TITLE; hint = Messages.BasicView_RETURN_TO_START_ACTION_HINT; break; } case RETURN_TO_END_BUTTON: { // create filter action text = Messages.BasicView_GO_TO_END_ACTION_TITLE; hint = Messages.BasicView_GO_TO_END_ACTION_HINT; break; } case SAVE_TO_XML: { // dump heap text = Messages.BasicView_SAVE_XML_ACTION_TITLE; hint = Messages.BasicView_SAVE_XML_ACTION_HINT; break; } case SAVE_RAW_TO_XML: { // dump heap text = Messages.BasicView_SAVE_RAW_XML_ACTION_TITLE; hint = Messages.BasicView_SAVE_RAW_XML_ACTION_HINT; break; } case OPEN_PROFILEVIS: { // dump heap text = Messages.BasicView_OPEN_PROFILEVIS_ACTION_TITLE; hint = Messages.BasicView_OPEN_PROFILEVIS_ACTION_HINT; break; } default: return; } _toolbarActionList.add( new BasicAction( this, text, action, hint ) ); } /** * Creates buttons on the tool bar of this view. */ private void createToolbarButtons() { // create and add buttons to tool bar IToolBarManager toolBarMgr = getViewSite().getActionBars().getToolBarManager(); // create actions if( ( _buttons & RETURN_TO_START_BUTTON ) != 0 ) { createToolbarAction( RETURN_TO_START_BUTTON ); } if( ( _buttons & BACKWARD_BUTTON ) != 0 ) { createToolbarAction( BACKWARD_BUTTON ); } if( ( _buttons & FORWARD_BUTTON ) != 0 ) { createToolbarAction( FORWARD_BUTTON ); } if( ( _buttons & RETURN_TO_END_BUTTON ) != 0 ) { createToolbarAction( RETURN_TO_END_BUTTON ); } if( ( _buttons & RETURN_TO_START_BUTTON ) != 0 || ( _buttons & BACKWARD_BUTTON ) != 0 || ( _buttons & FORWARD_BUTTON ) != 0 || ( _buttons & RETURN_TO_END_BUTTON ) != 0 ) _toolbarActionList.add( new Separator( "Navagition Group" ) ); if( ( _buttons & REFRESH_BUTTON ) != 0 ) { createToolbarAction( REFRESH_BUTTON ); } if( ( _buttons & SAVE_BUTTON ) != 0 ) { createToolbarAction( SAVE_BUTTON ); } if( ( _buttons & CLEAR_BUTTON ) != 0 ) { createToolbarAction( CLEAR_BUTTON ); } if( ( _buttons & OPTIONS_BUTTON ) != 0 ) { createToolbarAction( OPTIONS_BUTTON ); } if( ( _buttons & FILTER_BUTTON ) != 0 ) { createToolbarAction( FILTER_BUTTON ); } if( ( _buttons & COMPARE_BUTTON ) != 0 ) { createToolbarAction( COMPARE_BUTTON ); } if( ( _buttons & SNAPSHOT_BUTTON ) != 0 ) { createToolbarAction( SNAPSHOT_BUTTON ); } if( ( _buttons & GARBAGE_COLLECTION_BUTTON ) != 0 ) { createToolbarAction( GARBAGE_COLLECTION_BUTTON ); } if( ( _buttons & SAVE_TO_XML ) != 0 ) { createToolbarAction( SAVE_TO_XML ); } if( ( _buttons & SAVE_RAW_TO_XML ) != 0 ) { createToolbarAction( SAVE_RAW_TO_XML ); } if( ( _buttons & OPEN_PROFILEVIS ) != 0 ) { createToolbarAction( OPEN_PROFILEVIS ); } // add the buttons to the tool bar for( Iterator iterator = _toolbarActionList.iterator(); iterator.hasNext(); ) { Object obj = iterator.next(); if( obj instanceof BasicAction ) toolBarMgr.add( (BasicAction) obj ); else if( obj instanceof IContributionItem ) toolBarMgr.add( (IContributionItem) obj ); } } public void setFocus() { // nothing to do } /** * @see IDebugEventSetListener#handleDebugEvents(DebugEvent[]). * */ public void handleDebugEvents( DebugEvent[] events ) { if( events == null || events.length == 0 ) return; for( int i = 0; i < events.length; i++ ) { if( !DebugUtils.isFromRIMLaunch( events[ i ] ) ) { continue; } if( events[ i ].getKind() == DebugEvent.SUSPEND && !_isSuspended ) { _isSuspended = true; updateToolbar(); } else if( events[ i ].getKind() == DebugEvent.RESUME && _isSuspended ) { _isSuspended = false; updateToolbar(); } handleRIMDebugEvent( events[ i ] ); } } // method handleDebugEvents protected void handleRIMDebugEvent( DebugEvent event ) { // do nothing here } // ------ implementation of methods of ILaunchesListener2 ------ /** * @see ILaunchesListener2#launchesTerminated(ILaunch[]). */ public void launchesTerminated( ILaunch[] launches ) { debugTerminated( launches ); } /** * @see ILaunchesListener#launchesRemoved(ILaunch[]). */ public void launchesRemoved( ILaunch[] launches ) { // in hot-swap, only launch removed event is fired, there is no launch terminated event. debugTerminated( launches ); } /** * @see ILaunchesListener#launchesAdded(ILaunch[]). */ public void launchesAdded( ILaunch[] launches ) { } /** * @see ILaunchesListener#launchesChanged(ILaunch[]). */ public void launchesChanged( ILaunch[] launches ) { } /** * Set actions indicated by <code>actions</code> as <code>enabled</code>. * * @param actions * bit mask which indicates what actions will be enabled/disabled. * @param enabled * <code>true</code> enable the actions indicated by <code>actions</code>, <code>false</code> otherwise. */ public void enableActions( int actions, boolean enabled ) { for( Iterator iterator = _toolbarActionList.iterator(); iterator.hasNext(); ) { Object obj = iterator.next(); if( !( obj instanceof BasicAction ) ) continue; BasicAction action = (BasicAction) obj; if( ( action.getActionCode() & actions ) != 0 && action.isEnabled() != enabled ) action.setEnabled( enabled ); } } /** * Checks whether the debugger is suspended. * * @return <code>true</code>if the debugger is suspended, <code>false</code> otherwise. */ public boolean isSuspended() { return _isSuspended; } /** * Sets whether the debugger is suspended or not. * * @param suspeneded * <code>true</code>if the debugger is suspended, <code>false</code> otherwise. */ public void setSuspended( boolean suspeneded ) { _isSuspended = suspeneded; } /** * Despatch task when an action is executed (a button is clicked). * * @param action * the action executed. * @throws CoreException */ protected void run( BasicAction action ) throws CoreException { switch( action.getActionCode() ) { case REFRESH_BUTTON: { refresh(); return; } case SAVE_BUTTON: { save(); return; } case CLEAR_BUTTON: { clear(); return; } case OPTIONS_BUTTON: { setOptions(); return; } case COMPARE_BUTTON: { compare(); break; } case SNAPSHOT_BUTTON: { snapshot(); return; } case GARBAGE_COLLECTION_BUTTON: { gc(); return; } case FILTER_BUTTON: { filter(); return; } case FORWARD_BUTTON: { forward(); return; } case BACKWARD_BUTTON: { backward(); return; } case RETURN_TO_START_BUTTON: { returnToStart(); return; } case RETURN_TO_END_BUTTON: { returnToEnd(); return; } case SAVE_TO_XML: { saveXML(); return; } case SAVE_RAW_TO_XML: { saveRawToXML(); return; } case OPEN_PROFILEVIS: { openProfileVis(); return; } default: return; } } /** * Debug session is terminated. */ private void debugTerminated( ILaunch[] launches ) { List< ILaunch > rimLaunches = DebugUtils.getRIMLaunches( launches ); if( rimLaunches.size() == 0 ) { return; } _isSuspended = false; Display.getDefault().asyncExec( new Runnable() { public void run() { clear(); } } ); RIMDebugTerminated( rimLaunches.toArray( new ILaunch[ rimLaunches.size() ] ) ); } public void RIMDebugTerminated( ILaunch[] launches ) { // do nothing here } /** * Enables/Disables the buttons on the tool bar. */ public void updateToolbar() { enableActions( OPTIONS_BUTTON, optionsEnabled() ); if( isSuspended() ) { enableActions( REFRESH_BUTTON | GARBAGE_COLLECTION_BUTTON | FILTER_BUTTON, true ); if( _hasSnapShot ) enableActions( COMPARE_BUTTON, true ); else enableActions( COMPARE_BUTTON, false ); } else enableActions( REFRESH_BUTTON | GARBAGE_COLLECTION_BUTTON | COMPARE_BUTTON | FILTER_BUTTON | BACKWARD_BUTTON | FORWARD_BUTTON | RETURN_TO_START_BUTTON | RETURN_TO_END_BUTTON, false ); // set others if( _hasData ) enableActions( SNAPSHOT_BUTTON | SAVE_BUTTON | CLEAR_BUTTON | SAVE_TO_XML | SAVE_RAW_TO_XML | OPEN_PROFILEVIS, true ); else enableActions( SNAPSHOT_BUTTON | SAVE_BUTTON | CLEAR_BUTTON | SAVE_TO_XML | SAVE_RAW_TO_XML | OPEN_PROFILEVIS, false ); } /** * Checks if the options action button on the view is enabled.<p> * <b> The sub classes can override this method to make the options action button to be enabled under different conditions</b> * * @return */ public boolean optionsEnabled(){ return DebugUtils.isRIMDebuggerRunning(); } // subclasses of this class are supposed to override // these methods but can ignore the actions that are not // applied to them /** * Clears the current display content. * <p> * <b>subclasses need to override this method.</b> */ public void clear() { // do nothing; } /** * Save the currently displayed data into a csv file. * <p> * <b>subclasses need to override this method.</b> */ public void save() { // do nothing; } /** * Reloads the data and refresh the display. * <p> * <b>subclasses need to override this method.</b> * * @throws CoreException */ public void refresh() throws CoreException { // do nothing; } /** * Takes a snapshot of current data * <p> * <b>subclasses need to override this method.</b> */ public void snapshot() { // do nothing; } /** * Sets up options. * <p> * <b>subclasses need to override this method.</b> */ public void setOptions() { // do nothing; } /** * Compares the current data with the snapshot. * <p> * <b>subclasses need to override this method.</b> */ public void compare() { // do nothing; } /** * Perform garbage collection. * <p> * <b>subclasses need to override this method.</b> */ public void gc() { // do nothing; } /** * Sets filters. * <p> * <b>subclasses need to override this method.</b> */ public void filter() { // do nothing } /** * Forwards to the next step. * <p> * <b>subclasses need to override this method.</b> */ public void forward() { // do nothing } /** * Backwards to the last step. * <p> * <b>subclasses need to override this method.</b> */ public void backward() { // do nothing } /** * Returns to the start. * <p> * <b>subclasses need to override this method.</b> */ public void returnToStart() { // do nothing } /** * Goes to the end * <p> * <b>subclasses need to override this method.</b> */ public void returnToEnd() { // do nothing } /** * Save view content to a XML file. * <p> * <b>subclasses need to override this method.</b> */ public void saveXML() { // do nothing } /** * Save raw data of the view content to a XML file. * <p> * <b>subclasses need to override this method.</b> */ public void saveRawToXML() { // do nothing } /** * Open ProfileVisDesktop to display the collected profile data */ public void openProfileVis() { // do nothing } }