org.eclipse.ecf.raspberrypi.internal.test.gpio.ide.views.RpiGPIOPinView.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.ecf.raspberrypi.internal.test.gpio.ide.views.RpiGPIOPinView.java

Source

/*******************************************************************************
 * Copyright (c) 2014 Composent, Inc. 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: Scott Lewis - initial API and implementation
 ******************************************************************************/
package org.eclipse.ecf.raspberrypi.internal.test.gpio.ide.views;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.ecf.raspberrypi.gpio.IGPIOPin;
import org.eclipse.ecf.raspberrypi.gpio.IGPIOPinOutput;
import org.eclipse.ecf.raspberrypi.gpio.IGPIOPinOutputAsync;
import org.eclipse.ecf.remoteservice.IRemoteServiceProxy;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.part.ViewPart;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;

public class RpiGPIOPinView extends ViewPart implements ServiceTrackerCustomizer<IGPIOPinOutput, IGPIOPinOutput> {

    // static fields to hold the images
    private static final Image HIGH_IMAGE = Activator.getIconImage("icons/high.gif");
    private static final Image LOW_IMAGE = Activator.getIconImage("icons/low.gif");
    private static final Image WAITING_IMAGE = Activator.getIconImage("icons/waiting.gif");

    /**
     * The ID of the view as specified by the extension.
     */
    public static final String ID = "org.eclipse.ecf.raspberrypi.internal.test.gpio.ide.views.RpiGPIOPinView";

    public RpiGPIOPinView() {
    }

    // Model class to represent the GPIOPin in this UI
    class GPIOPin {

        private ServiceReference<IGPIOPinOutput> pinReference;
        private IGPIOPinOutput pinOutput;
        private IGPIOPinOutputAsync pinOutputAsync;
        private boolean state;
        private boolean waiting = false;

        public GPIOPin(ServiceReference<IGPIOPinOutput> pinReference, IGPIOPinOutput service, boolean initState) {
            this.pinReference = pinReference;
            this.pinOutput = service;
            if (this.pinOutput instanceof IGPIOPinOutputAsync)
                pinOutputAsync = (IGPIOPinOutputAsync) this.pinOutput;
            this.state = initState;
        }

        public String getPinId() {
            Integer i = IGPIOPin.Util.getPinId(this.pinReference);
            return String.valueOf(i.intValue());
        }

        public String getPinName() {
            return IGPIOPin.Util.getPinName(this.pinReference);
        }

        public boolean isHigh() {
            return state;
        }

        public boolean isWaiting() {
            return waiting;
        }

        public void toggle() {
            // Set waiting to true
            waiting = true;
            boolean newState = !this.state;
            // If we have asynchronous access to service,
            // then use it
            if (pinOutputAsync != null) {
                // Set state asynchronously to newState,
                // and when complete change the UI state
                // and refresh the viewer
                pinOutputAsync.setStateAsync(newState).whenComplete((result, exception) -> {
                    this.waiting = false;
                    if (viewer != null) {
                        // No exception means success
                        if (exception == null) {
                            // Set UI state to newState
                            state = newState;
                            asyncRefresh();
                        } else
                            showCommErrorDialog(exception);
                    }
                });

            } else {
                // If we do not have access to async service, then
                // call pinOutput synchronously
                pinOutput.setState(newState);
                state = newState;
            }
        }

        public void close() {
            this.pinReference = null;
            this.pinOutput = null;
            this.pinOutputAsync = null;
        }

        public String getServiceID() {
            if (this.pinOutput instanceof IRemoteServiceProxy) {
                IRemoteServiceProxy proxy = (IRemoteServiceProxy) this.pinOutput;
                return proxy.getRemoteServiceReference().getID().getContainerID().getName();
            }
            return null;
        }
    }

    private List<GPIOPin> elements = new ArrayList<GPIOPin>();
    private TableViewer viewer;

    private ServiceTracker<IGPIOPinOutput, IGPIOPinOutput> tracker;

    /**
     * This is a callback that will allow us to create the viewer and initialize
     * it.
     */
    public void createPartControl(Composite parent) {
        viewer = new TableViewer(parent, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL | SWT.FULL_SELECTION);

        String[] titles = { "Pin #", "Pin Name", "Pin State (click to toggle)", "Remote Service Container ID" };
        int[] bounds = { 100, 100, 150, 250 };

        TableViewerColumn col = createTableViewerColumn(titles[0], bounds[0], 0);
        col.setLabelProvider(new ColumnLabelProvider() {
            @Override
            public String getText(Object element) {
                return ((GPIOPin) element).getPinId();
            }
        });

        col = createTableViewerColumn(titles[1], bounds[1], 1);
        col.setLabelProvider(new ColumnLabelProvider() {
            @Override
            public String getText(Object element) {
                return ((GPIOPin) element).getPinName();
            }
        });

        col = createTableViewerColumn(titles[2], bounds[2], 2);
        col.setLabelProvider(new ColumnLabelProvider() {
            @Override
            public String getText(Object element) {
                return null;
            }

            @Override
            public Image getImage(Object element) {
                GPIOPin pin = (GPIOPin) element;
                if (pin.isWaiting())
                    return WAITING_IMAGE;
                return pin.isHigh() ? HIGH_IMAGE : LOW_IMAGE;
            }
        });

        col = createTableViewerColumn(titles[3], bounds[3], 3);
        col.setLabelProvider(new ColumnLabelProvider() {
            @Override
            public String getText(Object element) {
                return ((GPIOPin) element).getServiceID();
            }
        });

        final Table table = viewer.getTable();
        table.setHeaderVisible(true);

        table.addListener(SWT.MouseDown, new Listener() {
            @Override
            public void handleEvent(Event event) {
                Point pt = new Point(event.x, event.y);
                TableItem item = table.getItem(pt);
                if (item == null)
                    return;
                Rectangle rect = item.getBounds(2);
                if (rect.contains(pt))
                    ((GPIOPin) item.getData()).toggle();
            }
        });

        viewer.setContentProvider(ArrayContentProvider.getInstance());
        viewer.setInput(elements);

        // Setup and open service tracker to get IGPIOPinOutput
        // instances
        tracker = new ServiceTracker<IGPIOPinOutput, IGPIOPinOutput>(Activator.getContext(), IGPIOPinOutput.class,
                this);
        tracker.open();
    }

    private TableViewerColumn createTableViewerColumn(String title, int bound, final int colNumber) {
        final TableViewerColumn viewerColumn = new TableViewerColumn(viewer, SWT.NONE);
        final TableColumn column = viewerColumn.getColumn();
        column.setText(title);
        column.setWidth(bound);
        column.setResizable(true);
        column.setMoveable(true);
        return viewerColumn;
    }

    /**
     * Passing the focus request to the viewer's control.
     */
    public void setFocus() {
    }

    @Override
    public void dispose() {
        viewer = null;
        if (tracker != null) {
            tracker.close();
            tracker = null;
        }
        removePin(null);
        super.dispose();
    }

    @Override
    public IGPIOPinOutput addingService(final ServiceReference<IGPIOPinOutput> reference) {
        IGPIOPinOutput service = Activator.getContext().getService(reference);
        if (viewer == null)
            return service;
        if (service instanceof IGPIOPinOutputAsync) {
            // Get the current state
            ((IGPIOPinOutputAsync) service).getStateAsync().whenComplete((result, throwable) -> {
                // If we have a non-null result
                // then add the pin
                if (result != null)
                    addPin(reference, service, result);
                else
                    showCommErrorDialog(throwable);
            });
        } else {
            // If no async available, potentially block using
            // synchronous IGPIOPinOutput.getState()
            try {
                boolean initState = service.getState();
                addPin(reference, service, initState);
            } catch (Throwable t) {
                showCommErrorDialog(t);
            }
        }
        return service;
    }

    @Override
    public void modifiedService(ServiceReference<IGPIOPinOutput> reference, IGPIOPinOutput service) {
    }

    @Override
    public void removedService(ServiceReference<IGPIOPinOutput> reference, IGPIOPinOutput service) {
        if (viewer == null)
            return;
        removePin(reference);
        asyncRefresh();
    }

    // addPin and removePin methods used in addedService, and removedService
    private void addPin(ServiceReference<IGPIOPinOutput> reference, IGPIOPinOutput service, boolean initValue) {
        if (this.viewer == null)
            return;
        synchronized (elements) {
            elements.add(new GPIOPin(reference, service, initValue));
        }
        asyncRefresh();
    }

    private void removePin(ServiceReference<IGPIOPinOutput> reference) {
        synchronized (elements) {
            for (Iterator<GPIOPin> i = elements.iterator(); i.hasNext();) {
                GPIOPin pinUI = i.next();
                if (reference == null || pinUI.pinReference.equals(reference)) {
                    i.remove();
                    pinUI.close();
                }
            }
        }
    }

    // UI Utility methods
    void asyncExec(Runnable runnable) {
        TableViewer v = this.viewer;
        if (v == null)
            return;
        v.getControl().getDisplay().asyncExec(runnable);
    }

    void asyncRefresh() {
        asyncExec(new Runnable() {
            @Override
            public void run() {
                if (viewer == null)
                    return;
                viewer.refresh();
            }
        });
    }

    void showCommErrorDialog(Throwable exception) {
        if (viewer == null)
            return;
        MessageDialog.openError(viewer.getControl().getShell(), "GPIO Pin Error",
                "Error accessing GPIO Pin to get initial state.  Message: "
                        + ((exception == null) ? "no exception message" : exception.getMessage()));
    }

}