com.netxforge.netxstudio.screens.f4.JobRuns.java Source code

Java tutorial

Introduction

Here is the source code for com.netxforge.netxstudio.screens.f4.JobRuns.java

Source

/*******************************************************************************
 * Copyright (c) May 16, 2011 NetXForge.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser 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 Lesser 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.f4;

import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.map.IMapChangeListener;
import org.eclipse.core.databinding.observable.map.IObservableMap;
import org.eclipse.core.databinding.observable.map.MapChangeEvent;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.cdo.CDOObject;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.databinding.EMFDataBindingContext;
import org.eclipse.emf.databinding.EMFObservables;
import org.eclipse.emf.databinding.EMFProperties;
import org.eclipse.emf.databinding.IEMFListProperty;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.LabelProviderChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.ProgressBar;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.progress.UIJob;
import org.eclipse.wb.swt.TableViewerColumnSorter;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.netxforge.base.NonModelUtils;
import com.netxforge.netxstudio.common.model.StudioUtils;
import com.netxforge.netxstudio.scheduling.ComponentWorkFlowRun;
import com.netxforge.netxstudio.scheduling.Job;
import com.netxforge.netxstudio.scheduling.JobRunContainer;
import com.netxforge.netxstudio.scheduling.JobRunState;
import com.netxforge.netxstudio.scheduling.MetricSourceJob;
import com.netxforge.netxstudio.scheduling.SchedulingPackage;
import com.netxforge.netxstudio.scheduling.WorkFlowRun;
import com.netxforge.netxstudio.screens.AbstractScreen;
import com.netxforge.netxstudio.screens.editing.commands.WarningDeleteCommand;
import com.netxforge.netxstudio.screens.editing.tables.CDOElementComparer;
import com.netxforge.netxstudio.screens.f4.support.LogDialog;
import com.netxforge.netxstudio.screens.internal.ScreensActivator;
import com.netxforge.screens.editing.base.IDataScreenInjection;
import com.netxforge.screens.editing.base.actions.BaseSelectionListenerAction;

/**
 * @author Christophe Bouhier christophe.bouhier@netxforge.com
 * 
 */
public class JobRuns extends AbstractScreen implements IDataScreenInjection {

    private final FormToolkit toolkit = new FormToolkit(Display.getCurrent());
    // private Table table;

    private Menu jobRunMenu;

    private CleanJobRunsAction cleanJobRunsAction;

    /*
     * A Job responsible for refresh.
     */
    private RefreshUIJob refreshUIJob;

    public JobRuns(Composite parent, int style) {
        super(parent, style);

        refreshUIJob = new RefreshUIJob("refresh JobRuns");

        addDisposeListener(new DisposeListener() {
            public void widgetDisposed(DisposeEvent e) {
                toolkit.dispose();
            }
        });
        toolkit.adapt(this);
        toolkit.paintBordersFor(this);
    }

    private void buildUI() {
        setLayout(new FillLayout(SWT.HORIZONTAL));

        frmJobRuns = toolkit.createForm(this);
        frmJobRuns.setSeparatorVisible(true);
        cleanJobRunsAction = new CleanJobRunsAction("Clean up...");
        frmJobRuns.getMenuManager().add(cleanJobRunsAction);

        toolkit.paintBordersFor(frmJobRuns);

        frmJobRuns.setText("Job: \"Job name\"");
        frmJobRuns.getBody().setLayout(new FormLayout());

        Section sctnInfo = toolkit.createSection(frmJobRuns.getBody(), Section.EXPANDED | Section.TITLE_BAR);
        FormData fd_sctnInfo = new FormData();
        fd_sctnInfo.top = new FormAttachment(frmJobRuns.getBody(), 12);
        fd_sctnInfo.bottom = new FormAttachment(100, -12);
        fd_sctnInfo.right = new FormAttachment(100, -12);
        fd_sctnInfo.left = new FormAttachment(0, 12);
        sctnInfo.setLayoutData(fd_sctnInfo);
        toolkit.paintBordersFor(sctnInfo);
        sctnInfo.setText("Runs");

        Composite composite_1 = toolkit.createComposite(sctnInfo, SWT.NONE);
        toolkit.paintBordersFor(composite_1);
        sctnInfo.setClient(composite_1);
        GridLayout gl_composite_1 = new GridLayout(1, false);
        gl_composite_1.horizontalSpacing = 8;
        composite_1.setLayout(gl_composite_1);

        jobRunsTableViewer = new TableViewer(composite_1, SWT.BORDER | SWT.FULL_SELECTION);
        jobRunsTableViewer.setComparer(new CDOElementComparer());
        Table table = jobRunsTableViewer.getTable();

        table.setLinesVisible(true);
        table.setHeaderVisible(true);
        table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
        toolkit.paintBordersFor(table);

        TableViewerColumn tableViewerColumn_7 = new TableViewerColumn(jobRunsTableViewer, SWT.NONE);
        TableColumn tblclmnRunType = tableViewerColumn_7.getColumn();
        tblclmnRunType.setWidth(100);
        tblclmnRunType.setText("Run Type");

        TableViewerColumn tableViewerColumn = new TableViewerColumn(jobRunsTableViewer, SWT.NONE);
        TableColumn tblclmnStatus = tableViewerColumn.getColumn();
        tblclmnStatus.setWidth(97);
        tblclmnStatus.setText("Status");

        TableViewerColumn tblViewerColumnProgress = new TableViewerColumn(jobRunsTableViewer, SWT.NONE);
        TableColumn tblclmnProgress = tblViewerColumnProgress.getColumn();
        tblclmnProgress.setWidth(116);
        tblclmnProgress.setText("Progress");

        TableViewerColumn tableViewerColumn_2 = new TableViewerColumn(jobRunsTableViewer, SWT.NONE);
        TableColumn tblclmnTask = tableViewerColumn_2.getColumn();
        tblclmnTask.setWidth(300);
        tblclmnTask.setText("Task");

        TableViewerColumn tableViewerColumn_6 = new TableViewerColumn(jobRunsTableViewer, SWT.NONE);
        TableColumn tblclmnMessage = tableViewerColumn_6.getColumn();
        tblclmnMessage.setWidth(200);
        tblclmnMessage.setText("Message");

        TableViewerColumn tblViewerColumnStarted = new TableViewerColumn(jobRunsTableViewer, SWT.NONE);
        TableColumn tblclmnStarted = tblViewerColumnStarted.getColumn();
        tblclmnStarted.setWidth(120);
        tblclmnStarted.setText("Started");

        // Apply a sorter on the started date.
        TableViewerColumnSorter startedColumnSorter = new TableViewerColumnSorter(tblViewerColumnStarted) {
            protected int doCompare(Viewer viewer, Object e1, Object e2) {
                if (e1 instanceof WorkFlowRun && e2 instanceof WorkFlowRun) {

                    WorkFlowRun re1 = (WorkFlowRun) e1;
                    WorkFlowRun re2 = (WorkFlowRun) e2;

                    if (re1.eIsSet(SchedulingPackage.Literals.WORK_FLOW_RUN__STARTED)
                            && re2.eIsSet(SchedulingPackage.Literals.WORK_FLOW_RUN__STARTED))
                        return re1.getStarted().compare(re2.getStarted());
                }
                return -1;
            }

        };
        startedColumnSorter.setSorter(TableViewerColumnSorter.DESC);

        TableViewerColumn tblViewerColumnEnded = new TableViewerColumn(jobRunsTableViewer, SWT.NONE);
        TableColumn tblclmnEnded = tblViewerColumnEnded.getColumn();
        tblclmnEnded.setWidth(120);
        tblclmnEnded.setText("Ended");

        jobRunMenu = new Menu(table);
        table.setMenu(jobRunMenu);

        TableViewerColumn tableViewerColumn_3 = new TableViewerColumn(jobRunsTableViewer, SWT.NONE);
        TableColumn tblclmnLog = tableViewerColumn_3.getColumn();
        tblclmnLog.setWidth(100);
        tblclmnLog.setText("Log");
    }

    private TableViewer jobRunsTableViewer;
    private Form frmJobRuns;
    private Job job;
    private JobRunContainer jobContainer;

    class ShowLogAction extends BaseSelectionListenerAction {

        public ShowLogAction(String text) {
            super(text);
        }

        @Override
        protected boolean updateSelection(IStructuredSelection selection) {
            return assertHasLog(selection.getFirstElement());
        }

        @Override
        public void run() {

            WorkFlowRun wfr = (WorkFlowRun) getStructuredSelection().getFirstElement();
            String log = wfr.getLog();
            LogDialog ld = new LogDialog(JobRuns.this.getShell());
            ld.InjectData(log);
            ld.open();

        }

        private boolean assertHasLog(Object selectedObject) {
            return selectedObject instanceof WorkFlowRun
                    && ((WorkFlowRun) selectedObject).eIsSet(SchedulingPackage.Literals.WORK_FLOW_RUN__LOG);

        }

    }

    class CleanJobRunsAction extends Action {

        public CleanJobRunsAction(String text) {
            super(text);
        }

        @Override
        public void run() {
            if (jobContainer.getWorkFlowRuns().isEmpty()) {
                return;
            }

            boolean openQuestion = MessageDialog.openQuestion(JobRuns.this.getShell(), "Clean previous job runs",
                    "When pressing OK, the job runs for this job will be cleared\nThis action can not be reverted");
            if (openQuestion) {
                // yes selected, deletes the workflow runs.
                WarningDeleteCommand dc = new WarningDeleteCommand(editingService.getEditingDomain(),
                        jobContainer.getWorkFlowRuns());
                editingService.getEditingDomain().getCommandStack().execute(dc);

                if (editingService.isDirty()) {
                    editingService.doSave(new NullProgressMonitor());
                }
            }
        }
    }

    class ShowFailuresAction extends BaseSelectionListenerAction {

        public ShowFailuresAction(String text) {
            super(text);
        }

        @Override
        protected boolean updateSelection(IStructuredSelection selection) {
            return assertHasFailures(selection.getFirstElement()) || isMetricSourceJob(selection.getFirstElement());
        }

        private boolean assertHasFailures(Object selectedObject) {
            return selectedObject instanceof ComponentWorkFlowRun
                    && ((ComponentWorkFlowRun) selectedObject).getFailureRefs().size() > 0;
        }

        private boolean isMetricSourceJob(Object selectedObject) {
            return job instanceof MetricSourceJob;
        }

        @Override
        public void run() {

            if (job instanceof MetricSourceJob) {
                MessageDialog.openInformation(Display.getDefault().getActiveShell(), "Metric Source",
                        "Failures for job: " + job.getName()
                                + ", can be obtained from the mapping statistics for the corresponding Metric source(s)");
            } else {

                ComponentWorkFlowRun cwfr = (ComponentWorkFlowRun) this.getStructuredSelection().getFirstElement();
                JobFailuresDialog jf = new JobFailuresDialog(JobRuns.this.getShell());
                jf.setBlockOnOpen(true);
                int result = jf.open(cwfr);
                if (result == Window.OK) {
                }
            }
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.netxforge.netxstudio.data.IDataScreenInjection#injectData(java.lang
     * .Object, java.lang.Object)
     */
    public void injectData(Object owner, Object object) {

        // Ignore the owner, we don't add data.

        if (object instanceof Job) {
            job = (Job) object;

            buildUI();
            this.getScreenForm().setText("Job:" + job.getName());

            // Get the job container, forces the registration of invalidation
            // listeners.
            Resource containerResource = editingService.getData(SchedulingPackage.Literals.JOB_RUN_CONTAINER);
            jobContainer = StudioUtils.jobContainerForJob(job, containerResource);
            if (jobContainer != null) {
                initDataBindings_();
            } else {
                MessageDialog.openInformation(this.getShell(), "Job runs",
                        "This job has not run yet, wait for a server job to start. ");
                // TODO We should have a mechanims for invalidation.
            }
        }
    }

    private final List<IAction> actions = Lists.newArrayList();

    @Override
    public IAction[] getActions() {

        // lazy init actions.
        if (actions.isEmpty()) {
            actions.add(new ShowLogAction("Show Log..."));
            actions.add(new ShowFailuresAction("Show Failures..."));
        }

        return actions.toArray(new IAction[actions.size()]);

    }

    /*
     * (non-Javadoc)
     * 
     * @see com.netxforge.netxstudio.data.IDataScreenInjection#addData()
     */
    public void addData() {
        throw new java.lang.UnsupportedOperationException();
    }

    public EMFDataBindingContext initDataBindings_() {

        EMFDataBindingContext bindingContext = new EMFDataBindingContext();

        ObservableListContentProvider listContentProvider = new ObservableListContentProvider();
        jobRunsTableViewer.setContentProvider(listContentProvider);

        EAttribute dummyAttribute = EcoreFactory.eINSTANCE.createEAttribute();

        IObservableMap[] observeMaps = EMFObservables.observeMaps(listContentProvider.getKnownElements(),
                new EStructuralFeature[] { dummyAttribute, SchedulingPackage.Literals.WORK_FLOW_RUN__STATE,
                        SchedulingPackage.Literals.WORK_FLOW_RUN__PROGRESS,
                        SchedulingPackage.Literals.WORK_FLOW_RUN__PROGRESS_TASK,
                        SchedulingPackage.Literals.WORK_FLOW_RUN__PROGRESS_MESSAGE,
                        SchedulingPackage.Literals.WORK_FLOW_RUN__STARTED,
                        SchedulingPackage.Literals.WORK_FLOW_RUN__ENDED,
                        SchedulingPackage.Literals.WORK_FLOW_RUN__LOG });

        WorkflowRunObservableMapLabelProvider workflowRunObservableMapLabelProvider = new WorkflowRunObservableMapLabelProvider(
                observeMaps);
        workflowRunObservableMapLabelProvider.setTableViewer(jobRunsTableViewer);
        jobRunsTableViewer.setLabelProvider(workflowRunObservableMapLabelProvider);

        IEMFListProperty l = EMFProperties.list(SchedulingPackage.Literals.JOB_RUN_CONTAINER__WORK_FLOW_RUNS);
        IObservableList observeWorkFlowRuns = l.observe(jobContainer);
        jobRunsTableViewer.setInput(observeWorkFlowRuns);

        return bindingContext;
    }

    class WorkflowRunObservableMapLabelProvider extends LabelProvider
            implements ILabelProvider, ITableLabelProvider {

        protected IObservableMap[] attributeMaps;
        private TableViewer tableViewer;

        private Map<CDOID, TableEditor> progressCache = Maps.newHashMap();

        @SuppressWarnings("unused")
        private IMapChangeListener mapChangeListener = new IMapChangeListener() {
            public void handleMapChange(MapChangeEvent event) {
                @SuppressWarnings("rawtypes")
                Set affectedElements = event.diff.getChangedKeys();
                LabelProviderChangedEvent newEvent = new LabelProviderChangedEvent(
                        WorkflowRunObservableMapLabelProvider.this, affectedElements.toArray());

                fireLabelProviderChanged(newEvent);
                // @SuppressWarnings("rawtypes")
                // Set addedKeys = event.diff.getAddedKeys();
                // for (Object k : addedKeys) {
                // System.out.println(k);
                // addProgress(k);
                // }
            }
        };

        public WorkflowRunObservableMapLabelProvider(IObservableMap[] attributeMaps) {

            // Use invalidations to update the labels, so this won't depend on
            // the observables
            // on the actual objects. Invalidations are fired anyway.

            System.arraycopy(attributeMaps, 0, this.attributeMaps = new IObservableMap[attributeMaps.length], 0,
                    attributeMaps.length);
        }

        /*
         * Install a table editor, for the target object TableItem Note: locate
         * the table item first..
         */
        protected TableEditor addProgress(Object k) {

            if (k instanceof WorkFlowRun) {
                WorkFlowRun wfr = ((WorkFlowRun) k);
                if (progressCache.containsKey(wfr.cdoID())) {
                    return progressCache.get(wfr.cdoID());
                }

                // install a table editor on the last item...
                TableItem item = null;
                for (TableItem checkItem : tableViewer.getTable().getItems()) {
                    Object data = checkItem.getData();
                    if (data instanceof CDOObject && k instanceof CDOObject) {

                        CDOID cdoID2 = ((CDOObject) data).cdoID();
                        // System.out.println("table item with CDOID "
                        // + cdoID2.toString());
                        if (wfr.cdoID().toString().equals(cdoID2.toString())) {
                            item = checkItem;
                            break;
                        }
                    }
                    // if (EcoreUtil.equals((EObject) data, (EObject) k)) {
                    // item = checkItem;
                    // }
                }

                if (item != null) {
                    TableEditor progressEditor = new TableEditor(tableViewer.getTable());
                    progressEditor.grabHorizontal = true;
                    progressEditor.grabVertical = true;

                    ProgressControl progressControl = new ProgressControl(tableViewer.getTable(), SWT.NONE);

                    progressEditor.setEditor(progressControl, item, 2);
                    progressCache.put(wfr.cdoID(), progressEditor);
                    return progressEditor;
                }
            }
            return null;
        }

        public boolean hasProgress(CDOID current) {
            return progressCache.containsKey(current);
        }

        public WorkflowRunObservableMapLabelProvider(IObservableMap attributeMap) {
            this(new IObservableMap[] { attributeMap });
        }

        public void setTableViewer(TableViewer tableViewer) {
            this.tableViewer = tableViewer;
            // progressEditor = new TableEditor(table);
        }

        public String getText(Object element) {

            ((EObject) element).eContainmentFeature();

            return super.getText(element);
        }

        public Image getImage(Object element) {
            return getColumnImage(element, 0);
        }

        public Image getColumnImage(Object element, int columnIndex) {
            return null;
        }

        public String getColumnText(Object element, int columnIndex) {

            if (element instanceof WorkFlowRun) {
                WorkFlowRun j = (WorkFlowRun) element;

                if (columnIndex == 2) {
                    if (j.getState() == JobRunState.RUNNING) {
                        // When the application is aborted, the state will
                        // remain running.
                        //

                        // find the progress and update it.
                        TableEditor addProgress = addProgress(element);
                        if (addProgress != null) {
                            Control editor = addProgress.getEditor();
                            if (editor instanceof ProgressControl) {
                                ((ProgressControl) editor).updateProgress(j.getProgress());
                            }

                            // if (editor instanceof ProgressBar) {
                            // ((ProgressBar) editor).setSelection(j
                            // .getProgress());
                            // }
                        }
                    } else {
                        // dispose when we are not in running state.
                        if (this.hasProgress(j.cdoID())) {
                            TableEditor tableEditor = progressCache.get(j.cdoID());
                            tableEditor.getEditor().dispose();
                            tableEditor.dispose();
                            progressCache.remove(j.cdoID());

                            // System.out.println("Disposed progress for "
                            // + modelUtils.printModelObject(j));
                        }
                    }
                    // bar.set
                    // return null;
                }

                switch (columnIndex) {
                case 0: {
                    if (j instanceof ComponentWorkFlowRun) {
                        return "Expression run";
                    } else {
                        return "Workflow run";
                    }
                }
                case 1: {
                    switch (j.getState().getValue()) {
                    case JobRunState.RUNNING_VALUE: {
                        return "Running...";
                    }
                    case JobRunState.FINISHED_WITH_ERROR_VALUE: {
                        return "Done, errors occured";
                    }
                    case JobRunState.FINISHED_SUCCESSFULLY_VALUE: {
                        return "Done";
                    }
                    }
                }
                case 5: {
                    if (j.getStarted() != null) {
                        Date d = NonModelUtils.fromXMLDate(j.getStarted());
                        return NonModelUtils.date(d) + " @ " + NonModelUtils.time(d);
                    }
                }
                case 6: {
                    if (j.getEnded() != null) {
                        Date d = NonModelUtils.fromXMLDate(j.getEnded());
                        return NonModelUtils.date(d) + " @ " + NonModelUtils.time(d);
                    }
                }
                }
            }

            Object result = attributeMaps[columnIndex].get(element);
            return result == null ? "" : result.toString(); //$NON-NLS-1$

        }

        class ProgressControl extends Composite {

            private ProgressBar bar;
            private Label label;

            public ProgressControl(Composite parent, int style) {
                super(parent, style);
                StackLayout stackLayout = new StackLayout();
                stackLayout.marginHeight = 0;
                stackLayout.marginWidth = 0;

                this.setLayout(stackLayout);
                bar = new ProgressBar(this, SWT.SMOOTH);
                bar.setMaximum(100);
                bar.setSelection(0);
                // label = new Label(this, SWT.NONE);
                // label.setText("progress");
                stackLayout.topControl = bar;
            }

            public void updateProgress(int progress) {
                bar.setSelection(progress);
            }

            public void updateText(String progress) {
                label.setText(progress);
            }

            /*
             * (non-Javadoc)
             * 
             * @see
             * org.eclipse.swt.widgets.Widget#addDisposeListener(org.eclipse
             * .swt.events.DisposeListener)
             */
            @Override
            public void addDisposeListener(DisposeListener listener) {
                super.addDisposeListener(listener);
                label.dispose();
                bar.dispose();

            }
        }

    }

    // class CapacityEditingSupport extends EditingSupport {
    //
    // private TableViewer viewer;
    //
    // public CapacityEditingSupport(TableViewer viewer) {
    // super(viewer);
    // this.viewer = viewer;
    // }
    //
    // @Override
    // protected CellEditor getCellEditor(Object element) {
    // EnterCapacityCellEditor enterCapacityCellEditor = new
    // EnterCapacityCellEditor(
    // viewer.getTable());
    // enterCapacityCellEditor.setResource((NetXResource) element);
    // return enterCapacityCellEditor;
    // }
    //
    // @Override
    // protected boolean canEdit(Object element) {
    // return true;
    // }
    //
    // @Override
    // protected Object getValue(Object element) {
    // if (element instanceof NetXResource) {
    // Value v = modelUtils
    // .mostRecentCapacityValue((NetXResource) element);
    //
    // if (v != null) {
    // DecimalFormat numberFormatter = new DecimalFormat(
    // "###,###,##0.00");
    // numberFormatter.setDecimalSeparatorAlwaysShown(true);
    // return numberFormatter.format(v.getValue());
    // } else {
    // return "<not set>";
    // }
    // }
    // return null;
    // }
    //
    // @Override
    // protected void setValue(Object element, Object value) {
    // viewer.update(element, null);
    // }
    //
    // }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.ui.viewer.IViewerProvider#getViewer()
     */
    public Viewer getViewer() {
        return this.getTableViewerWidget();
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.netxforge.netxstudio.screens.editing.selector.IScreen#isValid()
     */
    public boolean isValid() {
        return true;
    }

    public TableViewer getTableViewerWidget() {
        return jobRunsTableViewer;
    }

    public Form getScreenForm() {
        return frmJobRuns;
    }

    public void disposeData() {
        // N/A
    }

    public String getScreenName() {
        return "Runs";
    }

    @Override
    public boolean shouldHandleRefresh() {
        return true;
    }

    @Override
    public void handleRefresh(Object... objects) {

        for (Object o : objects) {
            if (o instanceof Collection<?>) {
                Collection<?> dirtyObjects = (Collection<?>) o;
                for (Object dirty : dirtyObjects) {
                    handleRefresh(dirty);
                }
            }
            // Any objects which are Workflows?
            if (o instanceof WorkFlowRun) {

                // Multiple WorkFlowRuns would cancel our job, when going in
                // state DONE.

                WorkFlowRun wfr = (WorkFlowRun) o;
                JobRunState jobState = wfr.getState();
                if (jobState == JobRunState.RUNNING) {
                    if (refreshUIJob.getState() == org.eclipse.core.runtime.jobs.Job.NONE) {
                        // System.out.println("JobRuns: schedule refreshUI");
                        refreshUIJob.schedule();
                    }
                } else if (jobState == JobRunState.FINISHED_SUCCESSFULLY
                        || jobState == JobRunState.FINISHED_WITH_ERROR) {
                    refreshUIJob.cancel();
                    // Do one more to reflect the latest status.
                    getTableViewerWidget().refresh();

                }
            }
            if (o instanceof JobRunContainer) {
                refreshUIJob.schedule();
            }

        }
        // super.handleReshresh(objects);
    }

    /**
     * Updates the UI, while WorkFlow is in state running is running. TODO,
     * Potentially feed with the object, which needs to be refreshed.
     * 
     * @author Christophe Bouhier
     * 
     */
    class RefreshUIJob extends UIJob {

        public RefreshUIJob(String name) {
            super(name);
            this.setSystem(true);
        }

        @Override
        public IStatus runInUIThread(IProgressMonitor monitor) {

            if (monitor.isCanceled() || JobRuns.this.isDisposed())
                return new Status(IStatus.OK, ScreensActivator.PLUGIN_ID, IStatus.OK, "", null);

            // Potentially only update the relevant object.
            // getTableViewerWidget().up
            getTableViewerWidget().refresh();

            if (!monitor.isCanceled()) {
                refreshUIJob.schedule(500);
            }

            return new Status(IStatus.OK, PlatformUI.PLUGIN_ID, IStatus.OK, "", null);
        }
    }
}