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