]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.debug.ui/src/org/simantics/debug/ui/SearchResourceDialog.java
Filter also history items in resource search dialog
[simantics/platform.git] / bundles / org.simantics.debug.ui / src / org / simantics / debug / ui / SearchResourceDialog.java
index 8c88468e4ef424e7b956eb680968543e27c2025e..29cfd63bd45d9786bed42ad25a04b9e0cdc670a7 100644 (file)
-/*******************************************************************************\r
- * Copyright (c) 2007, 2013 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
- *     Semantum Oy - index based searching and graph manipulation (#4255)\r
- *******************************************************************************/\r
-package org.simantics.debug.ui;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Collection;\r
-import java.util.Collections;\r
-import java.util.Comparator;\r
-import java.util.HashSet;\r
-import java.util.Map;\r
-import java.util.Set;\r
-import java.util.TreeSet;\r
-import java.util.regex.Matcher;\r
-import java.util.regex.Pattern;\r
-\r
-import org.eclipse.core.runtime.CoreException;\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.jface.dialogs.IDialogSettings;\r
-import org.eclipse.jface.resource.JFaceResources;\r
-import org.eclipse.jface.resource.LocalResourceManager;\r
-import org.eclipse.jface.resource.ResourceManager;\r
-import org.eclipse.jface.viewers.IStructuredSelection;\r
-import org.eclipse.jface.viewers.LabelProvider;\r
-import org.eclipse.swt.events.DisposeEvent;\r
-import org.eclipse.swt.events.DisposeListener;\r
-import org.eclipse.swt.graphics.Image;\r
-import org.eclipse.swt.widgets.Composite;\r
-import org.eclipse.swt.widgets.Control;\r
-import org.eclipse.swt.widgets.Display;\r
-import org.eclipse.swt.widgets.Shell;\r
-import org.eclipse.ui.IMemento;\r
-import org.eclipse.ui.dialogs.FilteredItemsSelectionDialog;\r
-import org.simantics.Simantics;\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.Session;\r
-import org.simantics.db.common.primitiverequest.Adapter;\r
-import org.simantics.db.common.procedure.adapter.TransientCacheListener;\r
-import org.simantics.db.common.request.BinaryRead;\r
-import org.simantics.db.common.request.ObjectsWithType;\r
-import org.simantics.db.common.request.ReadRequest;\r
-import org.simantics.db.common.uri.UnescapedChildMapOfResource;\r
-import org.simantics.db.common.utils.NameUtils;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.layer0.migration.OntologiesFromLibrary;\r
-import org.simantics.db.layer0.variable.Variables.Role;\r
-import org.simantics.db.request.Read;\r
-import org.simantics.db.service.SerialisationSupport;\r
-import org.simantics.debug.ui.ResourceSearch.IResourceFilter;\r
-import org.simantics.debug.ui.internal.Activator;\r
-import org.simantics.debug.ui.internal.DebugUtils;\r
-import org.simantics.layer0.Layer0;\r
-import org.simantics.operation.Layer0X;\r
-import org.simantics.scl.runtime.function.Function;\r
-import org.simantics.ui.SimanticsUI;\r
-import org.simantics.ui.workbench.dialogs.ResourceLabelProvider;\r
-import org.simantics.utils.Container;\r
-import org.simantics.utils.ui.BundleUtils;\r
-\r
-/**\r
- * TODO Add Debugger Composite as preview!\r
- */\r
-public class SearchResourceDialog extends FilteredItemsSelectionDialog {\r
-\r
-    private static final String SEARCH_RESOURCE_DIALOG = "SearchResourceDialog"; //$NON-NLS-1$\r
-\r
-    Session session;\r
-    IStructuredSelection selection;\r
-    ResourceManager resourceManager;\r
-\r
-    // Needed in a subclass\r
-    protected IResourceFilter resourceFilter = ResourceSearch.FILTER_ALL;\r
-\r
-    LabelProvider detailsLabelProvider = new LabelProvider() {\r
-        @Override\r
-        public String getText(Object element) {\r
-            if (element == null)\r
-                return "null";\r
-            // This may happen if multiple choice is enabled\r
-            if (element instanceof String)\r
-                return (String) element;\r
-            @SuppressWarnings("unchecked")\r
-            Container<Resource> rc = (Container<Resource>) element;\r
-            final Resource r = rc.get();\r
-            try {\r
-                return session.syncRequest(new Read<String>() {\r
-                    @Override\r
-                    public String perform(ReadGraph g) throws DatabaseException {\r
-                        String name = NameUtils.getSafeName(g, r);\r
-                        String uri = g.getPossibleURI(r);\r
-                        String label = "[" + r.getResourceId() + "] - " + name;\r
-                        if (uri != null)\r
-                            label = label + " - " + uri;\r
-                        return label;\r
-                    }\r
-                });\r
-            } catch (DatabaseException e) {\r
-                Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Resource label provider failed unexpectedly.", e));\r
-                return "";\r
-            }\r
-        }\r
-    };\r
-\r
-    static class ElementLabelProvider extends ResourceLabelProvider {\r
-        public ElementLabelProvider(Display display) {\r
-            super(display);\r
-        }\r
-        @Override\r
-        public String getText(Object element) {\r
-            if (element==null)\r
-                return "null";\r
-            return element.toString();\r
-        }\r
-        @Override\r
-        public Image getImage(Object element) {\r
-            if (element == null)\r
-                return null;\r
-            @SuppressWarnings("unchecked")\r
-            Container<Resource> rc = (Container<Resource>) element;\r
-            final Resource r = rc.get();\r
-            return super.getImage(r);\r
-        }\r
-    };\r
-\r
-    ElementLabelProvider labelProvider;\r
-\r
-    public SearchResourceDialog(Session s, boolean multi, Shell shell, String title) {\r
-        this(s, multi, shell, title, null);\r
-    }\r
-\r
-    public SearchResourceDialog(Session s, boolean multi, Shell shell, String title, IStructuredSelection selection) {\r
-        super(shell, multi);\r
-        this.session = s;\r
-        resourceManager = new LocalResourceManager(JFaceResources.getResources());\r
-        this.labelProvider = new ElementLabelProvider(shell.getDisplay());\r
-        setMessage("Enter ID, URI or name");\r
-        setListLabelProvider(labelProvider);\r
-        setDetailsLabelProvider(detailsLabelProvider);\r
-        setImage((Image) resourceManager.get(BundleUtils.getImageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/cog_blue.png")));\r
-        setTitle(title);\r
-        //setInitialPattern("*", FilteredItemsSelectionDialog.FULL_SELECTION);\r
-        setSelectionHistory(new ResourceSelectionHistory());\r
-        this.selection = selection;\r
-        setSeparatorLabel("Previously selected above, others below");\r
-    }\r
-\r
-    @Override\r
-    protected void configureShell(Shell shell) {\r
-        super.configureShell(shell);\r
-        shell.addDisposeListener(new DisposeListener() {\r
-            @Override\r
-            public void widgetDisposed(DisposeEvent e) {\r
-                resourceManager.dispose();\r
-            }\r
-        });\r
-    }\r
-\r
-    class ResourceSelectionHistory extends FilteredItemsSelectionDialog.SelectionHistory {\r
-\r
-        @Override\r
-        protected Object restoreItemFromMemento(IMemento memento) {\r
-            String dada = memento.getTextData();\r
-            try {\r
-                SerialisationSupport support = SimanticsUI.getSession().getService(SerialisationSupport.class);\r
-                final Resource r = support.getResource(Long.parseLong(dada));\r
-                if (r == null) {\r
-                    return null;\r
-                }\r
-\r
-                String name = session.syncRequest(new Read<String>() {\r
-                    @Override\r
-                    public String perform(ReadGraph g) throws DatabaseException {\r
-                        if (!resourceFilter.acceptResource(g, r)) {\r
-                            return null;\r
-                        }\r
-                        String name = null;\r
-                        try {\r
-                            try {\r
-                                name = g.adapt(r, String.class);\r
-                            } catch (Exception ex) {\r
-                                System.out.println("Exception thrown from restoreItemFromMemento");\r
-                            }\r
-                            if (name != null) {\r
-                                return name;\r
-                            }\r
-                        } catch (Throwable t) {}\r
-                        return "" + r.getResourceId();\r
-                    }\r
-                });\r
-                if (name==null) return null;\r
-                return new LabeledResource(name, r);\r
-            } catch (NumberFormatException e) {\r
-                e.printStackTrace();\r
-                return null;\r
-            } catch (DatabaseException e) {\r
-                e.printStackTrace();\r
-                return null;\r
-            }\r
-        }\r
-\r
-        @SuppressWarnings("unchecked")\r
-        @Override\r
-        protected void storeItemToMemento(Object item, IMemento memento) {\r
-            if(item instanceof Container) {\r
-                try {\r
-                    SerialisationSupport support = SimanticsUI.getSession().getService(SerialisationSupport.class);\r
-                    memento.putTextData(String.valueOf(support.getRandomAccessId(((Container<Resource>)item).get())));\r
-                } catch (DatabaseException e) {\r
-                    e.printStackTrace();\r
-                }\r
-            }\r
-        }\r
-    };\r
-\r
-    @Override\r
-    protected Control createExtendedContentArea(Composite parent) {\r
-        return null;\r
-    }\r
-\r
-    @Override\r
-    protected ItemsFilter createFilter() {\r
-        // NOTE: filter must be created here.\r
-        return new ItemsFilter() {\r
-            @Override\r
-            public boolean matchItem(Object item) {\r
-                //return matches(item.toString());\r
-                return true;\r
-            }\r
-\r
-            // If this method returns true, it means fillContentProvider will\r
-            // not be called again, but the existing results are just re-filtered.\r
-            @Override\r
-            public boolean isSubFilter(ItemsFilter filter) {\r
-                //System.out.println(getPattern() + " vs. " + filter.getPattern());\r
-                return false;\r
-            }\r
-\r
-            @Override\r
-            public boolean isConsistentItem(Object item) {\r
-                return true;\r
-            }\r
-\r
-            @Override\r
-            public boolean equalsFilter(ItemsFilter filter) {\r
-                return false;\r
-            }\r
-        };\r
-    }\r
-\r
-    @Override\r
-    protected void fillContentProvider(final AbstractContentProvider contentProvider,\r
-            final ItemsFilter itemsFilter, final IProgressMonitor progressMonitor)\r
-                    throws CoreException {\r
-        final String pattern = itemsFilter.getPattern();\r
-        final boolean findUris = pattern.trim().startsWith("http:/");\r
-        final long referencedResourceId = referencedResourceId(pattern);\r
-        final boolean findIds = referencedResourceId != 0;\r
-\r
-        progressMonitor.beginTask("Searching", IProgressMonitor.UNKNOWN);\r
-\r
-        try {\r
-            session.syncRequest(new ReadRequest() {\r
-                @Override\r
-                public void run(ReadGraph graph) throws DatabaseException {\r
-                    // Find by ID first.\r
-                    if (findIds) {\r
-                        try {\r
-                            Resource r = graph.getService(SerialisationSupport.class).getResource(referencedResourceId);\r
-                            contentProvider.add(new LabeledResource(DebugUtils.getSafeLabel(graph, r), r), itemsFilter);\r
-                            //contentProvider.add(new LabeledResource(pattern, r), itemsFilter);\r
-                        } catch (DatabaseException e) {\r
-                            // No resource for specified id.\r
-                        }\r
-                    }\r
-                    if (findUris) {\r
-                        String uri = pattern;\r
-                        if (uri.endsWith(Role.CHILD.getIdentifier())) {\r
-                            uri = uri.substring(0, uri.length() - 1);\r
-                        }\r
-                        Resource r = graph.getPossibleResource(uri);\r
-                        if (r != null) {\r
-                            contentProvider.add(new LabeledResource(DebugUtils.getSafeURI(graph, r), r), itemsFilter );\r
-\r
-                            Map<String, Resource> children = graph.syncRequest(new UnescapedChildMapOfResource(r));\r
-                            for (Resource child : children.values()) {\r
-                                contentProvider.add(new LabeledResource(DebugUtils.getSafeURI(graph, child), child), itemsFilter );\r
-                            }\r
-                        }\r
-                    } else {\r
-                        Resource project = Simantics.peekProjectResource();\r
-                        if (project != null) {\r
-                            IResourceFilter rf = resourceFilter;\r
-                            String filter = getFilterForResourceFilter(rf);\r
-                            if (!filter.isEmpty())\r
-                                filter += " AND ";\r
-                            filter += "Name:" + pattern + "*";\r
-\r
-                            Layer0 L0 = Layer0.getInstance(graph);\r
-                            \r
-                            HashSet<Resource> indexRoots = new HashSet<Resource>();\r
-                            indexRoots.addAll(graph.syncRequest(new ObjectsWithType(project, L0.ConsistsOf, L0.IndexRoot)));\r
-                            indexRoots.addAll(graph.syncRequest(new OntologiesFromLibrary(graph.getRootLibrary())));\r
-                            for (Resource indexRoot : indexRoots) {\r
-                                Collection<Resource> hits = new ArrayList<Resource>(find(graph, indexRoot, filter));\r
-                                hits.add(indexRoot);\r
-                                for (Resource r : hits) {\r
-                                    if (rf != null && !rf.acceptResource(graph, r))\r
-                                        continue;\r
-                                    contentProvider.add(new LabeledResource(DebugUtils.getSafeLabel(graph, r), r), itemsFilter);\r
-                                }\r
-                            }\r
-                        }\r
-                    }\r
-                }\r
-\r
-                public Collection<Resource> find(ReadGraph graph, Resource index, String filter) throws DatabaseException {\r
-                    Collection<Resource> indexResult = graph.syncRequest(new QueryIndex(index, filter), TransientCacheListener.<Collection<Resource>>instance());\r
-\r
-//                    Layer0 L0 = Layer0.getInstance(graph);\r
-//                    Collection<Resource> linkedRoots = graph.syncRequest(new ObjectsWithType(index, L0.IsLinkedTo, L0.IndexRoot));\r
-//                    if (linkedRoots.isEmpty())\r
-                        return indexResult;\r
-\r
-//                    Collection<Resource> result = indexResult;\r
-//                    for (Resource dep : linkedRoots) {\r
-//                        Collection<Resource> linkedIndexResults = find(graph, dep, filter);\r
-//                        if (linkedIndexResults.isEmpty())\r
-//                            continue;\r
-//                        if (result == indexResult) {\r
-//                            result = new ArrayList<Resource>(indexResult.size() + linkedIndexResults.size());\r
-//                            result.addAll(indexResult);\r
-//                        } else {\r
-//                        }\r
-//                        result.addAll(linkedIndexResults);\r
-//                    }\r
-//                    return result;\r
-                }\r
-\r
-            });\r
-        } catch (DatabaseException ex) {\r
-            Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, ex.getMessage(), ex));\r
-        }\r
-\r
-        progressMonitor.done();\r
-    }\r
-\r
-    /**\r
-     * A (cacheable) query to optimize single index queries for immutable\r
-     * indexes such as ontologies.\r
-     */\r
-    static class QueryIndex extends BinaryRead<Resource, String, Collection<Resource>> {\r
-\r
-        public QueryIndex(Resource index, String filter) {\r
-            super(index, filter);\r
-        }\r
-\r
-        @Override\r
-        public Collection<Resource> perform(ReadGraph graph)\r
-                throws DatabaseException {\r
-            Layer0X L0X = Layer0X.getInstance(graph);\r
-\r
-            @SuppressWarnings({ "unchecked", "rawtypes" })\r
-            Function dependencies = graph.syncRequest(new Adapter(L0X.Dependencies, Function.class), TransientCacheListener.<Function>instance());\r
-\r
-            @SuppressWarnings("unchecked")\r
-            Collection<Map<String, Object>> results = (Collection<Map<String, Object>>)dependencies.apply(graph, parameter, parameter2);\r
-            if (results == null || results.isEmpty())\r
-                return Collections.emptyList();\r
-\r
-            // TreeSet to keep the results in deterministic order.\r
-            Set<Resource> resultSet = new TreeSet<Resource>();\r
-            for (Map<String, Object> entry : results) {\r
-                Resource res = (Resource)entry.get("Resource");\r
-                if (res != null && !resultSet.contains(res))\r
-                    resultSet.add(res);\r
-            }\r
-\r
-            return new ArrayList<Resource>(resultSet);\r
-        }\r
-\r
-    }\r
-\r
-    Pattern ID_PATTERN = Pattern.compile("\\$([0-9]+)");\r
-\r
-    private long referencedResourceId(String pattern) {\r
-        Matcher m = ID_PATTERN.matcher(pattern);\r
-        if (m.matches()) {\r
-           String id = m.group(1);\r
-           try {\r
-               return Long.parseLong(id);\r
-           } catch (NumberFormatException nfe) {\r
-           }\r
-        }\r
-        return 0;\r
-    }\r
-\r
-    @Override\r
-    protected IDialogSettings getDialogSettings() {\r
-        IDialogSettings settings = Activator.getDefault().getDialogSettings()\r
-        .getSection(SEARCH_RESOURCE_DIALOG);\r
-        if (settings == null) {\r
-            settings = Activator.getDefault().getDialogSettings()\r
-            .addNewSection(SEARCH_RESOURCE_DIALOG);\r
-        }\r
-        return settings;\r
-    }\r
-\r
-    @SuppressWarnings("unchecked")\r
-    @Override\r
-    public String getElementName(Object item) {\r
-        return ((Container<Resource>)item).get().getResourceId()+"";\r
-        //return item.toString();\r
-    }\r
-\r
-    @SuppressWarnings("rawtypes")\r
-    @Override\r
-    protected Comparator getItemsComparator() {\r
-        return new Comparator() {\r
-            @Override\r
-            public int compare(Object arg0, Object arg1) {\r
-                return arg0.toString().compareTo(arg1.toString());\r
-            }\r
-        };\r
-    }\r
-\r
-    @Override\r
-    protected IStatus validateItem(Object item) {\r
-        return Status.OK_STATUS;\r
-    }\r
-\r
-    public IResourceFilter getResourceFilter() {\r
-        return resourceFilter;\r
-    }\r
-\r
-    public void setResourceFilter(IResourceFilter resourceFilter) {\r
-        this.resourceFilter = resourceFilter;\r
-    }\r
-\r
-    private String getFilterForResourceFilter(IResourceFilter filter) {\r
-        if (filter == null || filter == ResourceSearch.FILTER_ALL)\r
-            return "";\r
-        if (filter == ResourceSearch.FILTER_RELATIONS)\r
-            return "Types:Relation"; \r
-        if (filter == ResourceSearch.FILTER_TYPES)\r
-            return "Types:Type"; \r
-        return "";\r
-    }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2016 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
+ *     Semantum Oy - index based searching and graph manipulation (#4255)
+ *******************************************************************************/
+package org.simantics.debug.ui;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.resource.ResourceManager;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.dialogs.FilteredItemsSelectionDialog;
+import org.simantics.Simantics;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.Session;
+import org.simantics.db.common.primitiverequest.PossibleAdapter;
+import org.simantics.db.common.procedure.adapter.TransientCacheListener;
+import org.simantics.db.common.request.BinaryRead;
+import org.simantics.db.common.request.ObjectsWithType;
+import org.simantics.db.common.request.ReadRequest;
+import org.simantics.db.common.request.UniqueRead;
+import org.simantics.db.common.uri.UnescapedChildMapOfResource;
+import org.simantics.db.common.utils.NameUtils;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.migration.OntologiesFromLibrary;
+import org.simantics.db.layer0.variable.Variables.Role;
+import org.simantics.db.request.Read;
+import org.simantics.db.service.SerialisationSupport;
+import org.simantics.debug.ui.ResourceSearch.IResourceFilter;
+import org.simantics.debug.ui.internal.Activator;
+import org.simantics.debug.ui.internal.DebugUtils;
+import org.simantics.layer0.Layer0;
+import org.simantics.operation.Layer0X;
+import org.simantics.scl.runtime.function.Function;
+import org.simantics.ui.selection.ResourceWorkbenchSelectionElement;
+import org.simantics.ui.workbench.dialogs.ResourceLabelProvider;
+import org.simantics.utils.Container;
+import org.simantics.utils.ui.BundleUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * TODO Add Debugger Composite as preview!
+ */
+public class SearchResourceDialog extends FilteredItemsSelectionDialog {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(SearchResourceDialog.class);
+
+    /**
+     * The default maximum amount of Dependencies index hits to produce as results.
+     */
+    private static final int DEFAULT_MAX_INDEX_HITS = 1000;
+
+    private static final Pattern ID_PATTERN = Pattern.compile("\\$([0-9]+)");
+
+    private static final String SEARCH_RESOURCE_DIALOG = "SearchResourceDialog"; //$NON-NLS-1$
+
+    private static final int SHOW_IN_BROWSER_ID = IDialogConstants.CLIENT_ID + 1;
+
+    private static final String SHOW_IN_BROWSER_LABEL = "Show In Browser";
+
+    private Session session;
+    @SuppressWarnings("unused")
+    private IStructuredSelection selection;
+    private ResourceManager resourceManager;
+    private IResourceFilter resourceFilter = ResourceSearch.FILTER_ALL;
+
+    LabelProvider detailsLabelProvider = new LabelProvider() {
+        @Override
+        public String getText(Object element) {
+            if (element == null)
+                return "null";
+            // This may happen if multiple choice is enabled
+            if (element instanceof String)
+                return (String) element;
+            @SuppressWarnings("unchecked")
+            Container<Resource> rc = (Container<Resource>) element;
+            final Resource r = rc.get();
+            try {
+                return session.syncRequest(new Read<String>() {
+                    @Override
+                    public String perform(ReadGraph g) throws DatabaseException {
+                        String name = NameUtils.getSafeName(g, r);
+                        String uri = DebugUtils.getPossibleRootRelativePath(g, r);
+                        return
+                                "[" + r.getResourceId() + "] - "
+                                + name
+                                + (uri != null ? " - " : "")
+                                + (uri != null ? uri : "");
+                    }
+                });
+            } catch (DatabaseException e) {
+                Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Resource label provider failed unexpectedly.", e));
+                return "";
+            }
+        }
+    };
+
+    static class ElementLabelProvider extends ResourceLabelProvider {
+        public ElementLabelProvider(Display display) {
+            super(display);
+        }
+        @Override
+        public String getText(Object element) {
+            if (element==null)
+                return "null";
+            return element.toString();
+        }
+        @Override
+        public Image getImage(Object element) {
+            if (element == null)
+                return null;
+            @SuppressWarnings("unchecked")
+            Container<Resource> rc = (Container<Resource>) element;
+            final Resource r = rc.get();
+            return super.getImage(r);
+        }
+    };
+
+    ElementLabelProvider labelProvider;
+
+    public SearchResourceDialog(Session s, boolean multi, Shell shell, String title) {
+        this(s, multi, shell, title, null);
+    }
+
+    public SearchResourceDialog(Session s, boolean multi, Shell shell, String title, IStructuredSelection selection) {
+        super(shell, multi);
+        this.session = s;
+        this.selection = selection;
+        this.labelProvider = new ElementLabelProvider(shell.getDisplay());
+        setMessage("Enter name, resource URI or ID");
+        setListLabelProvider(labelProvider);
+        setDetailsLabelProvider(detailsLabelProvider);
+        setTitle(title);
+        //setInitialPattern("*", FilteredItemsSelectionDialog.FULL_SELECTION);
+        setSelectionHistory(new ResourceSelectionHistory());
+        setSeparatorLabel("Previously selected above, others below");
+    }
+
+    @Override
+    protected void configureShell(Shell shell) {
+        this.resourceManager = new LocalResourceManager(JFaceResources.getResources(), shell);
+        setImage((Image) resourceManager.get(BundleUtils.getImageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/cog_blue.png")));
+        super.configureShell(shell);
+    }
+
+    @Override
+    protected void createButtonsForButtonBar(Composite parent) {
+        createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL,
+                true);
+        createButton(parent, SHOW_IN_BROWSER_ID, SHOW_IN_BROWSER_LABEL,
+                true);
+        createButton(parent, IDialogConstants.CANCEL_ID,
+                IDialogConstants.CANCEL_LABEL, false);
+    }
+
+    @Override
+    protected void buttonPressed(int buttonId) {
+        if (buttonId == SHOW_IN_BROWSER_ID) {
+            okPressed();
+            LabeledResource lr = (LabeledResource) getFirstResult();
+            ShowInBrowser.defaultExecute(new StructuredSelection(new ResourceWorkbenchSelectionElement(lr.resource)));
+            return;
+        }
+        super.buttonPressed(buttonId);
+    }
+
+    class ResourceSelectionHistory extends FilteredItemsSelectionDialog.SelectionHistory {
+
+        @Override
+        protected Object restoreItemFromMemento(IMemento memento) {
+            String data = memento.getTextData();
+            try {
+                SerialisationSupport support = Simantics.getSession().getService(SerialisationSupport.class);
+                Resource r = support.getResource(Long.parseLong(data));
+                if (r == null)
+                    return null;
+
+                String name = session.syncRequest(new UniqueRead<String>() {
+                    @Override
+                    public String perform(ReadGraph g) throws DatabaseException {
+                        if (!resourceFilter.acceptResource(g, r))
+                            return null;
+                        try {
+                            try {
+                                return DebugUtils.getSafeLabel(g, r);
+                            } catch (Exception ex) {
+                                System.out.println("Exception thrown from restoreItemFromMemento");
+                            }
+                        } catch (Throwable t) {}
+                        return "" + r.getResourceId();
+                    }
+                });
+                if (name==null) return null;
+                return new LabeledResource(name, r);
+            } catch (NumberFormatException | DatabaseException e) {
+                LOGGER.info("Search memento restoration failed.", e);
+                return null;
+            }
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        protected void storeItemToMemento(Object item, IMemento memento) {
+            if(item instanceof Container) {
+                try {
+                    SerialisationSupport support = Simantics.getSession().getService(SerialisationSupport.class);
+                    memento.putTextData(String.valueOf(support.getRandomAccessId(((Container<Resource>)item).get())));
+                } catch (DatabaseException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    };
+
+    @Override
+    protected Control createExtendedContentArea(Composite parent) {
+        return null;
+    }
+
+    @Override
+    protected ItemsFilter createFilter() {
+        // NOTE: filter must be created here.
+        return new ItemsFilterWithSearchResults();
+    }
+
+    private class ItemsFilterWithSearchResults extends ItemsFilter {
+        private Set<Object> searchResults = new HashSet<Object>();
+
+        public ItemsFilterWithSearchResults() {
+            
+            final String pattern = getPattern();
+            final boolean findUris = pattern.trim().startsWith("http:/");
+            final long referencedResourceId = referencedResourceId(pattern);
+            final boolean findIds = referencedResourceId != 0;
+
+            searchResults.clear();
+            if (pattern.isEmpty()) return;
+            //progressMonitor.beginTask("Searching", IProgressMonitor.UNKNOWN);
+
+            try {
+                session.syncRequest(new ReadRequest() {
+                    @Override
+                    public void run(ReadGraph graph) throws DatabaseException {
+                        // Find by ID first.
+                        if (findIds) {
+                            try {
+                                Resource r = graph.getService(SerialisationSupport.class).getResource(referencedResourceId);
+                                searchResults.add(new LabeledResource(DebugUtils.getSafeLabel(graph, r), r));
+                            } catch (DatabaseException e) {
+                                // No resource for specified id.
+                            }
+                        }
+                        if (findUris) {
+                            String uri = pattern;
+                            if (uri.endsWith(Role.CHILD.getIdentifier())) {
+                                uri = uri.substring(0, uri.length() - 1);
+                            }
+                            Resource r = graph.getPossibleResource(uri);
+                            if (r != null) {
+                               searchResults.add(new LabeledResource(DebugUtils.getSafeURI(graph, r), r));
+
+                                Map<String, Resource> children = graph.syncRequest(new UnescapedChildMapOfResource(r));
+                                for (Resource child : children.values()) {
+                                       searchResults.add(new LabeledResource(DebugUtils.getSafeURI(graph, child), child));
+                                }
+                            }
+                        } else {
+                            Resource project = Simantics.peekProjectResource();
+                            if (project != null) {
+                                IResourceFilter rf = resourceFilter;
+                                String filter = getFilterForResourceFilter(rf);
+                                if (!filter.isEmpty())
+                                    filter += " AND ";
+                                filter += "Name:" + pattern + "*";
+
+                                Layer0 L0 = Layer0.getInstance(graph);
+
+                                Set<Resource> indexRoots = new HashSet<>();
+                                indexRoots.addAll(graph.syncRequest(new ObjectsWithType(project, L0.ConsistsOf, L0.IndexRoot)));
+                                indexRoots.addAll(graph.syncRequest(new OntologiesFromLibrary(graph.getRootLibrary())));
+                                for (Resource indexRoot : indexRoots) {
+                                    Collection<Resource> hits = find(graph, indexRoot, filter);
+                                    for (Resource r : hits) {
+                                        if (rf != null && !rf.acceptResource(graph, r))
+                                            continue;
+                                        searchResults.add(new LabeledResource(DebugUtils.getSafeLabel(graph, r), r));
+                                    }
+                                }
+                            }
+                        }
+                    }
+
+                    public Collection<Resource> find(ReadGraph graph, Resource index, String filter) throws DatabaseException {
+                        //TimeLogger.resetTimeAndLog("find(" + graph.getURI(index) + ", " + filter + ")");
+                        Collection<Resource> indexResult = graph.syncRequest(new QueryIndex(index, filter), TransientCacheListener.<Collection<Resource>>instance());
+                        //TimeLogger.log("found " + indexResult.size());
+                        return indexResult;
+                    }
+
+                });
+            } catch (DatabaseException ex) {
+                Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, ex.getMessage(), ex));
+            }
+
+        }
+
+        @Override
+        public boolean matchItem(Object item) {
+            return searchResults.contains(item);
+        }
+
+        @Override
+        public boolean isSubFilter(ItemsFilter filter) {
+            return false;
+        }
+        
+        @Override
+        public boolean isConsistentItem(Object item) {
+            return true;
+        }
+        
+        @Override
+        public boolean equalsFilter(ItemsFilter filter) {
+            return false;
+        }
+        
+        public void fillContentProvider(final AbstractContentProvider contentProvider) {
+               for (Object item : searchResults) {
+                       contentProvider.add(item, this);
+               }
+        }
+    }
+    
+    @Override
+    protected void fillContentProvider(final AbstractContentProvider contentProvider,
+            final ItemsFilter itemsFilter, final IProgressMonitor progressMonitor)
+                    throws CoreException {
+        ((ItemsFilterWithSearchResults) itemsFilter).fillContentProvider(contentProvider);
+        progressMonitor.done();
+    }
+
+    /**
+     * A (cacheable) query to optimize single index queries for immutable
+     * indexes such as ontologies.
+     */
+    static class QueryIndex extends BinaryRead<Resource, String, Collection<Resource>> {
+
+        public QueryIndex(Resource index, String filter) {
+            super(index, filter);
+        }
+
+        @Override
+        public Collection<Resource> perform(ReadGraph graph)
+                throws DatabaseException {
+            Layer0X L0X = Layer0X.getInstance(graph);
+
+            @SuppressWarnings({ "unchecked", "rawtypes" })
+            Function dependencies = graph.syncRequest(new PossibleAdapter(L0X.DependencyResources, Function.class), TransientCacheListener.<Function>instance());
+            if (dependencies == null)
+                return Collections.emptyList();
+
+            @SuppressWarnings("unchecked")
+            List<Resource> results = (List<Resource>) dependencies.apply(graph, parameter, parameter2, DEFAULT_MAX_INDEX_HITS);
+            if (results == null || results.isEmpty())
+                return Collections.emptyList();
+
+            // TreeSet to keep the results in deterministic order and to prevent duplicates.
+            Set<Resource> resultSet = new TreeSet<>();
+            for (Resource res : results) {
+                if (res != null && !resultSet.contains(res))
+                    resultSet.add(res);
+            }
+            return new ArrayList<Resource>(resultSet);
+        }
+
+    }
+
+    private long referencedResourceId(String pattern) {
+        Matcher m = ID_PATTERN.matcher(pattern);
+        if (m.matches()) {
+           String id = m.group(1);
+           try {
+               return Long.parseLong(id);
+           } catch (NumberFormatException nfe) {
+           }
+        }
+        return 0;
+    }
+
+    @Override
+    protected IDialogSettings getDialogSettings() {
+        IDialogSettings settings = Activator.getDefault().getDialogSettings()
+        .getSection(SEARCH_RESOURCE_DIALOG);
+        if (settings == null) {
+            settings = Activator.getDefault().getDialogSettings()
+            .addNewSection(SEARCH_RESOURCE_DIALOG);
+        }
+        return settings;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public String getElementName(Object item) {
+        return ((Container<Resource>)item).get().getResourceId()+"";
+        //return item.toString();
+    }
+
+    @Override
+    protected Comparator<?> getItemsComparator() {
+        return (arg0, arg1) -> {
+            return arg0.toString().compareTo(arg1.toString());
+        };
+    }
+
+    @Override
+    protected IStatus validateItem(Object item) {
+        return Status.OK_STATUS;
+    }
+
+    public IResourceFilter getResourceFilter() {
+        return resourceFilter;
+    }
+
+    public void setResourceFilter(IResourceFilter resourceFilter) {
+        this.resourceFilter = resourceFilter;
+    }
+
+    private String getFilterForResourceFilter(IResourceFilter filter) {
+        if (filter == null || filter == ResourceSearch.FILTER_ALL)
+            return "";
+        if (filter == ResourceSearch.FILTER_RELATIONS)
+            return "Types:Relation"; 
+        if (filter == ResourceSearch.FILTER_TYPES)
+            return "Types:Type"; 
+        return "";
+    }
+
+}