Java tutorial
/* * 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; private TabFolder tabFolder; private int refreshCount; /* * (non-Javadoc) * * @see com.freescale.cdt.debug.cw.core.ui.os.OSView#createPartControl(org.eclipse.swt.widgets.Composite) */ @Override public void createPartControl(Composite parent) { 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); refreshCount++; 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"), //$NON-NLS-1$ IAction.AS_PUSH_BUTTON) { 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"), //$NON-NLS-1$ IAction.AS_PUSH_BUTTON) { 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"), //$NON-NLS-1$ IAction.AS_PUSH_BUTTON) { 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"), //$NON-NLS-1$ IAction.AS_PUSH_BUTTON) { 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"), //$NON-NLS-1$ Messages.getString("SymbianOSView.MessagePrefix") + message); //$NON-NLS-1$ } public 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. * */ public void DoAction_Refresh() { if (m_currentSession == null) return; disableTimedRefresh(); m_currentSession.getOSDataManager().setDataDirty(); computeInput(m_currentSession, this, true); } public void DoAction_ToggleAutoRefresh() { setAutoRefresh(!m_autoRefresh); } public void setAutoRefresh(boolean enabled) { m_autoRefresh = enabled; } public void DoAction_CollapseAll() { if (m_overviewTreeViewer != null) m_overviewTreeViewer.collapseAll(); } public 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(); } } }); } } } } @Override public Object getAdapter(Class adapter) { if (adapter.isInstance(this)) return this; if (adapter.isInstance(tabFolder)) return tabFolder; if (adapter.isInstance(m_currentViewer)) return m_currentViewer; return super.getAdapter(adapter); } public int getRefreshCount() { return refreshCount; } }