org.eclipse.cdt.dsf.gdb.internal.ui.osview.OSResourcesView.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.cdt.dsf.gdb.internal.ui.osview.OSResourcesView.java

Source

/*******************************************************************************
 * Copyright (c) 2011, 2012 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
 *******************************************************************************/

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.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.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.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.Event;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.ui.IActionBars;
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 && fResourceClass != null)
                        fSessionData.fetchData(fResourceClass);
            }
        });
        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) {
                fResourceClass = newClass;
                // Since user explicitly changed the class, initiate fetch immediately.
                fSessionData.fetchData(fResourceClass);
                // 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 && fResourceClass != null)
                    fSessionData.fetchData(fResourceClass);
            }
        };
        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.gif"); //$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.updateActionBars();

        fResourceClass = fResourceClassEditor.getResourceClassId();

        setupContextListener();
        DsfSession.addSessionEndedListener(this);
    }

    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.size() > 0) {
                @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 (fViewer == null || fViewer.getControl() == null)
            return;

        if (fViewer.getControl().isDisposed())
            return;

        boolean enable = fSessionData.canFetchData();
        fRefreshAction.setEnabled(enable);
        fResourceClass = 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 (fResourceClass == null) {
            fRefreshAction.setEnabled(false);
            fResourceClassEditor.setEnabled(true);
            hideTable(Messages.OSView_5);
            return;
        }

        final OSData data = fSessionData.existingData(fResourceClass);

        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(fResourceClass)));
            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(fResourceClass);
        if (fColumnLayout == null) {
            fColumnLayout = new ColumnLayout(fResourceClass);
            fColumnLayouts.put(fResourceClass, 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();
    }
}