com.netxforge.netxstudio.screens.f3.charts.ChartScreen.java Source code

Java tutorial

Introduction

Here is the source code for com.netxforge.netxstudio.screens.f3.charts.ChartScreen.java

Source

/*******************************************************************************
 * Copyright (c) 16 dec. 2012 NetXForge.
 * 
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details. You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>
 * 
 * Contributors: Christophe Bouhier - initial API and implementation and/or
 * initial documentation
 *******************************************************************************/
package com.netxforge.netxstudio.screens.f3.charts;

import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.databinding.EMFDataBindingContext;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.ShellAdapter;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.part.ShowInContext;

import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
import com.netxforge.base.cdo.MonitoringStateEvent;
import com.netxforge.netxstudio.common.model.ChartModelProvider;
import com.netxforge.netxstudio.common.model.IChartModel;
import com.netxforge.netxstudio.common.model.IChartResource;
import com.netxforge.netxstudio.common.model.IMonitoringSummary;
import com.netxforge.netxstudio.common.model.MonitoringStateModel;
import com.netxforge.netxstudio.common.model.MonitoringStateModel.JobCallBack;
import com.netxforge.netxstudio.common.model.MonitoringStateModel.MonitoringStateCallBack;
import com.netxforge.netxstudio.common.model.NetxresourceSummary;
import com.netxforge.netxstudio.library.Component;
import com.netxforge.netxstudio.library.NetXResource;
import com.netxforge.netxstudio.operators.ResourceMonitor;
import com.netxforge.netxstudio.screens.AbstractScreen;
import com.netxforge.netxstudio.screens.editing.ScreenRefresher;
import com.netxforge.netxstudio.screens.showins.ChartInput;
import com.netxforge.netxstudio.screens.showins.ChartMergeInput;
import com.netxforge.screens.editing.base.IDataScreenInjection;
import com.netxforge.screens.editing.base.IScreen;

/**
 * 
 * @author Christophe Bouhier
 */
public class ChartScreen extends AbstractScreen implements IDataScreenInjection, MonitoringStateCallBack {

    /** A provider for an {@link IChartModel}el */
    @Inject
    private ChartModelProvider chartModelProvider;

    /** Holds model data together for the chart */
    private IChartModel chartModel = null;

    /**
     * A specialized chart for {@link NetXResource} and {@link ResourceMonitor}
     * objects
     */
    private ChartNetXResource chart;

    private ShellAdapter shellAdapter;

    /**
     * Track the last selection.
     */
    private Object[] injectedObjects;

    @Inject
    private MonitoringStateModel monitoringState;

    private FormToolkit toolkit;

    /**
     * Monitoring callback job
     */
    private JobCallBack jobCallBack;

    private ModeScreenRefresher refreshSummaryJob;

    /**
     * The parent {@link Form}. The form text will be updated with a textual
     * representation of the chart info.
     * 
     */
    private Form form;

    /**
     * In this mode new objects are merged in the chart. Existing settings (i.e.
     * visibility) are maintained.
     */
    public static int MODE_MERGE_CHART = 1 << 1;

    /**
     * In this mode new objects are processed in a new {@link IChartModel}. All
     * specific settings will disappear as the {@link IChartModel} is cleared.
     */
    public static int MODE_REINIT_MODEL = 1 << 2;

    /**
     * Refreshes the Chart UI.
     * 
     * @author Christophe Bouhier
     */

    private void refreshSummaryUI(int mode, Collection<IMonitoringSummary> summaries) {

        // System.out.println("updating for mode: " + mode);

        if ((mode & MODE_REINIT_MODEL) > 0) {
            getChartModel().clear();
            for (IMonitoringSummary summary : summaries) {
                // Refactor
                if (summary instanceof NetxresourceSummary) {
                    getChartModel().addChartResource((NetxresourceSummary) summary);
                }
            }
        } else if ((mode & MODE_MERGE_CHART) > 0) {
            List<NetxresourceSummary> toAdd = Lists.newArrayList();
            for (IMonitoringSummary summary : summaries) {
                if (summary instanceof NetxresourceSummary) {
                    NetxresourceSummary netxSummary = (NetxresourceSummary) summary;
                    boolean found = false;
                    for (IChartResource r : getChartModel().getChartResources()) {
                        if (r.getNetXResource() == summary.getTarget()) {
                            // not found break and continue to the next summary.
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        toAdd.add(netxSummary);
                    }

                }
            }
            // now add them.
            // System.out.println("adding " + toAdd.size() + " chart(s)");
            for (NetxresourceSummary s : toAdd) {
                getChartModel().addChartResource(s);
            }
        }
        form.setText(getChartModel().getChartText());

        chart.initChartBinding(getChartModel());
    }

    public ChartScreen(Form form, int style) {
        super(form.getBody(), style);
        this.form = form;
        addDisposeListener(new DisposeListener() {
            public void widgetDisposed(DisposeEvent e) {
                chart.dispose();
                if (jobCallBack != null) {
                    monitoringState.deActivate(jobCallBack);
                }
                ChartScreen.this.getShell().removeShellListener(shellAdapter);
                disposeData();
            }
        });

    }

    public void buildUI(FormToolkit toolkit) {
        this.toolkit = toolkit;
        toolkit.adapt(this);
        toolkit.paintBordersFor(this);

        setLayout(new GridLayout(2, false));
        GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1);
        gridData.heightHint = 400;
        gridData.widthHint = 600;
        chart = new ChartNetXResource(this, SWT.NONE, gridData);

        // buildScrollStick(cmChart);
        // buildZoom(cmChart);

        // registerFocus(this);
        shellAdapter = new ShellAdapter() {
            @Override
            public void shellDeactivated(ShellEvent e) {
                focusLost(null);
            }

        };
        getShell().addShellListener(shellAdapter);

    }

    /**
     * @param cmChart
     */
    @SuppressWarnings("unused")
    private void buildZoom(Composite cmChart) {

        // ZOOM etc... buttons.

        Button btnZoomIn = toolkit.createButton(cmChart, "Z+", SWT.NONE);
        btnZoomIn.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                getChart().getAxisSet().zoomIn();
                getChart().redraw();
            }
        });
        GridData gd_btnZoomIn = new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1);
        gd_btnZoomIn.widthHint = 24;
        gd_btnZoomIn.heightHint = 18;
        btnZoomIn.setLayoutData(gd_btnZoomIn);

        Button btnZoomOut = toolkit.createButton(cmChart, "Z-", SWT.NONE);
        btnZoomOut.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                getChart().getAxisSet().zoomOut();
                getChart().redraw();
            }
        });

        GridData gd_btnZoomOut = new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1);
        gd_btnZoomOut.widthHint = 24;
        gd_btnZoomOut.heightHint = 18;
        btnZoomOut.setLayoutData(gd_btnZoomOut);
    }

    /**
     * A Scroll stick which scrolls the Y-Axis up or down, and the X-Axis left
     * and right.
     * 
     * @param parent
     * @param gd
     */
    @SuppressWarnings("unused")
    private void buildScrollStick(Composite parent) {

        GridData gridData = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);

        Composite compositeScrollStick = toolkit.createComposite(parent, SWT.NONE);
        compositeScrollStick.setLayoutData(gridData);
        toolkit.paintBordersFor(compositeScrollStick);
        GridLayout gl_compositeScrollStick = new GridLayout(3, false);
        gl_compositeScrollStick.marginTop = 3;
        gl_compositeScrollStick.verticalSpacing = 0;
        gl_compositeScrollStick.marginWidth = 0;
        gl_compositeScrollStick.marginHeight = 0;
        gl_compositeScrollStick.horizontalSpacing = 0;
        compositeScrollStick.setLayout(gl_compositeScrollStick);

        new Label(compositeScrollStick, SWT.NONE);
        Button btnUpScroll = toolkit.createButton(compositeScrollStick, "", SWT.ARROW | SWT.UP);
        btnUpScroll.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                getChart().getAxisSet().getYAxis(0).scrollUp();
                getChart().redraw();
            }
        });
        new Label(compositeScrollStick, SWT.NONE);

        Button btnLeftScroll = toolkit.createButton(compositeScrollStick, "", SWT.ARROW | SWT.LEFT);
        btnLeftScroll.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                getChart().getAxisSet().getXAxis(0).scrollDown();
                getChart().redraw();
            }
        });
        new Label(compositeScrollStick, SWT.NONE);
        Button btnRightScroll = toolkit.createButton(compositeScrollStick, "", SWT.ARROW | SWT.RIGHT);
        btnRightScroll.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                getChart().getAxisSet().getXAxis(0).scrollUp();
                getChart().redraw();
            }
        });

        new Label(compositeScrollStick, SWT.NONE);
        Button btnDownScroll = toolkit.createButton(compositeScrollStick, "", SWT.ARROW | SWT.DOWN);
        btnDownScroll.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                getChart().getAxisSet().getYAxis(0).scrollDown();
                getChart().redraw();
            }
        });
        new Label(compositeScrollStick, SWT.NONE);
    }

    public ChartNetXResource getChart() {
        return chart;
    }

    public Viewer getViewer() {
        return null;
    }

    @Override
    public void injectData(Object... objects) {
        internalInjectData(MODE_REINIT_MODEL, objects);
    }

    private void internalInjectData(int mode, Object... objects) {
        if (validSelection(objects)) {

            if ((mode & MODE_REINIT_MODEL) > 0) {
                setInjectedObjects(objects);
            } else if ((mode & MODE_MERGE_CHART) > 0) {
                // merge the objects, but instruct the refresher to only process
                // delta/added IMonitoringSummaries.
                mergeInjectedObjects(objects);
            }
            refreshSummary(mode);
            if (jobCallBack == null) {
                jobCallBack = monitoringState.new JobCallBack();
                jobCallBack.setCallBack(this);
            }

            monitoringState.deActivate(jobCallBack);

            // This will inform us of many monitoring events, but not necessarly
            // for our target injected object.
            // so make sure the call back analyses which objects this concerns.
            monitoringState.activate(jobCallBack);
        } else {
            // System.out.println("invalid selection: " + objects);
        }
    }

    /**
     * The selection should be objects of the type {@link EObject} and not be
     * already the currently injected objects in the {@link IScreen}.
     * 
     * @param selection
     * @return
     */
    private boolean validSelection(Object[] selection) {

        // Check if we are the same as previously injected.
        // Same length, same objects.
        if (injectedObjects != null && (selection.length == injectedObjects.length)) {
            boolean allEqual = false;
            final Iterator<Object> currentObjects = Lists.newArrayList(injectedObjects).iterator();
            for (Object o : selection) {
                allEqual |= Iterators.contains(currentObjects, o);
            }
            if (allEqual) {
                return false;
            }
        }

        for (Object o : selection) {
            if (o instanceof EObject) {
                continue;
            } else {
                return false;
            }
        }
        return true;
    }

    public void addData() {
        // N/A this is a view screen.
    }

    public boolean isValid() {
        return true;
    }

    public EMFDataBindingContext initDataBindings_() {
        EMFDataBindingContext context = new EMFDataBindingContext();
        // CB FIXME refactor markers.
        // if (chartModel.hasMarkers()) {
        // initMarkersBindingCollection();
        // } else {
        // markersTableViewer.getTable().setSelection(-1);
        // markersTableViewer.getTable().clearAll();
        // }

        return context;
    }

    public Form getScreenForm() {
        return form;
    }

    public void disposeData() {
    }

    public String getScreenName() {
        return "Resource graph";
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.netxforge.netxstudio.screens.AbstractScreenImpl#handleShowIn(org.
     * eclipse.ui.part.ShowInContext)
     */
    @SuppressWarnings("unchecked")
    @Override
    public boolean handleShowIn(ShowInContext context) {

        ISelection selection = context.getSelection();
        if (selection != null && !selection.isEmpty() && selection instanceof StructuredSelection) {
            IStructuredSelection ss = (StructuredSelection) selection;
            final Object[] objects = Lists.newArrayList(ss.iterator()).toArray();
            if (context.getInput() instanceof ChartMergeInput) {
                internalInjectData(MODE_MERGE_CHART, objects);
                return true;
            } else if (context.getInput() instanceof ChartInput) {
                internalInjectData(MODE_REINIT_MODEL, objects);
                return true;
            } else if (context.getInput() instanceof ChartMergeInput) {

            }
        }

        return false;
    }

    /**
     * process the injected object, obtains the {@link IMonitoringSummary} for
     * eligible objects and files a UI refresh job to reload the chart model or
     * add charts to the existing model.
     */
    private void refreshSummary(int mode) {

        List<IMonitoringSummary> summariesToRefresh = Lists.newArrayList();
        for (Object injectedObject : getInjectedObjects()) {
            if (injectedObject instanceof NetXResource) {
                NetXResource target = (NetXResource) injectedObject;

                if (MonitoringStateModel.isAdapted(target)) {

                    NetxresourceSummary summary = (NetxresourceSummary) MonitoringStateModel.getAdapted(target);
                    summariesToRefresh.add(summary);
                } else {
                    System.out.println("target not adapted: " + target);
                }
            } else if (injectedObject instanceof Component) {
                Component c = (Component) injectedObject;
                for (NetXResource target : c.getResourceRefs()) {
                    if (MonitoringStateModel.isAdapted(target)) {

                        NetxresourceSummary summary = (NetxresourceSummary) MonitoringStateModel.getAdapted(target);
                        summariesToRefresh.add(summary);
                    } else {
                        System.out.println("target not adapted: " + target);
                    }

                }
            }
        }

        if (summariesToRefresh.isEmpty()) {
            // Do not refresh the UI for not understood injections. (Should have
            // happened in validation!).
            return;
        }

        // Do the refresh.
        if (refreshSummaryJob == null) {
            refreshSummaryJob = new ModeScreenRefresher();
        }
        refreshSummaryJob.setSummary(summariesToRefresh);
        refreshSummaryJob.setMode(mode);
        refreshSummaryJob.schedule(100);

    }

    class ModeScreenRefresher extends ScreenRefresher {

        private int mode;

        @Override
        public void refreshSummaryUI(Collection<IMonitoringSummary> summaries) {

            // This clears the chart model.
            ChartScreen.this.refreshSummaryUI(mode, summaries);
        }

        public int getMode() {
            return mode;
        }

        public void setMode(int mode) {
            this.mode = mode;
        }
    }

    @Override
    public void focusLost(FocusEvent e) {
        // remove the markers.
        chart.hideHover();
    }

    public IChartModel getChartModel() {
        if (chartModel == null) {
            chartModel = chartModelProvider.get();
        }
        return chartModel;
    }

    /**
     * Reconstruct the chart for the given {@link IChartModel}. The
     */
    public void reinit() {
        form.setText(getChartModel().getChartText());
        getChart().initChartBinding(getChartModel());
    }

    public void toggleSum(boolean checked) {
        getChartModel().setShouldSum(checked);
        chart.updateSum();
    }

    public void toggleTrending(boolean checked) {
        getChartModel().setShouldTrend(checked);
        chart.updateTrending();
    }

    public void callBackEvent(MonitoringStateEvent event) {

        // We are called back for monitoring events.
        Object result = event.getResult();
        boolean shouldRefresh = false;
        if (result instanceof IMonitoringSummary) {
            Notifier target = ((IMonitoringSummary) result).getTarget();
            final Iterator<Object> currentObjects = Lists.newArrayList(getInjectedObjects()).iterator();
            if (Iterators.contains(currentObjects, target)) {
                shouldRefresh = true;
            }
        }
        if (shouldRefresh) {

            // The mode is depending on how it was initially requested.
            // It would be better to embed the model in the adapter, so
            // it always stays with the object to be processed.
            // for now, use a default, which is reinit the chart model.
            refreshSummary(MODE_REINIT_MODEL);
        }
        monitoringState.deActivate(jobCallBack);
    }

    // Screen model.

    public synchronized void setInjectedObjects(Object[] objects) {
        injectedObjects = objects;
    }

    public synchronized Object[] getInjectedObjects() {
        if (editingService.isDataAlive(injectedObjects)) {
            return injectedObjects;
        } else {
            // An empty array.
            return new Object[] {};
        }

    }

    public synchronized void clearInjectedObjects() {
        injectedObjects = null;
    }

    public void mergeInjectedObjects(Object[] objects) {
        List<Object> mergedObjects = Lists.newArrayList(this.getInjectedObjects());
        mergedObjects.addAll(Arrays.asList(objects));
        setInjectedObjects(mergedObjects.toArray());
        // System.out.println("objects size: " + getInjectedObjects().length);
    }

    @Override
    public String toString() {
        if (getChartModel() != null) {
            return getChartModel().getChartText();
        } else {
            return super.toString();
        }
    }
}