/******************************************************************************* * 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 allContents = new ArrayList(); private List contents = new ArrayList(); 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 null 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 null 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(""); 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(""); 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(""); 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(""); 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 propertyToLabelMap = new HashMap(); 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(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 sortHeaderLayer = new SortHeaderLayer( 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>() { private void browse(ReadGraph graph, Layer0 L0, Resource r, Set visited) throws DatabaseException { if(!visited.add(r)) return; for(Resource object : graph.getObjects(r, L0.DependsOn)) browse(graph, L0, object, visited); } @Override public List perform(ReadGraph graph) throws DatabaseException { SubMonitor sub = SubMonitor.convert(monitor, "Readying change information", 100); sub.setTaskName("Searching for change records"); ArrayList result = new ArrayList(); if(resource == null) return result; HashSet visited = new HashSet(); 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(); } }