gt: 		if(p != null)
context: package pt.iscte.pandionj;
  
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  
  import org.eclipse.draw2d.Border;
  import org.eclipse.draw2d.ColorConstants;
  import org.eclipse.draw2d.ConnectionAnchor;
  import org.eclipse.draw2d.Figure;
  import org.eclipse.draw2d.Graphics;
  import org.eclipse.draw2d.GridLayout;
  import org.eclipse.draw2d.IFigure;
  import org.eclipse.draw2d.LightweightSystem;
  import org.eclipse.draw2d.LineBorder;
  import org.eclipse.draw2d.PolylineConnection;
  import org.eclipse.draw2d.SWTGraphics;
  import org.eclipse.draw2d.ScalableLayeredPane;
  import org.eclipse.draw2d.geometry.Dimension;
  import org.eclipse.draw2d.geometry.Insets;
  import org.eclipse.draw2d.geometry.Rectangle;
  import org.eclipse.swt.SWT;
  import org.eclipse.swt.custom.ScrolledComposite;
  import org.eclipse.swt.events.KeyAdapter;
  import org.eclipse.swt.events.KeyEvent;
  import org.eclipse.swt.events.SelectionAdapter;
  import org.eclipse.swt.events.SelectionEvent;
  import org.eclipse.swt.events.VerifyEvent;
  import org.eclipse.swt.events.VerifyListener;
  import org.eclipse.swt.graphics.GC;
  import org.eclipse.swt.graphics.Image;
  import org.eclipse.swt.layout.FillLayout;
  import org.eclipse.swt.layout.GridData;
  import org.eclipse.swt.widgets.Canvas;
  import org.eclipse.swt.widgets.Composite;
  import org.eclipse.swt.widgets.Display;
  import org.eclipse.swt.widgets.Menu;
  import org.eclipse.swt.widgets.MenuItem;
  import org.eclipse.swt.widgets.Shell;
  import org.eclipse.swt.widgets.Text;
  
  import com.google.common.collect.ArrayListMultimap;
  import com.google.common.collect.Multimap;
  
  import pt.iscte.pandionj.extensibility.IEntityModel;
  import pt.iscte.pandionj.extensibility.IObjectModel;
  import pt.iscte.pandionj.extensibility.IReferenceModel;
  import pt.iscte.pandionj.extensibility.IStackFrameModel;
  import pt.iscte.pandionj.extensibility.IVariableModel;
  import pt.iscte.pandionj.extensibility.IVariableModel.Role;
  import pt.iscte.pandionj.extensibility.ModelObserver;
  import pt.iscte.pandionj.extensibility.PandionJConstants;
  import pt.iscte.pandionj.extensibility.PandionJUI;
  import pt.iscte.pandionj.figures.ObjectContainer;
  import pt.iscte.pandionj.figures.PandionJFigure;
  import pt.iscte.pandionj.figures.StackContainer;
  import pt.iscte.pandionj.model.RuntimeModel;
  import pt.iscte.pandionj.model.StackFrameModel;
  
  public class RuntimeViewer extends Composite {
  	private static RuntimeViewer instance = null;
  
  	private FigureProvider figProvider;
  	private Figure rootFig;
  	private StackContainer stackFig;
  	private ObjectContainer objectContainer;
  	private LightweightSystem lws;
  	private GridLayout rootGrid;
  	private ScrolledComposite scroll;
  	private Canvas canvas;
  	private Map<IReferenceModel, PolylineConnection> pointersMap;
  	private Multimap<Object, PolylineConnection> pointersMapOwners;
  	private List<ObjectContainer> objectContainers;
  
  	private MenuItem clearItem;
  
  	RuntimeViewer(Composite parent) {
  		super(parent, SWT.BORDER);
  		instance = this;
  
  		setLayout(new FillLayout());
  		setBackground(PandionJConstants.Colors.VIEW_BACKGROUND);
  		scroll = new ScrolledComposite(this, SWT.H_SCROLL | SWT.V_SCROLL);
  		scroll.setBackground(PandionJConstants.Colors.VIEW_BACKGROUND);
  		canvas = new Canvas(scroll, SWT.DOUBLE_BUFFERED);
  		canvas.setBackground(PandionJConstants.Colors.VIEW_BACKGROUND);
  		canvas.setLayoutData(new GridData(GridData.FILL_BOTH));
  		scroll.setContent(canvas);
  		addMenu();
  
  //		rootFig = new ScalableLayeredPane();
  //		((ScalableLayeredPane) rootFig).setScale(2);
  		
  		rootFig = new Figure();
  		rootFig.setOpaque(true);
  		rootFig.setBackgroundColor(PandionJConstants.Colors.VIEW_BACKGROUND);
  
  		rootGrid = new GridLayout(2, false);
  		rootGrid.horizontalSpacing = PandionJConstants.STACK_TO_OBJECTS_GAP;
  		rootGrid.marginWidth = PandionJConstants.CANVAS_MARGIN;
  		rootGrid.marginHeight = PandionJConstants.CANVAS_MARGIN;
  		rootFig.setLayoutManager(rootGrid);
  
  		stackFig = new StackContainer();
  		rootFig.add(stackFig);
  		org.eclipse.draw2d.GridData d = new org.eclipse.draw2d.GridData(SWT.BEGINNING, SWT.BEGINNING, true, true);
  		d.widthHint = Math.max(PandionJConstants.STACKCOLUMN_MIN_WIDTH, stackFig.getPreferredSize().width);
  		rootGrid.setConstraint(stackFig, d);
  
  		objectContainers = new ArrayList<>();
  		objectContainer = ObjectContainer.create(true);
  		rootFig.add(objectContainer);
  		rootGrid.setConstraint(objectContainer, new org.eclipse.draw2d.GridData(SWT.FILL, SWT.FILL, true, true));
  
  		lws = new LightweightSystem(canvas);
  		lws.setContents(rootFig);
  		pointersMap = new HashMap<>();
  		pointersMapOwners = ArrayListMultimap.create();
  	}
  
  	public static RuntimeViewer getInstance() {
  		return instance;
  	}
  
  	public FigureProvider getFigureProvider() {
  		return figProvider;
  	}
  
  	public void setInput(RuntimeModel model) {
  		figProvider = new FigureProvider(model);
  		model.registerObserver((e) -> refresh(model, e));
  	}
  
  	private void refresh(RuntimeModel model, RuntimeModel.Event<?> event) {
  		PandionJUI.executeUpdate(() -> {
  			if(event.type == RuntimeModel.Event.Type.NEW_STACK)
  				rebuildStack(model);
  			else if(event.type == RuntimeModel.Event.Type.REMOVE_FRAME) {
  				StackFrameModel f = (StackFrameModel) event.arg;
  				stackFig.removeFrame(f);
  
  				List<?> children = rootFig.getChildren();
  				for (IReferenceModel v : f.getReferenceVariables()) {
  					PolylineConnection c = pointersMap.remove(v);
  					if(c != null && children.contains(c))
  						rootFig.remove(c);
  				}
  			}
  			else if(event.type == RuntimeModel.Event.Type.NEW_FRAME) {
  				StackFrameModel frame = (StackFrameModel) event.arg;
  				if(frame.isInstance()) {
  					IObjectModel obj = (IObjectModel) model.getObject(frame.getStackFrame().getThis(), false, null);
  					addObject(obj);
  				}
  				else
  					stackFig.addFrame(frame, this, objectContainer, false);
  			}
  			stackFig.getLayoutManager().layout(stackFig);
  			updateLayout();
  
  			if(!clearItem.isDisposed())
  				clearItem.setEnabled(model.isTerminated());
  		});
  	}
  
  
  	private void rebuildStack(RuntimeModel model) {
  		clear();
  		IStackFrameModel staticVars = model.getStaticVars();
  		stackFig.addFrame(staticVars, this, objectContainer, true);
  	}
  
  	private void clear() {
  		for(PolylineConnection p : pointersMap.values())
  			rootFig.remove(p);
  
  		pointersMap.clear();
  		pointersMapOwners.clear();
  		stackFig.removeAll();
  		objectContainer.removeAll();
  	}
  
  
  	public void updateLayout() {
  		if(!canvas.isDisposed()) {
  			Dimension size = rootFig.getPreferredSize();
  			canvas.setSize(size.width, size.height);
  			org.eclipse.draw2d.GridData d = (org.eclipse.draw2d.GridData) rootGrid.getConstraint(stackFig);
  			d.widthHint = Math.max(PandionJConstants.STACKCOLUMN_MIN_WIDTH, stackFig.getPreferredSize().width);
  			rootGrid.layout(rootFig);
  			requestLayout();
  		}
  	}
  
  
  	private void addPointer(IReferenceModel ref, PolylineConnection pointer, Object owner) {
  		assert pointer != null;
  		rootFig.add(pointer);
  		pointersMap.put(ref, pointer);
  		pointersMapOwners.put(owner, pointer);
  		//		pointer.setToolTip(new Label(ref.toString()));
  	}
  
  
  	public void addPointer(IReferenceModel ref, ConnectionAnchor sourceAnchor, ConnectionAnchor targetAnchor, ObjectContainer container, Object owner) {
  		assert ref != null;
  		IEntityModel target = ref.getModelTarget();
  		PolylineConnection pointer = new PolylineConnection();
  		pointer.setVisible(!target.isNull());
  		pointer.setSourceAnchor(sourceAnchor);
  		pointer.setTargetAnchor(target.isNull() ? sourceAnchor : targetAnchor);
  		pointer.setForegroundColor(ref.getRole() == Role.FIXED_VALUE ? PandionJConstants.Colors.CONSTANT : ColorConstants.black);
  		Utils.addArrowDecoration(pointer);
  		addPointerObserver(ref, pointer, container);
  		addPointer(ref, pointer, owner);
  	}
  
  	static void addPointerObserver(IReferenceModel ref, PolylineConnection pointer, ObjectContainer container) {
  		ref.registerDisplayObserver(new ModelObserver<IVariableModel.VariableEvent<?>>() {
  			@Override
  			public void update(IVariableModel.VariableEvent<?> arg) {
  				IEntityModel target = ref.getModelTarget();
  				pointer.setVisible(!target.isNull());
  				if(!target.isNull()) {
  					PandionJFigure<?> targetFig = container.addObject(target, ref.getIndex());
  					pointer.setTargetAnchor(targetFig.getIncommingAnchor());
  					Utils.addArrowDecoration(pointer);
  				}
  			}
  		});
  	}
  
  	public void showPointer(IReferenceModel ref, boolean show) {
  		PolylineConnection p = pointersMap.get(ref);
  		if(p != null)
  			p.setVisible(show && !ref.getModelTarget().isNull());
  	}
  
  	public void showPointers(Object owner, boolean show) {
  		for(PolylineConnection pointer : pointersMapOwners.get(owner))
  			pointer.setVisible(show);
  	}
  
  	public void removePointer(IReferenceModel ref) {
  		PolylineConnection p = pointersMap.remove(ref);
  