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