debuggercdi/com.nokia.carbide.cpp.debug.kernelaware/src/com/nokia/carbide/cpp/debug/kernelaware/ui/SymbianOSView.java
/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/
package com.nokia.carbide.cpp.debug.kernelaware.ui;
import org.eclipse.cdt.debug.core.model.ICDebugTarget;
import org.eclipse.cdt.debug.core.model.ICStackFrame;
import org.eclipse.cdt.debug.core.model.ICThread;
import org.eclipse.cdt.debug.internal.core.model.CDebugElement;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.IDebugEventSetListener;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.IInputValidator;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.INullSelectionListener;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import com.freescale.cdt.debug.cw.core.CWPlugin;
import com.freescale.cdt.debug.cw.core.cdi.Session;
import com.nokia.carbide.cpp.debug.kernelaware.IDataChangedListener;
import com.nokia.carbide.cpp.debug.kernelaware.IOSObjectProperties;
import com.nokia.carbide.cpp.debug.kernelaware.KernelawarePlugin;
import com.nokia.carbide.cpp.debug.kernelaware.OSDataManager;
import com.nokia.carbide.cpp.debug.kernelaware.OSObjectProcess;
import com.nokia.carbide.cpp.debug.kernelaware.OSObjectThread;
import com.nokia.carbide.cpp.internal.featureTracker.FeatureUseTrackerConsts;
import com.nokia.carbide.cpp.internal.featureTracker.FeatureUseTrackerPlugin;
import cwdbg.EclipseDEConstants;
public class SymbianOSView extends ViewPart implements ISelectionListener,
INullSelectionListener, IDataChangedListener, Runnable,
IDebugEventSetListener {
/*
* Help context ID. Should be: PluginID + "." + <words without '.'>
*/
private static final String HelpID_Prefix = KernelawarePlugin
.getUniqueIdentifier()
+ "."; //$NON-NLS-1$
public static final String s_HelpID_View = HelpID_Prefix
+ "symbian_os_data_view"; //$NON-NLS-1$
public static final String s_HelpID_OverviewTab = HelpID_Prefix
+ "symbian_os_data_view_overview_tab"; //$NON-NLS-1$
public static final String s_HelpID_ProcessTab = HelpID_Prefix
+ "symbian_os_data_view_process_tab"; //$NON-NLS-1$
public static final String s_HelpID_ThreadTab = HelpID_Prefix
+ "symbian_os_data_view_thread_tab"; //$NON-NLS-1$
public static final String s_HelpID_ChunkTab = HelpID_Prefix
+ "symbian_os_data_view_chunk_tab"; //$NON-NLS-1$
public static final String s_HelpID_LibraryTab = HelpID_Prefix
+ "symbian_os_data_view_library_tab"; //$NON-NLS-1$
public static final ImageDescriptor clearImageDesc = AbstractUIPlugin.imageDescriptorFromPlugin(
PlatformUI.PLUGIN_ID, "$nl$/icons/full/etool16/clear_co.gif"); //$NON-NLS-1$
private TabItem m_overviewTabItem;
private TabItem m_processTabItem;
private TabItem m_threadTabItem;
private TabItem m_chunkTabItem;
private TabItem m_libraryTabItem;
private TreeViewer m_overviewTreeViewer;
private TableViewer m_processTableViewer;
private TableViewer m_threadTableViewer;
private TableViewer m_chunkTableViewer;
private TableViewer m_libraryTableViewer;
private StructuredViewer m_currentViewer;
private Session m_currentSession = null;
private Action m_actionRefresh;
private Action m_actionToggleAutoRefresh;
private Action m_actionDebug;
private Action m_actionProperties;
private Action m_actionSetTimer;
private Action m_actionCollapseAll;
private Action m_actionDoubleClick;
// in seconds.
private int m_timedRefreshInterval = 20;
// Is the view closed by user ?
private boolean m_disposed;
// Make this option static so that it's consistent across view sessions.
static boolean m_autoRefresh = true;
/*
* (non-Javadoc)
*
* @see com.freescale.cdt.debug.cw.core.ui.os.OSView#createPartControl(org.eclipse.swt.widgets.Composite)
*/
@Override
public void createPartControl(Composite parent) {
final TabFolder tabFolder = new TabFolder(parent, SWT.NONE);
tabFolder.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
DoAction_TabSelection(e.item);
}
});
ImageDescriptor imageDesc;
/***********************************************************************
* Overview (treeview) tab
*/
m_overviewTabItem = new TabItem(tabFolder, SWT.NONE);
m_overviewTabItem
.setToolTipText(Messages.getString("SymbianOSView.OverViewToolTip")); //$NON-NLS-1$
m_overviewTabItem.setText(Messages.getString("SymbianOSView.OverViewLabel")); //$NON-NLS-1$
imageDesc = KernelawarePlugin
.getImageDescriptor("icons//tab_overview.png"); //$NON-NLS-1$
m_overviewTabItem.setImage(imageDesc.createImage());
m_overviewTreeViewer = (new OverviewTab()).createControl(tabFolder,
m_overviewTabItem);
/***********************************************************************
* Process Tab
*/
m_processTabItem = new TabItem(tabFolder, SWT.NONE);
m_processTabItem
.setToolTipText(Messages.getString("SymbianOSView.ProcessesToolTip")); //$NON-NLS-1$
m_processTabItem.setText(Messages.getString("SymbianOSView.ProcessesLabel")); //$NON-NLS-1$
imageDesc = KernelawarePlugin
.getImageDescriptor("icons//tab_process.gif"); //$NON-NLS-1$
m_processTabItem.setImage(imageDesc.createImage());
m_processTableViewer = (new ProcessTab()).createControl(tabFolder,
m_processTabItem);
/***********************************************************************
* Thread Tab
*/
m_threadTabItem = new TabItem(tabFolder, SWT.NONE);
m_threadTabItem.setToolTipText(Messages.getString("SymbianOSView.ThreadsToolTip")); //$NON-NLS-1$
m_threadTabItem.setText(Messages.getString("SymbianOSView.ThreadsLabel")); //$NON-NLS-1$
imageDesc = KernelawarePlugin
.getImageDescriptor("icons//tab_thread.gif"); //$NON-NLS-1$
m_threadTabItem.setImage(imageDesc.createImage());
m_threadTableViewer = (new ThreadTab()).createControl(tabFolder,
m_threadTabItem);
/***********************************************************************
* Chunk Tab
*/
m_chunkTabItem = new TabItem(tabFolder, SWT.NONE);
m_chunkTabItem.setToolTipText(Messages.getString("SymbianOSView.ChunksToolTip")); //$NON-NLS-1$
m_chunkTabItem.setText(Messages.getString("SymbianOSView.ChunksLabel")); //$NON-NLS-1$
imageDesc = KernelawarePlugin
.getImageDescriptor("icons//tab_chunk.gif"); //$NON-NLS-1$
m_chunkTabItem.setImage(imageDesc.createImage());
m_chunkTableViewer = (new ChunkTab()).createControl(tabFolder,
m_chunkTabItem);
/***********************************************************************
* Library Tab
*/
m_libraryTabItem = new TabItem(tabFolder, SWT.NONE);
m_libraryTabItem
.setToolTipText(Messages.getString("SymbianOSView.LibrariesToolTip")); //$NON-NLS-1$
m_libraryTabItem.setText(Messages.getString("SymbianOSView.LibrariesLabel")); //$NON-NLS-1$
imageDesc = KernelawarePlugin
.getImageDescriptor("icons//tab_library.gif"); //$NON-NLS-1$
m_libraryTabItem.setImage(imageDesc.createImage());
m_libraryTableViewer = (new LibraryTab()).createControl(tabFolder,
m_libraryTabItem);
/***********************************************************************
* Other View setting
*/
// Default current tab.
tabFolder.setSelection(0);
// Default selection provider.
// add a viewer as selection provider of the view, so that selected item
// in the viewer can have its properties displayed in Properties View.
m_currentViewer = m_overviewTreeViewer;
getSite().setSelectionProvider(m_currentViewer);
// listen to selection in debug view
getSite().getPage().addSelectionListener(
IDebugUIConstants.ID_DEBUG_VIEW, this);
/***********************************************************************
* Help context IDs.
*/
PlatformUI.getWorkbench().getHelpSystem()
.setHelp(parent, s_HelpID_View);
PlatformUI.getWorkbench().getHelpSystem().setHelp(
m_overviewTabItem.getControl(), s_HelpID_OverviewTab);
PlatformUI.getWorkbench().getHelpSystem().setHelp(
m_processTabItem.getControl(), s_HelpID_ProcessTab);
PlatformUI.getWorkbench().getHelpSystem().setHelp(
m_threadTabItem.getControl(), s_HelpID_ThreadTab);
PlatformUI.getWorkbench().getHelpSystem().setHelp(
m_chunkTabItem.getControl(), s_HelpID_ChunkTab);
PlatformUI.getWorkbench().getHelpSystem().setHelp(
m_libraryTabItem.getControl(), s_HelpID_LibraryTab);
/***********************************************************************
* Actions
*/
makeActions();
hookContextMenu();
hookDoubleClickAction();
contributeToActionBars();
hookSelectionChangedListeners();
m_disposed = false;
// If there is already a debug session running, try to show OS data for
// it.
Session currSelectedSession = Session.getUIFocusSession();
if (currSelectedSession != null) {
// getUIFocusSession() above may give us a dead session. Excluse
// that case.
if (currSelectedSession.isActive()){
try {
showDataForDevice(currSelectedSession);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
updateActionStatus();
DebugPlugin.getDefault().addDebugEventListener(this);
}
public void dataDirty() {
// Must run this in UI thread.
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
public void run() {
showDataAsStale(true);
}
});
};
private void hookContextMenu() {
MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager manager) {
SymbianOSView.this.fillContextMenu(manager);
}
});
// Hook up context menu for each of the viewers.
//
Menu menu;
StructuredViewer viewer = m_overviewTreeViewer;
menu = menuMgr.createContextMenu(viewer.getControl());
viewer.getControl().setMenu(menu);
getSite().registerContextMenu(menuMgr, viewer);
viewer = m_processTableViewer;
menu = menuMgr.createContextMenu(viewer.getControl());
viewer.getControl().setMenu(menu);
getSite().registerContextMenu(menuMgr, viewer);
viewer = m_threadTableViewer;
menu = menuMgr.createContextMenu(viewer.getControl());
viewer.getControl().setMenu(menu);
getSite().registerContextMenu(menuMgr, viewer);
viewer = m_chunkTableViewer;
menu = menuMgr.createContextMenu(viewer.getControl());
viewer.getControl().setMenu(menu);
getSite().registerContextMenu(menuMgr, viewer);
viewer = m_libraryTableViewer;
menu = menuMgr.createContextMenu(viewer.getControl());
viewer.getControl().setMenu(menu);
getSite().registerContextMenu(menuMgr, viewer);
}
/**
* Hook up listeners for selection change in the view.
*/
private void hookSelectionChangedListeners() {
ISelectionChangedListener listener = new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
// Update status of commands.
updateActionStatus();
}
};
m_overviewTreeViewer.addSelectionChangedListener(listener);
m_processTableViewer.addSelectionChangedListener(listener);
m_threadTableViewer.addSelectionChangedListener(listener);
m_chunkTableViewer.addSelectionChangedListener(listener);
m_libraryTableViewer.addSelectionChangedListener(listener);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.part.ViewPart#init(org.eclipse.ui.IViewSite,
* org.eclipse.ui.IMemento)
*/
@Override
public void init(IViewSite site, IMemento memento) throws PartInitException {
super.init(site, memento);
FeatureUseTrackerPlugin.getFeatureUseProxy().startUsingFeature(FeatureUseTrackerConsts.CARBIDE_KERNELAWARE);
}
@Override
public void dispose() {
// Must do the following, otherwise a zombie will exist after user close
// the view.
//
m_disposed = true;
getSite().setSelectionProvider(null);
getSite().getPage().removeSelectionListener(
IDebugUIConstants.ID_DEBUG_VIEW, this);
DebugPlugin.getDefault().removeDebugEventListener(this);
// remove the timed task.
disableTimedRefresh();
FeatureUseTrackerPlugin.getFeatureUseProxy().stopUsingFeature(FeatureUseTrackerConsts.CARBIDE_KERNELAWARE);
super.dispose();
}
@Override
public void setFocus() {
// Make sure the current tab get the focus so that help system can
// get the correct context ID for the focused control so as to display
// matching context-sensitive help......12/18/06
m_currentViewer.getControl().setFocus();
}
// This is called when selection in workbench changes.
// We only honor the change in Debug View.
public void selectionChanged(IWorkbenchPart part, ISelection selection) {
if (!(selection instanceof IStructuredSelection))
return;
IStructuredSelection structSel = (IStructuredSelection) selection;
if (structSel.size() != 1)
return;
Object sel = structSel.getFirstElement();
// Allow StackFrame & thread for now.
// If we hornor selection of CDebugTarget, debugger may freeze on start
// when the OS View is open before debugger starts.
// Figure out a solution later..... 11/29/06
// Not a problem any more in Eclipse 3.3 + CDT4.0....... 11/15/07
//
if (!(sel instanceof ICStackFrame || sel instanceof ICThread || sel instanceof ICDebugTarget))
return;
Session newSession = Session.getSessionFromDebugContext(sel);
if (newSession == null) // how come ?
return;
/* A terminated session, or a special case:
* Start the first debug session while the OS View is open, the
* CDT Target (process) is created and auto selected in Debug View
* but corresponding CWProcess is not created yet. In such case
* we should not try to refresh. Part of fix to bug 5320.. 12/04/07
*/
if (! newSession.isActive())
return;
/*
* If user just selects a different item (stackframe, thread, process)
* in the same session, and the session's OS data is not dirty, don't
* bother to update.
*/
boolean refresh = false;
if (m_currentSession == null) {
refresh = true;
}
else if (!m_currentSession.equals(newSession))
// Different session is selected (by user).
refresh = true;
else {
// The same session is selected (by user or automatically done when debuggee
// is suspended). Refresh only when data is dirty and AutoRefresh is
// turned on.
if (newSession.getOSDataManager().isDataDirty() && m_autoRefresh) {
refresh = true;
// Check this for stop mode debug. Fix bug 3467...03/28/07
if (newSession.isSystemModeDebug()
&& newSession.isSystemRunning())
refresh = false;
}
}
if (refresh){
try {
showDataForDevice(newSession);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* Asynchronously get the OS data for the given session. Show progress and
* allow user cancel.
*
* @param session -
* for which session (i.e. machine) to get the OS data.
* @param listener -
* who's interested in finish event.
* @param userInitiated -
* is the compute initiated by user or automatically by program.
*/
private void computeInput(final Session session,
final IDataChangedListener listener, final boolean userInitiated) {
// Note the job name is also referenced in Target.java.
// So watch out when changing it !....04/07/07
Job refreshJob = new Job(Messages.getString("SymbianOSView.RefreshDataTitle")) { //$NON-NLS-1$
protected IStatus run(IProgressMonitor monitor) {
IStatus status = Status.OK_STATUS;
try {
OSDataManager osDM = (OSDataManager) session
.getOSDataManager();
if (osDM != null) {
/*
* For crash debugger, the refreshing is time consuming
* (more than one minute at present). So never do
* auto-refresh for it, only user-initiated refreshing
* is allowed. This way startup of crash debugger won't
* be slow.... [LW_20070213] 02/13/07
*/
if (!(session.getLaunchTypeName().contains("crash") && !userInitiated)) //$NON-NLS-1$
status = osDM.updateAll(monitor);
}
} catch (DebugException e) {
status = new Status(IStatus.ERROR, KernelawarePlugin
.getUniqueIdentifier(), 0, e.getMessage(), null);
}
listener.dataUpdated(session, status);
monitor.done();
return status;
}
};
refreshJob.setUser(userInitiated);
refreshJob.setPriority(Job.LONG);
refreshJob.schedule();
}
/**
* Given a session (namely a machine, or device), display its OS data in the
* view.
*
* @param newSession
*/
private void showDataForDevice(Session newSession) throws InterruptedException {
// Make the view be listener for dataChanged event from the underlying
// session.
if (m_currentSession != null)
((OSDataManager) m_currentSession.getOSDataManager())
.removeDataChangedListener(this);
((OSDataManager) newSession.getOSDataManager())
.addDataChangedListener(this);
// User selects a debug session of ours.
m_currentSession = newSession;
// This fixes the timing issue with attaching to a process @bug 7580
Thread.sleep(500);
updateActionStatus();
// if the new session is for stop mode, disable timer for auto-refresh.
// ...... 12/03/06
if (newSession.isSystemModeDebug()) {
// Stop the timed task.
disableTimedRefresh();
}
// The scheduled refresh may conflict with the computeInput()
// below and result in deadlock.
// Actually the timed refresh will be scheduled in computeInput().
// So don't do this here......... 12/04/2007
// else if (newSession.isActive()) // Don't if the session is a terminated one
// scheduleTimedRefresh();
showDataAsStale(true);
computeInput(m_currentSession, this, false);
/*
* Hide Chunk and Library tabs per debug session type. But I don't see
* an easy way in SWT yet.........Nov. 2006
*/
}
private void packTableViewer(TableViewer viewer) {
TableColumn[] cols = viewer.getTable().getColumns();
for (int i = 0; i < cols.length; i++)
if (cols[i].getResizable() != false)
cols[i].pack();
}
private void contributeToActionBars() {
IActionBars bars = getViewSite().getActionBars();
fillLocalPullDown(bars.getMenuManager());
fillLocalToolBar(bars.getToolBarManager());
}
private void fillContextMenu(IMenuManager manager) {
if (m_currentViewer == null)
return;
ISelection selection = m_currentViewer.getSelection();
if (selection == null)
return;
Object obj = ((IStructuredSelection) selection).getFirstElement();
if (obj == null)
return;
// Add "debug" command if selection is a process or thread.
if (obj instanceof OSObjectProcess || obj instanceof OSObjectThread) {
manager.add(m_actionDebug);
}
// For all others, add "properties" command.
manager.add(m_actionProperties);
// Other plug-ins can contribute their actions here
manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
}
private void fillLocalPullDown(IMenuManager manager) {
manager.add(m_actionRefresh);
manager.add(m_actionToggleAutoRefresh);
manager.add(m_actionDebug);
manager.add(new Separator());
manager.add(m_actionProperties);
manager.add(m_actionSetTimer);
manager.add(m_actionCollapseAll);
}
private void fillLocalToolBar(IToolBarManager manager) {
manager.add(m_actionRefresh);
manager.add(m_actionToggleAutoRefresh);
manager.add(m_actionDebug);
manager.add(m_actionProperties);
manager.add(m_actionSetTimer);
manager.add(m_actionCollapseAll);
}
private void makeActions() {
m_actionRefresh = new Action(Messages.getString("SymbianOSView.RefreshActionLabel"), IAction.AS_PUSH_BUTTON) { //$NON-NLS-1$
public void run() {
DoAction_Refresh();
}
};
m_actionRefresh.setToolTipText(Messages.getString("SymbianOSView.RefreshActionToolTip")); //$NON-NLS-1$
m_actionRefresh.setImageDescriptor(KernelawarePlugin
.getImageDescriptor("icons//refresh.gif")); //$NON-NLS-1$
m_actionToggleAutoRefresh = new Action(Messages.getString("SymbianOSView.AutoRefreshActionLabel"), //$NON-NLS-1$
IAction.AS_CHECK_BOX) {
public void run() {
DoAction_ToggleAutoRefresh();
}
};
m_actionToggleAutoRefresh
.setToolTipText(Messages.getString("SymbianOSView.AutoRefreshActionToolTip")); //$NON-NLS-1$
m_actionToggleAutoRefresh.setChecked(m_autoRefresh);
m_actionToggleAutoRefresh.setImageDescriptor(KernelawarePlugin
.getImageDescriptor("icons//auto_refresh.gif")); //$NON-NLS-1$
m_actionDebug = new Action(Messages.getString("SymbianOSView.DebugActionLabel"), IAction.AS_PUSH_BUTTON) { //$NON-NLS-1$
public void run() {
DoAction_Debug();
}
};
m_actionDebug.setToolTipText(Messages.getString("SymbianOSView.DebugActionToolTip")); //$NON-NLS-1$
m_actionDebug.setImageDescriptor(KernelawarePlugin
.getImageDescriptor("icons//Debug.png")); //$NON-NLS-1$
m_actionProperties = new Action(Messages.getString("SymbianOSView.PropertiesActionLabel"), IAction.AS_PUSH_BUTTON) { //$NON-NLS-1$
public void run() {
DoAction_Properties();
}
};
m_actionProperties
.setToolTipText(Messages.getString("SymbianOSView.PropertiesActionToolTip")); //$NON-NLS-1$
m_actionProperties.setImageDescriptor(KernelawarePlugin
.getImageDescriptor("icons//properties.gif")); //$NON-NLS-1$
m_actionSetTimer = new Action(Messages.getString("SymbianOSView.SetTimerActionLabel"), IAction.AS_PUSH_BUTTON) { //$NON-NLS-1$
public void run() {
DoAction_SetTimer();
}
};
m_actionSetTimer
.setToolTipText(Messages.getString("SymbianOSView.SetTimerActionToolTip")); //$NON-NLS-1$
m_actionSetTimer.setImageDescriptor(KernelawarePlugin
.getImageDescriptor("icons//set_timer.gif")); //$NON-NLS-1$
m_actionCollapseAll = new Action(Messages.getString("SymbianOSView.CollapseAllActionLabel"), IAction.AS_PUSH_BUTTON) { //$NON-NLS-1$
public void run() {
DoAction_CollapseAll();
}
};
m_actionCollapseAll.setToolTipText(Messages.getString("SymbianOSView.CollapseAllActionToolTip")); //$NON-NLS-1$
m_actionCollapseAll.setImageDescriptor(KernelawarePlugin
.getImageDescriptor("icons//collapseall.gif")); //$NON-NLS-1$
m_actionDoubleClick = new Action() {
public void run() {
DoAction_Debug();
}
};
}
private void hookDoubleClickAction() {
IDoubleClickListener listener = new IDoubleClickListener() {
public void doubleClick(DoubleClickEvent event) {
m_actionDoubleClick.run();
}
};
m_processTableViewer.addDoubleClickListener(listener);
m_threadTableViewer.addDoubleClickListener(listener);
}
private void showMessage(String message) {
MessageDialog
.openInformation(m_processTableViewer.getControl().getShell(),
Messages.getString("SymbianOSView.MessageTitle"), Messages.getString("SymbianOSView.MessagePrefix") + message); //$NON-NLS-1$ //$NON-NLS-2$
}
private void DoAction_TabSelection(Widget item) {
if (item == null)
return;
if (item.equals(m_overviewTabItem)) {
m_currentViewer = m_overviewTreeViewer;
} else if (item.equals(m_processTabItem))
m_currentViewer = m_processTableViewer;
else if (item.equals(m_threadTabItem))
m_currentViewer = m_threadTableViewer;
else if (item.equals(m_chunkTabItem))
m_currentViewer = m_chunkTableViewer;
else if (item.equals(m_libraryTabItem))
m_currentViewer = m_libraryTableViewer;
getSite().setSelectionProvider(m_currentViewer);
/*
* Now the tab selection has changed.
*
* At this time if user selects an item in the tab, the properties of
* the item won't be displayed in Properties View. That's because the
* above selectionProvider change is not honored until the view loses
* and regains focus (a platform bug ?). So we do this: change focus to
* any other view (here I choose Variable View as it's most likely
* present and in the same pane as this OS View) and then change it back
* to this view. This is not a perfect solution, but...
*
*
* This is also needed for the help system to get tab-specific context
* ID. See setFocus() for more.
*/
int viewState_old = IWorkbenchPage.STATE_RESTORED;
int viewState_new = IWorkbenchPage.STATE_RESTORED;
IWorkbenchPartReference thisRef = getSite().getPage()
.getReference(this);
if (thisRef != null)
viewState_old = getSite().getPage().getPartState(thisRef);
try {
getSite().getPage().showView(IDebugUIConstants.ID_VARIABLE_VIEW);
} catch (PartInitException e) {
e.printStackTrace();
}
if (thisRef != null)
viewState_new = getSite().getPage().getPartState(thisRef);
// Put focus back.
getSite().getPage().activate(this);
// Restore the state.
// Added the "new != old" check otherwise the setPartState() would cause
// NPE in core code in Eclipse 3.3
if (thisRef != null && viewState_new != viewState_old)
getSite().getPage().setPartState(thisRef, viewState_old);
// enable/disable actions/commands accordingly.
updateActionStatus();
}
/**
* Force refresh of all data in the view by re-reading from the target
* device.
*
*/
private void DoAction_Refresh() {
if (m_currentSession == null)
return;
disableTimedRefresh();
m_currentSession.getOSDataManager().setDataDirty();
computeInput(m_currentSession, this, true);
}
private void DoAction_ToggleAutoRefresh() {
m_autoRefresh = !m_autoRefresh;
}
private void DoAction_CollapseAll() {
if (m_overviewTreeViewer != null)
m_overviewTreeViewer.collapseAll();
}
private void DoAction_Debug() {
/*
* Attach debugger to a process or thread.
*/
if (m_currentViewer == null)
return;
if (m_currentSession == null || !m_currentSession.isActive())
return;
ISelection selection = m_currentViewer.getSelection();
if (selection == null)
return;
Object obj = ((IStructuredSelection) selection).getFirstElement();
if (obj == null)
return;
// Only allow attaching to a process
int procID, threadID;
String procName = ""; //$NON-NLS-1$
if (obj instanceof OSObjectProcess) {
// User select to debug a process
OSObjectProcess objProcess = (OSObjectProcess) obj;
procID = objProcess.getID();
if (m_currentSession.processBeingDebugged(procID)) {
showMessage(Messages.getString("SymbianOSView.ProcessUnderDebugMsg")); //$NON-NLS-1$
return;
}
procName = objProcess.getName();
// Just targetting the first thread in the process
OSObjectThread[] threads = objProcess.getThreads();
if (threads.length > 0)
threadID = threads[0].getID();
else
// no thread, should not happen.
return;
} else if (obj instanceof OSObjectThread) {
OSObjectThread thread = (OSObjectThread) obj;
procID = thread.getProcessID();
if (procID == EclipseDEConstants.J_OSObjectID_Invalid) // owner
// unknown
return;
threadID = thread.getID();
if (m_currentSession.threadBeingDebugged(procID, threadID)) {
showMessage(Messages.getString("SymbianOSView.ThreadUnderDebugMsg")); //$NON-NLS-1$
return;
}
if (m_currentSession.processBeingDebugged(procID)) {
// the owner process is already under debug
// no need to pass process name to backend.
procName = ""; //$NON-NLS-1$
} else {
procName = (String) thread
.getRawPropertyValue(IOSObjectProperties.ID.OwningProcessName);
}
} else
// other objects
return;
// With TRK, we may get process name like "app[ef1a9bef]0001".
// Do some adjustment here.
if (procName.length() > 0) {
int i = procName.indexOf('[');
if (i > 0)
procName = procName.substring(0, i);
// for a name without extension like "app", add .exe
if (!procName.contains(".")) //$NON-NLS-N$ //$NON-NLS-1$
procName = procName + ".exe"; //$NON-NLS-N$ //$NON-NLS-1$
}
// Now the real action...
try {
m_currentSession.attachToThread(procID, threadID, procName);
} catch (DebugException e) {
showMessage(e.getMessage());
}
}
/**
* Open Properties View and show property of selected item in current tab.
*/
private void DoAction_Properties() {
if (m_currentViewer == null)
return;
ISelection selection = m_currentViewer.getSelection();
if (selection == null)
return;
// Open the Properties view in case it's not.
try {
getSite().getPage().showView(
org.eclipse.ui.IPageLayout.ID_PROP_SHEET);
} catch (PartInitException e) {
e.printStackTrace();
}
// Change focus back to this view so that the selection in the viewer is
// displayed in the Properties View.
getSite().getPage().activate(this);
}
/**
* Pop up a dialog for user to enter the time interval.
*/
private void DoAction_SetTimer() {
// validator for user input.
class Validator implements IInputValidator {
public String isValid(String newText) {
int i;
try {
i = Integer.valueOf(newText);
} catch (Exception e) {
return Messages.getString("SymbianOSView.DecimalError"); //$NON-NLS-1$
}
if (i < 3 || i > 600)
return Messages.getString("SymbianOSView.RangeError"); //$NON-NLS-1$
return null;
}
}
int currentInterval = CWPlugin
.getDefault()
.getPluginPreferences()
.getInt(
cwdbg.PreferenceConstants.J_PN_OSViewAutoRefreshInterval);
InputDialog dg = new InputDialog(
this.getSite().getShell(),
Messages.getString("SymbianOSView.MessageTitle"), // $NON-NLS-1$ //$NON-NLS-1$
Messages.getString("SymbianOSView.IntervalMessage"), //$NON-NLS-1$
Integer.toString(currentInterval), new Validator());
if (dg.open() == Window.OK) {
String input = dg.getValue();
currentInterval = Integer.valueOf(input);
// Save in our global pref storage.
CWPlugin.getDefault().getPluginPreferences().setValue(
cwdbg.PreferenceConstants.J_PN_OSViewAutoRefreshInterval,
currentInterval);
}
}
/**
* Enable/disable actions based on current selection.
*/
private void updateActionStatus() {
boolean enableRefresh = false;
boolean enableToggleAutoRefresh = true;
boolean enableDebug = false;
boolean enableProperties = false;
boolean enableSetTimer = false;
boolean enableCollapseAll = false;
if (m_actionRefresh == null) // not created yet.
return;
if (m_currentSession != null && m_currentSession.isActive()) {
enableRefresh = true;
if (!m_currentSession.isSystemModeDebug())
// enable this for TRK debugger only.
enableSetTimer = true;
if (m_currentSession.getLaunchTypeName().contains("crash")) //$NON-NLS-1$
// disable auto-refresh for crash debugger. See my comment
// [LW_20070213].
enableToggleAutoRefresh = false;
if (m_currentViewer != null) {
// tab specific commands
//
if (m_currentViewer == m_overviewTreeViewer)
enableCollapseAll = true;
// Selection specific commands
//
ISelection selection = m_currentViewer.getSelection();
Object obj = ((IStructuredSelection) selection)
.getFirstElement();
if (obj != null) {
// This is true as long as there is a valid selection in the
// view.
enableProperties = true;
if (obj instanceof OSObjectProcess
|| obj instanceof OSObjectThread)
enableDebug = true;
}
}
}
m_actionRefresh.setEnabled(enableRefresh);
m_actionToggleAutoRefresh.setEnabled(enableToggleAutoRefresh);
m_actionDebug.setEnabled(enableDebug);
m_actionProperties.setEnabled(enableProperties);
m_actionSetTimer.setEnabled(enableSetTimer);
m_actionCollapseAll.setEnabled(enableCollapseAll);
}
/**
* Give visual hint on whether the data in the view is stale.
*
* @param stale
*/
private void showDataAsStale(boolean stale) {
if (m_disposed)
return;
Color co = stale ? PlatformUI.getWorkbench().getDisplay()
.getSystemColor(SWT.COLOR_DARK_GRAY) : null;
/*
* To show that data is stale, I display them in gray text. But the
* grayed out text is kinda hard to read. Another solution is to change
* the background to gray, but not ideal either..... 11/30/06
*/
// m_overviewTreeViewer.getControl().setBackground(co);
m_overviewTreeViewer.getControl().setForeground(co);
m_processTableViewer.getControl().setForeground(co);
m_threadTableViewer.getControl().setForeground(co);
m_chunkTableViewer.getControl().setForeground(co);
m_libraryTableViewer.getControl().setForeground(co);
}
private void scheduleTimedRefresh() {
if (m_currentSession == null || !m_currentSession.isActive())
return;
// Not for stop mode debug.
if (m_currentSession.isSystemModeDebug())
return;
// Honor preference settings real time.
m_timedRefreshInterval = CWPlugin
.getDefault()
.getPluginPreferences()
.getInt(
cwdbg.PreferenceConstants.J_PN_OSViewAutoRefreshInterval);
Runnable timedRunnable = this;
PlatformUI.getWorkbench().getDisplay().timerExec(
m_timedRefreshInterval * 1000 /* milliseconds */,
timedRunnable);
}
private void disableTimedRefresh() {
Runnable timedRunnable = this;
PlatformUI.getWorkbench().getDisplay().timerExec(-1, timedRunnable);
}
/**
* This is for timed auto-refresh of OS data in the view. Refer to where
* Display.timerExec() is invoked.
*
* @see java.lang.Runable#run
*/
public void run() {
// View is closed or session terminated
if (m_disposed || m_currentSession == null)
return;
// show as stale.
showDataAsStale(true);
// just in case this is cleared
if (m_currentSession == null)
return;
// Refresh data if so requested.
if (m_autoRefresh) {
// Mark cache as dirty.
m_currentSession.getOSDataManager().setDataDirty();
computeInput(m_currentSession, this, false);
} else
scheduleTimedRefresh();
}
public void dataUpdated(final Session session, final IStatus status) {
// User already selected another session during refreshing.
// Just do nothing. "selectionChanged()" will make sure data for the new
// session will be displayed.
if (session != m_currentSession) {
return;
}
final OSDataManager osDM = (OSDataManager) session.getOSDataManager();
if (osDM == null)
return;
/*
* Even if we got error, we treat the data as updated so that no more
* refreshing request will be handled until next auto-refresh or
* user-refresh. This way user won't get repeated error message when he,
* say, clicks on different target/thread of the same session in the debug view.
*/
osDM.setUpdatedFlag(0xFFFF);
Runnable runnable = new Runnable() {
public void run() {
if (status.isOK()) {
// Remember tree state
Object[] expandedNodes = m_overviewTreeViewer
.getExpandedElements();
ISelection selection = m_overviewTreeViewer.getSelection();
m_overviewTreeViewer.setInput(osDM);
// Restore tree state
m_overviewTreeViewer.setExpandedElements(expandedNodes);
m_overviewTreeViewer.setSelection(selection);
m_overviewTreeViewer.getTree().showSelection();
m_processTableViewer.setInput(osDM);
m_threadTableViewer.setInput(osDM);
m_chunkTableViewer.setInput(osDM);
m_libraryTableViewer.setInput(osDM);
/*
* The above call will populate the table. Here we can make
* sure each column is packed to show all info in preferred
* size. Do we really want to do this as it may be against
* user's desire ? Let's wait for user feedback....11/02/06
*/
packTableViewer(m_processTableViewer);
packTableViewer(m_threadTableViewer);
showDataAsStale(false);
}
// Data refreshed, reschedule our next timed refresh.
scheduleTimedRefresh();
if (status.getSeverity() != IStatus.OK
&& status.getSeverity() != IStatus.CANCEL) {
showDataAsStale(true);
// Now the computeInput() is done in a job, and job
// mechanism will display any error automatically.
}
}
};
// Don't update UI if the view is already closed by user.
if (!m_disposed)
PlatformUI.getWorkbench().getDisplay().asyncExec(runnable);
}
public void handleDebugEvents(DebugEvent[] events) {
for (int i = 0; i < events.length; i++) {
DebugEvent event = events[i];
if (! (event.getSource() instanceof CDebugElement))
continue;
CDebugElement elem = (CDebugElement) event.getSource();
if (elem == null || ! (elem.getCDISession() instanceof Session)) // not from our debugger
return;
final Session session = (Session) elem.getCDISession();
if (session == null)
return;
if (event.getKind() == DebugEvent.TERMINATE &&
elem instanceof ICDebugTarget)
{
// a Target (process) is terminated
if (session == m_currentSession && !session.isActive()) {
// and the session is terminated.
session.getOSDataManager().setDataDirty();
updateActionStatus();
// remove timed task, if any.
PlatformUI.getWorkbench().getDisplay().syncExec(
new Runnable() {
public void run() {
disableTimedRefresh();
// Show data as stale after end of session.
showDataAsStale(true);
}
});
m_currentSession = null;
}
}
else if (event.getKind() == DebugEvent.CREATE &&
elem instanceof ICThread)
{
// a thread in our debug session is created.
if (m_currentSession == null) {
// If the OS Data view has no associated session yet,
// associate it with the session so that OS Data View can
// show data for a never-stopped debug session. Fix bug 4428.
// ...... 12/04/07
// But only do that for run mode debug. For stop mode,
// we should only show data whenever the system is stopped
// and the thread in Debug View is selected...12/05/07
if (session.isSystemModeDebug())
return;
PlatformUI.getWorkbench().getDisplay().syncExec(
new Runnable() {
public void run() {
try {
showDataForDevice(session);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}
}
}