]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/view/ChangeInformationComposite.java
Improved Copy Visible Data usability in time series chart editor
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / view / ChangeInformationComposite.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.modeling.ui.view;
13
14 import java.util.ArrayList;
15 import java.util.Date;
16 import java.util.HashMap;
17 import java.util.HashSet;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Set;
21
22 import org.eclipse.core.runtime.Assert;
23 import org.eclipse.core.runtime.IProgressMonitor;
24 import org.eclipse.core.runtime.IStatus;
25 import org.eclipse.core.runtime.Status;
26 import org.eclipse.core.runtime.SubMonitor;
27 import org.eclipse.core.runtime.jobs.Job;
28 import org.eclipse.jface.action.IStatusLineManager;
29 import org.eclipse.jface.layout.GridDataFactory;
30 import org.eclipse.jface.resource.ColorDescriptor;
31 import org.eclipse.jface.resource.JFaceResources;
32 import org.eclipse.jface.resource.LocalResourceManager;
33 import org.eclipse.nebula.widgets.cdatetime.CDT;
34 import org.eclipse.nebula.widgets.cdatetime.CDateTime;
35 import org.eclipse.nebula.widgets.nattable.NatTable;
36 import org.eclipse.nebula.widgets.nattable.config.AbstractUiBindingConfiguration;
37 import org.eclipse.nebula.widgets.nattable.config.DefaultNatTableStyleConfiguration;
38 import org.eclipse.nebula.widgets.nattable.data.IDataProvider;
39 import org.eclipse.nebula.widgets.nattable.grid.GridRegion;
40 import org.eclipse.nebula.widgets.nattable.grid.data.DefaultBodyDataProvider;
41 import org.eclipse.nebula.widgets.nattable.grid.data.DefaultColumnHeaderDataProvider;
42 import org.eclipse.nebula.widgets.nattable.grid.data.DefaultCornerDataProvider;
43 import org.eclipse.nebula.widgets.nattable.grid.data.DefaultRowHeaderDataProvider;
44 import org.eclipse.nebula.widgets.nattable.grid.layer.ColumnHeaderLayer;
45 import org.eclipse.nebula.widgets.nattable.grid.layer.CornerLayer;
46 import org.eclipse.nebula.widgets.nattable.grid.layer.DefaultColumnHeaderDataLayer;
47 import org.eclipse.nebula.widgets.nattable.grid.layer.DefaultRowHeaderDataLayer;
48 import org.eclipse.nebula.widgets.nattable.grid.layer.GridLayer;
49 import org.eclipse.nebula.widgets.nattable.grid.layer.RowHeaderLayer;
50 import org.eclipse.nebula.widgets.nattable.layer.DataLayer;
51 import org.eclipse.nebula.widgets.nattable.layer.ILayer;
52 import org.eclipse.nebula.widgets.nattable.reorder.RowReorderLayer;
53 import org.eclipse.nebula.widgets.nattable.resize.action.AutoResizeColumnAction;
54 import org.eclipse.nebula.widgets.nattable.resize.action.ColumnResizeCursorAction;
55 import org.eclipse.nebula.widgets.nattable.resize.event.ColumnResizeEventMatcher;
56 import org.eclipse.nebula.widgets.nattable.resize.mode.ColumnResizeDragMode;
57 import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer;
58 import org.eclipse.nebula.widgets.nattable.selection.config.DefaultSelectionStyleConfiguration;
59 import org.eclipse.nebula.widgets.nattable.sort.SortHeaderLayer;
60 import org.eclipse.nebula.widgets.nattable.sort.config.SingleClickSortConfiguration;
61 import org.eclipse.nebula.widgets.nattable.style.HorizontalAlignmentEnum;
62 import org.eclipse.nebula.widgets.nattable.ui.action.ClearCursorAction;
63 import org.eclipse.nebula.widgets.nattable.ui.action.NoOpMouseAction;
64 import org.eclipse.nebula.widgets.nattable.ui.binding.UiBindingRegistry;
65 import org.eclipse.nebula.widgets.nattable.ui.matcher.MouseEventMatcher;
66 import org.eclipse.nebula.widgets.nattable.viewport.ViewportLayer;
67 import org.eclipse.swt.SWT;
68 import org.eclipse.swt.dnd.DND;
69 import org.eclipse.swt.dnd.DropTarget;
70 import org.eclipse.swt.dnd.DropTargetAdapter;
71 import org.eclipse.swt.dnd.DropTargetEvent;
72 import org.eclipse.swt.dnd.TextTransfer;
73 import org.eclipse.swt.dnd.Transfer;
74 import org.eclipse.swt.events.ModifyEvent;
75 import org.eclipse.swt.events.ModifyListener;
76 import org.eclipse.swt.events.SelectionEvent;
77 import org.eclipse.swt.events.SelectionListener;
78 import org.eclipse.swt.graphics.Color;
79 import org.eclipse.swt.graphics.RGB;
80 import org.eclipse.swt.layout.GridData;
81 import org.eclipse.swt.layout.GridLayout;
82 import org.eclipse.swt.widgets.Composite;
83 import org.eclipse.swt.widgets.Display;
84 import org.eclipse.swt.widgets.Group;
85 import org.eclipse.swt.widgets.Label;
86 import org.eclipse.swt.widgets.Text;
87 import org.eclipse.ui.IWorkbenchSite;
88 import org.simantics.DatabaseJob;
89 import org.simantics.databoard.util.URIStringUtils;
90 import org.simantics.db.ReadGraph;
91 import org.simantics.db.Resource;
92 import org.simantics.db.Session;
93 import org.simantics.db.common.ResourceArray;
94 import org.simantics.db.common.request.UniqueRead;
95 import org.simantics.db.common.utils.Logger;
96 import org.simantics.db.exception.DatabaseException;
97 import org.simantics.db.layer0.request.PossibleURI;
98 import org.simantics.db.service.SerialisationSupport;
99 import org.simantics.layer0.Layer0;
100 import org.simantics.modeling.ModelingResources;
101 import org.simantics.modeling.adapters.ChangeInformation;
102 import org.simantics.modeling.ui.Activator;
103 import org.simantics.ui.dnd.LocalObjectTransfer;
104 import org.simantics.ui.dnd.ResourceReferenceTransfer;
105 import org.simantics.ui.dnd.ResourceTransferUtils;
106 import org.simantics.ui.utils.ResourceAdaptionUtils;
107 import org.simantics.utils.ui.ErrorLogger;
108 import org.simantics.utils.ui.SWTUtils;
109 import org.simantics.utils.ui.dialogs.ShowMessage;
110 import org.simantics.utils.ui.workbench.WorkbenchUtils;
111
112
113 public class ChangeInformationComposite extends Composite {
114
115     private final LocalResourceManager                  resourceManager;
116
117     private final ColorDescriptor                       green = ColorDescriptor.createFrom(new RGB(0x57, 0xbc, 0x95));
118     
119     /**
120      * The Session used to access the graph. Received from outside of this
121      * class and therefore it is not disposed here, just used.
122      */
123     private final Session                               session;
124     
125     private   Resource                              resource;
126
127     private   List<Bean>                               allContents = new ArrayList<Bean>();
128
129     private   List<Bean>                               contents  = new ArrayList<Bean>();
130
131     protected Layer0                                    L0;
132
133     protected IWorkbenchSite                            site;
134     
135     private NatTable                                    table;
136     
137     private IDataProvider                               bodyDataProvider;
138     
139     private CDateTime                                   createdBefore; 
140     private CDateTime                                   createdAfter; 
141     private CDateTime                                   modifiedBefore; 
142     private CDateTime                                   modifiedAfter; 
143     
144     private Label dropLabel;
145     
146     private Text creatorText;
147     private Text modifierText;
148     private Text nameText;
149     private Text pathText;
150     private Text typesText;
151     
152     private BeanSortModel sortModel;
153
154     /**
155      * @param parent
156      * @param style
157      * @param session
158      * @param resource the initial resource to debug or <code>null</code> for
159      *        initially blank UI.
160      */
161     public ChangeInformationComposite(Composite parent, int style, final Session session, Resource resource, IWorkbenchSite site) {
162         super(parent, style);
163         Assert.isNotNull(session, "session is null");
164         this.session = session;
165         this.resource = resource;
166         this.resourceManager = new LocalResourceManager(JFaceResources.getResources(), parent);
167         this.site = site;
168     }
169
170     /**
171      * When given to setStatus, indicates that the message shouldn't be touched
172      * since <code>null</code> has a different meaning.
173      */
174     private static final String DONT_TOUCH = "DONT_TOUCH";
175
176     protected void setStatus(String message, String error) {
177         IStatusLineManager status = WorkbenchUtils.getStatusLine(site);
178         if (status != null) {
179             if (message != DONT_TOUCH)
180                 status.setMessage(message);
181             if (error != DONT_TOUCH)
182                 status.setErrorMessage(error);
183         }
184     }
185
186     public void defaultInitializeUI() {
187         
188         setLayout(new GridLayout(4, false));
189         setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
190
191         createDropLabel(this);
192         createContents(this);
193
194     }
195
196     public Label createDropLabel(Composite parent) {
197         dropLabel = new Label(parent, SWT.BORDER);
198         dropLabel.setAlignment(SWT.CENTER);
199         dropLabel.setText("Drag a resource here");
200         dropLabel.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));
201         GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(4, 1).grab(true, false).applyTo(dropLabel);
202
203         // Add resource id drop support to the drop-area.
204         DropTarget dropTarget = new DropTarget(dropLabel, DND.DROP_LINK | DND.DROP_COPY);
205         dropTarget.setTransfer(new Transfer[] { TextTransfer.getInstance(), ResourceReferenceTransfer.getInstance(), LocalObjectTransfer.getTransfer() });
206         dropTarget.addDropListener(new DropTargetAdapter() {
207             @Override
208             public void dragEnter(DropTargetEvent event) {
209                 event.detail = DND.DROP_LINK;
210                 dropLabel.setBackground((Color) resourceManager.get(green));
211                 return;
212             }
213             @Override
214             public void dragLeave(DropTargetEvent event) {
215                 dropLabel.setBackground(null);
216             }
217
218             @Override
219             public void drop(DropTargetEvent event) {
220                 dropLabel.setBackground(null);
221                 ResourceArray[] data = parseEventData(event);
222                 if (data == null || data.length != 1) {
223                     event.detail = DND.DROP_NONE;
224                     return;
225                 }
226                 final ResourceArray array = data[0];
227                 final Resource r = array.resources[array.resources.length - 1];
228
229                 changeLocation(r);
230             }
231
232             private ResourceArray[] parseEventData(DropTargetEvent event) {
233                 //System.out.println("DATA: " + event.data);
234                 if (event.data instanceof String) {
235                     try {
236                         SerialisationSupport support = session.getService(SerialisationSupport.class);
237                         return ResourceTransferUtils.readStringTransferable(support, (String) event.data).toResourceArrayArray();
238                     } catch (IllegalArgumentException e) {
239                         ErrorLogger.defaultLogError(e);
240                     } catch (DatabaseException e) {
241                         ErrorLogger.defaultLogError(e);
242                     }
243                 }
244                 ResourceArray[] ret = ResourceAdaptionUtils.toResourceArrays(event.data);
245                 if (ret.length > 0)
246                     return ret;
247                 return null;
248             }
249         });
250
251         return dropLabel;
252     }
253
254     public void createContents(Composite parent) {
255
256         Group fieldGroup = new Group(parent, SWT.NONE);
257         fieldGroup.setLayout(new GridLayout(2, false));
258         fieldGroup.setText("Filter modifications by text in columns");
259         GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).span(4, 1).grab(true, false).applyTo(fieldGroup);
260
261         {
262         
263                 final Label label = new Label(fieldGroup, SWT.NONE);
264                 label.setAlignment(SWT.CENTER);
265                 label.setText("Created By:");
266                 GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(false, false).applyTo(label);
267
268                 creatorText = new Text(fieldGroup, SWT.BORDER);
269                 GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(true, false).applyTo(creatorText);
270
271                 creatorText.addModifyListener(new ModifyListener() {
272
273                         @Override
274                         public void modifyText(ModifyEvent e) {
275                                 updateData(false);
276                         }
277                 });
278         
279         }
280
281         {
282                 
283                 final Label label = new Label(fieldGroup, SWT.NONE);
284                 label.setAlignment(SWT.CENTER);
285                 label.setText("Modified By:");
286                 GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(false, false).applyTo(label);
287
288                 modifierText = new Text(fieldGroup, SWT.BORDER);
289                 GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(true, false).applyTo(modifierText);
290
291                 modifierText.addModifyListener(new ModifyListener() {
292
293                         @Override
294                         public void modifyText(ModifyEvent e) {
295                                 updateData(false);
296                         }
297                 });
298         
299         }
300
301         {
302                 
303                 final Label label = new Label(fieldGroup, SWT.NONE);
304                 label.setAlignment(SWT.CENTER);
305                 label.setText("Name:");
306                 GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(false, false).applyTo(label);
307
308                 nameText = new Text(fieldGroup, SWT.BORDER);
309                 GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(true, false).applyTo(nameText);
310
311                 nameText.addModifyListener(new ModifyListener() {
312
313                         @Override
314                         public void modifyText(ModifyEvent e) {
315                                 updateData(false);
316                         }
317                 });
318         
319         }
320
321         {
322                 
323                 final Label label = new Label(fieldGroup, SWT.NONE);
324                 label.setAlignment(SWT.CENTER);
325                 label.setText("Path:");
326                 GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(false, false).applyTo(label);
327
328                 pathText = new Text(fieldGroup, SWT.BORDER);
329                 GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(true, false).applyTo(pathText);
330
331                 pathText.addModifyListener(new ModifyListener() {
332
333                         @Override
334                         public void modifyText(ModifyEvent e) {
335                                 updateData(false);
336                         }
337                 });
338         
339         }
340         
341         {
342                 
343                 final Label label = new Label(fieldGroup, SWT.NONE);
344                 label.setAlignment(SWT.CENTER);
345                 label.setText("Types:");
346                 GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(false, false).applyTo(label);
347
348                 typesText = new Text(fieldGroup, SWT.BORDER);
349                 GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(true, false).applyTo(typesText);
350
351                 typesText.addModifyListener(new ModifyListener() {
352
353                         @Override
354                         public void modifyText(ModifyEvent e) {
355                                 updateData(false);
356                         }
357                 });
358         
359         }
360
361
362         SelectionListener selectionListener = new SelectionListener() {
363                         
364                         @Override
365                         public void widgetSelected(SelectionEvent e) {
366                                 widgetDefaultSelected(e);
367                         }
368                         
369                         @Override
370                         public void widgetDefaultSelected(SelectionEvent e) {
371                                 updateData(false);
372                         }
373                 };
374         
375         Group timeGroup = new Group(parent, SWT.NONE);
376         timeGroup.setLayout(new GridLayout(2, false));
377         timeGroup.setText("Filter modifications by time");
378         GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).span(4, 1).grab(true, false).applyTo(timeGroup);
379         
380         createdAfter = new CDateTime(timeGroup, CDT.BORDER | CDT.DROP_DOWN | CDT.CLOCK_12_HOUR);
381         createdAfter.setPattern("'Created after 'd.M.yyy '@' H:mm");
382         createdAfter.setNullText("<choose created after>");
383         createdAfter.addSelectionListener(selectionListener);
384         GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(true, false).applyTo(createdAfter);
385         createdBefore = new CDateTime(timeGroup, CDT.BORDER | CDT.DROP_DOWN | CDT.CLOCK_12_HOUR);
386         createdBefore.setPattern("'Created before 'd.M.yyy '@' H:mm");
387         createdBefore.setNullText("<choose created before>");
388         createdBefore.addSelectionListener(selectionListener);
389         GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(true, false).applyTo(createdBefore);
390
391         modifiedAfter = new CDateTime(timeGroup, CDT.BORDER | CDT.DROP_DOWN | CDT.CLOCK_12_HOUR);
392         modifiedAfter.setPattern("'Modified after 'd.M.yyy '@' H:mm");
393         modifiedAfter.setNullText("<choose modified after>");
394         modifiedAfter.addSelectionListener(selectionListener);
395         GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(true, false).applyTo(modifiedAfter);
396         modifiedBefore = new CDateTime(timeGroup, CDT.BORDER | CDT.DROP_DOWN | CDT.CLOCK_12_HOUR);
397         modifiedBefore.setPattern("'Modified before 'd.M.yyy '@' H:mm");
398         modifiedBefore.setNullText("<choose modified before>");
399         modifiedBefore.addSelectionListener(selectionListener);
400         GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(1, 1).grab(true, false).applyTo(modifiedBefore);
401         
402         //property names of the Person class
403         String[] propertyNames = {"name", "path", "types", "createdBy", "createdAt", "modifiedBy", "modifiedAt"};
404         
405         //mapping from property to label, needed for column header labels
406         Map<String, String> propertyToLabelMap = new HashMap<String, String>();
407         propertyToLabelMap.put("name", "Name");
408         propertyToLabelMap.put("path", "Path");
409         propertyToLabelMap.put("types", "Types");
410         propertyToLabelMap.put("createdBy", "Created By");
411         propertyToLabelMap.put("createdAt", "Created At");
412         propertyToLabelMap.put("modifiedBy", "Last Modified By");
413         propertyToLabelMap.put("modifiedAt", "Last Modified At");
414         
415         //build the body layer stack 
416         //Usually you would create a new layer stack by extending AbstractIndexLayerTransform and
417         //setting the ViewportLayer as underlying layer. But in this case using the ViewportLayer
418         //directly as body layer is also working.
419         bodyDataProvider = new DefaultBodyDataProvider<Bean>(contents, propertyNames);
420         final DataLayer bodyDataLayer = new DataLayer(bodyDataProvider);
421         bodyDataLayer.setColumnWidthByPosition(0, 145);
422         bodyDataLayer.setColumnWidthByPosition(1, 170);
423         bodyDataLayer.setColumnWidthByPosition(2, 120);
424         bodyDataLayer.setColumnWidthByPosition(3, 85);
425         bodyDataLayer.setColumnWidthByPosition(4, 85);
426         bodyDataLayer.setColumnWidthByPosition(5, 115);
427         bodyDataLayer.setColumnWidthByPosition(6, 115);
428         
429         final RowReorderLayer rowReorderLayer = new RowReorderLayer(bodyDataLayer);
430         final SelectionLayer selectionLayer = new SelectionLayer(rowReorderLayer);
431         ViewportLayer viewportLayer = new ViewportLayer(selectionLayer);
432
433         //build the column header layer
434         IDataProvider columnHeaderDataProvider = new DefaultColumnHeaderDataProvider(propertyNames, propertyToLabelMap);
435         DataLayer columnHeaderDataLayer = new DefaultColumnHeaderDataLayer(columnHeaderDataProvider);
436         ColumnHeaderLayer columnHeaderLayer = new ColumnHeaderLayer(columnHeaderDataLayer, viewportLayer, selectionLayer);
437
438         sortModel = new BeanSortModel(allContents, contents);
439         
440         SortHeaderLayer<Bean> sortHeaderLayer = new SortHeaderLayer<Bean>(
441                         columnHeaderLayer, sortModel);
442         
443         //build the row header layer
444         IDataProvider rowHeaderDataProvider = new DefaultRowHeaderDataProvider(bodyDataProvider);
445         DataLayer rowHeaderDataLayer = new DefaultRowHeaderDataLayer(rowHeaderDataProvider);
446         rowHeaderDataLayer.setColumnWidthByPosition(0, 90);
447         
448         RowHeaderLayer rowHeaderLayer = new RowHeaderLayer(rowHeaderDataLayer, viewportLayer, selectionLayer);
449         
450         //build the corner layer
451         IDataProvider cornerDataProvider = new DefaultCornerDataProvider(columnHeaderDataProvider, rowHeaderDataProvider);
452         DataLayer cornerDataLayer = new DataLayer(cornerDataProvider);
453         ILayer cornerLayer = new CornerLayer(cornerDataLayer, rowHeaderLayer, sortHeaderLayer);
454         
455         //build the grid layer
456         GridLayer gridLayer = new GridLayer(viewportLayer, sortHeaderLayer, rowHeaderLayer, cornerLayer);
457         
458         table = new NatTable(parent, gridLayer, false);
459         
460         DefaultNatTableStyleConfiguration styleConfiguration = new DefaultNatTableStyleConfiguration();
461         styleConfiguration.hAlign = HorizontalAlignmentEnum.LEFT;
462         table.addConfiguration(styleConfiguration);
463         // Change the default sort key bindings. Note that 'auto configure' was turned off
464         table.addConfiguration(new SingleClickSortConfiguration());
465         table.addConfiguration(new DefaultSelectionStyleConfiguration());
466         
467         
468         table.addConfiguration(new AbstractUiBindingConfiguration() {
469
470                 @Override
471                 public void configureUiBindings(UiBindingRegistry uiBindingRegistry) {
472                         // Mouse move - Show resize cursor
473                         uiBindingRegistry.registerFirstMouseMoveBinding(new ColumnResizeEventMatcher(SWT.NONE,
474                                         GridRegion.ROW_HEADER, 0), new ColumnResizeCursorAction());
475                         uiBindingRegistry.registerMouseMoveBinding(new MouseEventMatcher(), new ClearCursorAction());
476
477                         // Column resize
478                         uiBindingRegistry.registerFirstMouseDragMode(new ColumnResizeEventMatcher(SWT.NONE,
479                                         GridRegion.ROW_HEADER, 1), new ColumnResizeDragMode());
480
481                         uiBindingRegistry.registerDoubleClickBinding(new ColumnResizeEventMatcher(SWT.NONE,
482                                         GridRegion.ROW_HEADER, 1), new AutoResizeColumnAction());
483                         uiBindingRegistry.registerSingleClickBinding(new ColumnResizeEventMatcher(SWT.NONE,
484                                         GridRegion.ROW_HEADER, 1), new NoOpMouseAction());
485                 }
486         });
487         
488         table.configure();
489         
490         GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(4, 1).grab(true, true).applyTo(table);
491         
492     }
493
494     public void changeLocation(Resource element) {
495         
496         resource = element;
497         
498                 try {
499                         String uri = session.syncRequest(new PossibleURI(resource));
500                         if(uri != null) {
501                                 uri = uri.replace("http://Projects/Development%20Project/", "");
502                                 uri = URIStringUtils.unescape(uri);
503                                 dropLabel.setText("Drag a resource here - searching at " + uri);
504                         }
505                 } catch (DatabaseException e) {
506                         Logger.defaultLogError(e);
507                 }
508         
509         refresh();
510         
511     }
512     
513     public void refresh() {
514
515         searchAndUpdate();
516
517     }
518
519     public void updateData(boolean sort) {
520
521         filter();
522         
523         if(sort) sortModel.sortCurrent();
524         
525         table.refresh();
526         
527         setStatus(DONT_TOUCH, null);
528
529     }
530     
531     private long getPossibleTime(CDateTime widget) {
532         Date d = widget.getSelection();
533         if(d == null) return 0;
534         else return d.getTime();
535     }
536     
537     public void filter() {
538         
539         long createdAfterTime = getPossibleTime(createdAfter);
540         long createdBeforeTime = getPossibleTime(createdBefore);
541         long modifiedAfterTime = getPossibleTime(modifiedAfter);
542         long modifiedBeforeTime = getPossibleTime(modifiedBefore);
543         
544         String creatorFilter = creatorText.getText().toLowerCase();
545         if(creatorFilter.isEmpty()) creatorFilter = null;
546         String modifierFilter = modifierText.getText().toLowerCase();
547         if(modifierFilter.isEmpty()) modifierFilter = null;
548         String[] nameFilter = null;
549         if(!nameText.getText().isEmpty()) nameFilter = nameText.getText().toLowerCase().split(" ");
550         String[] pathFilter = null;
551         if(!pathText.getText().isEmpty()) pathFilter = pathText.getText().toLowerCase().split(" ");
552         String[] typesFilter = null;
553         if(!typesText.getText().isEmpty()) typesFilter = typesText.getText().toLowerCase().split(" ");
554         
555         contents.clear();
556         for(Bean b : allContents) {
557                 
558                 if(createdAfterTime > 0 && b.createdAt < createdAfterTime) continue;
559                 if(createdBeforeTime > 0 && b.createdAt > createdBeforeTime) continue;
560                 if(modifiedAfterTime > 0 && b.modifiedAt < modifiedAfterTime) continue;
561                 if(modifiedBeforeTime > 0 && b.modifiedAt > modifiedBeforeTime) continue;
562                 
563                 if(creatorFilter != null && !b.getCreatedBy().toLowerCase().contains(creatorFilter)) continue;
564                 if(modifierFilter != null && !b.getModifiedBy().toLowerCase().contains(modifierFilter)) continue;
565                 if(nameFilter!= null) {
566                         String name = b.getName().toLowerCase();
567                         boolean ok = false;
568                         for(String t : nameFilter) {
569                         if(name.contains(t)) {
570                                 ok=true;
571                                 break;
572                         }
573                         }
574                         if(!ok) continue;
575                 }
576                 if(pathFilter!= null) {
577                         String name = b.getPath().toLowerCase();
578                         boolean ok = false;
579                         for(String t : pathFilter) {
580                         if(name.contains(t)) {
581                                 ok=true;
582                                 break;
583                         }
584                         }
585                         if(!ok) continue;
586                 }
587                 if(typesFilter != null) {
588                         String types = b.getTypes().toLowerCase();
589                         boolean ok = false;
590                         for(String t : typesFilter) {
591                         if(types.contains(t)) {
592                                 ok=true;
593                                 break;
594                         }
595                         }
596                         if(!ok) continue;
597                 }
598                 contents.add(b);
599         }
600         
601     }
602     
603     public void searchAndUpdate() {
604
605         final Display display = WorkbenchUtils.getActiveWorkbenchWindowShell().getDisplay();
606         Job job = new DatabaseJob("Processing change information") {
607                 @Override
608                 protected IStatus run(final IProgressMonitor monitor) {
609                         
610                         try {
611                                 
612                                 allContents.clear();
613                                 allContents.addAll(session.syncRequest(new UniqueRead<List<Bean>>() {
614
615                                         private void browse(ReadGraph graph, Layer0 L0, Resource r, Set<Resource> visited) throws DatabaseException {
616
617                                                 if(!visited.add(r)) return;
618
619                                                 for(Resource object : graph.getObjects(r, L0.DependsOn))
620                                                         browse(graph, L0, object, visited);
621
622                                         }
623
624                                         @Override
625                                         public List<Bean> perform(ReadGraph graph) throws DatabaseException {
626
627                                                 SubMonitor sub = SubMonitor.convert(monitor, "Readying change information", 100);
628
629                                                 sub.setTaskName("Searching for change records");
630                                                 
631                                                 ArrayList<Bean> result = new ArrayList<Bean>();
632                                                 if(resource == null) return result;
633
634                                                 HashSet<Resource> visited = new HashSet<Resource>();
635
636                                                 Layer0 L0 = Layer0.getInstance(graph);
637                                                 ModelingResources MOD = ModelingResources.getInstance(graph);
638                                                 
639                                                 browse(graph, L0, resource, visited);
640                                                 
641                                                 sub.worked(30);
642
643                                                 sub.setTaskName("Processing " + visited.size() + " change records");
644                                                 sub.setWorkRemaining(visited.size());
645
646                                                 String baseURI = graph.getPossibleURI(resource);
647                                                 
648                                                 for(Resource r : visited) {
649                                                         ChangeInformation ci = graph.getPossibleRelatedValue(r, MOD.changeInformation, ChangeInformation.BINDING);
650                                                         if(ci != null) result.add(new Bean(graph, r, ci, baseURI));
651                                                                 sub.worked(1);
652                                                 }
653                                                 
654                                                 return result;
655
656                                         }
657
658                                 }));
659                                 return Status.OK_STATUS;
660                         } catch (final DatabaseException e) {
661                                 showMessage(display, e.getMessage());
662                                 // WARNING, because we don't want the job system to pop up it's own error dialog
663                                 // which would happen if ERROR was used.
664                                 return new Status(IStatus.WARNING, Activator.PLUGIN_ID, "Errors while reading change information.", e);
665                         } finally {
666                                 monitor.done();
667                                 
668                     SWTUtils.asyncExec(display, new Runnable() {
669                         @Override
670                         public void run() {
671                                 updateData(true);
672                         }
673                     });
674
675                         }
676
677                 }
678                 
679             private void showMessage(Display display, final String message) {
680                 SWTUtils.asyncExec(display, new Runnable() {
681                     @Override
682                     public void run() {
683                         ShowMessage.showError("Problems while reading change information", message);
684                     }
685                 });
686             }
687
688         };
689         job.setUser(true);
690         job.schedule();
691     }
692
693 }