]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.workbench/src/org/simantics/workbench/internal/contributions/search/SearchServiceImpl.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.workbench / src / org / simantics / workbench / internal / contributions / search / SearchServiceImpl.java
index 07a9af5daf3c9b34111791b64c7108467ae40607..e0a96ed12c39d62c880743b945bd6a1fecea2738 100644 (file)
-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;
+       }
+
+}