Revision: 14684
http://gate.svn.sourceforge.net/gate/?rev=14684&view=rev
Author: valyt
Date: 2011-12-07 14:44:34 +0000 (Wed, 07 Dec 2011)
Log Message:
-----------
- support for displaying documents
- support for paginating results page
- support for history tokens (allows bookmarking search results)
- various CSS fixes.
Modified Paths:
--------------
mimir/trunk/mimir-web/grails-app/controllers/gate/mimir/web/SearchController.groovy
mimir/trunk/mimir-web/grails-app/services/gate/mimir/web/server/GwtRpcService.groovy
mimir/trunk/mimir-web/grails-app/taglib/gate/mimir/web/MimirTagLib.groovy
mimir/trunk/mimir-web/grails-app/views/search/index.gsp
mimir/trunk/mimir-web/src/gwt/gate/mimir/web/client/UI.java
mimir/trunk/mimir-web/src/java/gate/mimir/web/client/GwtRpcService.java
mimir/trunk/mimir-web/src/java/gate/mimir/web/client/GwtRpcServiceAsync.java
mimir/trunk/mimir-web/web-app/css/mimir.css
Added Paths:
-----------
mimir/trunk/mimir-web/grails-app/views/search/document.gsp
mimir/trunk/mimir-web/src/java/gate/mimir/web/client/MimirSearchException.java
Removed Paths:
-------------
mimir/trunk/mimir-web/src/java/gate/mimir/web/client/GwtRpcException.java
Modified:
mimir/trunk/mimir-web/grails-app/controllers/gate/mimir/web/SearchController.groovy
===================================================================
---
mimir/trunk/mimir-web/grails-app/controllers/gate/mimir/web/SearchController.groovy
2011-12-07 14:00:02 UTC (rev 14683)
+++
mimir/trunk/mimir-web/grails-app/controllers/gate/mimir/web/SearchController.groovy
2011-12-07 14:44:34 UTC (rev 14684)
@@ -102,6 +102,29 @@
}
/**
+ * Render the content of the given document. Most of the magic happens in
+ * the documentContent tag of the GusTagLib.
+ */
+ def document = {
+ QueryRunner runner = searchService.getQueryRunner(params.queryId)
+ if(runner){
+ Index index = Index.findByIndexId(params.indexId)
+ return [
+ indexId:params.indexId,
+ documentRank: params.documentRank,
+ queryId:params.queryId,
+ documentTitle:runner.getDocumentTitle(params.documentRank as int),
+ baseHref:index?.isUriIsExternalLink() ?
runner.getDocumentURI(params.documentRank as int) : null
+ ]
+ } else {
+ //query has expired
+ return [
+ queryId:params.queryId
+ ]
+ }
+ }
+
+ /**
* Action that forwards to the real GWT RPC controller.
*/
def gwtRpc = {
Modified:
mimir/trunk/mimir-web/grails-app/services/gate/mimir/web/server/GwtRpcService.groovy
===================================================================
---
mimir/trunk/mimir-web/grails-app/services/gate/mimir/web/server/GwtRpcService.groovy
2011-12-07 14:00:02 UTC (rev 14683)
+++
mimir/trunk/mimir-web/grails-app/services/gate/mimir/web/server/GwtRpcService.groovy
2011-12-07 14:44:34 UTC (rev 14684)
@@ -1,16 +1,16 @@
/**
-* GwtRpcService.java
-*
-* Copyright (c) 1995-2010, The University of Sheffield. See the file
-* COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
-*
-* This file is part of GATE (see http://gate.ac.uk/), and is free
-* software, licenced under the GNU Library General Public License,
-* Version 2, June 1991 (in the distribution as file licence.html,
-* and also available at http://gate.ac.uk/gate/licence.html).
-*
-* Valentin Tablan, 01 Dec 2011
-*/
+ * GwtRpcService.java
+ *
+ * Copyright (c) 1995-2010, The University of Sheffield. See the file
+ * COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
+ *
+ * This file is part of GATE (see http://gate.ac.uk/), and is free
+ * software, licenced under the GNU Library General Public License,
+ * Version 2, June 1991 (in the distribution as file licence.html,
+ * and also available at http://gate.ac.uk/gate/licence.html).
+ *
+ * Valentin Tablan, 01 Dec 2011
+ */
package gate.mimir.web.server
import gate.mimir.gus.client.SearchException;
@@ -26,7 +26,7 @@
import gate.mimir.search.query.Binding;
import gate.mimir.web.Index;
import gate.mimir.web.client.DocumentData;
-import gate.mimir.web.client.GwtRpcException
+import gate.mimir.web.client.MimirSearchException
import gate.mimir.web.client.ResultsData;
import gate.mimir.web.client.DocumentData;
@@ -69,22 +69,22 @@
try {
def index = Index.findByIndexId(indexId)
if(!index) {
- throw new GwtRpcException("Invalid index ID ${indexId}")
+ throw new MimirSearchException("Invalid index ID ${indexId}")
}
else if(index.state != Index.SEARCHING) {
- throw new GwtRpcException("Index ${indexId} is not open for
searching")
+ throw new MimirSearchException("Index ${indexId} is not open for
searching")
}
else {
String queryId = searchService.postQuery(index, query)
runningQueries.add(queryId)
return queryId
}
- } catch(GwtRpcException e) {
+ } catch(MimirSearchException e) {
log.warn("Exception starting search", e)
throw e
} catch(Exception e) {
log.warn("Exception starting search", e)
- throw new GwtRpcException("Could not start search. Error
was:\n${e.message}");
+ throw new MimirSearchException("Could not start search. Error
was:\n${e.message}");
}
}
}
@@ -101,9 +101,9 @@
}
/**
- * Obtains the types of annotation known to the index, and their features.
+ * Obtains the types of annotation known to the index, and their features.
* This method supports auto-completion in the GWT UI.
- */
+ */
String[][] getAnnotationsConfig(String indexId){
Index.withTransaction {
Index index = Index.findByIndexId(indexId)
@@ -111,60 +111,60 @@
return index.annotationsConfig()
}
else {
- return ([] as String[][])
+ return ([]as String[][])
}
}
}
@Override
- public ResultsData getResultsData(String queryId,
- int firstDocumentRank, int documentsCount) throws GwtRpcException {
+ public ResultsData getResultsData(String queryId,
+ int firstDocumentRank, int documentsCount) throws MimirSearchException {
QueryRunner qRunner = searchService.getQueryRunner(queryId);
if(qRunner) {
ResultsData rData = new ResultsData(
- resultsTotal:qRunner.getDocumentsCount(),
- resultsPartial: qRunner.getCurrentDocumentsCount())
+ resultsTotal:qRunner.getDocumentsCount(),
+ resultsPartial: qRunner.getCurrentDocumentsCount())
if(firstDocumentRank >= 0) {
// also obtain some documents data
List<DocumentData> documents = []
- for(int docRank = firstDocumentRank;
- docRank < firstDocumentRank + documentsCount;
- docRank++) {
+ for(int docRank = firstDocumentRank;
+ docRank < firstDocumentRank + documentsCount;
+ docRank++) {
DocumentData docData = new DocumentData(
- documentRank:docRank,
- documentTitle:qRunner.getDocumentTitle(docRank),
- documentUri:qRunner.getDocumentURI(docRank))
+ documentRank:docRank,
+ documentTitle:qRunner.getDocumentTitle(docRank),
+ documentUri:qRunner.getDocumentURI(docRank))
// create the snippets
List<String[]> snippets = new ArrayList<String[]>();
List<Binding> hits = qRunner.getDocumentHits(docRank).collect{it};
- StringBuilder str = new StringBuilder()
3.times {
if(hits) {
String[] snippet = new String[3];
Binding aHit = hits.remove(0)
int termPos = Math.max(0, aHit.termPosition - 3)
if(termPos < aHit.termPosition) {
- String[][] left = qRunner.getDocumentText(docRank, termPos,
- aHit.termPosition - termPos)
- left[0].each { str << (it + ' ') }
- snippet[0] = str.toString()
+ snippet[0] = qRunner.getDocumentText(docRank, termPos,
+ aHit.termPosition - termPos).toList().transpose().inject('')
{
+ acc, val -> acc + val[0] + (val[1] ? ' ' : '')
+ }
} else {
- snippet[0] = "";
+ snippet[0] = '';
}
- str = new StringBuilder()
- qRunner.getDocumentText(docRank, aHit.termPosition,
- aHit.length)[0].each{ str << (it + ' ')}
- snippet[1] = str.toString()
- str = new StringBuilder()
- qRunner.getDocumentText(docRank,
- aHit.termPosition + aHit.length, 3)[0].each{str << (it?:'' + '
')}
- snippet[2] = str.toString()
- snippets << snippet
+ snippet[1] = qRunner.getDocumentText(docRank, aHit.termPosition,
+ aHit.length).toList().transpose().inject('') {
+ acc, val -> acc + val[0] + (val[1] ? ' ' : '')
+ }
+ snippet[2] = qRunner.getDocumentText(docRank,
+ aHit.termPosition + aHit.length, 3).toList().
+ transpose().inject('') {
+ acc, val -> acc + val[0] + (val[1] ? ' ' : '')
+ }
+ snippets << snippet
}
}
if(hits) {
// more than 3 hits: show ellipsis
- snippets.add([" ", "...", " "] as String[])
+ snippets.add([" ", "...", " "]as String[])
}
docData.snippets = snippets
documents.add(docData)
@@ -173,12 +173,11 @@
}
return rData
} else {
- throw new GwtRpcException("Could not find your query. " +
+ throw new MimirSearchException(MimirSearchException.QUERY_ID_NOT_KNOWN,
+ "Could not find your query. " +
"Your search session may have expired, in which case you will need "
+
"to start your search again.")
}
}
-
-
}
Modified:
mimir/trunk/mimir-web/grails-app/taglib/gate/mimir/web/MimirTagLib.groovy
===================================================================
--- mimir/trunk/mimir-web/grails-app/taglib/gate/mimir/web/MimirTagLib.groovy
2011-12-07 14:00:02 UTC (rev 14683)
+++ mimir/trunk/mimir-web/grails-app/taglib/gate/mimir/web/MimirTagLib.groovy
2011-12-07 14:44:34 UTC (rev 14684)
@@ -12,12 +12,24 @@
*/
package gate.mimir.web;
+import gate.mimir.search.QueryRunner;
+
import java.util.Locale;
import java.text.NumberFormat;
-class MimirTagLib {
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+class MimirTagLib implements ApplicationContextAware {
+ /* This is slightly messy - I want to autowire the gusService but taglibs are
+ * singletons and the gusService is session-scoped. So instead I inject the
+ * applicationContext and then fetch the gusService bean from the context at
+ * call time to get the right instance for the current session.
+ */
+ ApplicationContext applicationContext
+
static namespace = "mimir"
/**
@@ -203,4 +215,20 @@
out << "<p><i>Information not available</i></p>\n"
}
}
+
+ def documentContent = { attrs, body ->
+ def queryId = attrs.queryId
+ def documentRank = attrs.documentRank as int
+ try {
+ QueryRunner qRunner =
applicationContext.searchService.getQueryRunner(queryId)
+ if(qRunner) {
+ qRunner.renderDocument(documentRank, out)
+ } else {
+ out << g.message(code:"gus.bad.query.id", args:[queryId])
+ }
+ } catch(Exception ex) {
+ log.error("Exception rendering document ${documentRank}", ex)
+ out << g.message(code:"gus.renderDocument.exception", args:[ex.message])
+ }
+ }
}
Added: mimir/trunk/mimir-web/grails-app/views/search/document.gsp
===================================================================
--- mimir/trunk/mimir-web/grails-app/views/search/document.gsp
(rev 0)
+++ mimir/trunk/mimir-web/grails-app/views/search/document.gsp 2011-12-07
14:44:34 UTC (rev 14684)
@@ -0,0 +1,19 @@
+<html>
+ <head>
+ <title><g:message code="gus.document.title" args="${[documentTitle]}"
/></title>
+ <meta name="layout" content="mimir" />
+ <%--
+ <g:if test="${baseHref}"><base href="${baseHref}"></g:if>
+ --%>
+ </head>
+ <body>
+ <g:if test="${documentTitle != null}">
+ <h1><g:message code="gus.document.heading" args="${[documentTitle]}"
/></h1>
+ <mimir:documentContent indexId="${indexId}"
documentRank="${documentRank}"
+ queryId="${queryId}" />
+ </g:if>
+ <g:else>
+ <p>Cannot find query with given ID; perhaps your session expired.
Please try your search again!</p>
+ </g:else>
+ </body>
+</html>
Modified: mimir/trunk/mimir-web/grails-app/views/search/index.gsp
===================================================================
--- mimir/trunk/mimir-web/grails-app/views/search/index.gsp 2011-12-07
14:00:02 UTC (rev 14683)
+++ mimir/trunk/mimir-web/grails-app/views/search/index.gsp 2011-12-07
14:44:34 UTC (rev 14684)
@@ -32,9 +32,9 @@
<!-- blank for a completely dynamic interface. -->
<h1>Searching Index ${index?.name}</h1>
- <div class="searchbox" id="searchBox"> </div>
+ <div class="searchBox" id="searchBox"> </div>
<div class="bluebar" id="resultsBar"></div>
- <div id="searchResults">
- </div>
+ <div id="searchResults" class="searchResults"></div>
+ <div id="pageLinks" class="pageLinks bluebar"></div>
</body>
</html>
Modified: mimir/trunk/mimir-web/src/gwt/gate/mimir/web/client/UI.java
===================================================================
--- mimir/trunk/mimir-web/src/gwt/gate/mimir/web/client/UI.java 2011-12-07
14:00:02 UTC (rev 14683)
+++ mimir/trunk/mimir-web/src/gwt/gate/mimir/web/client/UI.java 2011-12-07
14:44:34 UTC (rev 14684)
@@ -16,6 +16,7 @@
import java.util.ArrayList;
import java.util.List;
+import sun.awt.motif.MInputMethod;
import gate.mimir.gus.client.GusService;
import gate.mimir.gus.client.GusServiceAsync;
@@ -26,16 +27,27 @@
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
+import com.google.gwt.http.client.URL;
+import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
+import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HTMLPanel;
+import com.google.gwt.user.client.ui.Hyperlink;
+import com.google.gwt.user.client.ui.InlineHTML;
+import com.google.gwt.user.client.ui.InlineHyperlink;
import com.google.gwt.user.client.ui.InlineLabel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.TextArea;
+import com.google.gwt.user.client.ui.Widget;
/**
* Entry point classes define <code>onModuleLoad()</code>.
@@ -46,38 +58,71 @@
* A Timer implementation that fetches the latest results information from
the
* server and updates the results display accordingly.
*/
- protected class StatsUpdater extends Timer {
+ protected class ResultsUpdater extends Timer {
+
+ private int newFirstDocument;
+
+ public ResultsUpdater(int newFirstDocument) {
+ super();
+ this.newFirstDocument = newFirstDocument;
+ }
@Override
public void run() {
+ if(newFirstDocument != firstDocumentOnPage) {
+ // new page: clear data and old display
+ documentsData.clear();
+ searchResultsPanel.clear();
+ firstDocumentOnPage = newFirstDocument;
+ }
// calculate which documents we need now
int firstDoc = firstDocumentOnPage + documentsData.size();
int docCount = maxDocumentsOnPage - documentsData.size();
if(docCount <= 0) {
firstDoc = -1;
+ } else {
+ feedbackLabel.setText("Working");
}
gwtRpcService.getResultsData(queryId, firstDoc, docCount,
new AsyncCallback<ResultsData>() {
@Override
public void onSuccess(ResultsData result) {
updatePage(result);
- if(result.getResultsTotal() < 0) {
- // more to come
- schedule(500);
- }
+ boolean allDone = (result.getResultsTotal() >= 0) &&
+ ((documentsData.size() == maxDocumentsOnPage) ||
+ firstDocumentOnPage + documentsData.size() ==
result.getResultsTotal());
+ if(!allDone) schedule(500);
}
@Override
public void onFailure(Throwable caught) {
- // ignore and try again later
- schedule(500);
- // throw the exception so it's seen
- throw new RuntimeException(caught);
+ if(caught instanceof MimirSearchException &&
+ ((MimirSearchException)caught).getErrorCode() ==
+ MimirSearchException.QUERY_ID_NOT_KNOWN) {
+ // query ID not known -> re-post the query
+ if(queryString != null && queryString.length() > 0){
+ queryId = null;
+ postQuery(queryString);
+ }
+ } else {
+ // ignore and try again later
+ schedule(500);
+ // re-throw the exception so it's seen (useful when debugging)
+ throw new RuntimeException(caught);
+ }
}
});
}
}
+ private native String getIndexId() /*-{
+ return $wnd.indexId;
+ }-*/;
+
+ private native String getUriIsLink() /*-{
+ return $wnd.uriIsLink;
+ }-*/;
+
private GwtRpcServiceAsync gwtRpcService;
protected TextArea searchBox;
@@ -86,10 +131,18 @@
protected String queryId;
- protected Label resultStatsLabel;
+ protected String queryString;
+ protected String indexId;
+
+ protected boolean uriIsLink;
+
+ protected Label feedbackLabel;
+
protected HTMLPanel searchResultsPanel;
+ protected HTMLPanel pageLinksPanel;
+
/**
* The rank of the first document on page.
*/
@@ -97,6 +150,8 @@
protected int maxDocumentsOnPage = 20;
+ protected int maxPages = 20;
+
protected int maxSnippetLength = 100;
private List<DocumentData> documentsData;
@@ -111,12 +166,24 @@
String rpcUrl = GWT.getHostPageBaseURL() + "gwtRpc";
endpoint.setServiceEntryPoint(rpcUrl);
- queryId = null;
+ indexId = getIndexId();
+ uriIsLink = Boolean.parseBoolean(getUriIsLink());
+ initLocalData();
initGui();
initListeners();
}
+ protected void initLocalData() {
+ queryId = null;
+ firstDocumentOnPage = 0;
+ if(documentsData == null){
+ documentsData = new ArrayList<DocumentData>(maxDocumentsOnPage);
+ } else {
+ documentsData.clear();
+ }
+ }
+
protected void initGui() {
HTMLPanel searchDiv =
HTMLPanel.wrap(Document.get().getElementById("searchBox"));
@@ -127,14 +194,15 @@
searchButton = new Button();
searchButton.setText("Search");
+ searchButton.addStyleName("searchButton");
searchDiv.add(searchButton);
HTMLPanel resultsBar =
HTMLPanel.wrap(Document.get().getElementById("resultsBar"));
- resultStatsLabel = new Label("Ready");
- resultsBar.add(resultStatsLabel);
+ feedbackLabel = new Label("Ready");
+ resultsBar.add(feedbackLabel);
searchResultsPanel =
HTMLPanel.wrap(Document.get().getElementById("searchResults"));
-
+ pageLinksPanel =
HTMLPanel.wrap(Document.get().getElementById("pageLinks"));
}
protected void initListeners() {
@@ -144,32 +212,103 @@
startSearch();
}
});
+
+ History.addValueChangeHandler(new ValueChangeHandler<String>() {
+ @Override
+ public void onValueChange(ValueChangeEvent<String> event) {
+ String historyToken = event.getValue();
+ if(historyToken != null && historyToken.length() > 0) {
+ String newQueryId = null;
+ String newQueryString = null;
+ int newFirstDoc = 0;
+
+ String[] elems = historyToken.split("\\&");
+ for(String elem : elems) {
+ String[] keyVal = elem.split("=");
+ String key = keyVal[0].trim();
+ String value = keyVal[1].trim();
+ if(key.equalsIgnoreCase("queryId")) {
+ newQueryId = URL.decodeQueryString(value);
+ } else if(key.equalsIgnoreCase("queryString")) {
+ newQueryString = URL.decodeQueryString(value);
+ } else if(key.equalsIgnoreCase("firstDoc")) {
+ try{
+ newFirstDoc =Integer.parseInt(value);
+ } catch (NumberFormatException nfe) {
+ // ignore, and start results from zero
+ }
+ }
+ }
+ // now update the display accordingly
+ if(newQueryId != null && newQueryId.length() > 0) {
+ queryId = newQueryId;
+ queryString = newQueryString;
+ if(!searchBox.getText().trim().equalsIgnoreCase(
+ newQueryString.trim())){
+ searchBox.setText(newQueryString);
+ }
+ new ResultsUpdater(newFirstDoc).schedule(10);
+ }
+ }
+ }
+ });
+ // now read the current history
+ String historyToken = History.getToken();
+ if(historyToken != null && historyToken.length() > 0) {
+ History.fireCurrentHistoryState();
+ }
}
protected void startSearch() {
- String query = searchBox.getText();
- gwtRpcService.search(getIndexId(), query, new AsyncCallback<String>() {
+ // clean up old state
+ if(queryId != null) {
+ // release old query
+ gwtRpcService.releaseQuery(queryId, new AsyncCallback<Void>() {
+ @Override
+ public void onSuccess(Void result) {}
+ @Override
+ public void onFailure(Throwable caught) {}
+ });
+ }
+ // reset internal data
+ initLocalData();
+ // post the new query
+ postQuery(searchBox.getText());
+ }
+
+ protected void postQuery(final String newQueryString) {
+ feedbackLabel.setText("Working...");
+ // clear the old display
+ searchResultsPanel.clear();
+ gwtRpcService.search(getIndexId(), newQueryString, new
AsyncCallback<String>() {
@Override
public void onFailure(Throwable caught) {
- // TODO Auto-generated method stub
-
+ feedbackLabel.setText(caught.getLocalizedMessage());
}
@Override
- public void onSuccess(String result) {
- queryId = result;
- firstDocumentOnPage = 0;
- documentsData = new ArrayList<DocumentData>(maxDocumentsOnPage);
- searchResultsPanel.clear();
- new StatsUpdater().schedule(50);
+ public void onSuccess(String newQueryId) {
+ History.newItem(createHistoryToken(newQueryId, newQueryString,
+ firstDocumentOnPage));
}
- });
+ });
}
+ protected String createHistoryToken(String queryId, String queryString,
+ int firstDocument) {
+ return "queryId=" + URL.encodeQueryString(queryId) +
+ "&queryString=" + URL.encodeQueryString(queryString) +
+ "&firstDoc=" + firstDocument;
+ }
+
+ /**
+ * Updates the results display (including the feedback label)
+ * @param resultsData
+ */
protected void updatePage(ResultsData resultsData) {
int resTotal = resultsData.getResultsTotal();
int resPartial = resultsData.getResultsPartial();
StringBuilder textBuilder = new StringBuilder("Documents ");
- textBuilder.append(firstDocumentOnPage);
+ textBuilder.append(firstDocumentOnPage + 1);
textBuilder.append(" to ");
if(firstDocumentOnPage + maxDocumentsOnPage < resPartial) {
textBuilder.append(firstDocumentOnPage + maxDocumentsOnPage);
@@ -187,7 +326,7 @@
textBuilder.append(resPartial);
}
textBuilder.append(":");
- resultStatsLabel.setText(textBuilder.toString());
+ feedbackLabel.setText(textBuilder.toString());
if(resultsData.getDocuments() != null){
// now update the documents display
@@ -201,7 +340,7 @@
if(docPosition == documentsData.size()) {
documentsData.add(docData);
HTMLPanel documentDisplay = buildDocumentDisplay(docData);
- if(docPosition % 2 == 0) documentDisplay.addStyleName("even");
+// if(docPosition % 2 == 0) documentDisplay.addStyleName("even");
searchResultsPanel.add(documentDisplay);
} else {
if(documentsData.get(docPosition).documentRank ==
docData.documentRank) {
@@ -213,20 +352,65 @@
}
}
}
+
+ // page links
+ pageLinksPanel.clear();
+ int currentPage = firstDocumentOnPage / maxDocumentsOnPage;
+ int firstPage = Math.max(0, currentPage - (maxPages / 2));
+ int maxPage = resultsData.getResultsPartial() / maxDocumentsOnPage;
+ if(resultsData.getResultsPartial() % maxDocumentsOnPage > 0) maxPage++;
+ maxPage = Math.min(maxPage, firstPage + maxPages);
+ for(int pageNo = firstPage; pageNo < maxPage; pageNo++) {
+ Widget pageLink;
+ if(pageNo != currentPage) {
+ pageLink = new InlineHyperlink("" + (pageNo + 1),
+ createHistoryToken(queryId, queryString,
+ pageNo * maxDocumentsOnPage));
+ } else {
+ pageLink = new InlineLabel("" + (pageNo + 1));
+ }
+ pageLink.addStyleName("pageLink");
+ pageLinksPanel.add(pageLink);
+ }
}
private HTMLPanel buildDocumentDisplay(DocumentData docData) {
HTMLPanel documentDisplay = new HTMLPanel("");
documentDisplay.setStyleName("hit");
- HTMLPanel docTitle = new HTMLPanel(docData.documentTitle);
- docTitle.setStyleName("document-title");
- documentDisplay.add(docTitle);
+ String documentUri = docData.documentUri;
+ String documentTitle = docData.documentTitle;
+ if(documentTitle == null || documentTitle.trim().length() == 0) {
+ // we got no title to display: use the URI file
+ String [] pathElems = documentUri.split("/");
+ documentTitle = pathElems[pathElems.length -1];
+ }
+ String documentTitleText = "<span title=\"" + documentUri +
+ "\" class=\"document-title\">" +
+ docData.documentTitle + "</span>";
+ FlowPanel docLinkPanel = new FlowPanel();
+// docLinkPanel.setStyleName("document-title");
+ if(uriIsLink) {
+ // generate two links: original doc and cached
+ docLinkPanel.add(new Anchor(documentTitleText, true, documentUri));
+ docLinkPanel.add(new InlineLabel(" ("));
+ docLinkPanel.add(new Anchor("cached", false,
+ "document?documentRank=" + docData.documentRank +
+ "&queryId=" + queryId));
+ docLinkPanel.add(new InlineLabel(")"));
+ } else {
+ // generate one link: cached, with document name as text
+ docLinkPanel.add(new Anchor(documentTitle, true,
+ "document?documentRank=" + docData.documentRank +
+ "&queryId=" + queryId));
+ }
+ documentDisplay.add(docLinkPanel);
if(docData.snippets != null) {
+ StringBuilder snippetsText = new StringBuilder("<div
class=\"snippets\">");
// each row is left context, snippet, right context
for(String[] snippet : docData.snippets) {
- HTMLPanel snippetPanel = new HTMLPanel("");
- snippetPanel.setStyleName("snippet");
- snippetPanel.add(new InlineLabel(snippet[0]));
+ snippetsText.append("<span class=\"snippet\">");
+ snippetsText.append(snippet[0]);
+ snippetsText.append("<span class=\"snippet-text\">");
String snipText = snippet[1];
int snipLen = snipText.length();
if(snipLen > maxSnippetLength) {
@@ -235,21 +419,15 @@
" ... " +
snipText.substring((snipLen + toRemove) / 2);
}
- InlineLabel snippetLabel = new InlineLabel(snipText);
- snippetLabel.setStyleName("snippet-text");
- snippetPanel.add(snippetLabel);
- snippetPanel.add(new InlineLabel(snippet[2]));
- documentDisplay.add(snippetPanel);
+ snippetsText.append(snipText);
+ //close snippet-text span
+ snippetsText.append("</span>");
+ snippetsText.append(snippet[2]);
+ //close snippet span
+ snippetsText.append("</span>");
}
+ documentDisplay.add(new HTML(snippetsText.toString()));
}
return documentDisplay;
}
-
- private native String getIndexId() /*-{
- return $wnd.indexId;
- }-*/;
-
- private native String getUriIsLink() /*-{
- return $wnd.uriIsLink;
- }-*/;
}
Deleted:
mimir/trunk/mimir-web/src/java/gate/mimir/web/client/GwtRpcException.java
===================================================================
--- mimir/trunk/mimir-web/src/java/gate/mimir/web/client/GwtRpcException.java
2011-12-07 14:00:02 UTC (rev 14683)
+++ mimir/trunk/mimir-web/src/java/gate/mimir/web/client/GwtRpcException.java
2011-12-07 14:44:34 UTC (rev 14684)
@@ -1,28 +0,0 @@
-/**
- * GwtRpcException.java
- *
- * Copyright (c) 1995-2010, The University of Sheffield. See the file
- * COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
- *
- * This file is part of GATE (see http://gate.ac.uk/), and is free
- * software, licenced under the GNU Library General Public License,
- * Version 2, June 1991 (in the distribution as file licence.html,
- * and also available at http://gate.ac.uk/gate/licence.html).
- *
- * Valentin Tablan, 01 Dec 2011
- */
-package gate.mimir.web.client;
-
-import com.google.gwt.user.client.rpc.IsSerializable;
-
-public class GwtRpcException extends Exception implements IsSerializable {
- private static final long serialVersionUID = 1L;
-
- public GwtRpcException() {
- super();
- }
-
- public GwtRpcException(String message) {
- super(message);
- }
-}
Modified:
mimir/trunk/mimir-web/src/java/gate/mimir/web/client/GwtRpcService.java
===================================================================
--- mimir/trunk/mimir-web/src/java/gate/mimir/web/client/GwtRpcService.java
2011-12-07 14:00:02 UTC (rev 14683)
+++ mimir/trunk/mimir-web/src/java/gate/mimir/web/client/GwtRpcService.java
2011-12-07 14:44:34 UTC (rev 14684)
@@ -17,10 +17,10 @@
public interface GwtRpcService extends RemoteService {
public String search(java.lang.String indexId, java.lang.String query)
- throws GwtRpcException;
+ throws MimirSearchException;
public ResultsData getResultsData(String queryId, int firstDocumentRank,
- int documentsCount) throws GwtRpcException;
+ int documentsCount) throws MimirSearchException;
public void releaseQuery(java.lang.String queryId);
}
Modified:
mimir/trunk/mimir-web/src/java/gate/mimir/web/client/GwtRpcServiceAsync.java
===================================================================
---
mimir/trunk/mimir-web/src/java/gate/mimir/web/client/GwtRpcServiceAsync.java
2011-12-07 14:00:02 UTC (rev 14683)
+++
mimir/trunk/mimir-web/src/java/gate/mimir/web/client/GwtRpcServiceAsync.java
2011-12-07 14:44:34 UTC (rev 14684)
@@ -16,11 +16,13 @@
import com.google.gwt.user.client.rpc.AsyncCallback;
public interface GwtRpcServiceAsync {
+
public void search(java.lang.String indexId, java.lang.String query,
AsyncCallback<String> callback);
void getResultsData(String queryId, int firstDocumentRank,
int documentsCount, AsyncCallback<ResultsData> callback);
- public void releaseQuery(java.lang.String queryId, AsyncCallback callback);
+ public void releaseQuery(java.lang.String queryId,
+ AsyncCallback<Void> callback);
}
Copied:
mimir/trunk/mimir-web/src/java/gate/mimir/web/client/MimirSearchException.java
(from rev 14674,
mimir/trunk/mimir-web/src/java/gate/mimir/web/client/GwtRpcException.java)
===================================================================
---
mimir/trunk/mimir-web/src/java/gate/mimir/web/client/MimirSearchException.java
(rev 0)
+++
mimir/trunk/mimir-web/src/java/gate/mimir/web/client/MimirSearchException.java
2011-12-07 14:44:34 UTC (rev 14684)
@@ -0,0 +1,56 @@
+/**
+ * MimirSearchException.java
+ *
+ * Copyright (c) 1995-2010, The University of Sheffield. See the file
+ * COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
+ *
+ * This file is part of GATE (see http://gate.ac.uk/), and is free
+ * software, licenced under the GNU Library General Public License,
+ * Version 2, June 1991 (in the distribution as file licence.html,
+ * and also available at http://gate.ac.uk/gate/licence.html).
+ *
+ * Valentin Tablan, 01 Dec 2011
+ */
+package gate.mimir.web.client;
+
+import com.google.gwt.user.client.rpc.IsSerializable;
+
+/**
+ * Exceptions that can occur on the server side as an effect of remote GWT RPC
+ * calls (and that can be serialised and sent back to the client).
+ */
+public class MimirSearchException extends Exception implements IsSerializable {
+
+ private static final long serialVersionUID = 1L;
+
+ public static final int QUERY_ID_NOT_KNOWN = 1;
+
+ public static final int OTHER = 0;
+
+ private int errorCode;
+
+
+ public MimirSearchException(int errorCode) {
+ super();
+ this.errorCode = errorCode;
+ }
+
+ public MimirSearchException(int errorCode, String message) {
+ super(message);
+ this.errorCode = errorCode;
+ }
+
+ public MimirSearchException() {
+ errorCode = OTHER;
+ }
+
+ public MimirSearchException(String message) {
+ super(message);
+ errorCode = OTHER;
+ }
+
+ public int getErrorCode() {
+ return errorCode;
+ }
+
+}
Modified: mimir/trunk/mimir-web/web-app/css/mimir.css
===================================================================
--- mimir/trunk/mimir-web/web-app/css/mimir.css 2011-12-07 14:00:02 UTC (rev
14683)
+++ mimir/trunk/mimir-web/web-app/css/mimir.css 2011-12-07 14:44:34 UTC (rev
14684)
@@ -24,7 +24,7 @@
color: #006193;
font-weight: bold;
text-decoration: none;
-}
+}
h1, .bluebar {
color: #fff;
@@ -181,19 +181,41 @@
background: #e3ecf3;
}
+.searchBox {
+ margin: 10px;
+ text-align: center;
+ vertical-align: middle;
+}
+
+.searchButton {
+ margin-left: 5px;
+}
+
+.searchResults {
+ width: 80%;
+}
+
.hit {
font-size: medium;
- margin: 5px;
+ margin-top: 20px;
}
+.hit a {
+ font-weight: normal;
+}
+
.document-title {
- font-weight: bold;
+ font-weight:bold;
color: #006193;
}
+.snippets {
+ /* margin-left: 20px; */
+}
+
.snippet {
- margin-left: 20px;
font-size: small;
+ margin-right: 10px;
}
.snippet-text {
@@ -206,6 +228,27 @@
color: black;
}
+.pageLinks {
+ margin-top: 10px;
+ margin-bottom: 10px;
+ padding-top: 5px;
+ padding-bottom: 5px;
+ text-align: center;
+}
+
+.pageLink {
+ margin-left: 5px;
+ color: white;
+ padding-left: 2px;
+ padding-right: 2px;
+}
+
+a.pageLink {
+ color: white;
+ font-weight: normal;
+ border: thin solid white;
+}
+
/* LIST */
.list table {
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
Cloud Services Checklist: Pricing and Packaging Optimization
This white paper is intended to serve as a reference, checklist and point of
discussion for anyone considering optimizing the pricing and packaging model
of a cloud services business. Read Now!
http://www.accelacomm.com/jaw/sfnl/114/51491232/
_______________________________________________
GATE-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/gate-cvs