/******************************************************************************* * Copyright (c) 2011, 2016 Mentor Graphics and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Vladimir Prus (Mentor Graphics) - initial API and implementation * Teodor Madan (Freescale Semiconductor) - Bug 486521: attaching to selected process *******************************************************************************/ package org.eclipse.cdt.dsf.gdb.internal.ui.osview; import java.net.URL; import java.text.SimpleDateFormat; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.Query; import org.eclipse.cdt.dsf.datamodel.DMContexts; import org.eclipse.cdt.dsf.datamodel.IDMContext; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; import org.eclipse.cdt.dsf.gdb.launching.GdbLaunch; import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS2.IResourcesInformation; import org.eclipse.cdt.dsf.service.DsfServicesTracker; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.debug.ui.DebugUITools; import org.eclipse.debug.ui.contexts.DebugContextEvent; import org.eclipse.debug.ui.contexts.IDebugContextListener; import org.eclipse.debug.ui.contexts.IDebugContextManager; import org.eclipse.debug.ui.contexts.IDebugContextService; 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.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.Clipboard; import org.eclipse.swt.dnd.TextTransfer; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; 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.Event; import org.eclipse.swt.widgets.Link; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.ui.IActionBars; import org.eclipse.ui.ISharedImages; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.actions.ActionFactory; import org.eclipse.ui.part.ViewPart; import org.eclipse.ui.progress.UIJob; import org.osgi.framework.Bundle; /** * @since 2.4 */ public class OSResourcesView extends ViewPart implements DsfSession.SessionEndedListener { private final static String FETCH_LINK_TAG = "fetch"; //$NON-NLS-1$ // The data model for the selected session, or null if no session is // selected. private SessionOSData fSessionData; private Map<String, SessionOSData> fSessionDataCache = new HashMap<String, SessionOSData>(); // The data presently shown by table viewer. private OSData fTableShownData = null; // The data which was used to populate column selector menu private OSData fMenuShownData = null; private String fResourceClass = null; // Indicates that we've selected objects from different debug sessions. boolean fMultiple = false; // Indicates that we have selected object with a wrong type boolean fWrongType = false; // UI objects private TableViewer fViewer; private Comparator fComparator; private Composite fNothingLabelContainer; private Link fNothingLabel; private ResourceClassContributionItem fResourceClassEditor; private Action fRefreshAction; // Map from resource class name to table column layout. private Map<String, ColumnLayout> fColumnLayouts = new HashMap<String, ColumnLayout>(); private ColumnLayout fColumnLayout = null; private IDebugContextListener fDebugContextListener; @Override public void createPartControl(Composite xparent) { Composite parent = new Composite(xparent, SWT.NONE); GridLayout topLayout = new GridLayout(1, false); topLayout.marginWidth = 0; topLayout.marginHeight = 0; parent.setLayout(topLayout); fViewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); GridData viewerData = new GridData(GridData.FILL_BOTH); viewerData.exclude = true; fViewer.getControl().setLayoutData(viewerData); fViewer.setComparator(fComparator = new Comparator()); Table table = fViewer.getTable(); table.setHeaderVisible(true); table.setVisible(false); fNothingLabelContainer = new Composite(parent, SWT.NONE); GridData nothingLayout = new GridData(SWT.FILL, SWT.FILL, true, true); fNothingLabelContainer.setLayoutData(nothingLayout); GridLayout containerLayout = new GridLayout(1, false); fNothingLabelContainer.setLayout(containerLayout); fNothingLabel = new Link(fNothingLabelContainer, SWT.BORDER); fNothingLabel.setText(Messages.OSView_4); fNothingLabel.setBackground(fNothingLabel.getDisplay().getSystemColor( SWT.COLOR_LIST_BACKGROUND)); fNothingLabel.addListener (SWT.Selection, new Listener () { @Override public void handleEvent(Event event) { if (event.text.equals("fetch")) //$NON-NLS-1$ if (fSessionData != null && getResourceClass() != null) fSessionData.fetchData(getResourceClass()); } }); fNothingLabelContainer.setBackground(fNothingLabel.getBackground()); GridData nothingLabelLayout = new GridData(SWT.CENTER, SWT.TOP, true, false); fNothingLabel.setLayoutData(nothingLabelLayout); fResourceClassEditor = new ResourceClassContributionItem(); fResourceClassEditor.setListener(new ResourceClassContributionItem.Listener() { @Override public void resourceClassChanged(String newClass) { setResourceClass(newClass); // Since user explicitly changed the class, initiate fetch immediately. fSessionData.fetchData(getResourceClass()); // Do not call 'update()' here. fetchData call above will notify // us at necessary moments. } }); IActionBars bars = getViewSite().getActionBars(); bars.getToolBarManager().add(fResourceClassEditor); fRefreshAction = new Action() { @Override public void run() { if (fSessionData != null && getResourceClass() != null) fSessionData.fetchData(getResourceClass()); } }; fRefreshAction.setText(Messages.OSView_3); fRefreshAction.setToolTipText(Messages.OSView_3); try { Bundle bundle= Platform.getBundle("org.eclipse.ui"); //$NON-NLS-1$ URL url = bundle.getEntry("/"); //$NON-NLS-1$ url = new URL(url, "icons/full/elcl16/refresh_nav.png"); //$NON-NLS-1$ ImageDescriptor candidate = ImageDescriptor.createFromURL(url); if (candidate != null && candidate.getImageData() != null) { fRefreshAction.setImageDescriptor(candidate); } } catch (Exception e) { } bars.getToolBarManager().add(fRefreshAction); bars.setGlobalActionHandler(ActionFactory.COPY.getId(), new CopyAction()); bars.updateActionBars(); createContextMenu(); getSite().setSelectionProvider(fViewer); setResourceClass(fResourceClassEditor.getResourceClassId()); setupContextListener(); DsfSession.addSessionEndedListener(this); } private void createContextMenu() { MenuManager menuMgr= new MenuManager("#PopUp"); //$NON-NLS-1$ menuMgr.setRemoveAllWhenShown(true); menuMgr.addMenuListener(new IMenuListener() { @Override public void menuAboutToShow(IMenuManager manager) { manager.add(new CopyAction()); manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); } }); Menu menu= menuMgr.createContextMenu(fViewer.getControl()); fViewer.getControl().setMenu(menu); // register the context menu such that other plug-ins may contribute to it getSite().registerContextMenu(menuMgr, fViewer); } private void setupContextListener() { IDebugContextManager contextManager = DebugUITools.getDebugContextManager(); IDebugContextService contextService = contextManager .getContextService(getSite().getWorkbenchWindow()); fDebugContextListener = new IDebugContextListener() { @Override public void debugContextChanged(DebugContextEvent event) { if ((event.getFlags() & DebugContextEvent.ACTIVATED) != 0) { ISelection s = event.getContext(); setDebugContext(s); } } }; contextService.addDebugContextListener(fDebugContextListener); setDebugContext(contextService.getActiveContext()); } @Override public void dispose() { super.dispose(); IDebugContextManager contextManager = DebugUITools.getDebugContextManager(); IDebugContextService contextService = contextManager .getContextService(getSite().getWorkbenchWindow()); contextService.removeDebugContextListener(fDebugContextListener); setDebugContext((ICommandControlDMContext)null); DsfSession.removeSessionEndedListener(this); } private void setDebugContext(ISelection s) { ICommandControlDMContext context = null; fMultiple = false; fWrongType = false; if (s instanceof IStructuredSelection) { IStructuredSelection ss = (IStructuredSelection) s; if (!ss.isEmpty()) { @SuppressWarnings("rawtypes") Iterator i = ss.iterator(); context = getCommandControlContext(i.next()); if (context == null) fWrongType = true; while (i.hasNext()) { ICommandControlDMContext nextContext = getCommandControlContext(i.next()); if (nextContext == null) fWrongType = true; if (nextContext == null && context != null || nextContext != null && context == null || nextContext != null && context != null && !nextContext.equals(context)) { context = null; fMultiple = true; break; } } } } setDebugContext(context); } private ICommandControlDMContext getCommandControlContext(Object obj) { IDMContext context = null; if (obj instanceof IDMVMContext) context = ((IDMVMContext)obj).getDMContext(); else if (obj instanceof GdbLaunch) { GdbLaunch l = (GdbLaunch)obj; final DsfServicesTracker tracker = new DsfServicesTracker(GdbPlugin.getBundleContext(), l.getSession().getId()); Query<IDMContext> contextQuery = new Query<IDMContext>() { @Override protected void execute(DataRequestMonitor<IDMContext> rm) { ICommandControlService commandControl = tracker.getService(ICommandControlService.class); tracker.dispose(); if (commandControl != null) { rm.setData(commandControl.getContext()); } rm.done(); } }; l.getSession().getExecutor().submit(contextQuery); try { context = contextQuery.get(); } catch (Exception e) { } } return DMContexts.getAncestorOfType(context, ICommandControlDMContext.class); } private void setDebugContext(ICommandControlDMContext context) { DsfSession newSession = null; SessionOSData newSessionData = null; if (context != null) { newSession = DsfSession.getSession(context.getSessionId()); } if (newSession != null) { newSessionData = fSessionDataCache.get(newSession.getId()); if (newSessionData == null) { newSessionData = new SessionOSData(newSession, context); fSessionDataCache.put(newSession.getId(), newSessionData); newSessionData.setUIListener(new SessionOSData.Listener() { @Override public void update() { // Note that fSessionData always calls the listener in // UI thread, so we can directly call 'update' here. OSResourcesView.this.updateSessionDataContents(); } }, fViewer.getControl()); } } update(newSessionData); } @Override public void sessionEnded(DsfSession session) { String id = session.getId(); SessionOSData data = fSessionDataCache.remove(id); if (data != null) { data.dispose(); } } // Update UI to showing new session data. If this session data is already // shown, does nothing. private void update(SessionOSData newSessionData) { if (fViewer == null || fViewer.getControl() == null) return; if (fViewer.getControl().isDisposed()) return; if (newSessionData == null) { fSessionData = null; if (fMultiple) hideTable(Messages.OSView_14); else if (fWrongType) hideTable(Messages.OSView_4); else hideTable(Messages.OSView_15); fResourceClassEditor.setEnabled(false); fRefreshAction.setEnabled(false); return; } if (newSessionData != fSessionData) { fSessionData = newSessionData; updateSessionDataContents(); } } // Update the UI according to actual content of fSessionData, // which must be not null. private void updateSessionDataContents() { if (fSessionData == null) return; if (fViewer == null || fViewer.getControl() == null) return; if (fViewer.getControl().isDisposed()) return; boolean enable = fSessionData.canFetchData(); fRefreshAction.setEnabled(enable); setResourceClass(fResourceClassEditor.updateClasses(fSessionData.getResourceClasses())); fResourceClassEditor.setEnabled(enable); if (!fSessionData.osResourcesSupported()) { fRefreshAction.setEnabled(false); fResourceClassEditor.setEnabled(false); hideTable(Messages.OSView_10); return; } if (fSessionData.waitingForSessionInitialization()) { fRefreshAction.setEnabled(false); fResourceClassEditor.setEnabled(false); hideTable(Messages.OSView_13); return; } if (fSessionData.fetchingClasses()) { fRefreshAction.setEnabled(false); fResourceClassEditor.setEnabled(false); hideTable(Messages.OSView_11); return; } if (getResourceClass() == null) { fRefreshAction.setEnabled(false); fResourceClassEditor.setEnabled(true); hideTable(Messages.OSView_5); return; } final OSData data = fSessionData.existingData(getResourceClass()); if (fSessionData.fetchingContent()) { hideTable(Messages.OSView_6); } else if (data == null) { if (fSessionData.canFetchData()) hideTable(NLS.bind(Messages.OSView_7, FETCH_LINK_TAG)); else hideTable(Messages.OSView_12); } else { SimpleDateFormat format = new SimpleDateFormat(Messages.OSView_8); fRefreshAction.setToolTipText(format.format(fSessionData.timestamp(getResourceClass()))); if (data != fTableShownData) { Job job = new UIJob(Messages.OSView_9) { @Override public IStatus runInUIThread(IProgressMonitor monitor) { fTableShownData = data; populateTable(data); showTable(); return Status.OK_STATUS; } }; job.setPriority(Job.INTERACTIVE); job.schedule(); } else { assert fViewer.getTable().getColumnCount() == data.getColumnCount(); showTable(); } } fRefreshAction.setEnabled(fSessionData.canFetchData()); fResourceClassEditor.setEnabled(fSessionData.canFetchData()); } /* Hide the table that would show OS awareness data if it were available. Display * 'message' instead. */ private void hideTable(String message) { setContentDescription(""); //$NON-NLS-1$ fViewer.getControl().setVisible(false); ((GridData) fViewer.getControl().getLayoutData()).exclude = true; fNothingLabelContainer.setVisible(true); ((GridData) fNothingLabelContainer.getLayoutData()).exclude = false; fNothingLabelContainer.getParent().layout(); fNothingLabel.setText(message); fNothingLabelContainer.layout(); // If the table is not shown, we don't want the menu to have stale // list of columns to select from. IActionBars bars = getViewSite().getActionBars(); bars.getMenuManager().removeAll(); bars.updateActionBars(); fMenuShownData = null; } private void showTable() { assert fTableShownData != null; fViewer.getControl().setVisible(true); ((GridData) fViewer.getControl().getLayoutData()).exclude = false; fNothingLabelContainer.setVisible(false); ((GridData) fNothingLabelContainer.getLayoutData()).exclude = true; fNothingLabelContainer.getParent().layout(); populateViewMenu(fTableShownData); } private void populateTable(final OSData data) { final Table table = fViewer.getTable(); while (table.getColumnCount() > 0) table.getColumns()[0].dispose(); fColumnLayout = fColumnLayouts.get(getResourceClass()); if (fColumnLayout == null) { fColumnLayout = new ColumnLayout(getResourceClass()); fColumnLayouts.put(getResourceClass(), fColumnLayout); } for (int i = 0; i < data.getColumnCount(); ++i) { final String cn = data.getColumnName(i); final TableColumn c = new TableColumn(table, SWT.LEFT); c.setText(cn); c.addListener(SWT.Resize, new Listener() { @Override public void handleEvent(Event event) { fColumnLayout.setWidth(cn, c.getWidth()); } }); final int final_index = i; c.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { int dir = table.getSortDirection(); if (table.getSortColumn() == c) { dir = dir == SWT.UP ? SWT.DOWN : SWT.UP; } else { dir = SWT.DOWN; } table.setSortDirection(dir); table.setSortColumn(c); fComparator.configure(final_index, data); fComparator.setDirection(dir == SWT.DOWN ? 1 : -1); fColumnLayout.setSortColumn(final_index); fColumnLayout.setSortDirection(dir == SWT.DOWN ? 1 : -1); fViewer.refresh(); } }); } populateViewMenu(data); int sortColumn = fColumnLayout.getSortColumn(); if (sortColumn < data.getColumnCount()) { fComparator.configure(sortColumn, data); } fComparator.setDirection(fColumnLayout.getSortDirection()); fViewer.getTable().setEnabled(true); if (fViewer.getContentProvider() == null) { ContentLabelProviderWrapper<OSData> wrapper = new ContentLabelProviderWrapper<OSData>(data); fViewer.setContentProvider(wrapper); fViewer.setLabelProvider(wrapper); } else { // Retarget current content/label providers in atomic fashion. See comments // on ContentLabelProviderWrapper. @SuppressWarnings("unchecked") ContentLabelProviderWrapper<OSData> wrapper = (ContentLabelProviderWrapper<OSData>)fViewer.getContentProvider(); wrapper.setData(data); } fViewer.setInput(getViewSite()); fViewer.getControl().setVisible(true); for (int i = 0; i < fViewer.getTable().getColumnCount(); ++i) { TableColumn col = fViewer.getTable().getColumns()[i]; String cn = col.getText(); if (i == sortColumn) { table.setSortDirection(fColumnLayout.getSortDirection() == 1 ? SWT.DOWN : SWT.UP); table.setSortColumn(col); } if (fColumnLayout.getVisible(cn)) { int w = fColumnLayout.getWidth(cn); if (w > 0) col.setWidth(w); else col.pack(); } else { col.setWidth(0); col.setResizable(false); } } } private void populateViewMenu(final OSData data) { assert data.getColumnCount() == fViewer.getTable().getColumnCount(); if (data == fMenuShownData) return; IActionBars bars = getViewSite().getActionBars(); bars.getMenuManager().setVisible(true); bars.getMenuManager().removeAll(); for (int i = 0; i < data.getColumnCount(); ++i) { final String cn = data.getColumnName(i); final TableColumn c = fViewer.getTable().getColumns()[i]; Action a = new Action(cn, IAction.AS_CHECK_BOX) { @Override public void run() { if (isChecked()) { int w = fColumnLayout.getWidth(cn); if (w > 0) c.setWidth(w); else c.pack(); c.setResizable(true); } else { int w = c.getWidth(); c.setWidth(0); // Make sure we remember the width the column // had before hiding. fColumnLayout.setWidth(cn, w); c.setResizable(false); } fColumnLayout.setVisible(cn, isChecked()); } }; a.setChecked(fColumnLayout.getVisible(cn)); a.setText(cn); bars.getMenuManager().add(a); } bars.updateActionBars(); fMenuShownData = data; } class Comparator extends ViewerComparator { private int fColumn = 0; private OSData fData; private boolean fInteger = false; private int fDirection = 1; public void configure(int column, OSData data) { fColumn = column; fData = data; fInteger = data.getColumnIsInteger(column); } public void setDirection(int direction) { assert direction == 1 || direction == -1; fDirection = direction; } @Override public int compare(Viewer viewer, Object xe1, Object xe2) { String v1 = fData.getColumnText(xe1, fColumn); String v2 = fData.getColumnText(xe2, fColumn); if (fInteger) { Integer i1 = Integer.parseInt(v1); Integer i2 = Integer.parseInt(v2); return fDirection*(i1 - i2); } else { return fDirection*(v1.compareTo(v2)); } } }; @Override public void setFocus() { fViewer.getControl().setFocus(); } /** * @return the currently selected and displayed resource class */ public String getResourceClass() { return fResourceClass; } /** * @param resourceClass the resource class to set */ private void setResourceClass(String resourceClass) { fResourceClass = resourceClass; } /** * @return currently debug context for which resources are displayed */ public ICommandControlDMContext getSessionContext() { return fSessionData != null ? fSessionData.getContext() : null; } /** * Retargetted copy to clipboard action */ private final class CopyAction extends Action { private static final char COLUMN_SEPARATOR = ','; private final String EOL_CHAR = System.getProperty("line.separator"); //$NON-NLS-1$ private CopyAction() { setText(Messages.OSView_CopyAction); setImageDescriptor( PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_TOOL_COPY)); } @Override public boolean isEnabled() { return !fViewer.getSelection().isEmpty(); } @Override public void run() { ISelection selection = fViewer.getSelection(); if (selection.isEmpty()) return; if (selection instanceof IStructuredSelection) { @SuppressWarnings("unchecked") OSData data = ((ContentLabelProviderWrapper<OSData>) fViewer.getContentProvider()).getData(); StringBuilder exportStr = new StringBuilder(); for (Object elmnt : ((IStructuredSelection) selection).toList()) { assert elmnt instanceof IResourcesInformation; if (elmnt instanceof IResourcesInformation) { IResourcesInformation ri = (IResourcesInformation) elmnt; exportStr.append(data.getColumnText(ri, 0)); for (int i = 1; i < data.getColumnCount(); i++) { exportStr.append(COLUMN_SEPARATOR).append(data.getColumnText(ri, i)); } exportStr.append(EOL_CHAR); } } Clipboard cb = new Clipboard(Display.getDefault()); TextTransfer textTransfer = TextTransfer.getInstance(); cb.setContents(new Object[] { exportStr.toString() }, new Transfer[] { textTransfer }); } } } }