]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scenegraph.ui/src/org/simantics/scenegraph/ui/AttributeDialog.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.scenegraph.ui / src / org / simantics / scenegraph / ui / AttributeDialog.java
index bd6d7670ac84b544cbec4e426133ae68a9ce232f..08cac2fb83d21ea60e7a141fe65520cea4cb5aa3 100644 (file)
-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\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.scenegraph.ui;\r
-\r
-import java.lang.reflect.Field;\r
-import java.lang.reflect.Modifier;\r
-import java.util.ArrayList;\r
-import java.util.List;\r
-\r
-import org.eclipse.jface.dialogs.Dialog;\r
-import org.eclipse.jface.dialogs.IDialogSettings;\r
-import org.eclipse.jface.layout.GridDataFactory;\r
-import org.eclipse.jface.layout.GridLayoutFactory;\r
-import org.eclipse.jface.layout.TableColumnLayout;\r
-import org.eclipse.jface.resource.ColorDescriptor;\r
-import org.eclipse.jface.resource.FontDescriptor;\r
-import org.eclipse.jface.resource.JFaceResources;\r
-import org.eclipse.jface.resource.LocalResourceManager;\r
-import org.eclipse.jface.resource.ResourceManager;\r
-import org.eclipse.jface.viewers.ColumnLabelProvider;\r
-import org.eclipse.jface.viewers.ColumnWeightData;\r
-import org.eclipse.jface.viewers.ISelection;\r
-import org.eclipse.jface.viewers.ISelectionChangedListener;\r
-import org.eclipse.jface.viewers.ISelectionProvider;\r
-import org.eclipse.jface.viewers.IStructuredSelection;\r
-import org.eclipse.jface.viewers.ITreeContentProvider;\r
-import org.eclipse.jface.viewers.SelectionChangedEvent;\r
-import org.eclipse.jface.viewers.TableViewer;\r
-import org.eclipse.jface.viewers.TableViewerColumn;\r
-import org.eclipse.jface.viewers.Viewer;\r
-import org.eclipse.jface.viewers.ViewerCell;\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.events.KeyAdapter;\r
-import org.eclipse.swt.events.KeyEvent;\r
-import org.eclipse.swt.events.SelectionAdapter;\r
-import org.eclipse.swt.events.SelectionEvent;\r
-import org.eclipse.swt.graphics.Color;\r
-import org.eclipse.swt.graphics.Point;\r
-import org.eclipse.swt.graphics.RGB;\r
-import org.eclipse.swt.layout.GridData;\r
-import org.eclipse.swt.widgets.Composite;\r
-import org.eclipse.swt.widgets.Control;\r
-import org.eclipse.swt.widgets.Event;\r
-import org.eclipse.swt.widgets.Listener;\r
-import org.eclipse.swt.widgets.Shell;\r
-import org.eclipse.swt.widgets.ToolBar;\r
-import org.eclipse.swt.widgets.ToolItem;\r
-import org.simantics.scenegraph.INode;\r
-import org.simantics.scenegraph.g2d.IG2DNode;\r
-import org.simantics.scenegraph.utils.NodeUtil;\r
-import org.simantics.utils.datastructures.ValueUtils;\r
-\r
-/**\r
- * @author Tuukka Lehtonen\r
- */\r
-public class AttributeDialog extends Dialog implements ISelectionChangedListener {\r
-\r
-    private static final String      DIALOG = "AttributeDialog"; //$NON-NLS-1$\r
-\r
-    private IDialogSettings          dialogBoundsSettings;\r
-\r
-    private ResourceManager          resourceManager;\r
-\r
-    private TableViewer              viewer;\r
-\r
-    private final ISelectionProvider selectionProvider;\r
-\r
-    private final boolean            showClass      = true;\r
-    private boolean                  showTransient  = false;\r
-    private boolean                  showStatic     = false;\r
-\r
-    private final ColorDescriptor    staticColor    = ColorDescriptor.createFrom(new RGB(224, 224, 224));\r
-    private final ColorDescriptor    transientColor = ColorDescriptor.createFrom(new RGB(192, 255, 255));\r
-    \r
-    protected AttributeDialog(Shell parentShell, ISelectionProvider selectionProvider) {\r
-        super(parentShell);\r
-        this.selectionProvider = selectionProvider;\r
-\r
-        IDialogSettings settings = Activator.getDefault().getDialogSettings();\r
-        dialogBoundsSettings = settings.getSection(DIALOG);\r
-        if (dialogBoundsSettings == null)\r
-            dialogBoundsSettings = settings.addNewSection(DIALOG);\r
-    }\r
-\r
-    @Override\r
-    protected IDialogSettings getDialogBoundsSettings() {\r
-        return dialogBoundsSettings;\r
-    }\r
-\r
-    @Override\r
-    protected int getShellStyle() {\r
-        return SWT.RESIZE | SWT.MODELESS | SWT.TITLE | SWT.CLOSE | SWT.BORDER;\r
-    }\r
-\r
-    @Override\r
-    protected void configureShell(Shell newShell) {\r
-        super.configureShell(newShell);\r
-        newShell.setText("Scene Graph Node Attributes");\r
-    }\r
-\r
-    @Override\r
-    protected Control createButtonBar(Composite parent) {\r
-        return parent;\r
-    }\r
-\r
-    @Override\r
-    protected void createButtonsForButtonBar(Composite parent) {\r
-        // No buttons, this is a non-modal property dialog.\r
-    }\r
-\r
-    @Override\r
-    protected Point getInitialSize() {\r
-        Point defaultSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT, true);\r
-        Point result = super.getInitialSize();\r
-        if (defaultSize.equals(result))\r
-            return new Point(500, 300);\r
-        return result;\r
-    }\r
-\r
-    @Override\r
-    protected Control createDialogArea(Composite parent) {\r
-        Composite composite = (Composite) super.createDialogArea(parent);\r
-\r
-        this.resourceManager = new LocalResourceManager(JFaceResources.getResources());\r
-        composite.addListener(SWT.Dispose, new Listener() {\r
-            @Override\r
-            public void handleEvent(Event event) {\r
-                selectionProvider.removeSelectionChangedListener(AttributeDialog.this);\r
-                resourceManager.dispose();\r
-                resourceManager = null;\r
-            }\r
-        });\r
-\r
-        GridLayoutFactory.fillDefaults().margins(0, 0).spacing(0, 0).applyTo(composite);\r
-\r
-        ToolBar toolbar = new ToolBar(composite, SWT.NONE);\r
-        GridDataFactory.fillDefaults().grab(true, false).applyTo(toolbar);\r
-        final ToolItem showStaticItem = new ToolItem(toolbar, SWT.CHECK);\r
-        showStaticItem.setText("Show &Static");\r
-        showStaticItem.setToolTipText("Show Static Fields of Selected Object");\r
-        final ToolItem showTransientItem = new ToolItem(toolbar, SWT.CHECK);\r
-        showTransientItem.setText("Show &Transient");\r
-        showTransientItem.setToolTipText("Show Transient Fields of Selected Object");\r
-        final ToolItem refresh = new ToolItem(toolbar, SWT.PUSH);\r
-        refresh.setText("&Refresh");\r
-        refresh.setToolTipText("Refresh Values");\r
-\r
-        Composite tableComposite = new Composite(composite, SWT.NONE);\r
-        GridDataFactory.fillDefaults().grab(true, true).applyTo(tableComposite);\r
-\r
-        viewer = new TableViewer(tableComposite, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER | SWT.SINGLE | SWT.FULL_SELECTION);\r
-        viewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));\r
-        viewer.setContentProvider(new FieldContentProvider());\r
-        viewer.getTable().addKeyListener(new KeyAdapter() {\r
-            @Override\r
-            public void keyPressed(KeyEvent e) {\r
-                if (e.keyCode == SWT.F5)\r
-                    refresh();\r
-            }\r
-        });\r
-\r
-        TableColumnLayout ad = new TableColumnLayout();\r
-        tableComposite.setLayout(ad);\r
-\r
-        viewer.getTable().setHeaderVisible(true);\r
-        viewer.getTable().setLinesVisible(true);\r
-        viewer.setUseHashlookup(true);\r
-\r
-        TableViewerColumn nameColumn = new TableViewerColumn(viewer, SWT.LEFT);\r
-        nameColumn.setLabelProvider(new FieldName());\r
-        TableViewerColumn typeColumn = new TableViewerColumn(viewer, SWT.LEFT);\r
-        typeColumn.setLabelProvider(new FieldType());\r
-        TableViewerColumn valueColumn = new TableViewerColumn(viewer, SWT.LEFT);\r
-        valueColumn.setLabelProvider(new FieldValue());\r
-\r
-        typeColumn.getColumn().setText("Type");\r
-        typeColumn.getColumn().setWidth(20);\r
-        ad.setColumnData(typeColumn.getColumn(), new ColumnWeightData(10, 140));\r
-        nameColumn.getColumn().setText("Name");\r
-        nameColumn.getColumn().setWidth(20);\r
-        ad.setColumnData(nameColumn.getColumn(), new ColumnWeightData(10, 140));\r
-        valueColumn.getColumn().setText("Value");\r
-        valueColumn.getColumn().setWidth(20);\r
-        ad.setColumnData(valueColumn.getColumn(), new ColumnWeightData(90, 200));\r
-\r
-        selectionProvider.addSelectionChangedListener(this);\r
-\r
-        showStaticItem.addSelectionListener(new SelectionAdapter() {\r
-            @Override\r
-            public void widgetSelected(SelectionEvent e) {\r
-                showStatic = showStaticItem.getSelection();\r
-                refresh();\r
-            }\r
-        });\r
-        showTransientItem.addSelectionListener(new SelectionAdapter() {\r
-            @Override\r
-            public void widgetSelected(SelectionEvent e) {\r
-                showTransient = showTransientItem.getSelection();\r
-                refresh();\r
-            }\r
-        });\r
-        refresh.addSelectionListener(new SelectionAdapter() {\r
-            @Override\r
-            public void widgetSelected(SelectionEvent e) {\r
-                refresh();\r
-            }\r
-        });\r
-\r
-        // Bootstrap dialog.\r
-        refresh();\r
-\r
-        applyDialogFont(composite);\r
-        return composite;\r
-    }\r
-\r
-    static class Header {\r
-        String name;\r
-        public Header(String name) {\r
-            this.name = name;\r
-        }\r
-        @Override\r
-        public String toString() {\r
-            return name;\r
-        }\r
-    }\r
-\r
-    static class ComputedAttr {\r
-        public String name;\r
-        public Object object;\r
-        public String stringValue;\r
-        public ComputedAttr(String name, Object object) {\r
-            this(name, object, object != null ? object.toString() : "null");\r
-        }\r
-        public ComputedAttr(String name, Object object, String stringValue) {\r
-            this.name = name;\r
-            this.object = object;\r
-            this.stringValue = stringValue;\r
-        }\r
-        @Override\r
-        public String toString() {\r
-            return stringValue;\r
-        }\r
-    }\r
-\r
-    static class Attr {\r
-        Object object;\r
-        Field field;\r
-        public Attr(Object obj, Field f) {\r
-            this.object = obj;\r
-            this.field = f;\r
-        }\r
-        public Object getObject() {\r
-            return object;\r
-        }\r
-        public <T> T getObject(Class<T> clazz) {\r
-            return clazz.cast(object);\r
-        }\r
-        public Field getField() {\r
-            return field;\r
-        }\r
-        @Override\r
-        public String toString() {\r
-            return field.getName();\r
-        }\r
-    }\r
-\r
-    class FieldContentProvider implements ITreeContentProvider {\r
-        @Override\r
-        public Object[] getChildren(Object parentElement) {\r
-            return new Object[0];\r
-        }\r
-\r
-        @Override\r
-        public Object getParent(Object element) {\r
-            return null;\r
-        }\r
-\r
-        @Override\r
-        public boolean hasChildren(Object element) {\r
-            return false;\r
-        }\r
-\r
-        @Override\r
-        public Object[] getElements(Object inputElement) {\r
-            if (inputElement instanceof NodeProxy) {\r
-                NodeProxy np = (NodeProxy) inputElement;\r
-                INode node = np.getNode();\r
-                if (node == null)\r
-                    return new Object[0];\r
-                List<Object> result = new ArrayList<Object>();\r
-\r
-                if (node instanceof IG2DNode) {\r
-                    IG2DNode g2dnode = (IG2DNode) node;\r
-                    // Calculate some useful computational properties\r
-                    result.add(new Header("Computational IG2DNode properties"));\r
-                    result.add(new ComputedAttr("local bounds", g2dnode.getBoundsInLocal()));\r
-                    result.add(new ComputedAttr("world bounds", g2dnode.getBounds()));\r
-                    result.add(new ComputedAttr("local to world transform", NodeUtil.getLocalToGlobalTransform(g2dnode)));\r
-                }\r
-\r
-                Class<?> clazz = node.getClass();\r
-                while (clazz != null && clazz != Object.class) {\r
-                    if (showClass)\r
-                        result.add(clazz);\r
-                    Field[] fields = clazz.getDeclaredFields();\r
-                    for (int i = 0; i < fields.length; ++i) {\r
-                        Field f = fields[i];\r
-\r
-                        // Ignore transient properties, those are generally just caches.\r
-                        if (!showTransient && Modifier.isTransient(f.getModifiers()))\r
-                            continue;\r
-\r
-                        // Ignore statics, those shouldn't affect data transfer.\r
-                        if (!showStatic && Modifier.isStatic(f.getModifiers()))\r
-                            continue;\r
-\r
-                        result.add(new Attr(np, fields[i]));\r
-                    }\r
-                    clazz = clazz.getSuperclass();\r
-                }\r
-                return result.toArray();\r
-            }\r
-            return new Object[0];\r
-        }\r
-\r
-        @Override\r
-        public void dispose() {\r
-        }\r
-\r
-        @Override\r
-        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {\r
-        }\r
-    }\r
-\r
-    abstract class NodeLabelProvider extends ColumnLabelProvider {\r
-        @Override\r
-        public final void update(ViewerCell cell) {\r
-            Object elem = cell.getElement();\r
-            if (elem instanceof Attr) {\r
-                Attr attr = (Attr) elem;\r
-                NodeProxy np = attr.getObject(NodeProxy.class);\r
-                INode node = np.getNode();\r
-                update(cell, attr, node);\r
-            } else if (elem instanceof ComputedAttr) {\r
-                ComputedAttr attr = (ComputedAttr) elem;\r
-                update(cell, attr);\r
-            } else if (elem instanceof Header) {\r
-                updateHeader(cell, ((Header) elem).name);\r
-            } else if (elem instanceof Class<?>) {\r
-                Class<?> clazz = (Class<?>) elem;\r
-                updateHeader(cell, clazz.getSimpleName());\r
-            }\r
-        }\r
-\r
-        public abstract void update(ViewerCell cell, ComputedAttr attr);\r
-        public abstract void update(ViewerCell cell, Attr attr, INode node);\r
-        public void updateHeader(ViewerCell cell, String header) {\r
-            cell.setFont(resourceManager.createFont(FontDescriptor.createFrom(cell.getFont()).withStyle(SWT.BOLD|SWT.ITALIC)));\r
-            cell.setForeground(cell.getControl().getDisplay().getSystemColor(SWT.COLOR_INFO_FOREGROUND));\r
-            cell.setBackground(cell.getControl().getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND));\r
-        }\r
-    }\r
-\r
-    class FieldType extends NodeLabelProvider {\r
-        @Override\r
-        public void update(ViewerCell cell, ComputedAttr attr) {\r
-            cell.setText(attr.object != null ? attr.object.getClass().getSimpleName() : "null");\r
-        }\r
-        @Override\r
-        public void update(ViewerCell cell, Attr attr, INode node) {\r
-            Field f = attr.getField();\r
-            cell.setText(f.getType().getSimpleName());\r
-        }\r
-    }\r
-\r
-    class FieldName extends NodeLabelProvider {\r
-        @Override\r
-        public void update(ViewerCell cell, ComputedAttr attr) {\r
-            cell.setText(attr.name);\r
-        }\r
-        @Override\r
-        public void update(ViewerCell cell, Attr attr, INode node) {\r
-            Field f = attr.getField();\r
-            cell.setText(f.getName());\r
-        }\r
-        @Override\r
-        public void updateHeader(ViewerCell cell, String header) {\r
-            super.updateHeader(cell, header);\r
-            cell.setText(header);\r
-        }\r
-    }\r
-\r
-    class FieldValue extends NodeLabelProvider {\r
-        @Override\r
-        public void update(ViewerCell cell, ComputedAttr attr) {\r
-            cell.setText(attr.stringValue);\r
-        }\r
-        @Override\r
-        public void update(ViewerCell cell, Attr attr, INode node) {\r
-            Field f = attr.getField();\r
-            boolean accessible = f.isAccessible();\r
-            try {\r
-                if (!accessible)\r
-                    f.setAccessible(true);\r
-                Object value = f.get(node);\r
-                String label = value == null ? "null" : ValueUtils.toString(value);\r
-                cell.setText(label);\r
-\r
-                if (Modifier.isStatic(f.getModifiers())) {\r
-                    cell.setBackground((Color) resourceManager.get(staticColor));\r
-                } else if (Modifier.isTransient(f.getModifiers())) {\r
-                    cell.setBackground((Color) resourceManager.get(transientColor));\r
-                }\r
-            } catch (IllegalArgumentException e) {\r
-                e.printStackTrace();\r
-                cell.setText(e.getMessage());\r
-            } catch (IllegalAccessException e) {\r
-                e.printStackTrace();\r
-                cell.setText(e.getMessage());\r
-            } finally {\r
-                if (!accessible)\r
-                    f.setAccessible(false);\r
-            }\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public void selectionChanged(SelectionChangedEvent event) {\r
-        selectionChanged(event.getSelection());\r
-    }\r
-\r
-    public void selectionChanged(ISelection selection) {\r
-        //System.out.println("selection changed: " + event);\r
-        IStructuredSelection ss = (IStructuredSelection) selection;\r
-        Object obj = ss.getFirstElement();\r
-        if (ss.size() == 1 || (obj instanceof NodeProxy)) {\r
-            viewer.setInput(obj);\r
-        } else {\r
-            viewer.setInput(new Object());\r
-        }\r
-    }\r
-\r
-    public void refresh() {\r
-        selectionChanged(selectionProvider.getSelection());\r
-    }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * 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:
+ *     VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.scenegraph.ui;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.layout.TableColumnLayout;
+import org.eclipse.jface.resource.ColorDescriptor;
+import org.eclipse.jface.resource.FontDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.resource.ResourceManager;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerCell;
+import org.eclipse.swt.SWT;
+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.graphics.Color;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+import org.simantics.scenegraph.INode;
+import org.simantics.scenegraph.g2d.IG2DNode;
+import org.simantics.scenegraph.utils.NodeUtil;
+import org.simantics.utils.datastructures.ValueUtils;
+
+/**
+ * @author Tuukka Lehtonen
+ */
+public class AttributeDialog extends Dialog implements ISelectionChangedListener {
+
+    private static final String      DIALOG = "AttributeDialog"; //$NON-NLS-1$
+
+    private IDialogSettings          dialogBoundsSettings;
+
+    private ResourceManager          resourceManager;
+
+    private TableViewer              viewer;
+
+    private final ISelectionProvider selectionProvider;
+
+    private final boolean            showClass      = true;
+    private boolean                  showTransient  = false;
+    private boolean                  showStatic     = false;
+
+    private final ColorDescriptor    staticColor    = ColorDescriptor.createFrom(new RGB(224, 224, 224));
+    private final ColorDescriptor    transientColor = ColorDescriptor.createFrom(new RGB(192, 255, 255));
+    
+    protected AttributeDialog(Shell parentShell, ISelectionProvider selectionProvider) {
+        super(parentShell);
+        this.selectionProvider = selectionProvider;
+
+        IDialogSettings settings = Activator.getDefault().getDialogSettings();
+        dialogBoundsSettings = settings.getSection(DIALOG);
+        if (dialogBoundsSettings == null)
+            dialogBoundsSettings = settings.addNewSection(DIALOG);
+    }
+
+    @Override
+    protected IDialogSettings getDialogBoundsSettings() {
+        return dialogBoundsSettings;
+    }
+
+    @Override
+    protected int getShellStyle() {
+        return SWT.RESIZE | SWT.MODELESS | SWT.TITLE | SWT.CLOSE | SWT.BORDER;
+    }
+
+    @Override
+    protected void configureShell(Shell newShell) {
+        super.configureShell(newShell);
+        newShell.setText("Scene Graph Node Attributes");
+    }
+
+    @Override
+    protected Control createButtonBar(Composite parent) {
+        return parent;
+    }
+
+    @Override
+    protected void createButtonsForButtonBar(Composite parent) {
+        // No buttons, this is a non-modal property dialog.
+    }
+
+    @Override
+    protected Point getInitialSize() {
+        Point defaultSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
+        Point result = super.getInitialSize();
+        if (defaultSize.equals(result))
+            return new Point(500, 300);
+        return result;
+    }
+
+    @Override
+    protected Control createDialogArea(Composite parent) {
+        Composite composite = (Composite) super.createDialogArea(parent);
+
+        this.resourceManager = new LocalResourceManager(JFaceResources.getResources());
+        composite.addListener(SWT.Dispose, new Listener() {
+            @Override
+            public void handleEvent(Event event) {
+                selectionProvider.removeSelectionChangedListener(AttributeDialog.this);
+                resourceManager.dispose();
+                resourceManager = null;
+            }
+        });
+
+        GridLayoutFactory.fillDefaults().margins(0, 0).spacing(0, 0).applyTo(composite);
+
+        ToolBar toolbar = new ToolBar(composite, SWT.NONE);
+        GridDataFactory.fillDefaults().grab(true, false).applyTo(toolbar);
+        final ToolItem showStaticItem = new ToolItem(toolbar, SWT.CHECK);
+        showStaticItem.setText("Show &Static");
+        showStaticItem.setToolTipText("Show Static Fields of Selected Object");
+        final ToolItem showTransientItem = new ToolItem(toolbar, SWT.CHECK);
+        showTransientItem.setText("Show &Transient");
+        showTransientItem.setToolTipText("Show Transient Fields of Selected Object");
+        final ToolItem refresh = new ToolItem(toolbar, SWT.PUSH);
+        refresh.setText("&Refresh");
+        refresh.setToolTipText("Refresh Values");
+
+        Composite tableComposite = new Composite(composite, SWT.NONE);
+        GridDataFactory.fillDefaults().grab(true, true).applyTo(tableComposite);
+
+        viewer = new TableViewer(tableComposite, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER | SWT.SINGLE | SWT.FULL_SELECTION);
+        viewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+        viewer.setContentProvider(new FieldContentProvider());
+        viewer.getTable().addKeyListener(new KeyAdapter() {
+            @Override
+            public void keyPressed(KeyEvent e) {
+                if (e.keyCode == SWT.F5)
+                    refresh();
+            }
+        });
+
+        TableColumnLayout ad = new TableColumnLayout();
+        tableComposite.setLayout(ad);
+
+        viewer.getTable().setHeaderVisible(true);
+        viewer.getTable().setLinesVisible(true);
+        viewer.setUseHashlookup(true);
+
+        TableViewerColumn nameColumn = new TableViewerColumn(viewer, SWT.LEFT);
+        nameColumn.setLabelProvider(new FieldName());
+        TableViewerColumn typeColumn = new TableViewerColumn(viewer, SWT.LEFT);
+        typeColumn.setLabelProvider(new FieldType());
+        TableViewerColumn valueColumn = new TableViewerColumn(viewer, SWT.LEFT);
+        valueColumn.setLabelProvider(new FieldValue());
+
+        typeColumn.getColumn().setText("Type");
+        typeColumn.getColumn().setWidth(20);
+        ad.setColumnData(typeColumn.getColumn(), new ColumnWeightData(10, 140));
+        nameColumn.getColumn().setText("Name");
+        nameColumn.getColumn().setWidth(20);
+        ad.setColumnData(nameColumn.getColumn(), new ColumnWeightData(10, 140));
+        valueColumn.getColumn().setText("Value");
+        valueColumn.getColumn().setWidth(20);
+        ad.setColumnData(valueColumn.getColumn(), new ColumnWeightData(90, 200));
+
+        selectionProvider.addSelectionChangedListener(this);
+
+        showStaticItem.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                showStatic = showStaticItem.getSelection();
+                refresh();
+            }
+        });
+        showTransientItem.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                showTransient = showTransientItem.getSelection();
+                refresh();
+            }
+        });
+        refresh.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                refresh();
+            }
+        });
+
+        // Bootstrap dialog.
+        refresh();
+
+        applyDialogFont(composite);
+        return composite;
+    }
+
+    static class Header {
+        String name;
+        public Header(String name) {
+            this.name = name;
+        }
+        @Override
+        public String toString() {
+            return name;
+        }
+    }
+
+    static class ComputedAttr {
+        public String name;
+        public Object object;
+        public String stringValue;
+        public ComputedAttr(String name, Object object) {
+            this(name, object, object != null ? object.toString() : "null");
+        }
+        public ComputedAttr(String name, Object object, String stringValue) {
+            this.name = name;
+            this.object = object;
+            this.stringValue = stringValue;
+        }
+        @Override
+        public String toString() {
+            return stringValue;
+        }
+    }
+
+    static class Attr {
+        Object object;
+        Field field;
+        public Attr(Object obj, Field f) {
+            this.object = obj;
+            this.field = f;
+        }
+        public Object getObject() {
+            return object;
+        }
+        public <T> T getObject(Class<T> clazz) {
+            return clazz.cast(object);
+        }
+        public Field getField() {
+            return field;
+        }
+        @Override
+        public String toString() {
+            return field.getName();
+        }
+    }
+
+    class FieldContentProvider implements ITreeContentProvider {
+        @Override
+        public Object[] getChildren(Object parentElement) {
+            return new Object[0];
+        }
+
+        @Override
+        public Object getParent(Object element) {
+            return null;
+        }
+
+        @Override
+        public boolean hasChildren(Object element) {
+            return false;
+        }
+
+        @Override
+        public Object[] getElements(Object inputElement) {
+            if (inputElement instanceof NodeProxy) {
+                NodeProxy np = (NodeProxy) inputElement;
+                INode node = np.getNode();
+                if (node == null)
+                    return new Object[0];
+                List<Object> result = new ArrayList<Object>();
+
+                if (node instanceof IG2DNode) {
+                    IG2DNode g2dnode = (IG2DNode) node;
+                    // Calculate some useful computational properties
+                    result.add(new Header("Computational IG2DNode properties"));
+                    result.add(new ComputedAttr("local bounds", g2dnode.getBoundsInLocal()));
+                    result.add(new ComputedAttr("world bounds", g2dnode.getBounds()));
+                    result.add(new ComputedAttr("local to world transform", NodeUtil.getLocalToGlobalTransform(g2dnode)));
+                }
+
+                Class<?> clazz = node.getClass();
+                while (clazz != null && clazz != Object.class) {
+                    if (showClass)
+                        result.add(clazz);
+                    Field[] fields = clazz.getDeclaredFields();
+                    for (int i = 0; i < fields.length; ++i) {
+                        Field f = fields[i];
+
+                        // Ignore transient properties, those are generally just caches.
+                        if (!showTransient && Modifier.isTransient(f.getModifiers()))
+                            continue;
+
+                        // Ignore statics, those shouldn't affect data transfer.
+                        if (!showStatic && Modifier.isStatic(f.getModifiers()))
+                            continue;
+
+                        result.add(new Attr(np, fields[i]));
+                    }
+                    clazz = clazz.getSuperclass();
+                }
+                return result.toArray();
+            }
+            return new Object[0];
+        }
+
+        @Override
+        public void dispose() {
+        }
+
+        @Override
+        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+        }
+    }
+
+    abstract class NodeLabelProvider extends ColumnLabelProvider {
+        @Override
+        public final void update(ViewerCell cell) {
+            Object elem = cell.getElement();
+            if (elem instanceof Attr) {
+                Attr attr = (Attr) elem;
+                NodeProxy np = attr.getObject(NodeProxy.class);
+                INode node = np.getNode();
+                update(cell, attr, node);
+            } else if (elem instanceof ComputedAttr) {
+                ComputedAttr attr = (ComputedAttr) elem;
+                update(cell, attr);
+            } else if (elem instanceof Header) {
+                updateHeader(cell, ((Header) elem).name);
+            } else if (elem instanceof Class<?>) {
+                Class<?> clazz = (Class<?>) elem;
+                updateHeader(cell, clazz.getSimpleName());
+            }
+        }
+
+        public abstract void update(ViewerCell cell, ComputedAttr attr);
+        public abstract void update(ViewerCell cell, Attr attr, INode node);
+        public void updateHeader(ViewerCell cell, String header) {
+            cell.setFont(resourceManager.createFont(FontDescriptor.createFrom(cell.getFont()).withStyle(SWT.BOLD|SWT.ITALIC)));
+            cell.setForeground(cell.getControl().getDisplay().getSystemColor(SWT.COLOR_INFO_FOREGROUND));
+            cell.setBackground(cell.getControl().getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
+        }
+    }
+
+    class FieldType extends NodeLabelProvider {
+        @Override
+        public void update(ViewerCell cell, ComputedAttr attr) {
+            cell.setText(attr.object != null ? attr.object.getClass().getSimpleName() : "null");
+        }
+        @Override
+        public void update(ViewerCell cell, Attr attr, INode node) {
+            Field f = attr.getField();
+            cell.setText(f.getType().getSimpleName());
+        }
+    }
+
+    class FieldName extends NodeLabelProvider {
+        @Override
+        public void update(ViewerCell cell, ComputedAttr attr) {
+            cell.setText(attr.name);
+        }
+        @Override
+        public void update(ViewerCell cell, Attr attr, INode node) {
+            Field f = attr.getField();
+            cell.setText(f.getName());
+        }
+        @Override
+        public void updateHeader(ViewerCell cell, String header) {
+            super.updateHeader(cell, header);
+            cell.setText(header);
+        }
+    }
+
+    class FieldValue extends NodeLabelProvider {
+        @Override
+        public void update(ViewerCell cell, ComputedAttr attr) {
+            cell.setText(attr.stringValue);
+        }
+        @Override
+        public void update(ViewerCell cell, Attr attr, INode node) {
+            Field f = attr.getField();
+            boolean accessible = f.isAccessible();
+            try {
+                if (!accessible)
+                    f.setAccessible(true);
+                Object value = f.get(node);
+                String label = value == null ? "null" : ValueUtils.toString(value);
+                cell.setText(label);
+
+                if (Modifier.isStatic(f.getModifiers())) {
+                    cell.setBackground((Color) resourceManager.get(staticColor));
+                } else if (Modifier.isTransient(f.getModifiers())) {
+                    cell.setBackground((Color) resourceManager.get(transientColor));
+                }
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+                cell.setText(e.getMessage());
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+                cell.setText(e.getMessage());
+            } finally {
+                if (!accessible)
+                    f.setAccessible(false);
+            }
+        }
+    }
+
+    @Override
+    public void selectionChanged(SelectionChangedEvent event) {
+        selectionChanged(event.getSelection());
+    }
+
+    public void selectionChanged(ISelection selection) {
+        //System.out.println("selection changed: " + event);
+        IStructuredSelection ss = (IStructuredSelection) selection;
+        Object obj = ss.getFirstElement();
+        if (ss.size() == 1 || (obj instanceof NodeProxy)) {
+            viewer.setInput(obj);
+        } else {
+            viewer.setInput(new Object());
+        }
+    }
+
+    public void refresh() {
+        selectionChanged(selectionProvider.getSelection());
+    }
+
+}