]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.debug.ui/src/org/simantics/debug/ui/SearchResourceDialog.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.debug.ui / src / org / simantics / debug / ui / SearchResourceDialog.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2013 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *     Semantum Oy - index based searching and graph manipulation (#4255)\r
12  *******************************************************************************/\r
13 package org.simantics.debug.ui;\r
14 \r
15 import java.util.ArrayList;\r
16 import java.util.Collection;\r
17 import java.util.Collections;\r
18 import java.util.Comparator;\r
19 import java.util.HashSet;\r
20 import java.util.Map;\r
21 import java.util.Set;\r
22 import java.util.TreeSet;\r
23 import java.util.regex.Matcher;\r
24 import java.util.regex.Pattern;\r
25 \r
26 import org.eclipse.core.runtime.CoreException;\r
27 import org.eclipse.core.runtime.IProgressMonitor;\r
28 import org.eclipse.core.runtime.IStatus;\r
29 import org.eclipse.core.runtime.Status;\r
30 import org.eclipse.jface.dialogs.IDialogSettings;\r
31 import org.eclipse.jface.resource.JFaceResources;\r
32 import org.eclipse.jface.resource.LocalResourceManager;\r
33 import org.eclipse.jface.resource.ResourceManager;\r
34 import org.eclipse.jface.viewers.IStructuredSelection;\r
35 import org.eclipse.jface.viewers.LabelProvider;\r
36 import org.eclipse.swt.events.DisposeEvent;\r
37 import org.eclipse.swt.events.DisposeListener;\r
38 import org.eclipse.swt.graphics.Image;\r
39 import org.eclipse.swt.widgets.Composite;\r
40 import org.eclipse.swt.widgets.Control;\r
41 import org.eclipse.swt.widgets.Display;\r
42 import org.eclipse.swt.widgets.Shell;\r
43 import org.eclipse.ui.IMemento;\r
44 import org.eclipse.ui.dialogs.FilteredItemsSelectionDialog;\r
45 import org.simantics.Simantics;\r
46 import org.simantics.db.ReadGraph;\r
47 import org.simantics.db.Resource;\r
48 import org.simantics.db.Session;\r
49 import org.simantics.db.common.primitiverequest.Adapter;\r
50 import org.simantics.db.common.procedure.adapter.TransientCacheListener;\r
51 import org.simantics.db.common.request.BinaryRead;\r
52 import org.simantics.db.common.request.ObjectsWithType;\r
53 import org.simantics.db.common.request.ReadRequest;\r
54 import org.simantics.db.common.uri.UnescapedChildMapOfResource;\r
55 import org.simantics.db.common.utils.NameUtils;\r
56 import org.simantics.db.exception.DatabaseException;\r
57 import org.simantics.db.layer0.migration.OntologiesFromLibrary;\r
58 import org.simantics.db.layer0.variable.Variables.Role;\r
59 import org.simantics.db.request.Read;\r
60 import org.simantics.db.service.SerialisationSupport;\r
61 import org.simantics.debug.ui.ResourceSearch.IResourceFilter;\r
62 import org.simantics.debug.ui.internal.Activator;\r
63 import org.simantics.debug.ui.internal.DebugUtils;\r
64 import org.simantics.layer0.Layer0;\r
65 import org.simantics.operation.Layer0X;\r
66 import org.simantics.scl.runtime.function.Function;\r
67 import org.simantics.ui.SimanticsUI;\r
68 import org.simantics.ui.workbench.dialogs.ResourceLabelProvider;\r
69 import org.simantics.utils.Container;\r
70 import org.simantics.utils.ui.BundleUtils;\r
71 \r
72 /**\r
73  * TODO Add Debugger Composite as preview!\r
74  */\r
75 public class SearchResourceDialog extends FilteredItemsSelectionDialog {\r
76 \r
77     private static final String SEARCH_RESOURCE_DIALOG = "SearchResourceDialog"; //$NON-NLS-1$\r
78 \r
79     Session session;\r
80     IStructuredSelection selection;\r
81     ResourceManager resourceManager;\r
82 \r
83     // Needed in a subclass\r
84     protected IResourceFilter resourceFilter = ResourceSearch.FILTER_ALL;\r
85 \r
86     LabelProvider detailsLabelProvider = new LabelProvider() {\r
87         @Override\r
88         public String getText(Object element) {\r
89             if (element == null)\r
90                 return "null";\r
91             // This may happen if multiple choice is enabled\r
92             if (element instanceof String)\r
93                 return (String) element;\r
94             @SuppressWarnings("unchecked")\r
95             Container<Resource> rc = (Container<Resource>) element;\r
96             final Resource r = rc.get();\r
97             try {\r
98                 return session.syncRequest(new Read<String>() {\r
99                     @Override\r
100                     public String perform(ReadGraph g) throws DatabaseException {\r
101                         String name = NameUtils.getSafeName(g, r);\r
102                         String uri = g.getPossibleURI(r);\r
103                         String label = "[" + r.getResourceId() + "] - " + name;\r
104                         if (uri != null)\r
105                             label = label + " - " + uri;\r
106                         return label;\r
107                     }\r
108                 });\r
109             } catch (DatabaseException e) {\r
110                 Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Resource label provider failed unexpectedly.", e));\r
111                 return "";\r
112             }\r
113         }\r
114     };\r
115 \r
116     static class ElementLabelProvider extends ResourceLabelProvider {\r
117         public ElementLabelProvider(Display display) {\r
118             super(display);\r
119         }\r
120         @Override\r
121         public String getText(Object element) {\r
122             if (element==null)\r
123                 return "null";\r
124             return element.toString();\r
125         }\r
126         @Override\r
127         public Image getImage(Object element) {\r
128             if (element == null)\r
129                 return null;\r
130             @SuppressWarnings("unchecked")\r
131             Container<Resource> rc = (Container<Resource>) element;\r
132             final Resource r = rc.get();\r
133             return super.getImage(r);\r
134         }\r
135     };\r
136 \r
137     ElementLabelProvider labelProvider;\r
138 \r
139     public SearchResourceDialog(Session s, boolean multi, Shell shell, String title) {\r
140         this(s, multi, shell, title, null);\r
141     }\r
142 \r
143     public SearchResourceDialog(Session s, boolean multi, Shell shell, String title, IStructuredSelection selection) {\r
144         super(shell, multi);\r
145         this.session = s;\r
146         resourceManager = new LocalResourceManager(JFaceResources.getResources());\r
147         this.labelProvider = new ElementLabelProvider(shell.getDisplay());\r
148         setMessage("Enter ID, URI or name");\r
149         setListLabelProvider(labelProvider);\r
150         setDetailsLabelProvider(detailsLabelProvider);\r
151         setImage((Image) resourceManager.get(BundleUtils.getImageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/cog_blue.png")));\r
152         setTitle(title);\r
153         //setInitialPattern("*", FilteredItemsSelectionDialog.FULL_SELECTION);\r
154         setSelectionHistory(new ResourceSelectionHistory());\r
155         this.selection = selection;\r
156         setSeparatorLabel("Previously selected above, others below");\r
157     }\r
158 \r
159     @Override\r
160     protected void configureShell(Shell shell) {\r
161         super.configureShell(shell);\r
162         shell.addDisposeListener(new DisposeListener() {\r
163             @Override\r
164             public void widgetDisposed(DisposeEvent e) {\r
165                 resourceManager.dispose();\r
166             }\r
167         });\r
168     }\r
169 \r
170     class ResourceSelectionHistory extends FilteredItemsSelectionDialog.SelectionHistory {\r
171 \r
172         @Override\r
173         protected Object restoreItemFromMemento(IMemento memento) {\r
174             String dada = memento.getTextData();\r
175             try {\r
176                 SerialisationSupport support = SimanticsUI.getSession().getService(SerialisationSupport.class);\r
177                 final Resource r = support.getResource(Long.parseLong(dada));\r
178                 if (r == null) {\r
179                     return null;\r
180                 }\r
181 \r
182                 String name = session.syncRequest(new Read<String>() {\r
183                     @Override\r
184                     public String perform(ReadGraph g) throws DatabaseException {\r
185                         if (!resourceFilter.acceptResource(g, r)) {\r
186                             return null;\r
187                         }\r
188                         String name = null;\r
189                         try {\r
190                             try {\r
191                                 name = g.adapt(r, String.class);\r
192                             } catch (Exception ex) {\r
193                                 System.out.println("Exception thrown from restoreItemFromMemento");\r
194                             }\r
195                             if (name != null) {\r
196                                 return name;\r
197                             }\r
198                         } catch (Throwable t) {}\r
199                         return "" + r.getResourceId();\r
200                     }\r
201                 });\r
202                 if (name==null) return null;\r
203                 return new LabeledResource(name, r);\r
204             } catch (NumberFormatException e) {\r
205                 e.printStackTrace();\r
206                 return null;\r
207             } catch (DatabaseException e) {\r
208                 e.printStackTrace();\r
209                 return null;\r
210             }\r
211         }\r
212 \r
213         @SuppressWarnings("unchecked")\r
214         @Override\r
215         protected void storeItemToMemento(Object item, IMemento memento) {\r
216             if(item instanceof Container) {\r
217                 try {\r
218                     SerialisationSupport support = SimanticsUI.getSession().getService(SerialisationSupport.class);\r
219                     memento.putTextData(String.valueOf(support.getRandomAccessId(((Container<Resource>)item).get())));\r
220                 } catch (DatabaseException e) {\r
221                     e.printStackTrace();\r
222                 }\r
223             }\r
224         }\r
225     };\r
226 \r
227     @Override\r
228     protected Control createExtendedContentArea(Composite parent) {\r
229         return null;\r
230     }\r
231 \r
232     @Override\r
233     protected ItemsFilter createFilter() {\r
234         // NOTE: filter must be created here.\r
235         return new ItemsFilter() {\r
236             @Override\r
237             public boolean matchItem(Object item) {\r
238                 //return matches(item.toString());\r
239                 return true;\r
240             }\r
241 \r
242             // If this method returns true, it means fillContentProvider will\r
243             // not be called again, but the existing results are just re-filtered.\r
244             @Override\r
245             public boolean isSubFilter(ItemsFilter filter) {\r
246                 //System.out.println(getPattern() + " vs. " + filter.getPattern());\r
247                 return false;\r
248             }\r
249 \r
250             @Override\r
251             public boolean isConsistentItem(Object item) {\r
252                 return true;\r
253             }\r
254 \r
255             @Override\r
256             public boolean equalsFilter(ItemsFilter filter) {\r
257                 return false;\r
258             }\r
259         };\r
260     }\r
261 \r
262     @Override\r
263     protected void fillContentProvider(final AbstractContentProvider contentProvider,\r
264             final ItemsFilter itemsFilter, final IProgressMonitor progressMonitor)\r
265                     throws CoreException {\r
266         final String pattern = itemsFilter.getPattern();\r
267         final boolean findUris = pattern.trim().startsWith("http:/");\r
268         final long referencedResourceId = referencedResourceId(pattern);\r
269         final boolean findIds = referencedResourceId != 0;\r
270 \r
271         progressMonitor.beginTask("Searching", IProgressMonitor.UNKNOWN);\r
272 \r
273         try {\r
274             session.syncRequest(new ReadRequest() {\r
275                 @Override\r
276                 public void run(ReadGraph graph) throws DatabaseException {\r
277                     // Find by ID first.\r
278                     if (findIds) {\r
279                         try {\r
280                             Resource r = graph.getService(SerialisationSupport.class).getResource(referencedResourceId);\r
281                             contentProvider.add(new LabeledResource(DebugUtils.getSafeLabel(graph, r), r), itemsFilter);\r
282                             //contentProvider.add(new LabeledResource(pattern, r), itemsFilter);\r
283                         } catch (DatabaseException e) {\r
284                             // No resource for specified id.\r
285                         }\r
286                     }\r
287                     if (findUris) {\r
288                         String uri = pattern;\r
289                         if (uri.endsWith(Role.CHILD.getIdentifier())) {\r
290                             uri = uri.substring(0, uri.length() - 1);\r
291                         }\r
292                         Resource r = graph.getPossibleResource(uri);\r
293                         if (r != null) {\r
294                             contentProvider.add(new LabeledResource(DebugUtils.getSafeURI(graph, r), r), itemsFilter );\r
295 \r
296                             Map<String, Resource> children = graph.syncRequest(new UnescapedChildMapOfResource(r));\r
297                             for (Resource child : children.values()) {\r
298                                 contentProvider.add(new LabeledResource(DebugUtils.getSafeURI(graph, child), child), itemsFilter );\r
299                             }\r
300                         }\r
301                     } else {\r
302                         Resource project = Simantics.peekProjectResource();\r
303                         if (project != null) {\r
304                             IResourceFilter rf = resourceFilter;\r
305                             String filter = getFilterForResourceFilter(rf);\r
306                             if (!filter.isEmpty())\r
307                                 filter += " AND ";\r
308                             filter += "Name:" + pattern + "*";\r
309 \r
310                             Layer0 L0 = Layer0.getInstance(graph);\r
311                             \r
312                             HashSet<Resource> indexRoots = new HashSet<Resource>();\r
313                             indexRoots.addAll(graph.syncRequest(new ObjectsWithType(project, L0.ConsistsOf, L0.IndexRoot)));\r
314                             indexRoots.addAll(graph.syncRequest(new OntologiesFromLibrary(graph.getRootLibrary())));\r
315                             for (Resource indexRoot : indexRoots) {\r
316                                 Collection<Resource> hits = new ArrayList<Resource>(find(graph, indexRoot, filter));\r
317                                 hits.add(indexRoot);\r
318                                 for (Resource r : hits) {\r
319                                     if (rf != null && !rf.acceptResource(graph, r))\r
320                                         continue;\r
321                                     contentProvider.add(new LabeledResource(DebugUtils.getSafeLabel(graph, r), r), itemsFilter);\r
322                                 }\r
323                             }\r
324                         }\r
325                     }\r
326                 }\r
327 \r
328                 public Collection<Resource> find(ReadGraph graph, Resource index, String filter) throws DatabaseException {\r
329                     Collection<Resource> indexResult = graph.syncRequest(new QueryIndex(index, filter), TransientCacheListener.<Collection<Resource>>instance());\r
330 \r
331 //                    Layer0 L0 = Layer0.getInstance(graph);\r
332 //                    Collection<Resource> linkedRoots = graph.syncRequest(new ObjectsWithType(index, L0.IsLinkedTo, L0.IndexRoot));\r
333 //                    if (linkedRoots.isEmpty())\r
334                         return indexResult;\r
335 \r
336 //                    Collection<Resource> result = indexResult;\r
337 //                    for (Resource dep : linkedRoots) {\r
338 //                        Collection<Resource> linkedIndexResults = find(graph, dep, filter);\r
339 //                        if (linkedIndexResults.isEmpty())\r
340 //                            continue;\r
341 //                        if (result == indexResult) {\r
342 //                            result = new ArrayList<Resource>(indexResult.size() + linkedIndexResults.size());\r
343 //                            result.addAll(indexResult);\r
344 //                        } else {\r
345 //                        }\r
346 //                        result.addAll(linkedIndexResults);\r
347 //                    }\r
348 //                    return result;\r
349                 }\r
350 \r
351             });\r
352         } catch (DatabaseException ex) {\r
353             Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, ex.getMessage(), ex));\r
354         }\r
355 \r
356         progressMonitor.done();\r
357     }\r
358 \r
359     /**\r
360      * A (cacheable) query to optimize single index queries for immutable\r
361      * indexes such as ontologies.\r
362      */\r
363     static class QueryIndex extends BinaryRead<Resource, String, Collection<Resource>> {\r
364 \r
365         public QueryIndex(Resource index, String filter) {\r
366             super(index, filter);\r
367         }\r
368 \r
369         @Override\r
370         public Collection<Resource> perform(ReadGraph graph)\r
371                 throws DatabaseException {\r
372             Layer0X L0X = Layer0X.getInstance(graph);\r
373 \r
374             @SuppressWarnings({ "unchecked", "rawtypes" })\r
375             Function dependencies = graph.syncRequest(new Adapter(L0X.Dependencies, Function.class), TransientCacheListener.<Function>instance());\r
376 \r
377             @SuppressWarnings("unchecked")\r
378             Collection<Map<String, Object>> results = (Collection<Map<String, Object>>)dependencies.apply(graph, parameter, parameter2);\r
379             if (results == null || results.isEmpty())\r
380                 return Collections.emptyList();\r
381 \r
382             // TreeSet to keep the results in deterministic order.\r
383             Set<Resource> resultSet = new TreeSet<Resource>();\r
384             for (Map<String, Object> entry : results) {\r
385                 Resource res = (Resource)entry.get("Resource");\r
386                 if (res != null && !resultSet.contains(res))\r
387                     resultSet.add(res);\r
388             }\r
389 \r
390             return new ArrayList<Resource>(resultSet);\r
391         }\r
392 \r
393     }\r
394 \r
395     Pattern ID_PATTERN = Pattern.compile("\\$([0-9]+)");\r
396 \r
397     private long referencedResourceId(String pattern) {\r
398         Matcher m = ID_PATTERN.matcher(pattern);\r
399         if (m.matches()) {\r
400            String id = m.group(1);\r
401            try {\r
402                return Long.parseLong(id);\r
403            } catch (NumberFormatException nfe) {\r
404            }\r
405         }\r
406         return 0;\r
407     }\r
408 \r
409     @Override\r
410     protected IDialogSettings getDialogSettings() {\r
411         IDialogSettings settings = Activator.getDefault().getDialogSettings()\r
412         .getSection(SEARCH_RESOURCE_DIALOG);\r
413         if (settings == null) {\r
414             settings = Activator.getDefault().getDialogSettings()\r
415             .addNewSection(SEARCH_RESOURCE_DIALOG);\r
416         }\r
417         return settings;\r
418     }\r
419 \r
420     @SuppressWarnings("unchecked")\r
421     @Override\r
422     public String getElementName(Object item) {\r
423         return ((Container<Resource>)item).get().getResourceId()+"";\r
424         //return item.toString();\r
425     }\r
426 \r
427     @SuppressWarnings("rawtypes")\r
428     @Override\r
429     protected Comparator getItemsComparator() {\r
430         return new Comparator() {\r
431             @Override\r
432             public int compare(Object arg0, Object arg1) {\r
433                 return arg0.toString().compareTo(arg1.toString());\r
434             }\r
435         };\r
436     }\r
437 \r
438     @Override\r
439     protected IStatus validateItem(Object item) {\r
440         return Status.OK_STATUS;\r
441     }\r
442 \r
443     public IResourceFilter getResourceFilter() {\r
444         return resourceFilter;\r
445     }\r
446 \r
447     public void setResourceFilter(IResourceFilter resourceFilter) {\r
448         this.resourceFilter = resourceFilter;\r
449     }\r
450 \r
451     private String getFilterForResourceFilter(IResourceFilter filter) {\r
452         if (filter == null || filter == ResourceSearch.FILTER_ALL)\r
453             return "";\r
454         if (filter == ResourceSearch.FILTER_RELATIONS)\r
455             return "Types:Relation"; \r
456         if (filter == ResourceSearch.FILTER_TYPES)\r
457             return "Types:Type"; \r
458         return "";\r
459     }\r
460 \r
461 }\r