]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/view/ChangeInformationComposite.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / view / ChangeInformationComposite.java
diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/view/ChangeInformationComposite.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/view/ChangeInformationComposite.java
new file mode 100644 (file)
index 0000000..d9fab88
--- /dev/null
@@ -0,0 +1,693 @@
+/*******************************************************************************\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.modeling.ui.view;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Date;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Set;\r
+\r
+import org.eclipse.core.runtime.Assert;\r
+import org.eclipse.core.runtime.IProgressMonitor;\r
+import org.eclipse.core.runtime.IStatus;\r
+import org.eclipse.core.runtime.Status;\r
+import org.eclipse.core.runtime.SubMonitor;\r
+import org.eclipse.core.runtime.jobs.Job;\r
+import org.eclipse.jface.action.IStatusLineManager;\r
+import org.eclipse.jface.layout.GridDataFactory;\r
+import org.eclipse.jface.resource.ColorDescriptor;\r
+import org.eclipse.jface.resource.JFaceResources;\r
+import org.eclipse.jface.resource.LocalResourceManager;\r
+import org.eclipse.nebula.widgets.cdatetime.CDT;\r
+import org.eclipse.nebula.widgets.cdatetime.CDateTime;\r
+import org.eclipse.nebula.widgets.nattable.NatTable;\r
+import org.eclipse.nebula.widgets.nattable.config.AbstractUiBindingConfiguration;\r
+import org.eclipse.nebula.widgets.nattable.config.DefaultNatTableStyleConfiguration;\r
+import org.eclipse.nebula.widgets.nattable.data.IDataProvider;\r
+import org.eclipse.nebula.widgets.nattable.grid.GridRegion;\r
+import org.eclipse.nebula.widgets.nattable.grid.data.DefaultBodyDataProvider;\r
+import org.eclipse.nebula.widgets.nattable.grid.data.DefaultColumnHeaderDataProvider;\r
+import org.eclipse.nebula.widgets.nattable.grid.data.DefaultCornerDataProvider;\r
+import org.eclipse.nebula.widgets.nattable.grid.data.DefaultRowHeaderDataProvider;\r
+import org.eclipse.nebula.widgets.nattable.grid.layer.ColumnHeaderLayer;\r
+import org.eclipse.nebula.widgets.nattable.grid.layer.CornerLayer;\r
+import org.eclipse.nebula.widgets.nattable.grid.layer.DefaultColumnHeaderDataLayer;\r
+import org.eclipse.nebula.widgets.nattable.grid.layer.DefaultRowHeaderDataLayer;\r
+import org.eclipse.nebula.widgets.nattable.grid.layer.GridLayer;\r
+import org.eclipse.nebula.widgets.nattable.grid.layer.RowHeaderLayer;\r
+import org.eclipse.nebula.widgets.nattable.layer.DataLayer;\r
+import org.eclipse.nebula.widgets.nattable.layer.ILayer;\r
+import org.eclipse.nebula.widgets.nattable.reorder.RowReorderLayer;\r
+import org.eclipse.nebula.widgets.nattable.resize.action.AutoResizeColumnAction;\r
+import org.eclipse.nebula.widgets.nattable.resize.action.ColumnResizeCursorAction;\r
+import org.eclipse.nebula.widgets.nattable.resize.event.ColumnResizeEventMatcher;\r
+import org.eclipse.nebula.widgets.nattable.resize.mode.ColumnResizeDragMode;\r
+import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer;\r
+import org.eclipse.nebula.widgets.nattable.selection.config.DefaultSelectionStyleConfiguration;\r
+import org.eclipse.nebula.widgets.nattable.sort.SortHeaderLayer;\r
+import org.eclipse.nebula.widgets.nattable.sort.config.SingleClickSortConfiguration;\r
+import org.eclipse.nebula.widgets.nattable.style.HorizontalAlignmentEnum;\r
+import org.eclipse.nebula.widgets.nattable.ui.action.ClearCursorAction;\r
+import org.eclipse.nebula.widgets.nattable.ui.action.NoOpMouseAction;\r
+import org.eclipse.nebula.widgets.nattable.ui.binding.UiBindingRegistry;\r
+import org.eclipse.nebula.widgets.nattable.ui.matcher.MouseEventMatcher;\r
+import org.eclipse.nebula.widgets.nattable.viewport.ViewportLayer;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.dnd.DND;\r
+import org.eclipse.swt.dnd.DropTarget;\r
+import org.eclipse.swt.dnd.DropTargetAdapter;\r
+import org.eclipse.swt.dnd.DropTargetEvent;\r
+import org.eclipse.swt.dnd.TextTransfer;\r
+import org.eclipse.swt.dnd.Transfer;\r
+import org.eclipse.swt.events.ModifyEvent;\r
+import org.eclipse.swt.events.ModifyListener;\r
+import org.eclipse.swt.events.SelectionEvent;\r
+import org.eclipse.swt.events.SelectionListener;\r
+import org.eclipse.swt.graphics.Color;\r
+import org.eclipse.swt.graphics.RGB;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.layout.GridLayout;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Display;\r
+import org.eclipse.swt.widgets.Group;\r
+import org.eclipse.swt.widgets.Label;\r
+import org.eclipse.swt.widgets.Text;\r
+import org.eclipse.ui.IWorkbenchSite;\r
+import org.simantics.DatabaseJob;\r
+import org.simantics.databoard.util.URIStringUtils;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.common.ResourceArray;\r
+import org.simantics.db.common.request.UniqueRead;\r
+import org.simantics.db.common.utils.Logger;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.request.PossibleURI;\r
+import org.simantics.db.service.SerialisationSupport;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.modeling.ModelingResources;\r
+import org.simantics.modeling.adapters.ChangeInformation;\r
+import org.simantics.modeling.ui.Activator;\r
+import org.simantics.ui.dnd.LocalObjectTransfer;\r
+import org.simantics.ui.dnd.ResourceReferenceTransfer;\r
+import org.simantics.ui.dnd.ResourceTransferUtils;\r
+import org.simantics.ui.utils.ResourceAdaptionUtils;\r
+import org.simantics.utils.ui.ErrorLogger;\r
+import org.simantics.utils.ui.SWTUtils;\r
+import org.simantics.utils.ui.dialogs.ShowMessage;\r
+import org.simantics.utils.ui.workbench.WorkbenchUtils;\r
+\r
+\r
+public class ChangeInformationComposite extends Composite {\r
+\r
+    private final LocalResourceManager                  resourceManager;\r
+\r
+    private final ColorDescriptor                       green = ColorDescriptor.createFrom(new RGB(0x57, 0xbc, 0x95));\r
+    \r
+    /**\r
+     * The Session used to access the graph. Received from outside of this\r
+     * class and therefore it is not disposed here, just used.\r
+     */\r
+    private final Session                               session;\r
+    \r
+    private   Resource                              resource;\r
+\r
+    private   List<Bean>                               allContents = new ArrayList<Bean>();\r
+\r
+    private   List<Bean>                               contents  = new ArrayList<Bean>();\r
+\r
+    protected Layer0                                    L0;\r
+\r
+    protected IWorkbenchSite                            site;\r
+    \r
+    private NatTable                                    table;\r
+    \r
+    private IDataProvider                               bodyDataProvider;\r
+    \r
+    private CDateTime                                   createdBefore; \r
+    private CDateTime                                   createdAfter; \r
+    private CDateTime                                   modifiedBefore; \r
+    private CDateTime                                   modifiedAfter; \r
+    \r
+    private Label dropLabel;\r
+    \r
+    private Text creatorText;\r
+    private Text modifierText;\r
+    private Text nameText;\r
+    private Text pathText;\r
+    private Text typesText;\r
+    \r
+    private BeanSortModel sortModel;\r
+\r
+    /**\r
+     * @param parent\r
+     * @param style\r
+     * @param session\r
+     * @param resource the initial resource to debug or <code>null</code> for\r
+     *        initially blank UI.\r
+     */\r
+    public ChangeInformationComposite(Composite parent, int style, final Session session, Resource resource, IWorkbenchSite site) {\r
+        super(parent, style);\r
+        Assert.isNotNull(session, "session is null");\r
+        this.session = session;\r
+        this.resource = resource;\r
+        this.resourceManager = new LocalResourceManager(JFaceResources.getResources(), parent);\r
+        this.site = site;\r
+    }\r
+\r
+    /**\r
+     * When given to setStatus, indicates that the message shouldn't be touched\r
+     * since <code>null</code> has a different meaning.\r
+     */\r
+    private static final String DONT_TOUCH = "DONT_TOUCH";\r
+\r
+    protected void setStatus(String message, String error) {\r
+        IStatusLineManager status = WorkbenchUtils.getStatusLine(site);\r
+        if (status != null) {\r
+            if (message != DONT_TOUCH)\r
+                status.setMessage(message);\r
+            if (error != DONT_TOUCH)\r
+                status.setErrorMessage(error);\r
+        }\r
+    }\r
+\r
+    public void defaultInitializeUI() {\r
+       \r
+        setLayout(new GridLayout(4, false));\r
+        setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));\r
+\r
+        createDropLabel(this);\r
+        createContents(this);\r
+\r
+    }\r
+\r
+    public Label createDropLabel(Composite parent) {\r
+        dropLabel = new Label(parent, SWT.BORDER);\r
+        dropLabel.setAlignment(SWT.CENTER);\r
+        dropLabel.setText("Drag a resource here");\r
+        dropLabel.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));\r
+        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(4, 1).grab(true, false).applyTo(dropLabel);\r
+\r
+        // Add resource id drop support to the drop-area.\r
+        DropTarget dropTarget = new DropTarget(dropLabel, DND.DROP_LINK | DND.DROP_COPY);\r
+        dropTarget.setTransfer(new Transfer[] { TextTransfer.getInstance(), ResourceReferenceTransfer.getInstance(), LocalObjectTransfer.getTransfer() });\r
+        dropTarget.addDropListener(new DropTargetAdapter() {\r
+            @Override\r
+            public void dragEnter(DropTargetEvent event) {\r
+                event.detail = DND.DROP_LINK;\r
+                dropLabel.setBackground((Color) resourceManager.get(green));\r
+                return;\r
+            }\r
+            @Override\r
+            public void dragLeave(DropTargetEvent event) {\r
+                dropLabel.setBackground(null);\r
+            }\r
+\r
+            @Override\r
+            public void drop(DropTargetEvent event) {\r
+                dropLabel.setBackground(null);\r
+                ResourceArray[] data = parseEventData(event);\r
+                if (data == null || data.length != 1) {\r
+                    event.detail = DND.DROP_NONE;\r
+                    return;\r
+                }\r
+                final ResourceArray array = data[0];\r
+                final Resource r = array.resources[array.resources.length - 1];\r
+\r
+                changeLocation(r);\r
+            }\r
+\r
+            private ResourceArray[] parseEventData(DropTargetEvent event) {\r
+                //System.out.println("DATA: " + event.data);\r
+                if (event.data instanceof String) {\r
+                    try {\r
+                        SerialisationSupport support = session.getService(SerialisationSupport.class);\r
+                        return ResourceTransferUtils.readStringTransferable(support, (String) event.data).toResourceArrayArray();\r
+                    } catch (IllegalArgumentException e) {\r
+                        ErrorLogger.defaultLogError(e);\r
+                    } catch (DatabaseException e) {\r
+                        ErrorLogger.defaultLogError(e);\r
+                    }\r
+                }\r
+                ResourceArray[] ret = ResourceAdaptionUtils.toResourceArrays(event.data);\r
+                if (ret.length > 0)\r
+                    return ret;\r
+                return null;\r
+            }\r
+        });\r
+\r
+        return dropLabel;\r
+    }\r
+\r
+    public void createContents(Composite parent) {\r
+\r
+       Group fieldGroup = new Group(parent, SWT.NONE);\r
+       fieldGroup.setLayout(new GridLayout(2, false));\r
+       fieldGroup.setText("Filter modifications by text in columns");\r
+        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).span(4, 1).grab(true, false).applyTo(fieldGroup);\r
+\r
+       {\r
+       \r
+               final Label label = new Label(fieldGroup, SWT.NONE);\r
+               label.setAlignment(SWT.CENTER);\r
+               label.setText("Created By:");\r
+               GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(false, false).applyTo(label);\r
+\r
+               creatorText = new Text(fieldGroup, SWT.BORDER);\r
+               GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(true, false).applyTo(creatorText);\r
+\r
+               creatorText.addModifyListener(new ModifyListener() {\r
+\r
+                       @Override\r
+                       public void modifyText(ModifyEvent e) {\r
+                               updateData(false);\r
+                       }\r
+               });\r
+        \r
+       }\r
+\r
+       {\r
+               \r
+               final Label label = new Label(fieldGroup, SWT.NONE);\r
+               label.setAlignment(SWT.CENTER);\r
+               label.setText("Modified By:");\r
+               GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(false, false).applyTo(label);\r
+\r
+               modifierText = new Text(fieldGroup, SWT.BORDER);\r
+               GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(true, false).applyTo(modifierText);\r
+\r
+               modifierText.addModifyListener(new ModifyListener() {\r
+\r
+                       @Override\r
+                       public void modifyText(ModifyEvent e) {\r
+                               updateData(false);\r
+                       }\r
+               });\r
+        \r
+       }\r
+\r
+       {\r
+               \r
+               final Label label = new Label(fieldGroup, SWT.NONE);\r
+               label.setAlignment(SWT.CENTER);\r
+               label.setText("Name:");\r
+               GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(false, false).applyTo(label);\r
+\r
+               nameText = new Text(fieldGroup, SWT.BORDER);\r
+               GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(true, false).applyTo(nameText);\r
+\r
+               nameText.addModifyListener(new ModifyListener() {\r
+\r
+                       @Override\r
+                       public void modifyText(ModifyEvent e) {\r
+                               updateData(false);\r
+                       }\r
+               });\r
+        \r
+       }\r
+\r
+       {\r
+               \r
+               final Label label = new Label(fieldGroup, SWT.NONE);\r
+               label.setAlignment(SWT.CENTER);\r
+               label.setText("Path:");\r
+               GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(false, false).applyTo(label);\r
+\r
+               pathText = new Text(fieldGroup, SWT.BORDER);\r
+               GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(true, false).applyTo(pathText);\r
+\r
+               pathText.addModifyListener(new ModifyListener() {\r
+\r
+                       @Override\r
+                       public void modifyText(ModifyEvent e) {\r
+                               updateData(false);\r
+                       }\r
+               });\r
+        \r
+       }\r
+       \r
+       {\r
+               \r
+               final Label label = new Label(fieldGroup, SWT.NONE);\r
+               label.setAlignment(SWT.CENTER);\r
+               label.setText("Types:");\r
+               GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(false, false).applyTo(label);\r
+\r
+               typesText = new Text(fieldGroup, SWT.BORDER);\r
+               GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(true, false).applyTo(typesText);\r
+\r
+               typesText.addModifyListener(new ModifyListener() {\r
+\r
+                       @Override\r
+                       public void modifyText(ModifyEvent e) {\r
+                               updateData(false);\r
+                       }\r
+               });\r
+        \r
+       }\r
+\r
+\r
+       SelectionListener selectionListener = new SelectionListener() {\r
+                       \r
+                       @Override\r
+                       public void widgetSelected(SelectionEvent e) {\r
+                               widgetDefaultSelected(e);\r
+                       }\r
+                       \r
+                       @Override\r
+                       public void widgetDefaultSelected(SelectionEvent e) {\r
+                               updateData(false);\r
+                       }\r
+               };\r
+       \r
+       Group timeGroup = new Group(parent, SWT.NONE);\r
+        timeGroup.setLayout(new GridLayout(2, false));\r
+       timeGroup.setText("Filter modifications by time");\r
+        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).span(4, 1).grab(true, false).applyTo(timeGroup);\r
+       \r
+        createdAfter = new CDateTime(timeGroup, CDT.BORDER | CDT.DROP_DOWN | CDT.CLOCK_12_HOUR);\r
+        createdAfter.setPattern("'Created after 'd.M.yyy '@' H:mm");\r
+        createdAfter.setNullText("<choose created after>");\r
+        createdAfter.addSelectionListener(selectionListener);\r
+        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(true, false).applyTo(createdAfter);\r
+        createdBefore = new CDateTime(timeGroup, CDT.BORDER | CDT.DROP_DOWN | CDT.CLOCK_12_HOUR);\r
+        createdBefore.setPattern("'Created before 'd.M.yyy '@' H:mm");\r
+        createdBefore.setNullText("<choose created before>");\r
+        createdBefore.addSelectionListener(selectionListener);\r
+        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(true, false).applyTo(createdBefore);\r
+\r
+        modifiedAfter = new CDateTime(timeGroup, CDT.BORDER | CDT.DROP_DOWN | CDT.CLOCK_12_HOUR);\r
+        modifiedAfter.setPattern("'Modified after 'd.M.yyy '@' H:mm");\r
+        modifiedAfter.setNullText("<choose modified after>");\r
+        modifiedAfter.addSelectionListener(selectionListener);\r
+        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(true, false).applyTo(modifiedAfter);\r
+        modifiedBefore = new CDateTime(timeGroup, CDT.BORDER | CDT.DROP_DOWN | CDT.CLOCK_12_HOUR);\r
+        modifiedBefore.setPattern("'Modified before 'd.M.yyy '@' H:mm");\r
+        modifiedBefore.setNullText("<choose modified before>");\r
+        modifiedBefore.addSelectionListener(selectionListener);\r
+        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(true, false).applyTo(modifiedBefore);\r
+        \r
+        //property names of the Person class\r
+        String[] propertyNames = {"name", "path", "types", "createdBy", "createdAt", "modifiedBy", "modifiedAt"};\r
+        \r
+        //mapping from property to label, needed for column header labels\r
+        Map<String, String> propertyToLabelMap = new HashMap<String, String>();\r
+        propertyToLabelMap.put("name", "Name");\r
+        propertyToLabelMap.put("path", "Path");\r
+        propertyToLabelMap.put("types", "Types");\r
+        propertyToLabelMap.put("createdBy", "Created By");\r
+        propertyToLabelMap.put("createdAt", "Created At");\r
+        propertyToLabelMap.put("modifiedBy", "Last Modified By");\r
+        propertyToLabelMap.put("modifiedAt", "Last Modified At");\r
+        \r
+        //build the body layer stack \r
+        //Usually you would create a new layer stack by extending AbstractIndexLayerTransform and\r
+        //setting the ViewportLayer as underlying layer. But in this case using the ViewportLayer\r
+        //directly as body layer is also working.\r
+        bodyDataProvider = new DefaultBodyDataProvider<Bean>(contents, propertyNames);\r
+        final DataLayer bodyDataLayer = new DataLayer(bodyDataProvider);\r
+        bodyDataLayer.setColumnWidthByPosition(0, 145);\r
+        bodyDataLayer.setColumnWidthByPosition(1, 170);\r
+        bodyDataLayer.setColumnWidthByPosition(2, 120);\r
+        bodyDataLayer.setColumnWidthByPosition(3, 85);\r
+        bodyDataLayer.setColumnWidthByPosition(4, 85);\r
+        bodyDataLayer.setColumnWidthByPosition(5, 115);\r
+        bodyDataLayer.setColumnWidthByPosition(6, 115);\r
+        \r
+        final RowReorderLayer rowReorderLayer = new RowReorderLayer(bodyDataLayer);\r
+        final SelectionLayer selectionLayer = new SelectionLayer(rowReorderLayer);\r
+        ViewportLayer viewportLayer = new ViewportLayer(selectionLayer);\r
+\r
+        //build the column header layer\r
+        IDataProvider columnHeaderDataProvider = new DefaultColumnHeaderDataProvider(propertyNames, propertyToLabelMap);\r
+        DataLayer columnHeaderDataLayer = new DefaultColumnHeaderDataLayer(columnHeaderDataProvider);\r
+        ColumnHeaderLayer columnHeaderLayer = new ColumnHeaderLayer(columnHeaderDataLayer, viewportLayer, selectionLayer);\r
+\r
+        sortModel = new BeanSortModel(allContents, contents);\r
+        \r
+        SortHeaderLayer<Bean> sortHeaderLayer = new SortHeaderLayer<Bean>(\r
+                       columnHeaderLayer, sortModel);\r
+        \r
+        //build the row header layer\r
+        IDataProvider rowHeaderDataProvider = new DefaultRowHeaderDataProvider(bodyDataProvider);\r
+        DataLayer rowHeaderDataLayer = new DefaultRowHeaderDataLayer(rowHeaderDataProvider);\r
+        rowHeaderDataLayer.setColumnWidthByPosition(0, 90);\r
+        \r
+        RowHeaderLayer rowHeaderLayer = new RowHeaderLayer(rowHeaderDataLayer, viewportLayer, selectionLayer);\r
+        \r
+        //build the corner layer\r
+        IDataProvider cornerDataProvider = new DefaultCornerDataProvider(columnHeaderDataProvider, rowHeaderDataProvider);\r
+        DataLayer cornerDataLayer = new DataLayer(cornerDataProvider);\r
+        ILayer cornerLayer = new CornerLayer(cornerDataLayer, rowHeaderLayer, sortHeaderLayer);\r
+        \r
+        //build the grid layer\r
+        GridLayer gridLayer = new GridLayer(viewportLayer, sortHeaderLayer, rowHeaderLayer, cornerLayer);\r
+        \r
+        table = new NatTable(parent, gridLayer, false);\r
+        \r
+        DefaultNatTableStyleConfiguration styleConfiguration = new DefaultNatTableStyleConfiguration();\r
+        styleConfiguration.hAlign = HorizontalAlignmentEnum.LEFT;\r
+        table.addConfiguration(styleConfiguration);\r
+        // Change the default sort key bindings. Note that 'auto configure' was turned off\r
+        table.addConfiguration(new SingleClickSortConfiguration());\r
+        table.addConfiguration(new DefaultSelectionStyleConfiguration());\r
+        \r
+        \r
+        table.addConfiguration(new AbstractUiBindingConfiguration() {\r
+\r
+               @Override\r
+               public void configureUiBindings(UiBindingRegistry uiBindingRegistry) {\r
+                       // Mouse move - Show resize cursor\r
+                       uiBindingRegistry.registerFirstMouseMoveBinding(new ColumnResizeEventMatcher(SWT.NONE,\r
+                                       GridRegion.ROW_HEADER, 0), new ColumnResizeCursorAction());\r
+                       uiBindingRegistry.registerMouseMoveBinding(new MouseEventMatcher(), new ClearCursorAction());\r
+\r
+                       // Column resize\r
+                       uiBindingRegistry.registerFirstMouseDragMode(new ColumnResizeEventMatcher(SWT.NONE,\r
+                                       GridRegion.ROW_HEADER, 1), new ColumnResizeDragMode());\r
+\r
+                       uiBindingRegistry.registerDoubleClickBinding(new ColumnResizeEventMatcher(SWT.NONE,\r
+                                       GridRegion.ROW_HEADER, 1), new AutoResizeColumnAction());\r
+                       uiBindingRegistry.registerSingleClickBinding(new ColumnResizeEventMatcher(SWT.NONE,\r
+                                       GridRegion.ROW_HEADER, 1), new NoOpMouseAction());\r
+               }\r
+        });\r
+        \r
+        table.configure();\r
+        \r
+        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(4, 1).grab(true, true).applyTo(table);\r
+        \r
+    }\r
+\r
+    public void changeLocation(Resource element) {\r
+       \r
+        resource = element;\r
+        \r
+               try {\r
+                       String uri = session.syncRequest(new PossibleURI(resource));\r
+                       if(uri != null) {\r
+                               uri = uri.replace("http://Projects/Development%20Project/", "");\r
+                               uri = URIStringUtils.unescape(uri);\r
+                               dropLabel.setText("Drag a resource here - searching at " + uri);\r
+                       }\r
+               } catch (DatabaseException e) {\r
+                       Logger.defaultLogError(e);\r
+               }\r
+        \r
+        refresh();\r
+        \r
+    }\r
+    \r
+    public void refresh() {\r
+\r
+        searchAndUpdate();\r
+\r
+    }\r
+\r
+    public void updateData(boolean sort) {\r
+\r
+        filter();\r
+        \r
+       if(sort) sortModel.sortCurrent();\r
+        \r
+        table.refresh();\r
+        \r
+        setStatus(DONT_TOUCH, null);\r
+\r
+    }\r
+    \r
+    private long getPossibleTime(CDateTime widget) {\r
+       Date d = widget.getSelection();\r
+       if(d == null) return 0;\r
+       else return d.getTime();\r
+    }\r
+    \r
+    public void filter() {\r
+       \r
+       long createdAfterTime = getPossibleTime(createdAfter);\r
+       long createdBeforeTime = getPossibleTime(createdBefore);\r
+       long modifiedAfterTime = getPossibleTime(modifiedAfter);\r
+       long modifiedBeforeTime = getPossibleTime(modifiedBefore);\r
+       \r
+       String creatorFilter = creatorText.getText().toLowerCase();\r
+       if(creatorFilter.isEmpty()) creatorFilter = null;\r
+       String modifierFilter = modifierText.getText().toLowerCase();\r
+       if(modifierFilter.isEmpty()) modifierFilter = null;\r
+       String[] nameFilter = null;\r
+       if(!nameText.getText().isEmpty()) nameFilter = nameText.getText().toLowerCase().split(" ");\r
+       String[] pathFilter = null;\r
+       if(!pathText.getText().isEmpty()) pathFilter = pathText.getText().toLowerCase().split(" ");\r
+       String[] typesFilter = null;\r
+       if(!typesText.getText().isEmpty()) typesFilter = typesText.getText().toLowerCase().split(" ");\r
+       \r
+       contents.clear();\r
+       for(Bean b : allContents) {\r
+               \r
+               if(createdAfterTime > 0 && b.createdAt < createdAfterTime) continue;\r
+               if(createdBeforeTime > 0 && b.createdAt > createdBeforeTime) continue;\r
+               if(modifiedAfterTime > 0 && b.modifiedAt < modifiedAfterTime) continue;\r
+               if(modifiedBeforeTime > 0 && b.modifiedAt > modifiedBeforeTime) continue;\r
+               \r
+               if(creatorFilter != null && !b.getCreatedBy().toLowerCase().contains(creatorFilter)) continue;\r
+               if(modifierFilter != null && !b.getModifiedBy().toLowerCase().contains(modifierFilter)) continue;\r
+               if(nameFilter!= null) {\r
+                       String name = b.getName().toLowerCase();\r
+                       boolean ok = false;\r
+                       for(String t : nameFilter) {\r
+                       if(name.contains(t)) {\r
+                               ok=true;\r
+                               break;\r
+                       }\r
+                       }\r
+                       if(!ok) continue;\r
+               }\r
+               if(pathFilter!= null) {\r
+                       String name = b.getPath().toLowerCase();\r
+                       boolean ok = false;\r
+                       for(String t : pathFilter) {\r
+                       if(name.contains(t)) {\r
+                               ok=true;\r
+                               break;\r
+                       }\r
+                       }\r
+                       if(!ok) continue;\r
+               }\r
+               if(typesFilter != null) {\r
+                       String types = b.getTypes().toLowerCase();\r
+                       boolean ok = false;\r
+                       for(String t : typesFilter) {\r
+                       if(types.contains(t)) {\r
+                               ok=true;\r
+                               break;\r
+                       }\r
+                       }\r
+                       if(!ok) continue;\r
+               }\r
+               contents.add(b);\r
+       }\r
+       \r
+    }\r
+    \r
+    public void searchAndUpdate() {\r
+\r
+       final Display display = WorkbenchUtils.getActiveWorkbenchWindowShell().getDisplay();\r
+       Job job = new DatabaseJob("Processing change information") {\r
+               @Override\r
+               protected IStatus run(final IProgressMonitor monitor) {\r
+                       \r
+                       try {\r
+                               \r
+                               allContents.clear();\r
+                               allContents.addAll(session.syncRequest(new UniqueRead<List<Bean>>() {\r
+\r
+                                       private void browse(ReadGraph graph, Layer0 L0, Resource r, Set<Resource> visited) throws DatabaseException {\r
+\r
+                                               if(!visited.add(r)) return;\r
+\r
+                                               for(Resource object : graph.getObjects(r, L0.DependsOn))\r
+                                                       browse(graph, L0, object, visited);\r
+\r
+                                       }\r
+\r
+                                       @Override\r
+                                       public List<Bean> perform(ReadGraph graph) throws DatabaseException {\r
+\r
+                                               SubMonitor sub = SubMonitor.convert(monitor, "Readying change information", 100);\r
+\r
+                                               sub.setTaskName("Searching for change records");\r
+                                               \r
+                                               ArrayList<Bean> result = new ArrayList<Bean>();\r
+                                               if(resource == null) return result;\r
+\r
+                                               HashSet<Resource> visited = new HashSet<Resource>();\r
+\r
+                                               Layer0 L0 = Layer0.getInstance(graph);\r
+                                               ModelingResources MOD = ModelingResources.getInstance(graph);\r
+                                               \r
+                                               browse(graph, L0, resource, visited);\r
+                                               \r
+                                               sub.worked(30);\r
+\r
+                                               sub.setTaskName("Processing " + visited.size() + " change records");\r
+                                               sub.setWorkRemaining(visited.size());\r
+\r
+                                               String baseURI = graph.getPossibleURI(resource);\r
+                                               \r
+                                               for(Resource r : visited) {\r
+                                                       ChangeInformation ci = graph.getPossibleRelatedValue(r, MOD.changeInformation, ChangeInformation.BINDING);\r
+                                                       if(ci != null) result.add(new Bean(graph, r, ci, baseURI));\r
+                                                               sub.worked(1);\r
+                                               }\r
+                                               \r
+                                               return result;\r
+\r
+                                       }\r
+\r
+                               }));\r
+                               return Status.OK_STATUS;\r
+                       } catch (final DatabaseException e) {\r
+                               showMessage(display, e.getMessage());\r
+                               // WARNING, because we don't want the job system to pop up it's own error dialog\r
+                               // which would happen if ERROR was used.\r
+                               return new Status(IStatus.WARNING, Activator.PLUGIN_ID, "Errors while reading change information.", e);\r
+                       } finally {\r
+                               monitor.done();\r
+                               \r
+                    SWTUtils.asyncExec(display, new Runnable() {\r
+                        @Override\r
+                        public void run() {\r
+                               updateData(true);\r
+                        }\r
+                    });\r
+\r
+                       }\r
+\r
+               }\r
+               \r
+            private void showMessage(Display display, final String message) {\r
+                SWTUtils.asyncExec(display, new Runnable() {\r
+                    @Override\r
+                    public void run() {\r
+                       ShowMessage.showError("Problems while reading change information", message);\r
+                    }\r
+                });\r
+            }\r
+\r
+       };\r
+       job.setUser(true);\r
+       job.schedule();\r
+    }\r
+\r
+}\r