--- /dev/null
+package org.simantics.workbench.internal.contributions.search;\r
+\r
+import java.io.File;\r
+import java.io.IOException;\r
+import java.net.MalformedURLException;\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
+import java.net.URL;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Set;\r
+\r
+import org.eclipse.core.runtime.IProgressMonitor;\r
+import org.eclipse.core.runtime.IStatus;\r
+import org.eclipse.core.runtime.NullProgressMonitor;\r
+import org.eclipse.core.runtime.Status;\r
+import org.eclipse.core.runtime.SubMonitor;\r
+import org.eclipse.core.runtime.jobs.Job;\r
+import org.eclipse.jface.viewers.ISelection;\r
+import org.eclipse.jface.viewers.StructuredSelection;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.browser.LocationEvent;\r
+import org.eclipse.swt.browser.LocationListener;\r
+import org.eclipse.swt.events.DisposeEvent;\r
+import org.eclipse.swt.events.DisposeListener;\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.IViewPart;\r
+import org.eclipse.ui.IViewReference;\r
+import org.eclipse.ui.IWorkbenchPage;\r
+import org.eclipse.ui.IWorkbenchWindow;\r
+import org.eclipse.ui.PartInitException;\r
+import org.eclipse.ui.PlatformUI;\r
+import org.simantics.ObjectIdentitySchedulingRule;\r
+import org.simantics.Simantics;\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.adapter.Instances;\r
+import org.simantics.db.layer0.request.ActiveModels;\r
+import org.simantics.db.request.Read;\r
+import org.simantics.db.service.SerialisationSupport;\r
+import org.simantics.editors.Browser;\r
+import org.simantics.editors.BrowserInput;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.scl.runtime.function.Function;\r
+import org.simantics.scl.runtime.function.Function5;\r
+import org.simantics.ui.workbench.action.ChooseActionRequest;\r
+import org.simantics.utils.FileUtils;\r
+import org.simantics.utils.datastructures.MapList;\r
+import org.simantics.utils.datastructures.Pair;\r
+import org.simantics.utils.ui.ErrorLogger;\r
+import org.simantics.utils.ui.ExceptionUtils;\r
+import org.simantics.utils.ui.workbench.WorkbenchUtils;\r
+import org.simantics.workbench.internal.Activator;\r
+import org.simantics.workbench.ontology.WorkbenchResource;\r
+import org.simantics.workbench.search.ISearchService;\r
+import org.simantics.workbench.search.QueryResult;\r
+import org.simantics.workbench.search.SearchEngine;\r
+import org.simantics.workbench.search.SearchQuery;\r
+import org.simantics.workbench.search.SearchResult;\r
+import org.simantics.workbench.search.Searching;\r
+\r
+import freemarker.template.TemplateException;\r
+\r
+/**\r
+ * @author Tuukka Lehtonen\r
+ * @author Marko Luukkainen\r
+ */\r
+public class SearchServiceImpl implements ISearchService{\r
+\r
+ private static final String SEARCH_TEMP_FILE_SUFFIX = "search.html";\r
+ private static final String SEARCH_TEMP_DIR = "search";\r
+ private static final String BROWSER_VIEW = BrowserView.ID;\r
+ private static final Integer MAX_RESULTS = 1000;\r
+\r
+ @Override\r
+ public void performQuery(SearchQuery query, ResultBrowser browserType, boolean activateResultBrowser) {\r
+ try {\r
+ Set<SearchEngine> searchEngines = getSearchEngines();\r
+ \r
+ // if query does not define used engines, use all available engines.\r
+ boolean containsEngines = false;\r
+ for (SearchEngine e : searchEngines) {\r
+ if (query.getSearchFlags().containsKey(e.getId())) {\r
+ containsEngines = true;\r
+ break;\r
+ }\r
+ }\r
+ if (!containsEngines) {\r
+ for (SearchEngine e : searchEngines)\r
+ if (e.isEnabledByDefault())\r
+ query.setSearchFlag(e.getId(), "on");\r
+ }\r
+ } catch (DatabaseException e) {\r
+ ExceptionUtils.logError(e);\r
+ }\r
+ switch (browserType) {\r
+ case EDITOR:\r
+ performEditorQuery(query);\r
+ break;\r
+ case VIEW:\r
+ performViewQuery(query, activateResultBrowser);\r
+ break;\r
+ }\r
+ \r
+ }\r
+\r
+ private void performViewQuery(SearchQuery query, boolean activateResultBrowser) {\r
+ try {\r
+ browserView = (BrowserView) showLocalView(\r
+ BROWSER_VIEW,\r
+ activateResultBrowser ? IWorkbenchPage.VIEW_ACTIVATE : IWorkbenchPage.VIEW_CREATE);\r
+ if (browserView.getBrowser() != browserViewBrowser) {\r
+ browserViewBrowser = browserView.getBrowser();\r
+ browserViewTemporaryFiles = new ArrayList<File>();\r
+ browserViewTemporaryFiles.add(getNewTemporaryFile());\r
+ browserView.getBrowser().addLocationListener(browserViewLocationListener);\r
+ browserView.getBrowser().addDisposeListener(new DisposeListener() {\r
+ @Override\r
+ public void widgetDisposed(DisposeEvent e) {\r
+ browserViewBrowser = null;\r
+ }\r
+ });\r
+ }\r
+ browserView.setPartProperty(BrowserView.LAST_QUERY_PROPERTY, query.getOriginalQuery());\r
+ updateViewQuery(browserView, browserViewTemporaryFiles, query);\r
+ } catch (IOException e1) {\r
+ ErrorLogger.defaultLogError(e1);\r
+ } catch (PartInitException e1) {\r
+ ErrorLogger.defaultLogError(e1);\r
+ }\r
+ }\r
+\r
+ private IViewPart showLocalView(String id, int mode) throws PartInitException {\r
+ final IWorkbenchWindow wb = PlatformUI.getWorkbench().getActiveWorkbenchWindow();\r
+ if (wb == null)\r
+ return null;\r
+\r
+ // Is view already created in the currently active workbench window?\r
+ IViewPart vp = findViewFromWindow(wb, id, false);\r
+ if (vp != null) {\r
+ if (mode == IWorkbenchPage.VIEW_CREATE)\r
+ return vp;\r
+ IWorkbenchPage page = vp.getViewSite().getPage();\r
+ if (mode == IWorkbenchPage.VIEW_VISIBLE) {\r
+ page.bringToTop(vp);\r
+ } else if (mode == IWorkbenchPage.VIEW_ACTIVATE) {\r
+ page.activate(vp);\r
+ }\r
+ return vp;\r
+ }\r
+\r
+ // Create the view on the active window's active page\r
+ IWorkbenchPage page = wb.getActivePage();\r
+ if (page == null) {\r
+ IWorkbenchPage pages[] = wb.getPages();\r
+ if (pages.length == 0) return null;\r
+ page = pages[0];\r
+ }\r
+ return page.showView(id, null, mode);\r
+ }\r
+\r
+ private static IViewPart findViewFromWindow(IWorkbenchWindow wb, String viewId, boolean restore) {\r
+ for (IWorkbenchPage page : wb.getPages()) {\r
+ IViewReference vr = page.findViewReference(viewId);\r
+ if (vr != null) {\r
+ IViewPart vp = vr.getView(restore);\r
+ if (vp != null)\r
+ return vp;\r
+ }\r
+ }\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * There's always only one of these around.\r
+ */\r
+ BrowserView browserView = null;\r
+\r
+ org.eclipse.swt.browser.Browser browserViewBrowser = null;\r
+\r
+ List<File> browserViewTemporaryFiles = null;\r
+\r
+ LocationListener browserViewLocationListener = new LocationListener() {\r
+ @Override\r
+ public void changing(LocationEvent event) {\r
+ //System.out.println("changing: " + event);\r
+ try {\r
+ URI newUri = new URI(event.location);\r
+\r
+ // Handle resource links by opening an editor for them\r
+ if ("resource".equals(newUri.getScheme())) {\r
+ event.doit = false;\r
+ openResource(getShell(event), newUri.getSchemeSpecificPart());\r
+ return;\r
+ }\r
+ } catch (URISyntaxException e) {\r
+ // This URI was not needed anyway, resource: URIs will always parse properly so let\r
+ // it go without logging.\r
+ } catch (DatabaseException e) {\r
+ ErrorLogger.defaultLogError(e);\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public void changed(LocationEvent event) {\r
+ // System.out.println("changed: " + event);\r
+ try {\r
+ URL newUrl = new URL(event.location);\r
+ String query = newUrl.getQuery();\r
+ if (query != null) {\r
+ SearchQuery searchQuery = SearchQuery.decode(newUrl);\r
+ if (searchQuery.getOriginalQuery() != null) {\r
+ event.doit = updateViewQuery(\r
+ browserView,\r
+ browserViewTemporaryFiles,\r
+ searchQuery);\r
+ \r
+ }\r
+ }\r
+ } catch (IOException e) {\r
+ ErrorLogger.defaultLogError(e);\r
+ }\r
+ }\r
+ };\r
+\r
+ class ViewQueryJob extends Job {\r
+\r
+ SearchQuery query;\r
+\r
+ List<File> temporaryFiles;\r
+\r
+ BrowserView browserView;\r
+\r
+ Display display;\r
+\r
+ public ViewQueryJob(SearchQuery query, List<File> temporaryFiles, BrowserView browserView) {\r
+ super("Search...");\r
+ this.query = query;\r
+ this.temporaryFiles = temporaryFiles;\r
+ this.browserView = browserView;\r
+ this.display = browserView.getBrowser().getDisplay();\r
+ }\r
+\r
+ @Override\r
+ protected IStatus run(IProgressMonitor monitor) {\r
+ try {\r
+ SubMonitor mon = SubMonitor.convert(monitor);\r
+ monitor.beginTask("Performing search '" + query + "'", 10);\r
+ monitor.subTask("Querying index");\r
+ final List<QueryResult> result = createResultPage(mon.newChild(8), query, MAX_RESULTS);\r
+ if (result == null) {\r
+ return Status.CANCEL_STATUS;\r
+ }\r
+ monitor.worked(8);\r
+ monitor.subTask("Generating results");\r
+ updatePages(result, temporaryFiles);\r
+ monitor.worked(2);\r
+ updateBrowser(browserView, result.get(0));\r
+ return Status.OK_STATUS;\r
+ } catch (DatabaseException e1) {\r
+ return new Status(IStatus.ERROR, Activator.PLUGIN_ID,\r
+ "Unexpected database problems during search result processing, see exception.", e1);\r
+ } catch (IOException e1) {\r
+ return new Status(IStatus.ERROR, Activator.PLUGIN_ID,\r
+ "Unexpected I/O problems during search result processing, see exception.", e1);\r
+ } finally {\r
+ monitor.done();\r
+ }\r
+ }\r
+\r
+ void updateBrowser(final BrowserView browserView, final QueryResult result) {\r
+ if (display.isDisposed())\r
+ return;\r
+ display.asyncExec(new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ if (browserView.isDisposed())\r
+ return;\r
+\r
+ try {\r
+ long t1 = System.currentTimeMillis();\r
+ browserView.setUrl(temporaryFiles.get(0).toURI().toURL());\r
+ //browserView.setContentDescription("'" + query + "' - " + result.getHitCount() + " matches in active model");\r
+ long t2 = System.currentTimeMillis();\r
+ System.out.println("Updating UI " + (t2-t1) + " ms");\r
+ } catch (MalformedURLException e) {\r
+ ErrorLogger.defaultLogError(e);\r
+ }\r
+ }\r
+ });\r
+ }\r
+ }\r
+\r
+ protected boolean updateViewQuery(BrowserView browserView, List<File> temporaryFiles, SearchQuery query) {\r
+ ViewQueryJob job = new ViewQueryJob(query, temporaryFiles, browserView);\r
+ job.setRule(new ObjectIdentitySchedulingRule(browserView));\r
+ job.schedule();\r
+ return true;\r
+ }\r
+\r
+ protected Shell getShell(LocationEvent event) {\r
+ if (event.widget instanceof Control) {\r
+ Control c = (Control) event.widget;\r
+ if (c.isDisposed())\r
+ return null;\r
+ return c.getShell();\r
+ }\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * @param query\r
+ */\r
+ protected void performEditorQuery(final SearchQuery query) {\r
+ try {\r
+ final List<File> temporaryFiles = new ArrayList<File>();\r
+ temporaryFiles.add(getNewTemporaryFile());\r
+ final BrowserInput input = createBrowserInput(temporaryFiles.get(0), query);\r
+ updateInput(input, temporaryFiles.get(0), query);\r
+\r
+ final Browser browser = (Browser) WorkbenchUtils.openEditor("org.simantics.editors.browser", input);\r
+\r
+ browser.getBrowser().addLocationListener(new LocationListener() {\r
+ @Override\r
+ public void changing(LocationEvent event) {\r
+ // System.out.println("changing: " + event);\r
+ try {\r
+ // TODO : is there a better way to escape location?\r
+ URI newUri = new URI(event.location.replaceAll(" ", "%20"));\r
+ // Handle resource links by opening an editor for them\r
+ if ("resource".equals(newUri.getScheme())) {\r
+ event.doit = false;\r
+ openResource(getShell(event), newUri.getSchemeSpecificPart());\r
+ return;\r
+ }\r
+ } catch (URISyntaxException e) {\r
+ ErrorLogger.defaultLogError(e);\r
+ } catch (DatabaseException e) {\r
+ ErrorLogger.defaultLogError(e);\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public void changed(LocationEvent event) {\r
+ if (query != null) {\r
+ // OpenEditor does not seem to pass any parameters (anything after '?' character) \r
+ SearchQuery searchQuery = query;\r
+ if (searchQuery.getOriginalQuery() != null) {\r
+ event.doit = updateQuery(browser, input, temporaryFiles, searchQuery);\r
+ }\r
+ }\r
+ }\r
+ });\r
+ } catch (IOException e1) {\r
+ ErrorLogger.defaultLogError(e1);\r
+ } catch (PartInitException e1) {\r
+ ErrorLogger.defaultLogError(e1);\r
+ }\r
+ }\r
+\r
+ protected void openResource(Shell shell, String link) throws DatabaseException {\r
+ try {\r
+ Session session = Simantics.getSession();\r
+ final long id = Long.parseLong(link);\r
+\r
+ Resource resource = session.syncRequest(new Read<Resource>() {\r
+ @Override\r
+ public Resource perform(ReadGraph graph) throws DatabaseException {\r
+ SerialisationSupport ss = graph.getService(SerialisationSupport.class);\r
+ return ss.getResource(id);\r
+ }\r
+ });\r
+\r
+ ISelection input = new StructuredSelection(resource);\r
+ String perspectiveId = WorkbenchUtils.getCurrentPerspectiveId();\r
+\r
+ // Try the doubleClick-extensions\r
+ session.asyncRequest(new ChooseActionRequest(shell, input, perspectiveId, false, true));\r
+ } catch (NumberFormatException e) {\r
+ return;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * @param query\r
+ */\r
+ protected static boolean updateQuery(Browser browser, BrowserInput input, List<File> temporaryFiles, final SearchQuery query) {\r
+ try {\r
+ String url = browser.getBrowser().getUrl();\r
+ String inputUrl = input.getUrl().toString();\r
+ if (url.equals(inputUrl))\r
+ return false;\r
+\r
+ List<QueryResult> result = createResultPage(new NullProgressMonitor(), query, MAX_RESULTS);\r
+ updateInput(input, temporaryFiles.get(0), query);\r
+ updatePages(result,temporaryFiles);\r
+ // browser.getBrowser().setUrl(inputUrl);\r
+ browser.getBrowser().refresh();\r
+ // temporaryFile.delete();\r
+ for (File temporaryFile : temporaryFiles)\r
+ temporaryFile.deleteOnExit();\r
+ return true;\r
+ } catch (DatabaseException e1) {\r
+ ErrorLogger.defaultLogError(e1);\r
+ } catch (IOException e1) {\r
+ ErrorLogger.defaultLogError(e1);\r
+ }\r
+ return false;\r
+ }\r
+\r
+ private static File ensureTemporaryDirectoryExists() throws IOException {\r
+ return Simantics.getTemporaryDirectory(SEARCH_TEMP_DIR); \r
+ }\r
+\r
+ /**\r
+ * @param html\r
+ * @return\r
+ * @throws IOException\r
+ */\r
+ private static File getNewTemporaryFile() throws IOException {\r
+ return Simantics.getTempfile(SEARCH_TEMP_DIR, SEARCH_TEMP_FILE_SUFFIX); \r
+ }\r
+\r
+ /**\r
+ * @param query\r
+ * @param html\r
+ * @return\r
+ * @throws IOException\r
+ */\r
+ private static BrowserInput createBrowserInput(File file, SearchQuery query) throws IOException {\r
+ // new BrowserInput(file.toURI().toURL()\r
+ return new BrowserInput(SearchQuery.encode(file, query), query.getOriginalQuery(), false, false, SWT.NONE);\r
+ }\r
+ \r
+ private static void updatePages(List<QueryResult> result, List<File> temporaryFiles) throws IOException{\r
+ ensureTemporaryDirectoryExists();\r
+ for (int i = temporaryFiles.size(); i < result.size(); i++) {\r
+ temporaryFiles.add(getNewTemporaryFile());\r
+ }\r
+ if (result.size() > 1) {\r
+ createPageControls(result,temporaryFiles);\r
+ }\r
+ if (result.size() > 0) {\r
+ for (int i = 0; i < result.size(); i++) {\r
+ updatePage(temporaryFiles.get(i), result.get(i).getHtml());\r
+ }\r
+ } else {\r
+ updatePage(temporaryFiles.get(0), "");\r
+ }\r
+ }\r
+\r
+ /**\r
+ * @param html\r
+ * @return\r
+ * @throws IOException\r
+ */\r
+ private static void updatePage(File file, String html) throws IOException {\r
+ long t1 = System.currentTimeMillis();\r
+ FileUtils.writeFile(file, html.getBytes("UTF-8"));\r
+ long t2 = System.currentTimeMillis();\r
+ System.out.println("Writing html page took " + (t2-t1) + " ms");\r
+ }\r
+ \r
+ private static void createPageControls(List<QueryResult> result, List<File> temporaryFiles) throws IOException{\r
+ if (result.size() == 1)\r
+ return;\r
+ for (int i = 0; i < result.size(); i++) {\r
+ boolean first = i == 0;\r
+ boolean last = i == result.size() -1;\r
+ QueryResult current = result.get(i);\r
+ String pageContrtol = "<div class=\"resultInfo\">";\r
+ pageContrtol += "Page " + (i+1) + " of "+ + result.size() + " ";\r
+ if (first) {\r
+ pageContrtol += "First";\r
+ pageContrtol += " Previous";\r
+ pageContrtol += " <a href=\"" + temporaryFiles.get(i+1).toURI().toURL().toString() + "\">Next</a>";\r
+ pageContrtol += " <a href=\"" + temporaryFiles.get(result.size()-1).toURI().toURL().toString() + "\">Last</a>";\r
+ } else if (last) {\r
+ pageContrtol += "<a href=\"" + temporaryFiles.get(0).toURI().toURL().toString() + "\">First</a>";\r
+ pageContrtol += " <a href=\"" + temporaryFiles.get(i-1).toURI().toURL().toString() + "\">Previous</a>";\r
+ pageContrtol += " Next";\r
+ pageContrtol += " Last";\r
+ } else {\r
+ pageContrtol += "<a href=\"" + temporaryFiles.get(0).toURI().toURL().toString() + "\">First</a>";\r
+ pageContrtol += " <a href=\"" + temporaryFiles.get(i-1).toURI().toURL().toString() + "\">Previous</a>";\r
+ pageContrtol += " <a href=\"" + temporaryFiles.get(i+1).toURI().toURL().toString() + "\">Next</a>";\r
+ pageContrtol += " <a href=\"" + temporaryFiles.get(result.size()-1).toURI().toURL().toString() + "\">Last</a>";\r
+ }\r
+ pageContrtol += "</div><br>";\r
+ \r
+ result.set(i, new QueryResult(current.getHeader(), pageContrtol+current.getContent()+pageContrtol,current.getFooter(),current.getHitCount()));\r
+ }\r
+ \r
+ }\r
+ \r
+ \r
+\r
+ /**\r
+ * @param html\r
+ * @return\r
+ * @throws IOException\r
+ */\r
+ private static void updateInput(BrowserInput input, File file, SearchQuery query) throws IOException {\r
+ URL url = SearchQuery.encode(file, query);\r
+ input.setUrl(url);\r
+ input.setName(query.getOriginalQuery());\r
+ // System.out.println("update input: " + url + " - " + query + " - " + input);\r
+ }\r
+ \r
+ private static Set<SearchEngine> getSearchEngines() throws DatabaseException{\r
+ return Simantics.getSession().syncRequest(new Read<Set<SearchEngine>>() {\r
+ @Override\r
+ public Set<SearchEngine> perform(ReadGraph graph)\r
+ throws DatabaseException {\r
+ Resource project = Simantics.peekProjectResource();\r
+ if (project == null)\r
+ return Collections.emptySet();\r
+ return getSearchEngines(graph, project);\r
+ }\r
+ });\r
+ }\r
+ \r
+ private static Set<SearchEngine> getSearchEngines(ReadGraph graph, Resource project) throws DatabaseException{\r
+ Set<SearchEngine> searchEngines = new HashSet<SearchEngine>();\r
+ Map<Resource, Set<SearchEngine>> result = getSearchEnginesByModel(graph, project);\r
+ for (Set<SearchEngine> set : result.values())\r
+ searchEngines.addAll(set);\r
+ return searchEngines;\r
+ }\r
+ \r
+ \r
+ private static Map<Resource,Set<SearchEngine>> getSearchEnginesByModel(ReadGraph graph, Resource project) throws DatabaseException{\r
+ WorkbenchResource WB = WorkbenchResource.getInstance(graph);\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ Map<Resource, Set<SearchEngine>> result = new HashMap<Resource, Set<SearchEngine>>();\r
+ Collection<Resource> activeModels = graph.syncRequest(new ActiveModels(project));\r
+ for (Resource model : activeModels) {\r
+ Set<SearchEngine> searchEngines = new HashSet<SearchEngine>();\r
+ \r
+ List<Resource> searchFunctions = new ArrayList<Resource>();\r
+ searchFunctions.addAll(graph.getObjects(model, WB.HasWorkbenchSearchFunction));\r
+ if (searchFunctions.size() == 0) {\r
+ searchEngines.addAll(findSearchContributions(graph, model));\r
+ }\r
+ if (searchFunctions.isEmpty() && searchEngines.isEmpty()) {\r
+ // TODO : backwards compatibility, to be removed.\r
+ searchFunctions.addAll(graph.getObjects(project, WB.HasWorkbenchSearchFunction));\r
+ }\r
+ if (searchFunctions.isEmpty() && searchEngines.isEmpty())\r
+ searchFunctions.add( WB.DependenciesSearchFunction);\r
+\r
+ for (Resource searchFunction : searchFunctions) {\r
+ @SuppressWarnings("rawtypes")\r
+ Function f = graph.adapt(searchFunction, Function.class);\r
+ String id = graph.getURI(searchFunction);\r
+ String name = graph.getPossibleRelatedValue2(searchFunction, L0.HasLabel);\r
+ @SuppressWarnings("unchecked")\r
+ SearchEngine engine = new SearchEngine(id,name,(Function5<IProgressMonitor, ReadGraph, Resource, SearchQuery, Integer, SearchResult>)f, true);\r
+ {\r
+ engine.addSupportedParam("Name");\r
+ engine.addSupportedParam("Types");\r
+ }\r
+ searchEngines.add(engine);\r
+ }\r
+ result.put(model, searchEngines);\r
+ }\r
+ return result;\r
+ }\r
+ \r
+\r
+ /**\r
+ * @param subMonitor \r
+ * @param query\r
+ * @param maxResults\r
+ * @return\r
+ * @throws DatabaseException\r
+ */\r
+ private static List<QueryResult> createResultPage(final IProgressMonitor monitor, final SearchQuery query, final int maxResults) throws DatabaseException {\r
+ return Simantics.getSession().syncRequest(new Read<List<QueryResult>>() {\r
+ @Override\r
+ public List<QueryResult> perform(ReadGraph graph) throws DatabaseException {\r
+ Resource project = Simantics.peekProjectResource();\r
+ if (project == null)\r
+ return null;\r
+\r
+ Collection<Resource> activeModels = graph.syncRequest(new ActiveModels(project));\r
+ //if (activeModels.isEmpty())\r
+ // return null;\r
+ long t1 = System.currentTimeMillis();\r
+ Set<SearchEngine> searchEngines = new HashSet<SearchEngine>();\r
+ MapList<Resource, Pair<SearchEngine,SearchResult>> searchResults = new MapList<Resource, Pair<SearchEngine,SearchResult>>();\r
+ Map<Resource,Set<SearchEngine>> searchEngineMap = getSearchEnginesByModel(graph, project);\r
+ \r
+ for (Resource model : activeModels) {\r
+ for (SearchEngine engine : searchEngineMap.get(model)) {\r
+ \r
+ if (query.getBooleanFlag(engine.getId())) {\r
+ SearchResult result = engine.getSearchFunction().apply(monitor, graph, model, query, maxResults);\r
+ if (!result.isEmpty()) {\r
+ searchResults.add(model, new Pair<SearchEngine,SearchResult>(engine, result));\r
+ }\r
+ }\r
+ searchEngines.add(engine);\r
+ }\r
+// searchResults.put(model, result);\r
+ }\r
+ long t2 = System.currentTimeMillis();\r
+ System.out.println("Running search queries took " + (t2-t1) + " ms for query '" + query + "'");\r
+\r
+ try {\r
+ return Searching.generatePage(graph, searchEngines,query, maxResults, searchResults);\r
+ } catch (IOException e) {\r
+ Activator.logError("I/O problem while generating search result page.", e);\r
+ } catch (TemplateException e) {\r
+ Activator.logError("Template definition problem in search result page generation. Please inform the developers.", e);\r
+ }\r
+ return null;\r
+ }\r
+ });\r
+ }\r
+\r
+ private static Collection<SearchEngine> findSearchContributions(ReadGraph graph, Resource model) throws DatabaseException {\r
+ WorkbenchResource WB = WorkbenchResource.getInstance(graph);\r
+ Instances contributionFinder = graph.adapt(WB.SearchContribution, Instances.class);\r
+ Resource index = model;\r
+ List<SearchEngine> result = new ArrayList<SearchEngine>();\r
+ for (Resource r : contributionFinder.find(graph, index)) {\r
+ SearchEngine engine = contributionToEngine(graph, r);\r
+ if (engine != null)\r
+ result.add(engine);\r
+ }\r
+ return result;\r
+ }\r
+\r
+ private static SearchEngine contributionToEngine(ReadGraph graph, Resource searchContribution) throws DatabaseException {\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ WorkbenchResource WB = WorkbenchResource.getInstance(graph);\r
+\r
+ Resource searchFunction = graph.getPossibleObject(searchContribution, WB.hasSearchFunction);\r
+ if (searchFunction == null)\r
+ return null;\r
+\r
+ @SuppressWarnings("rawtypes")\r
+ Function f = graph.adapt(searchFunction, Function.class);\r
+ String id = graph.getURI(searchFunction);\r
+ String name = graph.getPossibleRelatedValue2(searchFunction, L0.HasLabel);\r
+\r
+ Boolean enabledByDefault = graph.getPossibleRelatedValue2(searchContribution, WB.SearchContribution_isEnabledByDefault, Bindings.BOOLEAN);\r
+ boolean enabled = !Boolean.FALSE.equals(enabledByDefault);\r
+\r
+ @SuppressWarnings("unchecked")\r
+ SearchEngine engine = new SearchEngine(id,name,(Function5<IProgressMonitor, ReadGraph, Resource, SearchQuery, Integer, SearchResult>)f, enabled);\r
+ {\r
+ engine.addSupportedParam("Name");\r
+ engine.addSupportedParam("Types");\r
+ }\r
+ return engine;\r
+ }\r
+\r
+}\r