]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.workbench/src/org/simantics/workbench/internal/contributions/search/SearchServiceImpl.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.workbench / src / org / simantics / workbench / internal / contributions / search / SearchServiceImpl.java
1 package org.simantics.workbench.internal.contributions.search;\r
2 \r
3 import java.io.File;\r
4 import java.io.IOException;\r
5 import java.net.MalformedURLException;\r
6 import java.net.URI;\r
7 import java.net.URISyntaxException;\r
8 import java.net.URL;\r
9 import java.util.ArrayList;\r
10 import java.util.Collection;\r
11 import java.util.Collections;\r
12 import java.util.HashMap;\r
13 import java.util.HashSet;\r
14 import java.util.List;\r
15 import java.util.Map;\r
16 import java.util.Set;\r
17 \r
18 import org.eclipse.core.runtime.IProgressMonitor;\r
19 import org.eclipse.core.runtime.IStatus;\r
20 import org.eclipse.core.runtime.NullProgressMonitor;\r
21 import org.eclipse.core.runtime.Status;\r
22 import org.eclipse.core.runtime.SubMonitor;\r
23 import org.eclipse.core.runtime.jobs.Job;\r
24 import org.eclipse.jface.viewers.ISelection;\r
25 import org.eclipse.jface.viewers.StructuredSelection;\r
26 import org.eclipse.swt.SWT;\r
27 import org.eclipse.swt.browser.LocationEvent;\r
28 import org.eclipse.swt.browser.LocationListener;\r
29 import org.eclipse.swt.events.DisposeEvent;\r
30 import org.eclipse.swt.events.DisposeListener;\r
31 import org.eclipse.swt.widgets.Control;\r
32 import org.eclipse.swt.widgets.Display;\r
33 import org.eclipse.swt.widgets.Shell;\r
34 import org.eclipse.ui.IViewPart;\r
35 import org.eclipse.ui.IViewReference;\r
36 import org.eclipse.ui.IWorkbenchPage;\r
37 import org.eclipse.ui.IWorkbenchWindow;\r
38 import org.eclipse.ui.PartInitException;\r
39 import org.eclipse.ui.PlatformUI;\r
40 import org.simantics.ObjectIdentitySchedulingRule;\r
41 import org.simantics.Simantics;\r
42 import org.simantics.databoard.Bindings;\r
43 import org.simantics.db.ReadGraph;\r
44 import org.simantics.db.Resource;\r
45 import org.simantics.db.Session;\r
46 import org.simantics.db.exception.DatabaseException;\r
47 import org.simantics.db.layer0.adapter.Instances;\r
48 import org.simantics.db.layer0.request.ActiveModels;\r
49 import org.simantics.db.request.Read;\r
50 import org.simantics.db.service.SerialisationSupport;\r
51 import org.simantics.editors.Browser;\r
52 import org.simantics.editors.BrowserInput;\r
53 import org.simantics.layer0.Layer0;\r
54 import org.simantics.scl.runtime.function.Function;\r
55 import org.simantics.scl.runtime.function.Function5;\r
56 import org.simantics.ui.workbench.action.ChooseActionRequest;\r
57 import org.simantics.utils.FileUtils;\r
58 import org.simantics.utils.datastructures.MapList;\r
59 import org.simantics.utils.datastructures.Pair;\r
60 import org.simantics.utils.ui.ErrorLogger;\r
61 import org.simantics.utils.ui.ExceptionUtils;\r
62 import org.simantics.utils.ui.workbench.WorkbenchUtils;\r
63 import org.simantics.workbench.internal.Activator;\r
64 import org.simantics.workbench.ontology.WorkbenchResource;\r
65 import org.simantics.workbench.search.ISearchService;\r
66 import org.simantics.workbench.search.QueryResult;\r
67 import org.simantics.workbench.search.SearchEngine;\r
68 import org.simantics.workbench.search.SearchQuery;\r
69 import org.simantics.workbench.search.SearchResult;\r
70 import org.simantics.workbench.search.Searching;\r
71 \r
72 import freemarker.template.TemplateException;\r
73 \r
74 /**\r
75  * @author Tuukka Lehtonen\r
76  * @author Marko Luukkainen\r
77  */\r
78 public class SearchServiceImpl implements ISearchService{\r
79 \r
80         private static final String SEARCH_TEMP_FILE_SUFFIX = "search.html";\r
81         private static final String SEARCH_TEMP_DIR = "search";\r
82         private static final String        BROWSER_VIEW = BrowserView.ID;\r
83         private static final Integer       MAX_RESULTS = 1000;\r
84 \r
85         @Override\r
86         public void performQuery(SearchQuery query, ResultBrowser browserType, boolean activateResultBrowser) {\r
87                 try {\r
88                         Set<SearchEngine> searchEngines = getSearchEngines();\r
89                         \r
90                         // if query does not define used engines, use all available engines.\r
91                         boolean containsEngines = false;\r
92                         for (SearchEngine e : searchEngines) {\r
93                                 if (query.getSearchFlags().containsKey(e.getId())) {\r
94                                         containsEngines = true;\r
95                                         break;\r
96                                 }\r
97                         }\r
98                         if (!containsEngines) {\r
99                                 for (SearchEngine e : searchEngines)\r
100                                         if (e.isEnabledByDefault())\r
101                                                 query.setSearchFlag(e.getId(), "on");\r
102                         }\r
103                 } catch (DatabaseException e) {\r
104                         ExceptionUtils.logError(e);\r
105                 }\r
106         switch (browserType) {\r
107             case EDITOR:\r
108                 performEditorQuery(query);\r
109                 break;\r
110             case VIEW:\r
111                 performViewQuery(query, activateResultBrowser);\r
112                 break;\r
113         }\r
114                 \r
115         }\r
116 \r
117          private void performViewQuery(SearchQuery query, boolean activateResultBrowser) {\r
118                 try {\r
119                     browserView = (BrowserView) showLocalView(\r
120                             BROWSER_VIEW,\r
121                             activateResultBrowser ? IWorkbenchPage.VIEW_ACTIVATE : IWorkbenchPage.VIEW_CREATE);\r
122                     if (browserView.getBrowser() != browserViewBrowser) {\r
123                         browserViewBrowser = browserView.getBrowser();\r
124                         browserViewTemporaryFiles = new ArrayList<File>();\r
125                         browserViewTemporaryFiles.add(getNewTemporaryFile());\r
126                         browserView.getBrowser().addLocationListener(browserViewLocationListener);\r
127                         browserView.getBrowser().addDisposeListener(new DisposeListener() {\r
128                             @Override\r
129                             public void widgetDisposed(DisposeEvent e) {\r
130                                 browserViewBrowser = null;\r
131                             }\r
132                         });\r
133                     }\r
134                     browserView.setPartProperty(BrowserView.LAST_QUERY_PROPERTY, query.getOriginalQuery());\r
135                     updateViewQuery(browserView, browserViewTemporaryFiles, query);\r
136                 } catch (IOException e1) {\r
137                     ErrorLogger.defaultLogError(e1);\r
138                 } catch (PartInitException e1) {\r
139                     ErrorLogger.defaultLogError(e1);\r
140                 }\r
141             }\r
142 \r
143     private IViewPart showLocalView(String id, int mode) throws PartInitException {\r
144         final IWorkbenchWindow wb = PlatformUI.getWorkbench().getActiveWorkbenchWindow();\r
145         if (wb == null)\r
146             return null;\r
147 \r
148         // Is view already created in the currently active workbench window?\r
149         IViewPart vp = findViewFromWindow(wb, id, false);\r
150         if (vp != null) {\r
151             if (mode == IWorkbenchPage.VIEW_CREATE)\r
152                 return vp;\r
153             IWorkbenchPage page = vp.getViewSite().getPage();\r
154             if (mode == IWorkbenchPage.VIEW_VISIBLE) {\r
155                 page.bringToTop(vp);\r
156             } else if (mode == IWorkbenchPage.VIEW_ACTIVATE) {\r
157                 page.activate(vp);\r
158             }\r
159             return vp;\r
160         }\r
161 \r
162         // Create the view on the active window's active page\r
163         IWorkbenchPage page = wb.getActivePage();\r
164         if (page == null) {\r
165             IWorkbenchPage pages[] = wb.getPages();\r
166             if (pages.length == 0) return null;\r
167             page = pages[0];\r
168         }\r
169         return page.showView(id, null, mode);\r
170     }\r
171 \r
172     private static IViewPart findViewFromWindow(IWorkbenchWindow wb, String viewId, boolean restore) {\r
173         for (IWorkbenchPage page : wb.getPages()) {\r
174             IViewReference vr = page.findViewReference(viewId);\r
175             if (vr != null) {\r
176                 IViewPart vp = vr.getView(restore);\r
177                 if (vp != null)\r
178                     return vp;\r
179             }\r
180         }\r
181         return null;\r
182     }\r
183 \r
184         /**\r
185              * There's always only one of these around.\r
186              */\r
187             BrowserView                     browserView                 = null;\r
188 \r
189             org.eclipse.swt.browser.Browser browserViewBrowser          = null;\r
190 \r
191             List<File>                      browserViewTemporaryFiles    = null;\r
192 \r
193             LocationListener                browserViewLocationListener = new LocationListener() {\r
194                 @Override\r
195                 public void changing(LocationEvent event) {\r
196                     //System.out.println("changing: " + event);\r
197                     try {\r
198                         URI newUri = new URI(event.location);\r
199 \r
200                         // Handle resource links by opening an editor for them\r
201                         if ("resource".equals(newUri.getScheme())) {\r
202                             event.doit = false;\r
203                             openResource(getShell(event), newUri.getSchemeSpecificPart());\r
204                             return;\r
205                         }\r
206                     } catch (URISyntaxException e) {\r
207                         // This URI was not needed anyway, resource: URIs will always parse properly so let\r
208                         // it go without logging.\r
209                     } catch (DatabaseException e) {\r
210                         ErrorLogger.defaultLogError(e);\r
211                     }\r
212                 }\r
213 \r
214                 @Override\r
215                 public void changed(LocationEvent event) {\r
216                     // System.out.println("changed: " + event);\r
217                     try {\r
218                         URL newUrl = new URL(event.location);\r
219                         String query = newUrl.getQuery();\r
220                         if (query != null) {\r
221                                 SearchQuery searchQuery = SearchQuery.decode(newUrl);\r
222                                 if (searchQuery.getOriginalQuery() != null) {\r
223                                     event.doit = updateViewQuery(\r
224                                             browserView,\r
225                                             browserViewTemporaryFiles,\r
226                                             searchQuery);\r
227                                 \r
228                             }\r
229                         }\r
230                     } catch (IOException e) {\r
231                         ErrorLogger.defaultLogError(e);\r
232                     }\r
233                 }\r
234             };\r
235 \r
236             class ViewQueryJob extends Job {\r
237 \r
238                 SearchQuery      query;\r
239 \r
240                 List<File>        temporaryFiles;\r
241 \r
242                 BrowserView browserView;\r
243 \r
244                 Display     display;\r
245 \r
246                 public ViewQueryJob(SearchQuery query, List<File> temporaryFiles, BrowserView browserView) {\r
247                     super("Search...");\r
248                     this.query = query;\r
249                     this.temporaryFiles = temporaryFiles;\r
250                     this.browserView = browserView;\r
251                     this.display = browserView.getBrowser().getDisplay();\r
252                 }\r
253 \r
254                 @Override\r
255                 protected IStatus run(IProgressMonitor monitor) {\r
256                     try {\r
257                         SubMonitor mon = SubMonitor.convert(monitor);\r
258                         monitor.beginTask("Performing search '" + query + "'", 10);\r
259                         monitor.subTask("Querying index");\r
260                         final List<QueryResult> result = createResultPage(mon.newChild(8), query, MAX_RESULTS);\r
261                         if (result == null) {\r
262                             return Status.CANCEL_STATUS;\r
263                         }\r
264                         monitor.worked(8);\r
265                         monitor.subTask("Generating results");\r
266                         updatePages(result, temporaryFiles);\r
267                         monitor.worked(2);\r
268                         updateBrowser(browserView, result.get(0));\r
269                         return Status.OK_STATUS;\r
270                     } catch (DatabaseException e1) {\r
271                         return new Status(IStatus.ERROR, Activator.PLUGIN_ID,\r
272                                 "Unexpected database problems during search result processing, see exception.", e1);\r
273                     } catch (IOException e1) {\r
274                         return new Status(IStatus.ERROR, Activator.PLUGIN_ID,\r
275                                 "Unexpected I/O problems during search result processing, see exception.", e1);\r
276                     } finally {\r
277                         monitor.done();\r
278                     }\r
279                 }\r
280 \r
281                 void updateBrowser(final BrowserView browserView, final QueryResult result) {\r
282                     if (display.isDisposed())\r
283                         return;\r
284                     display.asyncExec(new Runnable() {\r
285                         @Override\r
286                         public void run() {\r
287                             if (browserView.isDisposed())\r
288                                 return;\r
289 \r
290                             try {\r
291                                 long t1 = System.currentTimeMillis();\r
292                                 browserView.setUrl(temporaryFiles.get(0).toURI().toURL());\r
293                                 //browserView.setContentDescription("'" + query + "' - " + result.getHitCount() + " matches in active model");\r
294                                 long t2 = System.currentTimeMillis();\r
295                                 System.out.println("Updating UI " + (t2-t1) + " ms");\r
296                             } catch (MalformedURLException e) {\r
297                                 ErrorLogger.defaultLogError(e);\r
298                             }\r
299                         }\r
300                     });\r
301                 }\r
302             }\r
303 \r
304             protected boolean updateViewQuery(BrowserView browserView, List<File> temporaryFiles, SearchQuery query) {\r
305                 ViewQueryJob job = new ViewQueryJob(query, temporaryFiles, browserView);\r
306                 job.setRule(new ObjectIdentitySchedulingRule(browserView));\r
307                 job.schedule();\r
308                 return true;\r
309             }\r
310 \r
311             protected Shell getShell(LocationEvent event) {\r
312                 if (event.widget instanceof Control) {\r
313                     Control c = (Control) event.widget;\r
314                     if (c.isDisposed())\r
315                         return null;\r
316                     return c.getShell();\r
317                 }\r
318                 return null;\r
319             }\r
320 \r
321             /**\r
322              * @param query\r
323              */\r
324             protected void performEditorQuery(final SearchQuery query) {\r
325                 try {\r
326                     final List<File> temporaryFiles = new ArrayList<File>();\r
327                     temporaryFiles.add(getNewTemporaryFile());\r
328                     final BrowserInput input = createBrowserInput(temporaryFiles.get(0), query);\r
329                     updateInput(input, temporaryFiles.get(0), query);\r
330 \r
331                     final Browser browser = (Browser) WorkbenchUtils.openEditor("org.simantics.editors.browser", input);\r
332 \r
333                     browser.getBrowser().addLocationListener(new LocationListener() {\r
334                         @Override\r
335                         public void changing(LocationEvent event) {\r
336                             // System.out.println("changing: " + event);\r
337                             try {\r
338                                 // TODO : is there a better way to escape location?\r
339                                 URI newUri = new URI(event.location.replaceAll(" ", "%20"));\r
340                                 // Handle resource links by opening an editor for them\r
341                                 if ("resource".equals(newUri.getScheme())) {\r
342                                     event.doit = false;\r
343                                     openResource(getShell(event), newUri.getSchemeSpecificPart());\r
344                                     return;\r
345                                 }\r
346                             } catch (URISyntaxException e) {\r
347                                 ErrorLogger.defaultLogError(e);\r
348                             } catch (DatabaseException e) {\r
349                                 ErrorLogger.defaultLogError(e);\r
350                             }\r
351                         }\r
352 \r
353                         @Override\r
354                         public void changed(LocationEvent event) {\r
355                             if (query != null) {\r
356                                 // OpenEditor does not seem to pass any parameters (anything after '?' character) \r
357                                 SearchQuery searchQuery = query;\r
358                                 if (searchQuery.getOriginalQuery() != null) {\r
359                                     event.doit = updateQuery(browser, input, temporaryFiles, searchQuery);\r
360                                 }\r
361                             }\r
362                         }\r
363                     });\r
364                 } catch (IOException e1) {\r
365                     ErrorLogger.defaultLogError(e1);\r
366                 } catch (PartInitException e1) {\r
367                     ErrorLogger.defaultLogError(e1);\r
368                 }\r
369             }\r
370 \r
371             protected void openResource(Shell shell, String link) throws DatabaseException {\r
372                 try {\r
373                     Session session = Simantics.getSession();\r
374                     final long id = Long.parseLong(link);\r
375 \r
376                     Resource resource = session.syncRequest(new Read<Resource>() {\r
377                         @Override\r
378                         public Resource perform(ReadGraph graph) throws DatabaseException {\r
379                             SerialisationSupport ss = graph.getService(SerialisationSupport.class);\r
380                             return ss.getResource(id);\r
381                         }\r
382                     });\r
383 \r
384                     ISelection input = new StructuredSelection(resource);\r
385                     String perspectiveId = WorkbenchUtils.getCurrentPerspectiveId();\r
386 \r
387                     // Try the doubleClick-extensions\r
388                     session.asyncRequest(new ChooseActionRequest(shell, input, perspectiveId, false, true));\r
389                 } catch (NumberFormatException e) {\r
390                     return;\r
391                 }\r
392             }\r
393 \r
394             /**\r
395              * @param query\r
396              */\r
397             protected static boolean updateQuery(Browser browser, BrowserInput input, List<File> temporaryFiles, final SearchQuery query) {\r
398                 try {\r
399                     String url = browser.getBrowser().getUrl();\r
400                     String inputUrl = input.getUrl().toString();\r
401                     if (url.equals(inputUrl))\r
402                         return false;\r
403 \r
404                     List<QueryResult> result = createResultPage(new NullProgressMonitor(), query, MAX_RESULTS);\r
405                     updateInput(input, temporaryFiles.get(0), query);\r
406                     updatePages(result,temporaryFiles);\r
407                     // browser.getBrowser().setUrl(inputUrl);\r
408                     browser.getBrowser().refresh();\r
409                     // temporaryFile.delete();\r
410                     for (File temporaryFile : temporaryFiles)\r
411                         temporaryFile.deleteOnExit();\r
412                     return true;\r
413                 } catch (DatabaseException e1) {\r
414                     ErrorLogger.defaultLogError(e1);\r
415                 } catch (IOException e1) {\r
416                     ErrorLogger.defaultLogError(e1);\r
417                 }\r
418                 return false;\r
419             }\r
420 \r
421             private static File ensureTemporaryDirectoryExists() throws IOException {\r
422                 return Simantics.getTemporaryDirectory(SEARCH_TEMP_DIR); \r
423             }\r
424 \r
425             /**\r
426              * @param html\r
427              * @return\r
428              * @throws IOException\r
429              */\r
430             private static File getNewTemporaryFile() throws IOException {\r
431                 return Simantics.getTempfile(SEARCH_TEMP_DIR, SEARCH_TEMP_FILE_SUFFIX); \r
432             }\r
433 \r
434             /**\r
435              * @param query\r
436              * @param html\r
437              * @return\r
438              * @throws IOException\r
439              */\r
440             private static BrowserInput createBrowserInput(File file, SearchQuery query) throws IOException {\r
441                 // new BrowserInput(file.toURI().toURL()\r
442                 return new BrowserInput(SearchQuery.encode(file, query), query.getOriginalQuery(), false, false, SWT.NONE);\r
443             }\r
444             \r
445             private static void updatePages(List<QueryResult> result, List<File> temporaryFiles) throws IOException{\r
446                 ensureTemporaryDirectoryExists();\r
447                 for (int i = temporaryFiles.size(); i < result.size(); i++) {\r
448                         temporaryFiles.add(getNewTemporaryFile());\r
449                 }\r
450                 if (result.size() > 1) {\r
451                         createPageControls(result,temporaryFiles);\r
452                 }\r
453                 if (result.size() > 0) {\r
454                         for (int i = 0; i < result.size(); i++) {\r
455                                 updatePage(temporaryFiles.get(i), result.get(i).getHtml());\r
456                         }\r
457                 } else {\r
458                         updatePage(temporaryFiles.get(0), "");\r
459                 }\r
460             }\r
461 \r
462             /**\r
463              * @param html\r
464              * @return\r
465              * @throws IOException\r
466              */\r
467             private static void updatePage(File file, String html) throws IOException {\r
468                 long t1 = System.currentTimeMillis();\r
469                 FileUtils.writeFile(file, html.getBytes("UTF-8"));\r
470                 long t2 = System.currentTimeMillis();\r
471                 System.out.println("Writing html page took " + (t2-t1) + " ms");\r
472             }\r
473             \r
474             private static void createPageControls(List<QueryResult> result, List<File> temporaryFiles) throws IOException{\r
475                 if (result.size() == 1)\r
476                         return;\r
477                 for (int i = 0; i < result.size(); i++) {\r
478                         boolean first = i == 0;\r
479                         boolean last = i == result.size() -1;\r
480                         QueryResult current = result.get(i);\r
481                         String pageContrtol = "<div class=\"resultInfo\">";\r
482                         pageContrtol += "Page " + (i+1) + " of "+ + result.size() + " ";\r
483                         if (first) {\r
484                                 pageContrtol += "First";\r
485                                 pageContrtol += " Previous";\r
486                                 pageContrtol += " <a href=\"" + temporaryFiles.get(i+1).toURI().toURL().toString() + "\">Next</a>";\r
487                                 pageContrtol += " <a href=\"" + temporaryFiles.get(result.size()-1).toURI().toURL().toString() + "\">Last</a>";\r
488                         } else if (last) {\r
489                                 pageContrtol += "<a href=\"" + temporaryFiles.get(0).toURI().toURL().toString() + "\">First</a>";\r
490                                 pageContrtol += " <a href=\"" + temporaryFiles.get(i-1).toURI().toURL().toString() + "\">Previous</a>";\r
491                                 pageContrtol += " Next";\r
492                                 pageContrtol += " Last";\r
493                         } else {\r
494                                 pageContrtol += "<a href=\"" + temporaryFiles.get(0).toURI().toURL().toString() + "\">First</a>";\r
495                                 pageContrtol += " <a href=\"" + temporaryFiles.get(i-1).toURI().toURL().toString() + "\">Previous</a>";\r
496                                 pageContrtol += " <a href=\"" + temporaryFiles.get(i+1).toURI().toURL().toString() + "\">Next</a>";\r
497                                 pageContrtol += " <a href=\"" + temporaryFiles.get(result.size()-1).toURI().toURL().toString() + "\">Last</a>";\r
498                         }\r
499                         pageContrtol += "</div><br>";\r
500                         \r
501                         result.set(i, new QueryResult(current.getHeader(), pageContrtol+current.getContent()+pageContrtol,current.getFooter(),current.getHitCount()));\r
502                 }\r
503                 \r
504             }\r
505             \r
506             \r
507 \r
508             /**\r
509              * @param html\r
510              * @return\r
511              * @throws IOException\r
512              */\r
513             private static void updateInput(BrowserInput input, File file, SearchQuery query) throws IOException {\r
514                 URL url = SearchQuery.encode(file, query);\r
515                 input.setUrl(url);\r
516                 input.setName(query.getOriginalQuery());\r
517                 // System.out.println("update input: " + url + " - " + query + " - " + input);\r
518             }\r
519             \r
520             private static Set<SearchEngine> getSearchEngines() throws DatabaseException{\r
521                   return Simantics.getSession().syncRequest(new Read<Set<SearchEngine>>() {\r
522                           @Override\r
523                         public Set<SearchEngine> perform(ReadGraph graph)\r
524                                         throws DatabaseException {\r
525                                   Resource project = Simantics.peekProjectResource();\r
526                                   if (project == null)\r
527                                           return Collections.emptySet();\r
528                                   return getSearchEngines(graph, project);\r
529                         }\r
530                   });\r
531             }\r
532             \r
533             private static Set<SearchEngine> getSearchEngines(ReadGraph graph, Resource project) throws DatabaseException{\r
534                 Set<SearchEngine> searchEngines = new HashSet<SearchEngine>();\r
535                 Map<Resource, Set<SearchEngine>> result = getSearchEnginesByModel(graph, project);\r
536                 for (Set<SearchEngine> set : result.values())\r
537                         searchEngines.addAll(set);\r
538                 return searchEngines;\r
539             }\r
540             \r
541            \r
542                 private static Map<Resource,Set<SearchEngine>> getSearchEnginesByModel(ReadGraph graph, Resource project) throws DatabaseException{\r
543                 WorkbenchResource WB = WorkbenchResource.getInstance(graph);\r
544                 Layer0 L0 = Layer0.getInstance(graph);\r
545                 Map<Resource, Set<SearchEngine>> result = new HashMap<Resource, Set<SearchEngine>>();\r
546                 Collection<Resource> activeModels = graph.syncRequest(new ActiveModels(project));\r
547                 for (Resource model : activeModels) {\r
548                         Set<SearchEngine> searchEngines = new HashSet<SearchEngine>();\r
549                         \r
550                         List<Resource> searchFunctions = new ArrayList<Resource>();\r
551                     searchFunctions.addAll(graph.getObjects(model, WB.HasWorkbenchSearchFunction));\r
552                     if (searchFunctions.size() == 0) {\r
553                         searchEngines.addAll(findSearchContributions(graph, model));\r
554                     }\r
555                     if (searchFunctions.isEmpty() && searchEngines.isEmpty()) {\r
556                         // TODO : backwards compatibility, to be removed.\r
557                         searchFunctions.addAll(graph.getObjects(project, WB.HasWorkbenchSearchFunction));\r
558                     }\r
559                     if (searchFunctions.isEmpty() && searchEngines.isEmpty())\r
560                         searchFunctions.add( WB.DependenciesSearchFunction);\r
561 \r
562                     for (Resource searchFunction : searchFunctions) {\r
563                         @SuppressWarnings("rawtypes")\r
564                         Function f = graph.adapt(searchFunction, Function.class);\r
565                         String id = graph.getURI(searchFunction);\r
566                         String name = graph.getPossibleRelatedValue2(searchFunction, L0.HasLabel);\r
567                         @SuppressWarnings("unchecked")\r
568                         SearchEngine engine = new SearchEngine(id,name,(Function5<IProgressMonitor, ReadGraph, Resource, SearchQuery, Integer, SearchResult>)f, true);\r
569                         {\r
570                                 engine.addSupportedParam("Name");\r
571                                 engine.addSupportedParam("Types");\r
572                         }\r
573                         searchEngines.add(engine);\r
574                     }\r
575                     result.put(model, searchEngines);\r
576                 }\r
577                 return result;\r
578             }\r
579             \r
580 \r
581             /**\r
582              * @param subMonitor \r
583              * @param query\r
584              * @param maxResults\r
585              * @return\r
586              * @throws DatabaseException\r
587              */\r
588             private static List<QueryResult> createResultPage(final IProgressMonitor monitor, final SearchQuery query, final int maxResults) throws DatabaseException {\r
589                 return Simantics.getSession().syncRequest(new Read<List<QueryResult>>() {\r
590                                 @Override\r
591                     public List<QueryResult> perform(ReadGraph graph) throws DatabaseException {\r
592                         Resource project = Simantics.peekProjectResource();\r
593                         if (project == null)\r
594                             return null;\r
595 \r
596                         Collection<Resource> activeModels = graph.syncRequest(new ActiveModels(project));\r
597                         //if (activeModels.isEmpty())\r
598                         //    return null;\r
599                         long t1 = System.currentTimeMillis();\r
600                         Set<SearchEngine> searchEngines = new HashSet<SearchEngine>();\r
601                         MapList<Resource, Pair<SearchEngine,SearchResult>> searchResults = new MapList<Resource, Pair<SearchEngine,SearchResult>>();\r
602                         Map<Resource,Set<SearchEngine>> searchEngineMap = getSearchEnginesByModel(graph, project);\r
603                         \r
604                         for (Resource model : activeModels) {\r
605                                 for (SearchEngine engine : searchEngineMap.get(model)) {\r
606                   \r
607                                     if (query.getBooleanFlag(engine.getId())) {\r
608                                             SearchResult result = engine.getSearchFunction().apply(monitor, graph, model, query, maxResults);\r
609                                             if (!result.isEmpty()) {\r
610                                                 searchResults.add(model, new Pair<SearchEngine,SearchResult>(engine, result));\r
611                                             }\r
612                                     }\r
613                                     searchEngines.add(engine);\r
614                             }\r
615 //                          searchResults.put(model, result);\r
616                         }\r
617                         long t2 = System.currentTimeMillis();\r
618                         System.out.println("Running search queries took " + (t2-t1) + " ms for query '" + query + "'");\r
619 \r
620                         try {\r
621                             return Searching.generatePage(graph, searchEngines,query, maxResults, searchResults);\r
622                         } catch (IOException e) {\r
623                             Activator.logError("I/O problem while generating search result page.", e);\r
624                         } catch (TemplateException e) {\r
625                             Activator.logError("Template definition problem in search result page generation. Please inform the developers.", e);\r
626                         }\r
627                         return null;\r
628                     }\r
629                 });\r
630             }\r
631 \r
632         private static Collection<SearchEngine> findSearchContributions(ReadGraph graph, Resource model) throws DatabaseException {\r
633                 WorkbenchResource WB = WorkbenchResource.getInstance(graph);\r
634                 Instances contributionFinder = graph.adapt(WB.SearchContribution, Instances.class);\r
635                 Resource index = model;\r
636                 List<SearchEngine> result = new ArrayList<SearchEngine>();\r
637                 for (Resource r : contributionFinder.find(graph, index)) {\r
638                         SearchEngine engine = contributionToEngine(graph, r);\r
639                         if (engine != null)\r
640                                 result.add(engine);\r
641                 }\r
642                 return result;\r
643         }\r
644 \r
645         private static SearchEngine contributionToEngine(ReadGraph graph, Resource searchContribution) throws DatabaseException {\r
646                 Layer0 L0 = Layer0.getInstance(graph);\r
647                 WorkbenchResource WB = WorkbenchResource.getInstance(graph);\r
648 \r
649                 Resource searchFunction = graph.getPossibleObject(searchContribution, WB.hasSearchFunction);\r
650                 if (searchFunction == null)\r
651                         return null;\r
652 \r
653                 @SuppressWarnings("rawtypes")\r
654                 Function f = graph.adapt(searchFunction, Function.class);\r
655                 String id = graph.getURI(searchFunction);\r
656                 String name = graph.getPossibleRelatedValue2(searchFunction, L0.HasLabel);\r
657 \r
658                 Boolean enabledByDefault = graph.getPossibleRelatedValue2(searchContribution, WB.SearchContribution_isEnabledByDefault, Bindings.BOOLEAN);\r
659                 boolean enabled = !Boolean.FALSE.equals(enabledByDefault);\r
660 \r
661                 @SuppressWarnings("unchecked")\r
662                 SearchEngine engine = new SearchEngine(id,name,(Function5<IProgressMonitor, ReadGraph, Resource, SearchQuery, Integer, SearchResult>)f, enabled);\r
663                 {\r
664                         engine.addSupportedParam("Name");\r
665                         engine.addSupportedParam("Types");\r
666                 }\r
667                 return engine;\r
668         }\r
669 \r
670 }\r