Bläddra i källkod

Issue simulationview improvements (#1712)

* Improvements to simulationview. Added dropdown for debug session control. Added timelabel. Smart resizing of treeviewer. added native checkbox widgets for boolean values. changed simulation perspective.

* Improvements to simulationview. Added dropdown for debug session control. Added timelabel. Smart resizing of treeviewer. added native checkbox widgets for boolean values. changed simulation perspective.

* fixed repositioning bug of native checkbox widgets in simview treeviewer

* fixed repositioning bug of native checkbox widgets in simview treeviewer

* fixed merge issues. removed duplicate getter timetaskscheduler. removed old methodcall in simulationview

* removed duplicate code in ExecutionContextLabelProvider

* Update plugin.xml

* Update ExecutionContextLabelProvider.java

* changed back view id from simulationview to delcarationview, due to compatibility aspect
Robert Rudi 7 år sedan
förälder
incheckning
4ffc42c1f4

+ 0 - 2
plugins/org.yakindu.sct.simulation.core/src/org/yakindu/sct/simulation/core/engine/scheduling/DefaultTimeTaskScheduler.java

@@ -41,7 +41,6 @@ public class DefaultTimeTaskScheduler implements ITimeTaskScheduler {
 	protected boolean suspended;
 	protected boolean terminated;
 
-
 	public DefaultTimeTaskScheduler() {
 		tasks = new PriorityQueue<TimeTask>();
 		lock = new ReentrantLock();
@@ -197,7 +196,6 @@ public class DefaultTimeTaskScheduler implements ITimeTaskScheduler {
 	public void resume() {
 		suspended = false;
 		start();
-
 	}
 
 	@Override

+ 1 - 2
plugins/org.yakindu.sct.simulation.core/src/org/yakindu/sct/simulation/core/engine/scheduling/ITimeTaskScheduler.java

@@ -35,7 +35,7 @@ public interface ITimeTaskScheduler {
 	public void step();
 
 	public void terminate();
-	
+
 	public long getCurrentTime();
 
 	public static class TimeTask implements Runnable, Comparable<TimeTask> {
@@ -105,5 +105,4 @@ public interface ITimeTaskScheduler {
 			this.nextExecutionTime = nextExecutionTime;
 		}
 	}
-
 }

BIN
plugins/org.yakindu.sct.simulation.ui/icons/Clock-16.png


+ 3 - 1
plugins/org.yakindu.sct.simulation.ui/src/org/yakindu/sct/simulation/ui/SimulationImages.java

@@ -45,7 +45,9 @@ public enum SimulationImages {
 
 	LAUNCHER_ICON("icons/Statechart-Launcher-16.png"), 
 	
-	VARIABLE_LOCK("icons/Variable_lock.gif");
+	VARIABLE_LOCK("icons/Variable_lock.gif"),
+	
+	SIMULATION_CLOCK("icons/Clock-16.png");
 	
 	private final String path;
 

+ 8 - 2
plugins/org.yakindu.sct.simulation.ui/src/org/yakindu/sct/simulation/ui/perspective/SCTPerspectiveManager.java

@@ -26,6 +26,7 @@ import org.eclipse.debug.core.ILaunchConfigurationType;
 import org.eclipse.debug.core.ILaunchListener;
 import org.eclipse.debug.core.model.IDebugTarget;
 import org.eclipse.debug.internal.ui.DebugUIPlugin;
+import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
 import org.eclipse.debug.internal.ui.launchConfigurations.PerspectiveManager;
 import org.eclipse.debug.internal.ui.viewers.AsynchronousSchedulingRuleFactory;
 import org.eclipse.ui.IWorkbenchWindow;
@@ -47,9 +48,14 @@ import org.yakindu.sct.simulation.core.debugmodel.SCTDebugTarget;
 @SuppressWarnings("restriction")
 public class SCTPerspectiveManager extends PerspectiveManager implements ILaunchListener, IDebugEventSetListener {
 
-	private static final String DEBUG_VIEW_ID = "org.eclipse.debug.ui.DebugView";
+	private static final String SIMULATION_VIEW_ID = "org.yakindu.sct.simulation.ui.declarationview"; //$NON-NLS-1$
 	private static final String LAUNCH_TYPE = "org.yakindu.sct.simulation.core.launch.statechart";
 
+	public SCTPerspectiveManager() {
+		DebugUIPlugin.getDefault().getPreferenceStore().setValue(IInternalDebugUIConstants.PREF_ACTIVATE_DEBUG_VIEW,
+				false);
+	}
+
 	public void launchAdded(ILaunch launch) {
 		try {
 			ILaunchConfigurationType type = launch.getLaunchConfiguration().getType();
@@ -99,7 +105,7 @@ public class SCTPerspectiveManager extends PerspectiveManager implements ILaunch
 				// Force the debug view to open
 				if (window != null) {
 					try {
-						window.getWorkbench().getActiveWorkbenchWindow().getActivePage().showView(DEBUG_VIEW_ID);
+						window.getWorkbench().getActiveWorkbenchWindow().getActivePage().showView(SIMULATION_VIEW_ID);
 					} catch (PartInitException e) {
 						e.printStackTrace();
 					}

+ 6 - 11
plugins/org.yakindu.sct.simulation.ui/src/org/yakindu/sct/simulation/ui/perspective/SimulationPerspectiveFactory.java

@@ -31,24 +31,19 @@ public class SimulationPerspectiveFactory implements IPerspectiveFactory {
 	private void defineLayout(IPageLayout layout) {
 		String editorArea = layout.getEditorArea();
 
-		IFolderLayout left = layout.createFolder("left", IPageLayout.LEFT,
-				0.16f, editorArea);
+		IFolderLayout left = layout.createFolder("left", IPageLayout.LEFT, 0.16f, editorArea);
 		left.addView(IPageLayout.ID_PROJECT_EXPLORER);
 		// Included to get rid of a warning issued by the workbench
 		left.addPlaceholder("org.eclipse.jdt.ui.PackageExplorer");
 
-		IFolderLayout topRight = layout.createFolder("topRight",
-				IPageLayout.RIGHT, 0.84f, editorArea);
-		topRight.addView(IPageLayout.ID_OUTLINE);
+		IFolderLayout bottomleft = layout.createFolder("bottomLeft", IPageLayout.BOTTOM, 0.68f, "left");
+		bottomleft.addView(IPageLayout.ID_OUTLINE);
 
-		IFolderLayout bottomRight = layout.createFolder("bottomRight",
-				IPageLayout.BOTTOM, 0.33f, "topRight");
+		IFolderLayout bottomRight = layout.createFolder("right", IPageLayout.RIGHT, 0.76f, editorArea);
 		bottomRight.addView("org.yakindu.sct.simulation.ui.declarationview");
 		bottomRight.addView("org.eclipse.debug.ui.BreakpointView");
-
-		IFolderLayout top = layout.createFolder("top", IPageLayout.TOP, 0.22f,
-				editorArea);
-		top.addView("org.eclipse.debug.ui.DebugView");
+		bottomRight.addView("org.yakindu.sct.simulation.snapshots.ui.snapshotsview");
+		bottomRight.addPlaceholder("org.eclipse.debug.ui.DebugView");
 	}
 
 	private void defineActions(IPageLayout layout) {

+ 37 - 11
plugins/org.yakindu.sct.simulation.ui/src/org/yakindu/sct/simulation/ui/view/AbstractDebugTargetView.java

@@ -15,6 +15,8 @@ import org.eclipse.core.runtime.PlatformObject;
 import org.eclipse.debug.core.DebugEvent;
 import org.eclipse.debug.core.DebugPlugin;
 import org.eclipse.debug.core.IDebugEventSetListener;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchListener;
 import org.eclipse.debug.core.Launch;
 import org.eclipse.debug.core.model.IDebugTarget;
 import org.eclipse.debug.ui.DebugUITools;
@@ -33,7 +35,10 @@ import org.yakindu.sct.simulation.core.debugmodel.SCTDebugTarget;
  * 
  */
 public abstract class AbstractDebugTargetView extends ViewPart
-		implements IDebugContextListener, IDebugEventSetListener {
+		implements
+			IDebugEventSetListener,
+			IDebugContextListener,
+			ILaunchListener {
 
 	protected IDebugTarget debugTarget;
 
@@ -48,12 +53,14 @@ public abstract class AbstractDebugTargetView extends ViewPart
 	protected void registerListeners() {
 		DebugUITools.getDebugContextManager().addDebugContextListener(this);
 		DebugPlugin.getDefault().addDebugEventListener(this);
+		DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this);
 	}
 
 	@Override
 	public void dispose() {
 		DebugUITools.getDebugContextManager().removeDebugContextListener(this);
 		DebugPlugin.getDefault().removeDebugEventListener(this);
+		DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(this);
 		super.dispose();
 	}
 
@@ -88,22 +95,41 @@ public abstract class AbstractDebugTargetView extends ViewPart
 			} else {
 				newTarget = (IDebugTarget) object.getAdapter(IDebugTarget.class);
 			}
-			if(newTarget == debugTarget) {
-				return;
-			}
-			if (newTarget != debugTarget && newTarget != null && !newTarget.isTerminated()) {
-				debugTarget = newTarget;
-				activeTargetChanged(newTarget);
-			} else {
-				setActiveSession();
-			}
+			changeTarget(newTarget);
+		}
+	}
+
+	private void changeTarget(IDebugTarget newTarget) {
+		if (newTarget == debugTarget) {
+			return;
+		}
+		if (newTarget != debugTarget && newTarget != null && !newTarget.isTerminated()) {
+			debugTarget = newTarget;
+			activeTargetChanged(newTarget);
+		} else {
+			setActiveSession();
 		}
+	}
+
+	public void launchAdded(ILaunch launch) {
+		// do nothing - already handled by debugevents
+	}
+
+	@Override
+	public void launchRemoved(ILaunch launch) {
+		// do nothing - already handled by debugevents
+	}
 
+	@Override
+	public void launchChanged(ILaunch launch) {
+		for (IDebugTarget newTarget : launch.getDebugTargets()) {
+			changeTarget(newTarget);
+		}
 	}
 
 	public final void handleDebugEvents(DebugEvent[] events) {
 		for (DebugEvent debugEvent : events) {
-			//Only notify about events fired from the active debug target
+			// Only notify about events fired from the active debug target
 			if ((debugEvent.getSource() instanceof SCTDebugTarget) && debugEvent.getSource() == debugTarget)
 				handleDebugEvent(debugEvent);
 		}

+ 93 - 94
plugins/org.yakindu.sct.simulation.ui/src/org/yakindu/sct/simulation/ui/view/ExecutionContextContentProvider.java

@@ -1,94 +1,93 @@
-/**
- * Copyright (c) 2011 committers of YAKINDU and others.
- * 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:
- * 	committers of YAKINDU - initial API and implementation
- * 
- */
-package org.yakindu.sct.simulation.ui.view;
-
-import org.eclipse.jface.preference.IPreferenceStore;
-import org.eclipse.jface.util.IPropertyChangeListener;
-import org.eclipse.jface.util.PropertyChangeEvent;
-import org.eclipse.jface.viewers.ITreeContentProvider;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.widgets.Label;
-import org.yakindu.sct.model.sruntime.CompositeSlot;
-import org.yakindu.sct.model.sruntime.ExecutionContext;
-import org.yakindu.sct.simulation.ui.SimulationActivator;
-import org.yakindu.sct.simulation.ui.view.actions.HideTimeEventsAction;
-
-/**
- * 
- * @author andreas muelder - Initial contribution and API
- * 
- */
-public class ExecutionContextContentProvider implements ITreeContentProvider, IPropertyChangeListener {
-
-	private boolean shouldUpdate = true;
-	private Viewer viewer;
-
-	public void dispose() {
-		getStore().removePropertyChangeListener(this);
-	}
-
-	public ExecutionContextContentProvider() {
-		getStore().addPropertyChangeListener(this);
-	}
-
-	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
-		this.viewer = viewer;
-	}
-
-	public Object[] getElements(Object inputElement) {
-		if (inputElement == null) {
-			return new Object[] {};
-		}
-		if (inputElement instanceof ExecutionContext) {
-			return ((ExecutionContext) inputElement).getSlots().toArray();
-		}
-		return new Object[]{};
-
-	}
-
-	public Object[] getChildren(Object parentElement) {
-		if (parentElement instanceof CompositeSlot) {
-			return ((CompositeSlot) parentElement).getSlots().toArray();
-		}
-		return new Object[]{};
-	}
-
-	public Object getParent(Object element) {
-		return null;
-	}
-
-	public boolean hasChildren(Object element) {
-		if (element instanceof CompositeSlot) {
-			return ((CompositeSlot) element).getSlots().size() > 0;
-		}
-		return false;
-	}
-
-	private IPreferenceStore getStore() {
-		return SimulationActivator.getDefault().getPreferenceStore();
-	}
-
-	public void propertyChange(PropertyChangeEvent event) {
-		if (event.getProperty() == HideTimeEventsAction.HIDE_KEY) {
-			if (viewer != null && !viewer.getControl().isDisposed())
-				viewer.refresh();
-		}
-	}
-
-	public boolean isShouldUpdate() {
-		return shouldUpdate;
-	}
-
-	public void setShouldUpdate(boolean shouldUpdate) {
-		this.shouldUpdate = shouldUpdate;
-	}
-
-}
+/**
+ * Copyright (c) 2011 committers of YAKINDU and others.
+ * 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:
+ * 	committers of YAKINDU - initial API and implementation
+ * 
+ */
+package org.yakindu.sct.simulation.ui.view;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.yakindu.sct.model.sruntime.CompositeSlot;
+import org.yakindu.sct.model.sruntime.ExecutionContext;
+import org.yakindu.sct.simulation.ui.SimulationActivator;
+import org.yakindu.sct.simulation.ui.view.actions.HideTimeEventsAction;
+
+/**
+ * 
+ * @author andreas muelder - Initial contribution and API
+ * 
+ */
+public class ExecutionContextContentProvider implements ITreeContentProvider, IPropertyChangeListener {
+
+	private boolean shouldUpdate = true;
+	private Viewer viewer;
+
+	public void dispose() {
+		getStore().removePropertyChangeListener(this);
+	}
+
+	public ExecutionContextContentProvider() {
+		getStore().addPropertyChangeListener(this);
+	}
+
+	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+		this.viewer = viewer;
+	}
+
+	public Object[] getElements(Object inputElement) {
+		if (inputElement == null) {
+			return new Object[]{};
+		}
+		if (inputElement instanceof ExecutionContext) {
+			return ((ExecutionContext) inputElement).getSlots().toArray();
+		}
+		return new Object[]{};
+
+	}
+
+	public Object[] getChildren(Object parentElement) {
+		if (parentElement instanceof CompositeSlot) {
+			return ((CompositeSlot) parentElement).getSlots().toArray();
+		}
+		return new Object[]{};
+	}
+
+	public Object getParent(Object element) {
+		return null;
+	}
+
+	public boolean hasChildren(Object element) {
+		if (element instanceof CompositeSlot) {
+			return ((CompositeSlot) element).getSlots().size() > 0;
+		}
+		return false;
+	}
+
+	private IPreferenceStore getStore() {
+		return SimulationActivator.getDefault().getPreferenceStore();
+	}
+
+	public void propertyChange(PropertyChangeEvent event) {
+		if (event.getProperty() == HideTimeEventsAction.HIDE_KEY) {
+			if (viewer != null && !viewer.getControl().isDisposed())
+				viewer.refresh();
+		}
+	}
+
+	public boolean isShouldUpdate() {
+		return shouldUpdate;
+	}
+
+	public void setShouldUpdate(boolean shouldUpdate) {
+		this.shouldUpdate = shouldUpdate;
+	}
+
+}

+ 139 - 0
plugins/org.yakindu.sct.simulation.ui/src/org/yakindu/sct/simulation/ui/view/ExecutionContextLabelProvider.java

@@ -10,11 +10,26 @@
  */
 package org.yakindu.sct.simulation.ui.view;
 
+import java.util.HashSet;
+
 import org.eclipse.draw2d.ColorConstants;
 import org.eclipse.jface.viewers.StyledCellLabelProvider;
 import org.eclipse.jface.viewers.ViewerCell;
+import org.eclipse.swt.SWT;
 import org.eclipse.swt.custom.StyleRange;
+import org.eclipse.swt.custom.TreeEditor;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+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.swt.widgets.TreeItem;
 import org.yakindu.base.types.EnumerationType;
+import org.yakindu.base.types.PrimitiveType;
 import org.yakindu.sct.model.sruntime.CompositeSlot;
 import org.yakindu.sct.model.sruntime.ExecutionEvent;
 import org.yakindu.sct.model.sruntime.ExecutionOperation;
@@ -23,6 +38,8 @@ import org.yakindu.sct.model.sruntime.ExecutionVariable;
 import org.yakindu.sct.model.sruntime.ReferenceSlot;
 import org.yakindu.sct.simulation.ui.SimulationImages;
 
+import com.google.common.collect.Sets;
+
 /**
  * 
  * @author andreas muelder - Initial contribution and API
@@ -31,6 +48,7 @@ import org.yakindu.sct.simulation.ui.SimulationImages;
 public class ExecutionContextLabelProvider extends StyledCellLabelProvider {
 
 	private final int index;
+	private static HashSet<TreeItem> viewerCells = Sets.newHashSet();
 
 	public ExecutionContextLabelProvider(int index) {
 		this.index = index;
@@ -66,6 +84,23 @@ public class ExecutionContextLabelProvider extends StyledCellLabelProvider {
 					EnumerationType enumType = (EnumerationType) ((ExecutionSlot) element).getType().getOriginType();
 					String text = enumType.getEnumerator().get(((Long) value).intValue()).getName();
 					cell.setText(text);
+				}
+				if (((ExecutionSlot) element).getType().getOriginType() instanceof PrimitiveType) {
+					PrimitiveType primitiveType = (PrimitiveType) ((ExecutionSlot) element).getType().getOriginType();
+					if (primitiveType != null
+							&& Boolean.class.getSimpleName().equalsIgnoreCase(primitiveType.getName())) {
+						TreeItem currentItem = (TreeItem) cell.getItem();
+						if (!viewerCells.contains(currentItem)) {
+							NativeCellWidgetUtil.addNativeCheckbox(cell, element, value,
+									new TreeEditorDisposeListener(currentItem));
+							viewerCells.add(currentItem);
+						}
+						// layout cells with checkbox widgets to update positions if tree contents have
+						// changed
+						cell.getControl().getParent().layout();
+					} else {
+						cell.setText(value.toString());
+					}
 				} else {
 					cell.setText(value.toString());
 				}
@@ -113,4 +148,108 @@ public class ExecutionContextLabelProvider extends StyledCellLabelProvider {
 		}
 	}
 
+	/**
+	 * 
+	 * @author robert rudi - Initial contribution and API
+	 * 
+	 */
+	protected class TreeEditorDisposeListener implements DisposeListener {
+
+		private static final String LISTENER_DATA = "DISPOSELISTENER";
+		private static final String EDITOR_DATA = "EDITOR";
+		private final TreeItem currentItem;
+
+		protected TreeEditorDisposeListener(TreeItem currentItem) {
+			this.currentItem = currentItem;
+
+		}
+		public void widgetDisposed(DisposeEvent e) {
+			disposeTreeEditor();
+		}
+
+		protected void disposeTreeEditor() {
+			if (currentItem.getData(EDITOR_DATA) != null) {
+				TreeEditor editor = (TreeEditor) currentItem.getData(EDITOR_DATA);
+				editor.getEditor().dispose();
+				editor.dispose();
+			}
+		}
+		protected void removeDisposeListener() {
+			if (currentItem.getData(LISTENER_DATA) != null) {
+				currentItem.removeDisposeListener((DisposeListener) currentItem.getData(LISTENER_DATA));
+			}
+		}
+	}
+
+	/**
+	 * 
+	 * @author robert rudi - Initial contribution and API
+	 * 
+	 */
+	protected static class NativeCellWidgetUtil {
+		protected static void addNativeCheckbox(ViewerCell cell, Object element, Object value,
+				TreeEditorDisposeListener listener) {
+
+			TreeItem currentItem = (TreeItem) cell.getItem();
+			manageEditorDisposal(currentItem, listener);
+			TreeEditor editor = createEditor(currentItem);
+			Composite comp = createEditorComposite(currentItem);
+			createNativeCheckboxCellWidget(element, comp);
+			editor.setEditor(comp, currentItem, cell.getColumnIndex()); // update editor content
+		}
+
+		protected static Button createNativeCheckboxCellWidget(Object element, Composite comp) {
+			Button button = new Button(comp, SWT.CHECK);
+			button.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, false, true));
+			Label label = new Label(comp, SWT.BOLD);
+			label.setForeground(ColorConstants.gray);
+			label.setText(((ExecutionSlot) element).getValue().toString());
+			label.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+			button.addSelectionListener(new SelectionListener() {
+
+				@Override
+				public void widgetSelected(SelectionEvent e) {
+					((ExecutionSlot) element).setValue(!(Boolean) ((ExecutionSlot) element).getValue());
+					label.setText(((ExecutionSlot) element).getValue().toString());
+				}
+
+				@Override
+				public void widgetDefaultSelected(SelectionEvent e) {
+				}
+			});
+			restoreSelection(((ExecutionSlot) element).getValue(), button);
+			return button;
+		}
+
+		protected static Composite createEditorComposite(TreeItem currentItem) {
+			Composite comp = new Composite(currentItem.getParent(), SWT.INHERIT_DEFAULT);
+			comp.setBackground(currentItem.getBackground());
+			comp.setBackgroundMode(SWT.INHERIT_DEFAULT);
+			GridLayout layout = new GridLayout(2, false);
+			layout.marginHeight = 0;
+			layout.marginWidth = 3;
+			comp.setLayout(layout);
+			return comp;
+		}
+
+		protected static TreeEditor createEditor(TreeItem currentItem) {
+			TreeEditor editor = new TreeEditor(currentItem.getParent());
+			editor.grabVertical = true;
+			editor.grabHorizontal = true;
+			currentItem.setData(TreeEditorDisposeListener.EDITOR_DATA, editor);
+			return editor;
+		}
+
+		protected static void manageEditorDisposal(TreeItem currentItem, TreeEditorDisposeListener listener) {
+			listener.disposeTreeEditor();
+			listener.removeDisposeListener();
+			currentItem.addDisposeListener(listener);
+			currentItem.setData(TreeEditorDisposeListener.LISTENER_DATA, listener);
+		}
+
+		protected static void restoreSelection(Object value, Button button) {
+			if (((Boolean) value).booleanValue() != button.getSelection())
+				button.setSelection(((Boolean) value).booleanValue());
+		}
+	}
 }

+ 23 - 9
plugins/org.yakindu.sct.simulation.ui/src/org/yakindu/sct/simulation/ui/view/ExecutionContextViewerFactory.java

@@ -10,13 +10,16 @@
  */
 package org.yakindu.sct.simulation.ui.view;
 
+import org.eclipse.jface.layout.TreeColumnLayout;
 import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent;
 import org.eclipse.jface.viewers.ColumnViewerEditorActivationListener;
 import org.eclipse.jface.viewers.ColumnViewerEditorDeactivationEvent;
+import org.eclipse.jface.viewers.ColumnWeightData;
 import org.eclipse.jface.viewers.TreeViewer;
 import org.eclipse.jface.viewers.TreeViewerColumn;
 import org.eclipse.jface.viewers.ViewerFilter;
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.widgets.Composite;
 import org.yakindu.sct.simulation.ui.view.editing.BooleanEditingSupport;
 import org.yakindu.sct.simulation.ui.view.editing.EnumerationEditingSupport;
@@ -33,23 +36,36 @@ import org.yakindu.sct.simulation.ui.view.editing.StringEditingSupport;
  */
 public class ExecutionContextViewerFactory {
 
+	private static final int NAME_COL_MIN_WIDTH = 100;
+	private static final int NAME_COL_WIDTH_RATIO = 3;
+	private static final int VALUE_COL_MIN_WIDTH = 80;
+	private static final int VALUE_COL_WIDTH_RATIO = 1;
+
 	public static TreeViewer createViewer(Composite parent, boolean readOnly, ITypeSystemProvider provider) {
-		final TreeViewer viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
+		Composite comp = new Composite(parent, SWT.NONE);
+		comp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
+		TreeColumnLayout layout = new TreeColumnLayout();
+		comp.setLayout(layout);
+		final TreeViewer viewer = new TreeViewer(comp,
+				SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER);
 		viewer.getTree().setHeaderVisible(true);
 		viewer.getTree().setLinesVisible(true);
 		ExecutionContextContentProvider contentProvider = new ExecutionContextContentProvider();
 		viewer.setContentProvider(contentProvider);
 		viewer.setFilters(new ViewerFilter[]{new TimeEventViewerFilter()});
-		TreeViewerColumn nameColumn = new TreeViewerColumn(viewer, SWT.DEFAULT);
+    
+		TreeViewerColumn nameColumn = new TreeViewerColumn(viewer, SWT.NONE);
 		nameColumn.getColumn().setText("Name");
-		nameColumn.getColumn().setMoveable(true);
-		nameColumn.getColumn().setWidth(150);
+		nameColumn.getColumn().setResizable(true);
 		nameColumn.setLabelProvider(new ExecutionContextLabelProvider(0));
 
-		TreeViewerColumn valueColumn = new TreeViewerColumn(viewer, SWT.DEFAULT);
+		TreeViewerColumn valueColumn = new TreeViewerColumn(viewer, SWT.NONE);
 		valueColumn.getColumn().setText("Value");
-		valueColumn.getColumn().setMoveable(true);
-		valueColumn.getColumn().setWidth(100);
+		valueColumn.getColumn().setResizable(false);
+		valueColumn.setLabelProvider(new ExecutionContextLabelProvider(1));
+
+		layout.setColumnData(nameColumn.getColumn(), new ColumnWeightData(NAME_COL_WIDTH_RATIO, NAME_COL_MIN_WIDTH));
+		layout.setColumnData(valueColumn.getColumn(), new ColumnWeightData(VALUE_COL_WIDTH_RATIO, VALUE_COL_MIN_WIDTH));
 		if (!readOnly)
 			valueColumn.setEditingSupport(new MultiEditingSupport(viewer,
 					/*
@@ -61,8 +77,6 @@ public class ExecutionContextViewerFactory {
 					new BooleanEditingSupport(viewer, provider), //
 					new StringEditingSupport(viewer, provider)));//
 
-		valueColumn.setLabelProvider(new ExecutionContextLabelProvider(1));
-
 		valueColumn.getViewer().getColumnViewerEditor()
 				.addEditorActivationListener(new ColumnViewerEditorActivationListener() {
 					@Override

+ 191 - 45
plugins/org.yakindu.sct.simulation.ui/src/org/yakindu/sct/simulation/ui/view/SimulationView.java

@@ -10,22 +10,36 @@
  */
 package org.yakindu.sct.simulation.ui.view;
 
+
+import java.util.HashSet;
+import java.util.concurrent.TimeUnit;
+
 import org.apache.commons.lang.time.DurationFormatUtils;
 import org.eclipse.debug.core.DebugEvent;
 import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
 import org.eclipse.debug.core.model.IDebugTarget;
 import org.eclipse.debug.core.model.IStep;
 import org.eclipse.debug.internal.ui.commands.actions.ResumeCommandAction;
 import org.eclipse.debug.internal.ui.commands.actions.StepOverCommandAction;
 import org.eclipse.debug.internal.ui.commands.actions.SuspendCommandAction;
 import org.eclipse.debug.internal.ui.commands.actions.TerminateCommandAction;
-import org.eclipse.draw2d.ColorConstants;
+import org.eclipse.debug.ui.contexts.DebugContextEvent;
+
 import org.eclipse.emf.ecore.EObject;
 import org.eclipse.jface.action.ActionContributionItem;
 import org.eclipse.jface.action.IAction;
 import org.eclipse.jface.action.IContributionItem;
 import org.eclipse.jface.action.IToolBarManager;
 import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
 import org.eclipse.jface.viewers.TreeViewer;
 import org.eclipse.jface.viewers.Viewer;
 import org.eclipse.jface.viewers.ViewerCell;
@@ -40,6 +54,7 @@ import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.layout.FillLayout;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Combo;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Label;
@@ -51,20 +66,26 @@ import org.yakindu.sct.model.sruntime.ExecutionEvent;
 import org.yakindu.sct.simulation.core.engine.ISimulationEngine;
 import org.yakindu.sct.simulation.core.engine.scheduling.DefaultTimeTaskScheduler;
 import org.yakindu.sct.simulation.core.engine.scheduling.ITimeTaskScheduler;
+import org.yakindu.sct.simulation.ui.SimulationImages;
+import org.yakindu.sct.simulation.ui.model.presenter.SCTSourceDisplayDispatcher;
 import org.yakindu.sct.simulation.ui.view.actions.CollapseAllAction;
 import org.yakindu.sct.simulation.ui.view.actions.ExpandAllAction;
 import org.yakindu.sct.simulation.ui.view.actions.HideTimeEventsAction;
 import org.yakindu.sct.simulation.ui.view.editing.ScopeSlotEditingSupport.ITypeSystemProvider;
 
 import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
 
 /**
  * 
  * @author andreas muelder - Initial contribution and API
  * 
  */
+@SuppressWarnings("restriction")
 public class SimulationView extends AbstractDebugTargetView implements ITypeSystemProvider {
 
+	public static final String ID = "org.yakindu.sct.simulation.ui.declarationview"; //$NON-NLS-1$
+
 	private TreeViewer viewer;
 	private ViewerRefresher viewerRefresher;
 	private FormToolkit kit;
@@ -72,20 +93,27 @@ public class SimulationView extends AbstractDebugTargetView implements ITypeSyst
 	private RaiseEventSelectionListener selectionListener;
 	private ITypeSystem typeSystem;
 	private ITimeTaskScheduler timeScheduler;
-	private Label timeSchedulerLabel;
+	private Label timeLabel;
+	private Label timeIconLabel;
+	private ComboViewer sessionDropdown;
+	private HashSet<IDebugTarget> targets = Sets.newHashSet();
+	private static SCTSourceDisplayDispatcher sctSourceDisplayDispatcher;
 
 	public SimulationView() {
 		kit = new FormToolkit(Display.getDefault());
 		kit.setBorderStyle(SWT.BORDER);
 		font = new Font(Display.getDefault(), new FontData("Courier", 10, SWT.BOLD));
+		sctSourceDisplayDispatcher = new SCTSourceDisplayDispatcher();
 	}
 
 	@Override
 	public void dispose() {
 		selectionListener.dispose();
 		font.dispose();
-		disposeTimeSchedulerComponent();
+		sctSourceDisplayDispatcher = null;
+		disposeSessionDropDownComponent();
 		disposeViewerRefresher();
+		disposeTimeLabels();
 		super.dispose();
 	}
 
@@ -96,9 +124,20 @@ public class SimulationView extends AbstractDebugTargetView implements ITypeSyst
 		}
 	}
 
-	protected void disposeTimeSchedulerComponent() {
-		if (timeSchedulerLabel != null && !timeSchedulerLabel.isDisposed()) {
-			timeSchedulerLabel.dispose();
+	protected void disposeTimeLabels() {
+		if (timeLabel != null && !timeLabel.isDisposed()) {
+			timeLabel.dispose();
+		}
+		if (timeIconLabel != null && !timeIconLabel.isDisposed()) {
+			timeIconLabel.dispose();
+		}
+	}
+
+	protected void disposeSessionDropDownComponent() {
+		if (sessionDropdown != null && sessionDropdown.getControl() != null
+				&& !sessionDropdown.getControl().isDisposed()) {
+			sessionDropdown.getControl().dispose();
+
 		}
 	}
 
@@ -106,13 +145,58 @@ public class SimulationView extends AbstractDebugTargetView implements ITypeSyst
 	public void createPartControl(Composite parent) {
 		parent.setLayout(new FillLayout(SWT.VERTICAL));
 		Composite top = kit.createComposite(parent);
-		top.setLayout(new FillLayout(SWT.VERTICAL));
+		top.setLayout(new GridLayout(2, false));
+		createSessionSelectorComponent(top);
+		createTimeSchedulerComponent(top);
 		createViewer(top);
-		createTimeScheduler(top);
 		hookActions();
 		super.createPartControl(parent);
 	}
 
+	protected ComboViewer createSessionSelectorComponent(Composite top) {
+		Combo combo = new Combo(top, SWT.DROP_DOWN | SWT.READ_ONLY);
+		combo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+		this.sessionDropdown = new ComboViewer(combo);
+		this.sessionDropdown.setContentProvider(new ArrayContentProvider());
+		this.sessionDropdown.setLabelProvider(new LabelProvider() {
+
+			@Override
+			public String getText(Object element) {
+				IDebugTarget target = ((IDebugTarget) element);
+				boolean isTerminated = target.isTerminated();
+				boolean isSuspended = target.isSuspended();
+
+				if (target.getLaunch().getDebugTarget() != null)
+					try {
+						return target.getLaunch().getDebugTarget().getName() + " ["
+								+ (isTerminated ? "terminated" : isSuspended ? "suspended" : "active") + "]";
+					} catch (DebugException e) {
+						return "unkown state";
+					}
+				else
+					return "No simulation running";
+			}
+		});
+
+		this.sessionDropdown.addPostSelectionChangedListener(new SessionSelectionChangedListener());
+
+		targets.clear();
+		for (ILaunch iLaunch : DebugPlugin.getDefault().getLaunchManager().getLaunches()) {
+			for (IDebugTarget iDebugTarget : iLaunch.getDebugTargets()) {
+				if (!iDebugTarget.isTerminated())
+					targets.add(iDebugTarget);
+			}
+		}
+		sessionDropdown.setInput(targets);
+		if (!targets.isEmpty()) {
+			IDebugTarget dt = targets.iterator().next();
+			sessionDropdown.setSelection(new StructuredSelection(dt), true);
+			activeTargetChanged(dt);
+		}
+
+		return this.sessionDropdown;
+	}
+
 	@Override
 	public void setFocus() {
 		viewer.getTree().setFocus();
@@ -124,14 +208,18 @@ public class SimulationView extends AbstractDebugTargetView implements ITypeSyst
 		return viewer;
 	}
 
-	public Label createTimeScheduler(Composite parent) {
-		Composite comp = new Composite(parent, SWT.BORDER);
-		GridLayout layout = new GridLayout();
-		comp.setLayout(layout);
-		timeSchedulerLabel = new Label(comp, SWT.NONE);
-		timeSchedulerLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, true));
-		timeSchedulerLabel.setToolTipText("Displays the duration since the simulation is running");
-		return timeSchedulerLabel;
+
+	public Label createTimeSchedulerComponent(Composite parent) {
+		Composite comp = new Composite(parent, SWT.NONE);
+		comp.setLayout(new GridLayout(2, false));
+		timeIconLabel = new Label(comp, SWT.NONE);
+		timeIconLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false));
+		timeIconLabel.setImage(SimulationImages.SIMULATION_CLOCK.image());
+		timeIconLabel.setToolTipText("Displays the duration since the simulation is running");
+		timeIconLabel.setVisible(false);
+		timeLabel = new Label(comp, SWT.NONE);
+		timeLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false));
+		return timeLabel;
 	}
 
 	protected void setViewerInput(Object input) {
@@ -141,13 +229,13 @@ public class SimulationView extends AbstractDebugTargetView implements ITypeSyst
 			if (viewerRefresher == null)
 				this.viewerRefresher = new ViewerRefresher();
 		}
-		if (input != null) {
+
+		Display.getDefault().asyncExec(() -> {
 			this.viewer.setInput(input);
 			if (this.viewerRefresher.isCancel())
 				this.viewerRefresher.cancel = false;
-
 			new Thread(viewerRefresher).start();
-		}
+		});
 
 	}
 
@@ -155,17 +243,27 @@ public class SimulationView extends AbstractDebugTargetView implements ITypeSyst
 		updateActions();
 		switch (debugEvent.getKind()) {
 			case DebugEvent.TERMINATE :
-				Display.getDefault().asyncExec(new Runnable() {
-					public void run() {
-						setViewerInput(null);
-					}
-				});
+				setViewerInput(null);
 				break;
 			case DebugEvent.SUSPEND :
 				break;
 			case DebugEvent.RESUME :
 				break;
 		}
+		Display.getDefault().asyncExec(() -> {
+			if (debugEvent.getSource() != null) {
+				sessionDropdown.update(debugEvent.getSource(), null);
+				sessionDropdown.refresh();
+				targets.removeIf(dt -> dt.isTerminated());
+			}
+		});
+	}
+
+	@Override
+	public void debugContextChanged(DebugContextEvent event) {
+		super.debugContextChanged(event);
+		if (debugTarget != null)
+			this.sessionDropdown.setSelection(new StructuredSelection(debugTarget));
 	}
 
 	protected void activeTargetChanged(final IDebugTarget debugTarget) {
@@ -173,8 +271,24 @@ public class SimulationView extends AbstractDebugTargetView implements ITypeSyst
 		ISimulationEngine engine = (ISimulationEngine) debugTarget.getAdapter(ISimulationEngine.class);
 		timeScheduler = (DefaultTimeTaskScheduler) engine.getTimeTaskScheduler();
 		setViewerInput(engine.getExecutionContext());
-		(new ExpandAllAction(viewer)).run();
 		updateActions();
+		updateSessionDropdownInput(debugTarget);
+	}
+
+	protected void updateSessionDropdownInput(final IDebugTarget debugTarget) {
+		Display.getDefault().asyncExec(() -> {
+			if (debugTarget != null) {
+				if (!targets.contains(debugTarget)) {
+					targets.add(debugTarget);
+					sessionDropdown.setInput(targets);
+					sessionDropdown.setSelection(new StructuredSelection(debugTarget), true);
+					sessionDropdown.refresh();
+				} else {
+					sessionDropdown.update(debugTarget, null);
+					sessionDropdown.refresh();
+				}
+			}
+		});
 	}
 
 	protected void updateActions() {
@@ -209,6 +323,21 @@ public class SimulationView extends AbstractDebugTargetView implements ITypeSyst
 		getViewSite().getActionBars().getToolBarManager().update(true);
 	}
 
+	/**
+	 * @author robert rudi - Initial contribution and API
+	 *
+	 */
+	protected final class SessionSelectionChangedListener implements ISelectionChangedListener {
+		@Override
+		public void selectionChanged(SelectionChangedEvent event) {
+			IStructuredSelection selection = (IStructuredSelection) event.getSelection();
+			if ((IDebugTarget) selection.getFirstElement() != null) {
+				launchChanged(((IDebugTarget) selection.getFirstElement()).getLaunch());
+				sctSourceDisplayDispatcher.displaySource(debugTarget, SimulationView.this.getSite().getPage(), true);
+			}
+		}
+	}
+
 	/**
 	 * Listens for event selections within the Context TreeViewer
 	 * 
@@ -265,7 +394,6 @@ public class SimulationView extends AbstractDebugTargetView implements ITypeSyst
 		return typeSystem;
 	}
 
-	@SuppressWarnings("restriction")
 	protected class StepOverAction extends StepOverCommandAction implements IAction {
 		@Override
 		public void run() {
@@ -290,7 +418,6 @@ public class SimulationView extends AbstractDebugTargetView implements ITypeSyst
 		}
 	}
 
-	@SuppressWarnings("restriction")
 	protected class TerminateAction extends TerminateCommandAction implements IAction {
 		@Override
 		public void run() {
@@ -313,7 +440,6 @@ public class SimulationView extends AbstractDebugTargetView implements ITypeSyst
 		}
 	}
 
-	@SuppressWarnings("restriction")
 	protected class SuspendAction extends SuspendCommandAction implements IAction {
 		@Override
 		public void run() {
@@ -336,7 +462,6 @@ public class SimulationView extends AbstractDebugTargetView implements ITypeSyst
 		}
 	}
 
-	@SuppressWarnings("restriction")
 	protected class ResumeAction extends ResumeCommandAction implements IAction {
 		@Override
 		public void run() {
@@ -366,19 +491,22 @@ public class SimulationView extends AbstractDebugTargetView implements ITypeSyst
 
 		@Override
 		public void run() {
-			while (!cancel && viewer.getInput() != null) {
+			while (!cancel) {
 				try {
 					Thread.sleep(UPDATE_INTERVAL);
-					Display.getDefault().asyncExec(new Runnable() {
-						public void run() {
-							if (viewer != null && !viewer.getControl().isDisposed()
-									&& ((ExecutionContextContentProvider) viewer.getContentProvider())
-											.isShouldUpdate()) {
-								viewer.refresh();
-							}
-							if (timeSchedulerLabel != null && !timeSchedulerLabel.isDisposed()) {
-								updateTimestamp(timeScheduler.getCurrentTime());
-							}
+					Display.getDefault().asyncExec(() -> {
+						if (viewer != null && !viewer.getControl().isDisposed()
+								&& ((ExecutionContextContentProvider) viewer.getContentProvider()).isShouldUpdate()) {
+							viewer.refresh();
+						}
+
+						if (timeLabel != null && !timeLabel.isDisposed() && timeScheduler != null && debugTarget != null
+								&& !debugTarget.isTerminated() && timeLabel != null && !timeLabel.isDisposed()) {
+							updateTimestamp(timeScheduler.getCurrentTime());
+						} else {
+							if (timeIconLabel != null && !timeIconLabel.isDisposed() && timeIconLabel.isVisible())
+								updateTimestamp(0);
+
 						}
 					});
 				} catch (InterruptedException e) {
@@ -386,11 +514,30 @@ public class SimulationView extends AbstractDebugTargetView implements ITypeSyst
 				}
 			}
 		}
-		
 		protected void updateTimestamp(long timestamp) {
-			String formatDurationHMS = DurationFormatUtils.formatDuration(timestamp, "HH:mm:ss.SSS");
-			timeSchedulerLabel.setText("Simulation time: " + formatDurationHMS);
-			timeSchedulerLabel.update();
+			String formatDurationHMS = DurationFormatUtils.formatDuration(timestamp,
+					(timestamp == 0 ? "--:--:--.---" : "HH:mm:ss.SSS"), true);
+			timeLabel.setText(formatDurationHMS);
+			String time = getReadableSimulationTime(timestamp);
+			boolean isValidTime = time != null || (time != null && !time.isEmpty()) || timestamp != 0;
+			timeIconLabel.setVisible(isValidTime);
+			if (isValidTime) {
+				timeLabel.setToolTipText("Simulation running since " + time);
+				timeLabel.getParent().getParent().layout(); // layout all time-relevant components
+			}
+		}
+
+		protected String getReadableSimulationTime(long timestamp) {
+			long days = TimeUnit.MILLISECONDS.toDays(timestamp);
+			long hours = TimeUnit.MILLISECONDS.toHours(timestamp);
+			long minutes = TimeUnit.MILLISECONDS.toMinutes(timestamp);
+			long seconds = TimeUnit.MILLISECONDS.toSeconds(timestamp);
+			return DurationFormatUtils
+					.formatDuration(timestamp,
+							(days > 0 ? "dd 'days '" : "") + (hours > 0 ? "HH 'hours '" : "")
+									+ (minutes > 0 ? "mm 'minutes '" : "") + (seconds > 0 ? "ss 'seconds '" : ""),
+							false);
+
 		}
 
 		public boolean isCancel() {
@@ -401,5 +548,4 @@ public class SimulationView extends AbstractDebugTargetView implements ITypeSyst
 			this.cancel = cancel;
 		}
 	}
-
 }

+ 3 - 4
plugins/org.yakindu.sct.simulation.ui/src/org/yakindu/sct/simulation/ui/view/editing/BooleanEditingSupport.java

@@ -11,8 +11,8 @@
 package org.yakindu.sct.simulation.ui.view.editing;
 
 import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.CheckboxCellEditor;
 import org.eclipse.jface.viewers.ColumnViewer;
-import org.eclipse.jface.viewers.ComboBoxCellEditor;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.widgets.Composite;
 import org.yakindu.base.types.Type;
@@ -33,8 +33,7 @@ public class BooleanEditingSupport extends ScopeSlotEditingSupport {
 
 	@Override
 	public CellEditor getCellEditor(Object element) {
-		return new ComboBoxCellEditor((Composite) getViewer().getControl(), new String[] { "true", "false" },
-				SWT.READ_ONLY);
+		return new CheckboxCellEditor((Composite) getViewer().getControl(), SWT.READ_ONLY);
 	}
 
 	@Override
@@ -45,7 +44,7 @@ public class BooleanEditingSupport extends ScopeSlotEditingSupport {
 	public Object getValue(Object element) {
 		if (element instanceof ExecutionSlot) {
 			Boolean value = (Boolean) ((ExecutionSlot) element).getValue();
-			return value ? 0 : 1;
+			return value ? false : true;
 		}
 		return null;
 	}