/* * Copyright (C) 2006-2016 DLR, Germany * * All rights reserved * * http://www.rcenvironment.de/ */ package de.rcenvironment.core.gui.workflow.view.properties; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ScheduledFuture; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.viewers.ISelection; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.TreeEditor; 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.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeColumn; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.views.properties.tabbed.AbstractPropertySection; import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage; import de.rcenvironment.core.communication.common.InstanceNodeSessionId; import de.rcenvironment.core.communication.management.WorkflowHostSetListener; import de.rcenvironment.core.component.workflow.execution.api.WorkflowExecutionInformation; import de.rcenvironment.core.datamodel.api.EndpointType; import de.rcenvironment.core.gui.workflow.EndpointContentProvider; import de.rcenvironment.core.gui.workflow.editor.connections.EndpointTreeViewer; import de.rcenvironment.core.toolkitbridge.transitional.ConcurrencyUtils; import de.rcenvironment.core.utils.incubator.ServiceRegistry; import de.rcenvironment.core.utils.incubator.ServiceRegistryPublisherAccess; import de.rcenvironment.toolkit.modules.concurrency.api.TaskDescription; /** * Property section for displaying and editing inputs. * * @author Doreen Seider */ public abstract class AbstractInputSection extends AbstractPropertySection { private static final long REFRESH_INTERVAL = 1000; private static final int COLUMN_WIDTH_ONE = 250; private static final int COLUMN_WIDTH_THREE = 50; protected WorkflowExecutionInformation wfExeInfo; protected EndpointTreeViewer inputTreeViewer; private Composite parent; private List<TreeEditor> treeEditors; private InputModel inputModel; private Display display; private ServiceRegistryPublisherAccess serviceRegistryAccess; private CountDownLatch modelInitializedLatch; private ScheduledFuture<?> refreshFuture; /** * Periodically refreshes this section. * * @author Doreen Seider */ private class RefreshTask implements Runnable { @TaskDescription("Refresh inputs processed by components") @Override public void run() { if (inputTreeViewer != null && !inputTreeViewer.getTree().isDisposed()) { inputTreeViewer.getTree().getDisplay().syncExec(new Runnable() { @Override public void run() { if (inputModel != null) { refreshTable(); InputQueueDialogController inputQueueDialogController = InputQueueDialogController.getInstance(); if (inputQueueDialogController != null) { inputQueueDialogController.redrawTable(); } } } }); } } } public AbstractInputSection() { treeEditors = new ArrayList<TreeEditor>(); modelInitializedLatch = new CountDownLatch(1); Job job = new Job("Opening inputs view") { @Override protected IStatus run(IProgressMonitor monitor) { inputModel = InputModel.getInstance(); modelInitializedLatch.countDown(); return Status.OK_STATUS; } }; job.schedule(); } @Override public void setInput(IWorkbenchPart part, ISelection selection) { super.setInput(part, selection); retrieveWorkflowInformation(part, selection); initializeTreeViewer(part, selection); inputTreeViewer.expandAll(); setInputQueueButton(inputTreeViewer.getTree()); refresh(); } protected abstract void retrieveWorkflowInformation(IWorkbenchPart part, ISelection selection); protected abstract void initializeTreeViewer(IWorkbenchPart part, ISelection selection); @Override public void createControls(final Composite aParent, TabbedPropertySheetPage aTabbedPropertySheetPage) { super.createControls(parent, aTabbedPropertySheetPage); parent = aParent; display = parent.getShell().getDisplay(); GridLayout gridLayout = new GridLayout(2, false); gridLayout.horizontalSpacing = 0; gridLayout.marginWidth = 0; gridLayout.marginHeight = 0; parent.setLayout(gridLayout); inputTreeViewer = new EndpointTreeViewer(parent, SWT.FULL_SELECTION); inputTreeViewer.setContentProvider(new EndpointContentProvider(EndpointType.INPUT)); final Tree endpointTree = inputTreeViewer.getTree(); endpointTree.setHeaderVisible(true); TreeColumn inputColumn = new TreeColumn(endpointTree, SWT.LEFT); inputColumn.setText(Messages.inputs); inputColumn.setWidth(COLUMN_WIDTH_ONE); TreeColumn currentInputColumn = new TreeColumn(endpointTree, SWT.CENTER); currentInputColumn.setText(Messages.latestInput); currentInputColumn.setWidth(COLUMN_WIDTH_ONE); TreeColumn inputQueueColumn = new TreeColumn(endpointTree, SWT.LEFT); inputQueueColumn.setText(Messages.inputQueue); inputQueueColumn.setWidth(COLUMN_WIDTH_THREE); endpointTree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1)); endpointTree.setLinesVisible(true); registerWorkflowHostSetListener(); scheduleRefreshTimer(); } /** * Registers an event listener for network changes as an OSGi service (whiteboard pattern). * * @param display */ private void registerWorkflowHostSetListener() { serviceRegistryAccess = ServiceRegistry.createPublisherAccessFor(this); serviceRegistryAccess.registerService(WorkflowHostSetListener.class, new WorkflowHostSetListener() { @Override public void onReachableWorkflowHostsChanged(Set<InstanceNodeSessionId> reachableWfHosts, Set<InstanceNodeSessionId> addedWfHosts, Set<InstanceNodeSessionId> removedWfHosts) { try { modelInitializedLatch.await(); } catch (InterruptedException e) { // TODO better handling? throw new RuntimeException("Interrupted while waiting for input model creation to complete", e); } inputModel.updateSubscriptions(); display.asyncExec(new Runnable() { @Override public void run() { if (inputTreeViewer != null && !inputTreeViewer.getTree().isDisposed()) { inputTreeViewer.refresh(); } } }); } }); } @Override public void dispose() { if (refreshFuture != null) { refreshFuture.cancel(true); } if (serviceRegistryAccess != null) { serviceRegistryAccess.dispose(); } super.dispose(); } /** * Schedules the refresh timer responsible for refreshing the view every 500 milliseconds. */ public void scheduleRefreshTimer() { refreshFuture = ConcurrencyUtils.getAsyncTaskService().scheduleAtFixedRate(new RefreshTask(), REFRESH_INTERVAL); } /** * Cancels the refresh timer responsible for refreshing the view every 500 milliseconds. */ public void cancelRefreshTimer() { refreshFuture.cancel(true); } /** * Refrehes the table. Same action timer does. */ public void refreshTable() { if (inputTreeViewer != null && inputTreeViewer.getTree() != null && !inputTreeViewer.getTree().isDisposed()) { inputTreeViewer.getControl().setRedraw(false); inputTreeViewer.refresh(); inputTreeViewer.expandAll(); inputTreeViewer.getControl().setRedraw(true); setInputQueueButton(inputTreeViewer.getTree()); inputTreeViewer.getControl().redraw(); } } private void setInputQueueButton(final Tree tree) { for (TreeEditor treeEditor : treeEditors) { Control oldEditor = treeEditor.getEditor(); if (oldEditor != null) { oldEditor.dispose(); } } treeEditors.clear(); for (final TreeItem treeItem : inputTreeViewer.getTree().getItems()) { setInputQueueButton(treeItem); } } private void setInputQueueButton(final TreeItem treeItem) { if (treeItem.getItemCount() > 0) { for (final TreeItem childTreeItem : treeItem.getItems()) { setInputQueueButton(childTreeItem); } } else { TreeEditor treeEditor = new TreeEditor(inputTreeViewer.getTree()); Button button = new Button(inputTreeViewer.getTree(), SWT.PUSH); button.setText("..."); button.computeSize(SWT.DEFAULT, inputTreeViewer.getTree().getItemHeight()); treeEditor.grabHorizontal = true; treeEditor.minimumHeight = button.getSize().y; treeEditor.minimumWidth = button.getSize().x; treeEditor.setEditor(button, treeItem, 2); treeEditors.add(treeEditor); button.addSelectionListener(new SelectionAdapter() { private TreeItem item = treeItem; @Override public void widgetSelected(SelectionEvent event) { openInputDialog(item); } }); } } protected abstract void openInputDialog(TreeItem item); }