| /******************************************************************************* |
| * Copyright (c) 2018 Agence spatiale canadienne / Canadian Space Agency |
| * 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: |
| * Pierre Allard, |
| * Regent L'Archeveque, |
| * Olivier L. Larouche - initial API and implementation |
| * |
| * SPDX-License-Identifier: EPL-1.0 |
| * |
| *******************************************************************************/ |
| package org.eclipse.apogy.core.invocator.ui.parts; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import javax.inject.Inject; |
| |
| import org.eclipse.apogy.common.emf.transaction.ApogyCommonTransactionFacade; |
| import org.eclipse.apogy.common.emf.ui.parts.AbstractEObjectSelectionPart; |
| import org.eclipse.apogy.core.invocator.AbstractProgramRuntime; |
| import org.eclipse.apogy.core.invocator.ApogyCoreInvocatorFacade; |
| import org.eclipse.apogy.core.invocator.ApogyCoreInvocatorFactory; |
| import org.eclipse.apogy.core.invocator.ApogyCoreInvocatorPackage; |
| import org.eclipse.apogy.core.invocator.OperationCall; |
| import org.eclipse.apogy.core.invocator.OperationCallsListProgramRuntime; |
| import org.eclipse.apogy.core.invocator.Program; |
| import org.eclipse.apogy.core.invocator.ProgramRuntimeState; |
| import org.eclipse.apogy.core.invocator.ui.ApogyCoreInvocatorUIRCPConstants; |
| import org.eclipse.apogy.core.invocator.ui.ProgramUIFactoriesRegistry; |
| import org.eclipse.apogy.core.invocator.ui.ProgramUIFactory; |
| import org.eclipse.apogy.core.invocator.ui.composites.OperationCallsListComposite; |
| import org.eclipse.e4.core.services.events.IEventBroker; |
| import org.eclipse.e4.ui.model.application.ui.basic.MPart; |
| import org.eclipse.e4.ui.workbench.UIEvents; |
| import org.eclipse.e4.ui.workbench.modeling.ISelectionListener; |
| import org.eclipse.emf.common.notify.Adapter; |
| import org.eclipse.emf.common.notify.Notification; |
| import org.eclipse.emf.common.notify.impl.AdapterImpl; |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.jface.viewers.ISelection; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.layout.FillLayout; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.ui.IWorkbenchPart; |
| |
| public class ProgramPart extends AbstractEObjectSelectionPart implements org.eclipse.ui.ISelectionListener { |
| |
| List<AbstractProgramRuntime> runtimes; |
| private Adapter runtimeAdapter; |
| |
| @Inject |
| private IEventBroker broker; |
| |
| private Program selectedProgram = null; |
| |
| private Composite top; |
| |
| @Override |
| protected void createContentComposite(Composite parent, int style) { |
| this.top = new Composite(parent, SWT.NONE); |
| this.top.setLayout(new FillLayout()); |
| } |
| |
| @Override |
| protected void setCompositeContents(EObject eObject) { |
| if (this.runtimes != null) { |
| for (AbstractProgramRuntime runtime : this.runtimes) { |
| runtime.eAdapters().remove(getRuntimeAdapter()); |
| } |
| } |
| this.runtimes.clear(); |
| |
| // Remove previous composite child. |
| if (!this.top.isDisposed()) { |
| for (Control control : this.top.getChildren()) { |
| if (!control.isDisposed()) |
| control.dispose(); |
| } |
| } |
| |
| if (eObject instanceof Program) { |
| this.selectedProgram = (Program) eObject; |
| |
| ProgramUIFactory programUIFactory = ProgramUIFactoriesRegistry.INSTANCE |
| .getFactory(this.selectedProgram.eClass()); |
| |
| if (programUIFactory != null) { |
| programUIFactory.createProgramComposite(this.top, (Program) eObject, this); |
| |
| /** Creates the runtimesList if null. */ |
| if (ApogyCoreInvocatorFacade.INSTANCE.getActiveInvocatorSession().getProgramRuntimesList() == null) { |
| ApogyCommonTransactionFacade.INSTANCE.basicSet( |
| ApogyCoreInvocatorFacade.INSTANCE.getActiveInvocatorSession(), |
| ApogyCoreInvocatorPackage.Literals.INVOCATOR_SESSION__PROGRAM_RUNTIMES_LIST, |
| ApogyCoreInvocatorFactory.eINSTANCE.createProgramRuntimesList()); |
| } |
| |
| /** Gets the current runtimes. */ |
| for (AbstractProgramRuntime runtime : ApogyCoreInvocatorFacade.INSTANCE.getActiveInvocatorSession() |
| .getProgramRuntimesList().getProgramRuntimes()) { |
| if (runtime.getProgram() == eObject) { |
| newRuntime(runtime); |
| } |
| } |
| /** To trigger a notify changed to display colors. */ |
| if (!this.runtimes.isEmpty()) { |
| AbstractProgramRuntime runtime = this.runtimes.get(this.runtimes.size() - 1); |
| ApogyCommonTransactionFacade.INSTANCE.basicSet(runtime, |
| ApogyCoreInvocatorPackage.Literals.ABSTRACT_PROGRAM_RUNTIME__STATE, runtime.getState()); |
| } |
| } else { |
| setEObject(null); |
| } |
| } else { |
| this.selectedProgram = null; |
| } |
| |
| this.top.layout(); |
| |
| } |
| |
| @Override |
| protected HashMap<String, ISelectionListener> getSelectionProvidersIdsToSelectionListeners() { |
| HashMap<String, ISelectionListener> selectionProvidersIdsToSelectionListeners = new HashMap<String, ISelectionListener>(); |
| |
| selectionProvidersIdsToSelectionListeners |
| .put(ApogyCoreInvocatorUIRCPConstants.PART__SCRIPT_BASED_PROGRAMS_LIST__ID, this.DEFAULT_LISTENER); |
| |
| return selectionProvidersIdsToSelectionListeners; |
| } |
| |
| @Override |
| public void userPostConstruct(MPart mPart) { |
| this.runtimes = new ArrayList<AbstractProgramRuntime>(); |
| super.userPostConstruct(mPart); |
| } |
| |
| public void newRuntime(AbstractProgramRuntime runtime) { |
| this.runtimes.add(runtime); |
| runtime.eAdapters().add(getRuntimeAdapter()); |
| } |
| |
| public List<AbstractProgramRuntime> getRuntimes() { |
| return this.runtimes; |
| } |
| |
| public Program getSelectedProgram() { |
| return this.selectedProgram; |
| } |
| |
| private Adapter getRuntimeAdapter() { |
| if (this.runtimeAdapter == null) { |
| this.runtimeAdapter = new AdapterImpl() { |
| @SuppressWarnings("unchecked") |
| @Override |
| public void notifyChanged(Notification msg) { |
| if (msg.getNotifier() == ProgramPart.this.runtimes.get(ProgramPart.this.runtimes.size() - 1)) { |
| |
| Display.getDefault().syncExec(new Runnable() { |
| @Override |
| public void run() { |
| /** |
| * If the feature changed is the state of the runtime |
| */ |
| if (msg.getFeature() == ApogyCoreInvocatorPackage.Literals.ABSTRACT_PROGRAM_RUNTIME__STATE) { |
| /** Update the part */ |
| ProgramPart.this.broker.send(UIEvents.REQUEST_ENABLEMENT_UPDATE_TOPIC, |
| UIEvents.ALL_ELEMENT_ID); |
| |
| /** If the state is terminated */ |
| if (msg.getNewValue() == ProgramRuntimeState.TERMINATED) { |
| if (getActualComposite() instanceof OperationCallsListComposite) { |
| /** Set background colors */ |
| ((OperationCallsListComposite) getActualComposite()) |
| .setBackgroudColor(Collections.EMPTY_MAP); |
| } |
| |
| /** |
| * Remove the adapter and remove the runtime from the list |
| */ |
| AbstractProgramRuntime runtime = (AbstractProgramRuntime) msg.getNotifier(); |
| runtime.eAdapters().remove(this); |
| ProgramPart.this.runtimes.remove(runtime); |
| } |
| } |
| |
| /** To update the colors */ |
| if (getActualComposite() instanceof OperationCallsListComposite) { |
| OperationCallsListComposite composite = (OperationCallsListComposite) getActualComposite(); |
| |
| if (msg.getFeature() == ApogyCoreInvocatorPackage.Literals.ABSTRACT_PROGRAM_RUNTIME__STATE |
| || msg.getFeature() == ApogyCoreInvocatorPackage.Literals.OPERATION_CALLS_LIST_PROGRAM_RUNTIME__INDEX_CURRENTLY_EXECUTED |
| || msg.getFeature() == ApogyCoreInvocatorPackage.Literals.OPERATION_CALLS_LIST_PROGRAM_RUNTIME__INDEX_LAST_EXECUTED) { |
| |
| Map<OperationCall, Integer> map = new HashMap<>(); |
| OperationCallsListProgramRuntime runtime = (OperationCallsListProgramRuntime) msg |
| .getNotifier(); |
| EList<OperationCall> opsCall = composite.getOperationCallsList() |
| .getOperationCalls(); |
| |
| /** If the runtime is running */ |
| if (runtime.getState() == ProgramRuntimeState.RUNNING |
| || runtime.getState() == ProgramRuntimeState.RUNNING_SUSPENDED |
| || runtime.getState() == ProgramRuntimeState.RUNNING_TERMINATED) { |
| if (runtime.getIndexCurrentlyExecuted() != -1) { |
| /** |
| * Set the currently executed opCall background green |
| */ |
| map.put(opsCall.get(runtime.getIndexCurrentlyExecuted()), |
| SWT.COLOR_GREEN); |
| } |
| } |
| /** |
| * Otherwise, if the runtime is suspended |
| */ |
| else if (runtime.getState() == ProgramRuntimeState.SUSPENDED) { |
| if (runtime.getIndexLastExecuted() != -1 |
| && runtime.getIndexLastExecuted() + 1 != opsCall.size()) { |
| /** |
| * Set the next executed opCall background yellow |
| */ |
| map.put(opsCall.get(runtime.getIndexLastExecuted() + 1), |
| SWT.COLOR_YELLOW); |
| } |
| } |
| composite.setBackgroudColor(map); |
| } |
| |
| } |
| |
| } |
| }); |
| } |
| |
| } |
| }; |
| } |
| return this.runtimeAdapter; |
| } |
| |
| @Override |
| public void userPreDestroy(MPart mPart) { |
| if (this.runtimes != null) { |
| for (AbstractProgramRuntime runtime : this.runtimes) { |
| runtime.eAdapters().remove(getRuntimeAdapter()); |
| } |
| } |
| super.userPreDestroy(mPart); |
| } |
| |
| @Override |
| public void selectionChanged(IWorkbenchPart arg0, ISelection selection) { |
| if (selection instanceof IStructuredSelection) { |
| IStructuredSelection iStructuredSelection = (IStructuredSelection) selection; |
| this.selectionService.setSelection(iStructuredSelection.getFirstElement()); |
| } |
| } |
| |
| } |