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