]> gerrit.simantics Code Review - simantics/3d.git/blobdiff - org.simantics.g3d/src/org/simantics/proconf/g3d/base/ThreeDimensionalEditorBase.java
git-svn-id: https://www.simantics.org/svn/simantics/3d/trunk@22280 ac1ea38d-2e2b...
[simantics/3d.git] / org.simantics.g3d / src / org / simantics / proconf / g3d / base / ThreeDimensionalEditorBase.java
diff --git a/org.simantics.g3d/src/org/simantics/proconf/g3d/base/ThreeDimensionalEditorBase.java b/org.simantics.g3d/src/org/simantics/proconf/g3d/base/ThreeDimensionalEditorBase.java
new file mode 100644 (file)
index 0000000..51f47fe
--- /dev/null
@@ -0,0 +1,740 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007- VTT Technical Research Centre of Finland.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.proconf.g3d.base;\r
+\r
+import java.awt.event.MouseEvent;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import javax.vecmath.Tuple3d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.eclipse.jface.action.Action;\r
+import org.eclipse.jface.action.IMenuListener;\r
+import org.eclipse.jface.action.IMenuManager;\r
+import org.eclipse.jface.action.IToolBarManager;\r
+import org.eclipse.jface.action.MenuManager;\r
+import org.eclipse.jface.action.Separator;\r
+import org.eclipse.jface.dialogs.MessageDialog;\r
+import org.eclipse.jface.viewers.ISelection;\r
+import org.eclipse.jface.viewers.ISelectionChangedListener;\r
+import org.eclipse.jface.viewers.SelectionChangedEvent;\r
+import org.eclipse.swt.events.PaintEvent;\r
+import org.eclipse.swt.events.PaintListener;\r
+import org.eclipse.swt.graphics.Point;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Menu;\r
+import org.eclipse.ui.IActionBars;\r
+import org.eclipse.ui.ISharedImages;\r
+import org.eclipse.ui.IWorkbenchActionConstants;\r
+import org.eclipse.ui.IWorkbenchPart;\r
+import org.eclipse.ui.PlatformUI;\r
+import org.eclipse.ui.internal.WorkbenchWindow;\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.GraphRequestAdapter;\r
+import org.simantics.db.GraphRequestStatus;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.events.GraphChangeEvent;\r
+import org.simantics.db.management.ISessionContext;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.proconf.g3d.Activator;\r
+import org.simantics.proconf.g3d.actions.CameraAction;\r
+import org.simantics.proconf.g3d.actions.ContextAction;\r
+import org.simantics.proconf.g3d.actions.InteractiveAction;\r
+import org.simantics.proconf.g3d.base.SelectionAdapter.SelectionType;\r
+import org.simantics.proconf.g3d.common.JmeComposite;\r
+import org.simantics.proconf.g3d.common.JmeSinglePassRenderingComponent;\r
+import org.simantics.proconf.g3d.common.OrbitalCamera;\r
+import org.simantics.proconf.g3d.dialogs.JMEDialog;\r
+import org.simantics.proconf.g3d.dnd.ShapeDropTarget;\r
+import org.simantics.proconf.g3d.gizmo.Gizmo;\r
+import org.simantics.proconf.g3d.input.InputProvider;\r
+import org.simantics.proconf.g3d.input.SWTInputProvider;\r
+import org.simantics.proconf.g3d.scenegraph.IGeometryNode;\r
+import org.simantics.proconf.g3d.scenegraph.IGraphicsNode;\r
+import org.simantics.proconf.g3d.tools.ScenegraphLockTraverser;\r
+import org.simantics.utils.ui.ErrorLogger;\r
+import org.simantics.utils.ui.jface.MenuTools;\r
+\r
+import com.jme.math.Ray;\r
+import com.jme.math.Vector2f;\r
+import com.jme.math.Vector3f;\r
+import com.jme.renderer.ColorRGBA;\r
+\r
+\r
+public abstract class ThreeDimensionalEditorBase implements  Runnable {\r
+\r
+       private Resource inputResource;\r
+       \r
+       private List<EditorContribution> editorContributions = new ArrayList<EditorContribution>();\r
+       \r
+       private EditorContribution currentEditorContribution;\r
+       \r
+    protected List<ContextAction> actions = new ArrayList<ContextAction>();\r
+    \r
+    private List<Action> contributionSelectionActions = new ArrayList<Action>();\r
+      \r
+    protected Composite parent;\r
+    \r
+    protected ISessionContext sessionContext;\r
+    \r
+    protected Session session;\r
+    \r
+    protected ScenegraphAdapter adapter;\r
+    \r
+    protected SelectionAdapter selectionAdapter;\r
+    \r
+    protected Action refreshAction;\r
+    \r
+    protected Action configureJMEAction;\r
+    \r
+    private Action lockScenegraphAction;\r
+\r
+    protected Menu contextMenu;\r
+\r
+    private JmeComposite renderingComposite = null;  \r
+\r
+    protected OrbitalCamera camera = new OrbitalCamera();\r
+\r
+    protected boolean viewChanged = true;\r
+\r
+    private InteractiveAction currentAction = null;\r
+    \r
+    private Gizmo currentGizmo = null;\r
+    \r
+    private InteractiveAction cameraAction = null;\r
+    \r
+    private JmeRenderingComponent component = null;\r
+    \r
+    protected InputProvider input = null;\r
+    \r
+    protected ShapeDropTarget dropTarget;\r
+\r
+//    protected IEditorActionBarContributor actionBarContributor;\r
+    protected IActionBars actionBars;\r
+    protected IToolBarManager toolBarManager;\r
+    protected IMenuManager menuManager;\r
+    \r
+    public ThreeDimensionalEditorBase(ISessionContext session) {\r
+       this.sessionContext = session;\r
+       this.session = session.getSession();\r
+       component = new JmeSinglePassRenderingComponent();\r
+    }\r
+\r
+    public ThreeDimensionalEditorBase(ISessionContext session, JmeRenderingComponent component) {\r
+       this.sessionContext = session;\r
+       this.session = session.getSession();\r
+       this.component = component;\r
+    }\r
+    \r
+    protected void setRenderingComponent(JmeRenderingComponent component) {\r
+       assert(renderingComposite == null); // ensure that this is called before initialization\r
+       this.component = component;\r
+    }\r
+    \r
+//    public void setActionBarContributor(IEditorActionBarContributor contributor) {\r
+//     actionBarContributor = contributor;\r
+//    }\r
+    \r
+    public void setActionBars(IActionBars actionBars) {\r
+       this.actionBars = actionBars;\r
+       this.menuManager = actionBars.getMenuManager();\r
+       this.toolBarManager = actionBars.getToolBarManager();\r
+    }\r
+    \r
+   \r
+    \r
+    \r
+    public ISessionContext getSessionContext() {\r
+       return sessionContext;\r
+    }\r
+    \r
+    public Session getSession() {\r
+       return session;\r
+    }\r
+    \r
+    /**\r
+     * Creates basic UI for ThreeDimenionalEditors.\r
+     * Note : inputResource has not been set at this point.\r
+     * \r
+     * @param graph\r
+     * @param parent\r
+     */\r
+    public void createControl(Graph graph, Composite parent) {\r
+       this.parent = parent;\r
+       renderingComposite = new JmeComposite(parent,component);\r
+       // add listeners to force repaint on size changes\r
+        renderingComposite.getCanvas().addPaintListener(new PaintListener() {\r
+               public void paintControl(PaintEvent e) {\r
+                       viewChanged = true;     \r
+               }\r
+        });\r
+\r
+        \r
+        input = new SWTInputProvider();\r
+        \r
+        renderingComposite.initGL();\r
+        camera.setCamera(component.getCamera());\r
+        camera.updateCamera();  \r
+        makeActions(graph);\r
+        hookContextMenu();\r
+\r
+        // provide selection events for properies view\r
+        this.adapter = createScenegraphAdapter();\r
+        this.selectionAdapter = createSelectionAdapter();\r
+        \r
+        this.selectionAdapter.addSelectionChangedListener(new ISelectionChangedListener() {\r
+               public void selectionChanged(SelectionChangedEvent event) {\r
+                       setCurrentAction(getDefaultAction());   \r
+               }\r
+        });\r
+        hookDragAndDrop();      \r
+        hookInput();\r
+        VisualizationScheduler.getInstance().addVisualization(this);\r
+        \r
+        if (editorContributions.size() > 0) {\r
+            // setActiveEditorContribution(editorContributions.get(0));\r
+           // } else if (editorContributions.size() > 1) {\r
+               // create actions for selecting contribution\r
+               for (EditorContribution ec : editorContributions) {\r
+                       final EditorContribution e = ec;\r
+                       Action a = new Action(e.getName(),Action.AS_RADIO_BUTTON) {\r
+                               @Override\r
+                               public void run() {\r
+                                       \r
+                                       setActiveEditorContribution(e);\r
+                               }\r
+                       };\r
+                       contributionSelectionActions.add(a);\r
+                       \r
+               }\r
+         }\r
+       \r
+    }\r
+    \r
+    public void addEditorContribution(EditorContribution e) {\r
+       if (parent != null)\r
+               throw new RuntimeException("Editor contributions must be added before editor is created.");\r
+       editorContributions.add(e);\r
+    }\r
+    \r
+    private void initializeEditorContributions(Graph graph) {\r
+        for (EditorContribution e : editorContributions) {\r
+               e.initialize(graph);\r
+         }\r
+        if (editorContributions.size() > 0)\r
+                parent.getDisplay().asyncExec(new Runnable() {\r
+                        @Override\r
+                       public void run() {\r
+                                setActiveEditorContribution(editorContributions.get(0));\r
+                       }\r
+                });     \r
+    }\r
+    \r
+    \r
+    private void hookInput() {\r
+        renderingComposite.getCanvas().addKeyListener((SWTInputProvider) input);\r
+        renderingComposite.getCanvas().addMouseListener((SWTInputProvider) input);\r
+        renderingComposite.getCanvas().addMouseMoveListener((SWTInputProvider) input);\r
+        renderingComposite.getCanvas().addMouseTrackListener((SWTInputProvider) input);\r
+        renderingComposite.getCanvas().addFocusListener((SWTInputProvider) input);\r
+    }\r
+    \r
+    protected abstract ScenegraphAdapter createScenegraphAdapter();\r
+    protected abstract SelectionAdapter createSelectionAdapter();\r
+\r
+    \r
+    public JmeComposite getRenderingComposite() {\r
+        return renderingComposite;\r
+   }\r
+    \r
+    public JmeRenderingComponent getRenderingComponent() {\r
+      return component;\r
+    }\r
+\r
+    public ScenegraphAdapter getScenegraphAdapter() {\r
+       return adapter;\r
+    }\r
+    \r
+    public SelectionAdapter getSelectionAdapter() {\r
+       return selectionAdapter;\r
+    }\r
+\r
+    public OrbitalCamera getCamera() {\r
+        return camera;\r
+    }\r
+    \r
+    public void setViewChanged(boolean b) {\r
+        viewChanged = b;\r
+    }\r
+\r
+    protected void hookContextMenu() {\r
+        MenuManager menuMgr = new MenuManager("#PopupMenu");\r
+        menuMgr.setRemoveAllWhenShown(true);\r
+        menuMgr.addMenuListener(new IMenuListener() {\r
+            public void menuAboutToShow(IMenuManager manager) {\r
+               final IMenuManager m = manager;\r
+               GraphRequestAdapter r = new GraphRequestAdapter() {\r
+                       @Override\r
+                       public GraphRequestStatus perform(Graph g) throws Exception {\r
+                               ThreeDimensionalEditorBase.this.fillContextMenu(g,m);\r
+                               return GraphRequestStatus.transactionComplete();\r
+                       }\r
+               };\r
+               \r
+               session.syncRead(r);\r
+                \r
+            }\r
+        });\r
+\r
+        contextMenu = menuMgr.createContextMenu(renderingComposite);\r
+    }\r
+\r
+    \r
+\r
+    protected void fillContextMenu(Graph graph,IMenuManager manager) {\r
+        manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));\r
+        \r
+        List<Resource> selected = selectionAdapter.getSelectedResources();\r
+        for (ContextAction action : actions) {\r
+            if(action.usable(graph,selected)) {\r
+                manager.add(action);\r
+            }\r
+        }\r
+        if (currentEditorContribution != null) {\r
+               currentEditorContribution.fillContextMenu(graph, manager, selectionAdapter.getCurrentSelection());\r
+               for (ContextAction action : currentEditorContribution.getActions()) {\r
+                       if(action.usable(graph,selected)) {\r
+                               manager.add(action);\r
+                }\r
+            }\r
+        }\r
+\r
+    }\r
+\r
+    protected void fillLocalToolBar() {\r
+\r
+       if (currentEditorContribution != null)\r
+               currentEditorContribution.fillLocalToolBar(toolBarManager);\r
+    }\r
+    \r
+    protected void fillLocalPullDown() {\r
+       for (Action a : contributionSelectionActions) {\r
+               IMenuManager menu = MenuTools.getOrCreate(getMenuID(),"View", menuManager);\r
+               menu.add(a);\r
+       }\r
+       MenuTools.getOrCreate(getMenuID(),"Advanced", menuManager).add(refreshAction);\r
+       if (configureJMEAction != null) {\r
+               MenuTools.getOrCreate(getMenuID(),"Advanced", menuManager).add(configureJMEAction);\r
+       }\r
+\r
+       MenuTools.getOrCreate(getMenuID(),"Advanced", menuManager).add(lockScenegraphAction);\r
+       if (currentEditorContribution != null)\r
+               currentEditorContribution.fillLocalPullDown(menuManager);\r
+    }\r
+    \r
+    public String getMenuID() {\r
+       return Long.toString(getInputResource().getResourceId());\r
+    }\r
+\r
+    protected void makeActions(Graph graph) {\r
+        \r
+        refreshAction = new Action() {\r
+\r
+            public void run() {\r
+               GraphRequestAdapter r = new GraphRequestAdapter() {\r
+                       public GraphRequestStatus perform(Graph g) throws Exception {\r
+//                              Stack<IGraphicsNode> stack = new Stack<IGraphicsNode>();\r
+//                         stack.push(adapter.getNode(adapter.getRootResource()));\r
+//                         while(!stack.isEmpty()) {\r
+//                             IGraphicsNode node = stack.pop();\r
+//                             stack.addAll(node.getChildren());\r
+//                             if (node instanceof IGeometryNode) {\r
+//                                 ((IGeometryNode)node).updateGeometry(g);\r
+//                             }\r
+//                         }\r
+                                for (IGraphicsNode node : adapter.getNodes())\r
+                                        if (node instanceof IGeometryNode)\r
+                                                ((IGeometryNode)node).updateGeometry(g);\r
+                         viewChanged = true;\r
+                         return GraphRequestStatus.transactionComplete();\r
+                       };\r
+               };\r
+               session.asyncRead(r);\r
+               \r
+            }\r
+        };\r
+        refreshAction.setText("Refresh");\r
+        refreshAction.setToolTipText("Refreshes the visualization");\r
+        refreshAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(\r
+                ISharedImages.IMG_TOOL_UP));\r
+        if (getRenderingComponent() instanceof JmeSinglePassRenderingComponent) {\r
+               configureJMEAction = new Action() {\r
+                       public void run() {\r
+                               JmeSinglePassRenderingComponent c = (JmeSinglePassRenderingComponent)getRenderingComponent();\r
+                               JMEDialog dialog = new JMEDialog(ThreeDimensionalEditorBase.this.parent.getShell());\r
+                               c.getDisplaySystem().setCurrent();\r
+                               dialog.setBounds(c.isShowBounds());\r
+                               dialog.setNormals(c.isShowNormals());\r
+                               dialog.setWireframe(c.isShowWireframe());\r
+                               ColorRGBA col = c.getDisplaySystem().getRenderer().getBackgroundColor();\r
+                               dialog.setFloatColor(new float[]{col.r,col.g,col.b});\r
+                               if (dialog.open() == JMEDialog.CANCEL)\r
+                                       return;\r
+                               c.setShowBounds(dialog.isBounds());\r
+                               c.setShowNormals(dialog.isNormals());\r
+                               c.setShowWireframe(dialog.isWireframe());\r
+                               if (dialog.getFloatColor() != null) {\r
+                                       c.getDisplaySystem().setCurrent();\r
+                                       c.getDisplaySystem().getRenderer().setBackgroundColor(new ColorRGBA(dialog.getFloatColor()[0],dialog.getFloatColor()[1],dialog.getFloatColor()[2],0.f));\r
+                               }\r
+                       }\r
+               };\r
+               configureJMEAction.setText("Configure JME");\r
+               configureJMEAction.setImageDescriptor(Activator.imageDescriptorFromPlugin("fi.vtt.proconf.ode", "icons/silk/wrench.png"));\r
+        }\r
+        \r
+        lockScenegraphAction = new Action("Lock scenegraph",Action.AS_CHECK_BOX) {\r
+               public void run() {\r
+                       new ScenegraphLockTraverser(adapter.getRoot(),this.isChecked());\r
+               }\r
+        };\r
+        \r
+        cameraAction = new CameraAction(this); \r
+        currentAction = cameraAction;\r
+        \r
+        \r
+    }\r
+    \r
+    public InteractiveAction getDefaultAction() {\r
+        return cameraAction;\r
+    }\r
+    \r
+    public void createPickRay(Vector3d o, Vector3d d) {\r
+       Ray r = createPickRay();\r
+       o.x = r.origin.x;\r
+       o.y = r.origin.y;\r
+       o.z = r.origin.z;\r
+       d.x = r.direction.x;\r
+       d.y = r.direction.y;\r
+       d.z = r.direction.z;\r
+       d.normalize();\r
+    }\r
+    \r
+    public Ray createPickRay() {\r
+       Vector2f screenPos = new Vector2f();\r
+               screenPos.set(input.mouseX(),renderingComposite.getBounds().height - input.mouseY());\r
+               \r
+               \r
+               Ray mouseRay;\r
+               if (component.getCamera().isParallelProjection()) {\r
+                       Vector3f worldCoords = renderingComposite.getDisplaySystem().getWorldCoordinates(screenPos, 0.0f);\r
+                       mouseRay = new Ray(worldCoords,\r
+                               component.getCamera().getDirection());\r
+               } else {\r
+                       Vector3f worldCoords = renderingComposite.getDisplaySystem().getWorldCoordinates(screenPos, 1.0f);\r
+                       mouseRay = new Ray(component.getCamera().getLocation(), worldCoords\r
+                                       .subtractLocal(component.getCamera().getLocation()));\r
+               }\r
+               return mouseRay;\r
+    }\r
+    \r
+    public Vector2f getScreenCoord(Tuple3d worldCoord) {\r
+       Vector3f v = renderingComposite.getDisplaySystem().getScreenCoordinates(VecmathJmeTools.get(worldCoord));\r
+       return new Vector2f(v.x,v.y);\r
+    }\r
+    \r
+    \r
+    public InputProvider getInputProvider() {\r
+        return input;\r
+    }\r
+\r
+    /**\r
+     * Changes current action \r
+     * \r
+     * @param type\r
+     */\r
+    public void setCurrentAction(InteractiveAction action) {\r
+       if (currentAction == action)\r
+               return;\r
+       if (toolBarManager != null) {\r
+               toolBarManager.removeAll();\r
+               fillLocalToolBar();\r
+       }\r
+        if (currentAction != null)\r
+            currentAction.deactivate();\r
+        currentAction = action;\r
+        if (currentAction != null) {\r
+            currentAction.activate();\r
+            if (toolBarManager != null) {\r
+               currentAction.fillToolBar(toolBarManager);\r
+            }\r
+        }\r
+        \r
+        updateBars();\r
+    }\r
+    \r
+    public InteractiveAction getCurrentAction() {\r
+       return currentAction;\r
+    }\r
+    \r
+    public void setActiveEditorContribution(EditorContribution contribution) {\r
+       if (currentEditorContribution == contribution)\r
+               return;\r
+       if (currentAction != getDefaultAction())\r
+               return;\r
+       if (currentEditorContribution != null)\r
+               currentEditorContribution.disposeControl();\r
+       currentEditorContribution = contribution;\r
+       int index = editorContributions.indexOf(contribution);\r
+       for (int i = 0; i < contributionSelectionActions.size(); i++) {\r
+               if (i != index)\r
+                       contributionSelectionActions.get(i).setChecked(false);\r
+               else\r
+                       contributionSelectionActions.get(i).setChecked(true);\r
+       }\r
+       if (currentEditorContribution != null)\r
+               currentEditorContribution.createControl(parent);\r
+       \r
+       actionBars.clearGlobalActionHandlers();\r
+       \r
+       parent.layout(true, true);\r
+       if (toolBarManager != null) {\r
+               toolBarManager.removeAll();\r
+               fillLocalToolBar();\r
+       }\r
+       if (menuManager != null) {              \r
+               menuManager.removeAll();\r
+               fillLocalPullDown();\r
+       }\r
+       \r
+       updateBars();\r
+    }\r
+    \r
+    protected void updateBars() {\r
+       // TODO : actionBars.updateActionBars does not update toolbar, updating toolBar directly layouts code \r
+       //        generated widgets top of contributed (extension) widgets. Only way to achieve proper update\r
+       //        is to use WorkbenchWindow.getCoolBarManager.update(true)\r
+        actionBars.updateActionBars();\r
+//     if (toolBarManager != null) {\r
+//             toolBarManager.update(true);\r
+//     }\r
+       WorkbenchWindow w = (WorkbenchWindow)PlatformUI.getWorkbench().getActiveWorkbenchWindow();\r
+        w.getCoolBarManager().update(true);\r
+    }\r
+    \r
+    public void setGizmo(Gizmo gizmo) {\r
+        if (currentGizmo != null) {\r
+               currentGizmo.getNode().removeFromParent();\r
+        }\r
+        currentGizmo = gizmo;\r
+        selectionAdapter.setCurrentGizmo(gizmo);\r
+        viewChanged = true;\r
+    }\r
+    \r
+//    public void setInfoText(String text) {\r
+//        if (useInfoComposite) {\r
+//            infoText.setText(text);\r
+//        }\r
+//    }\r
+\r
+    public void showMessage(String message) {\r
+        MessageDialog.openInformation(parent.getShell(), "Shape Editor", //$NON-NLS-1$\r
+                message);\r
+    }\r
+\r
+\r
+    /**\r
+     * Passing the focus request to the viewer's control.\r
+     */\r
+    public void setFocus() {\r
+       renderingComposite.getCanvas().setFocus();\r
+    }\r
+\r
+    public void dispose() {\r
+       //System.out.println("ThreeDimensionalEditorBase.dispose()");\r
+        VisualizationScheduler.getInstance().removeVisualization(this);\r
+\r
+        if (currentAction != null)\r
+            currentAction.deactivate();\r
+\r
+        for (EditorContribution e : editorContributions)\r
+               e.dispose();\r
+        \r
+        renderingComposite.dispose();\r
+\r
+        // copy of the set is needed to avoid ConcurrentModificationException\r
+        adapter.dispose();\r
+        component.dispose();\r
+    }\r
+\r
+    public final void reload(Graph g, Resource res) {\r
+       inputResource = res;\r
+        reloadFrom(EntityFactory.create(g, res));\r
+        // at this point we can initialize editor contributions, which may require inputResource\r
+        initializeEditorContributions(g);\r
+    }\r
+\r
+    public Resource getInputResource() {\r
+       return inputResource;\r
+    }\r
+    \r
+    public void update(GraphChangeEvent event) {\r
+//        System.out.println("Transaction " + this + " : " + event.getTransactionId() + " Arg1: " + event.getArg1()\r
+//                + " arg2: " + event.getArg2() + " sender: " + event.getSender() + " source: " + event.getSource());\r
+        \r
+//        if (event.added.size() > 0) {\r
+//            System.out.println("Added:");\r
+//            for (Triplet t : event.added)\r
+//                System.out.println(t);\r
+//        }\r
+//        if (event.changed.size() > 0) {\r
+//            System.out.println("Changed:");\r
+//            for (Triplet t : event.changed)\r
+//                System.out.println(t);\r
+//        }\r
+//        if (event.removed.size() > 0) {\r
+//            System.out.println("Removed:");\r
+//            for (Triplet t : event.removed)\r
+//                System.out.println(t);\r
+//        }\r
+\r
+    }\r
+\r
+    \r
+\r
+    /**\r
+     * Loads the initial scene: all further updates to the view are done by\r
+     * listening changes in the shapes and int the shape group\r
+     * \r
+     * @param resource\r
+     */\r
+    protected abstract void reloadFrom(IEntity thing);\r
+\r
+\r
+       protected void viewUpdated() {\r
+\r
+       }\r
+\r
+    /*\r
+     * (non-Javadoc)\r
+     * \r
+     * @see java.lang.Runnable#run()\r
+     */\r
+    public void run() {\r
+       if (currentEditorContribution != null)\r
+               currentEditorContribution.run();\r
+       if (parent.isDisposed() || !parent.isVisible())\r
+                       return;\r
+       //renderingComposite.getDisplaySystem().setCurrent();\r
+               input.update();\r
+               if (input.mouseClicked()) {\r
+                       int downMask = MouseEvent.CTRL_DOWN_MASK;\r
+\r
+                       if ((input.clickModifiers() & downMask) > 0) {\r
+                               selectionAdapter.setSelectionType(SelectionType.MODIFY);\r
+                       } else {\r
+                               selectionAdapter.setSelectionType(SelectionType.SET);\r
+                       }\r
+               }\r
+               if (input.mouseMoved()) {\r
+                       Ray mouseRay = createPickRay();\r
+                       selectionAdapter.updateHighlights(mouseRay);\r
+               }\r
+               if (currentAction == cameraAction && input.mouseClicked()) {\r
+                       selectionAdapter.pickHighlighted();\r
+               }\r
+               if (currentAction == cameraAction && input.mousePressed()\r
+                               && (input.pressModifiers() & MouseEvent.BUTTON3_MASK) > 0) {\r
+                       Point p = renderingComposite.toDisplay(input.mouseX(), input\r
+                                       .mouseY());\r
+                       contextMenu.setLocation(p.x, p.y);\r
+                       contextMenu.setVisible(true);\r
+               }\r
+\r
+               if (currentAction != null)\r
+                       try {\r
+                               currentAction.update();\r
+                       } catch (Exception e) {\r
+                               ErrorLogger.defaultLogError("Action error!", e);\r
+                               setCurrentAction(getDefaultAction());\r
+                       }\r
+\r
+               if (component.update())\r
+                       viewChanged = true;\r
+                   \r
+               if (!geometryUpdateRequestAdapter.isRunning() && adapter.needsUpdateGeometry()) {\r
+                       session.asyncRead(geometryUpdateRequestAdapter);        \r
+               }\r
+               \r
+               viewChanged |= adapter.isChanged();\r
+                if (viewChanged) {\r
+                       viewChanged = false;\r
+                       adapter.setChanged(false);\r
+                       camera.updateCamera();\r
+                       viewUpdated();\r
+                       component.render();\r
+               }\r
+       }\r
+    // TODO : there is some sort of synchronization bug in rendering:\r
+    //        part of the rendered objects are rendered with different camera transformation than others.\r
+    //        re-rendering the scene hides the worst problems.\r
+    //        Using shadows is the reason: shadowed objects are rendered with different transformation than non-shadowed.\r
+    //private boolean lastChanged = false;\r
+    \r
+    private GeometryUpdateRequestAdapter geometryUpdateRequestAdapter = new GeometryUpdateRequestAdapter();\r
+       \r
+    private class GeometryUpdateRequestAdapter extends GraphRequestAdapter {\r
+       private boolean running;\r
+       @Override\r
+               public GraphRequestStatus perform(Graph g) throws Exception {\r
+               running = true;\r
+                       adapter.updateGeometry(g);\r
+                       return GraphRequestStatus.transactionComplete();\r
+               }\r
+               @Override\r
+               public void requestCompleted(GraphRequestStatus status) {\r
+                       running = false;\r
+                       adapter.setChanged(true);\r
+               }\r
+               \r
+               public boolean isRunning() {\r
+                       return running;\r
+               }\r
+    }\r
+\r
+   \r
+    \r
+    protected void hookDragAndDrop() {\r
+       dropTarget = new ShapeDropTarget(this);\r
+    }\r
+\r
+    /**\r
+     * Receives selection changes\r
+     * \r
+     * @param part\r
+     * @param selection\r
+     */\r
+    protected abstract void pageSelectionChanged(IWorkbenchPart part, ISelection selection);\r
+\r
+    /**\r
+     * EditorPart or ViewPart uses this method to forward getAdapter(Class)\r
+     * @see org.eclipse.ui.part.WorkbenchPart.getAdapter(Class adapter)\r
+     * @param adapter\r
+     * @return\r
+     */\r
+    public Object getAdapter(Class adapter) {\r
+       return null;\r
+    }\r
+\r
+}
\ No newline at end of file