Updated EMF visualization: removed class variables, added model change listeners
diff --git a/plugins/org.eclipse.app4mc.emf.visualizations/src/org/eclipse/app4mc/emf/visualizations/EObjectRefsConfig.java b/plugins/org.eclipse.app4mc.emf.visualizations/src/org/eclipse/app4mc/emf/visualizations/EObjectRefsConfig.java
index cb3fdab..5bf5e7d 100644
--- a/plugins/org.eclipse.app4mc.emf.visualizations/src/org/eclipse/app4mc/emf/visualizations/EObjectRefsConfig.java
+++ b/plugins/org.eclipse.app4mc.emf.visualizations/src/org/eclipse/app4mc/emf/visualizations/EObjectRefsConfig.java
@@ -15,11 +15,15 @@
 
 package org.eclipse.app4mc.emf.visualizations;
 
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+
 /**
  * Configuration of the visualization
  *
  */
 public class EObjectRefsConfig {
+	private final PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);
 
 	private boolean horizontalLayout = false;
 	private boolean showDerivedReferences = false;
@@ -31,7 +35,8 @@
 	}
 
 	public void setHorizontalLayout(boolean horizontal) {
-		this.horizontalLayout = horizontal;
+		horizontalLayout = horizontal;
+		firePropertyChange("parameter1", null, horizontalLayout);
 	}
 
 	public boolean isShowDerivedReferences() {
@@ -39,7 +44,8 @@
 	}
 
 	public void setShowDerivedReferences(boolean showDerived) {
-		this.showDerivedReferences = showDerived;
+		showDerivedReferences = showDerived;
+		firePropertyChange("parameter2", null, showDerivedReferences);
 	}
 
 	public boolean isShowReferenceLabels() {
@@ -47,7 +53,8 @@
 	}
 
 	public void setShowReferenceLabels(boolean showLabels) {
-		this.showReferenceLabels = showLabels;
+		showReferenceLabels = showLabels;
+		firePropertyChange("parameter3", null, showReferenceLabels);
 	}
 
 	public int getScale() {
@@ -57,14 +64,17 @@
 	/**
 	 * Sets a new scale value (if the new value is different and within the bounds [10, 200])
 	 * 
-	 * @param scale
+	 * @param newScale
 	 * @return true if value was changed
 	 */
-	public boolean setScale(int scale) {
-		if (this.scale == scale || scale < 10 || scale > 200) {
+	public boolean setScale(int newScale) {
+		if (scale == newScale || newScale < 10 || newScale > 200) {
 			return false;	
 		}
-		this.scale = scale;
+
+		int oldScale = scale;
+		scale = newScale;
+		firePropertyChange("scale", oldScale, newScale);
 		return true;
 	}
 
@@ -76,4 +86,18 @@
 		return setScale(Math.min(200, scale + 10)); // maximum 200 %
 	}
 
+	// property change handling
+
+	public void addChangeListener(PropertyChangeListener listener) {
+		changeSupport.addPropertyChangeListener(listener);
+	}
+
+	public void removeChangeListener(PropertyChangeListener listener) {
+		changeSupport.removePropertyChangeListener(listener);
+	}
+
+	protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
+		changeSupport.firePropertyChange(propertyName, oldValue, newValue);
+	}
+
 }
diff --git a/plugins/org.eclipse.app4mc.emf.visualizations/src/org/eclipse/app4mc/emf/visualizations/EObjectRefsVisualization.java b/plugins/org.eclipse.app4mc.emf.visualizations/src/org/eclipse/app4mc/emf/visualizations/EObjectRefsVisualization.java
index 6caee10..c94aac4 100644
--- a/plugins/org.eclipse.app4mc.emf.visualizations/src/org/eclipse/app4mc/emf/visualizations/EObjectRefsVisualization.java
+++ b/plugins/org.eclipse.app4mc.emf.visualizations/src/org/eclipse/app4mc/emf/visualizations/EObjectRefsVisualization.java
@@ -45,19 +45,12 @@
 })
 public class EObjectRefsVisualization implements Visualization {
 
-	private EObject object;
-	private PlantUmlDiagram diagram = new PlantUmlDiagram();
-	private static EObjectRefsConfig config = new EObjectRefsConfig();
-
-	private CLabel scaleLabel;
-	private Browser browser;
-
 	/**
 	 * Entry point for the visualization framework
 	 * 
-	 * @param eObject  Ecore object that shall be visualized
-	 * @param parent  parent component
-	 * @param broker  event broker for element selection
+	 * @param eObject	Ecore object that shall be visualized
+	 * @param parent	parent component
+	 * @param broker	event broker for element selection
 	 */
 	@PostConstruct
 	public void createVisualization(
@@ -65,51 +58,63 @@
 			Composite parent,
 			IEventBroker broker) {
 
-		this.object = eObject;
+		// Create central context object with all relevant inputs
+		final Context context = new Context(eObject);
+
+		// Update context.config with stored parameters and scale ... (to be implemented)
 
 		Composite pane = new Composite(parent, SWT.NONE);
 		GridLayoutFactory.fillDefaults().applyTo(pane);
 		Composite buttonArea = new Composite(pane, SWT.NONE);
 
-		this.browser = new Browser(pane, SWT.NONE);
-		if (broker != null) {
-			setupElementNavigation(broker);
-		}
+		addToggleButton(buttonArea, "Horizontal Layout", context.config::setHorizontalLayout, context.config.isHorizontalLayout());
+		addToggleButton(buttonArea, "Show Derived Refs", context.config::setShowDerivedReferences, context.config.isShowDerivedReferences());
+		addToggleButton(buttonArea, "Show Labels", context.config::setShowReferenceLabels, context.config.isShowReferenceLabels());
 
-		addToggleButton(buttonArea, "Horizontal Layout", config::setHorizontalLayout, config.isHorizontalLayout());
-		addToggleButton(buttonArea, "Show Derived Refs", config::setShowDerivedReferences, config.isShowDerivedReferences());
-		addToggleButton(buttonArea, "Show Labels", config::setShowReferenceLabels, config.isShowReferenceLabels());
-
-		addZoomBox(buttonArea);
+		addZoomBox(buttonArea, context);
 
 		RowLayoutFactory.swtDefaults().fill(true).applyTo(buttonArea);
 
+		Browser browser = addBrowser(pane, broker, context);
+		
 		GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(browser);
-		visualize();
+
+		// Create and display content
+		updateContent(browser, context);
 	}
 
-	/**
-	 * Setup navigation to a selected element in the model viewer
-	 * 
-	 * @param broker
-	 */
-	private void setupElementNavigation(IEventBroker broker) {
-		browser.addLocationListener(LocationListener.changingAdapter(c -> {
-			c.doit = true;
+	private Browser addBrowser(Composite pane, IEventBroker broker, final Context context) {
+		Browser browser = new Browser(pane, SWT.NONE);
 
-			Object target = null;
-			int idx = c.location.lastIndexOf('#');
-			if (idx >= 0) {
-				target = diagram.getObjectById(c.location.substring(idx + 1));
-			}
-			if (target != null) {
-				HashMap<String, Object> data = new HashMap<>();
-				data.put("modelElements", Collections.singletonList(target));
-				broker.send("org/eclipse/app4mc/amalthea/editor/SELECT", data);
+		// Setup navigation to a selected element in the model viewer
+		if (broker != null) {
+			browser.addLocationListener(LocationListener.changingAdapter(c -> {
+				c.doit = true;
+			
+				Object target = null;
+				int idx = c.location.lastIndexOf('#');
+				if (idx >= 0) {
+					target = context.diagram.getObjectById(c.location.substring(idx + 1));
+				}
+				if (target != null) {
+					HashMap<String, Object> data = new HashMap<>();
+					data.put("modelElements", Collections.singletonList(target));
+					broker.send("org/eclipse/app4mc/amalthea/editor/SELECT", data);
+			
+					c.doit = false;
+				}
+			}));
+		}
 
-				c.doit = false;
-			}
-		}));
+		// React to configuration parameter changes
+		context.config.addChangeListener(e -> {
+			if (e.getPropertyName().equals("scale"))
+				updateSvgScale(browser, (int) e.getNewValue());
+			if (e.getPropertyName().startsWith("parameter"))
+				updateContent(browser, context);
+		});
+
+		return browser;
 	}
 
 	/**
@@ -117,8 +122,7 @@
 	 * 
 	 * @param parent          container element
 	 * @param text            label
-	 * @param f               button select action; takes the button's selection
-	 *                        status as an argument
+	 * @param f               button select action; takes the button's selection status as an argument
 	 * @param initialSelected initial selection state of the button
 	 */
 	private void addToggleButton(Composite parent, String text, final Consumer<Boolean> f, boolean initialSelected) {
@@ -127,11 +131,10 @@
 		btn.setSelection(initialSelected);
 		btn.addListener(SWT.Selection, e -> {
 			f.accept(btn.getSelection());
-			visualize();
 		});
 	}
 
-	private void addZoomBox(Composite buttonArea) {
+	private void addZoomBox(Composite buttonArea, Context context) {
 		// Align the box with the other buttons
 		final Composite zoomArea = new Composite(buttonArea, SWT.NONE);
 		RowLayoutFactory.fillDefaults().margins(1, 1).applyTo(zoomArea);
@@ -139,50 +142,58 @@
 		final Composite box = new Composite(zoomArea, SWT.BORDER);
 
 		final Button btnLeft = new Button(box, SWT.ARROW | SWT.LEFT | SWT.FLAT);
-		scaleLabel = new CLabel(box, SWT.FLAT | SWT.CENTER);
-		scaleLabel.setText(" ___ % ");
+		btnLeft.addListener(SWT.Selection, e -> context.config.decrementScale());
+
+		final CLabel scaleLabel = new CLabel(box, SWT.FLAT | SWT.CENTER);
+		scaleLabel.setText(String.format("%d %%", context.config.getScale())); // set initial label text
+
+		context.config.addChangeListener(e -> {
+			if (e.getPropertyName().equals("scale"))
+				scaleLabel.setText(String.format("%d %%", (int) e.getNewValue())); // update label text
+		});
+
 		final Button btnRight = new Button(box, SWT.ARROW | SWT.RIGHT | SWT.FLAT);
+		btnRight.addListener(SWT.Selection, e -> context.config.incrementScale());
 
 		RowLayoutFactory.fillDefaults().fill(true).applyTo(box);
+	}
 
-		// Add listeners
-		btnLeft.addListener(SWT.Selection, e -> {
-			boolean changed = config.decrementScale();
-			if (changed) {
-				updateSvgScale(config.getScale());
-			}
-		});
-
-		btnRight.addListener(SWT.Selection, e -> {
-			boolean changed = config.incrementScale();
-			if (changed) {
-				updateSvgScale(config.getScale());
-			}
-		});
+	private void updateSvgScale(Browser browser, int newScale) {
+		// Update SVG size in browser via JavaScript/DOM
+		if (browser != null) {
+			browser.execute(SvgUtil.buildUpdateScaleCommand(newScale));
+		}
 	}
 
 	/**
-	 * Visualizes a given model element in a browser. The plantUML graph is constructed
-	 * and compiled in a separate thread.
+	 * Visualizes a given model element in a browser.
+	 * <p>
+	 * The plantUML graph is constructed and compiled in a separate thread.
+	 * 
+	 * @param browser 
+	 * @param context 
 	 */
-	private void visualize() {
+	private void updateContent(Browser browser, Context context) {
 		new Thread(() -> {
-			// Build PlantUML diagram
-			EObjectRefsGenerator.updateDiagram(diagram, object, config);
+			// Build PlantUML diagram text
+			EObjectRefsGenerator.updateDiagram(context.diagram, context.object, context.config);
 
+			// Render to SVG
 			String result;
 			try {
-				result = diagram.renderToSvg();
+				result = context.diagram.renderToSvg();
 			} catch (IOException e) {
-				result = prepareErrorMessage(e);
+				result = "Error invoking PlantUML: \"" + e.getMessage()
+				+ "\". Make sure you have configured the path to the dot executable properly in the PlantUML preferences.";
 				Platform.getLog(EObjectRefsVisualization.class).error(result, e);
+				return;
 			}
 
+			// Apply initial scale and display
 			if (result != null && !browser.isDisposed()) {
-				final String browserContent = SvgUtil.initiallyApplyScale(result, config.getScale());
+				final String browserContent = SvgUtil.initiallyApplyScale(result, context.config.getScale());
 				browser.getDisplay().asyncExec(() -> {
 					if (!browser.isDisposed()) {
-						scaleLabel.setText(String.format("%d %%", config.getScale()));	
 						browser.setText(browserContent);
 					}
 				});
@@ -191,19 +202,13 @@
 		}).start();
 	}
 
-	private String prepareErrorMessage(IOException e) {
-		return "Error invoking PlantUML: \"" + e.getMessage()
-				+ "\". Make sure you have configured the path to the dot executable properly in the PlantUML preferences.";
-	}
+	static class Context {
+		public final EObject object;
+		public final PlantUmlDiagram diagram = new PlantUmlDiagram();
+		public final EObjectRefsConfig config = new EObjectRefsConfig();
 
-	private void updateSvgScale(int newScale) {
-		// update scale label
-		if (scaleLabel != null) {
-			scaleLabel.setText(String.format("%d %%", newScale));							
-		}
-		// update SVG size in browser via Javascript/DOM
-		if (browser != null) {
-			browser.execute(SvgUtil.buildUpdateScaleCommand(newScale));
+		public Context(EObject eObject) {
+			this.object = eObject;
 		}
 	}