/** * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at the * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Initial code contributed and copyrighted by<br> * frentix GmbH, http://www.frentix.com * <p> */ package org.olat.search.ui; import java.util.ArrayList; import java.util.List; import org.olat.core.CoreSpringFactory; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.core.gui.components.form.flexible.impl.Form; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; import org.olat.core.gui.components.link.Link; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.search.SearchResults; import org.olat.search.SearchServiceUIFactory; import org.olat.search.model.ResultDocument; /** * Description:<br> * Controller which show the list of results, with paging. * <P> * Events: * <ul> * <li>SearchEvent</li> * </ul> * * Initial Date: 3 dec. 2009 <br> * @author srosse, stephane.rosse@frentix.com */ public class ResultsController extends FormBasicController { private FormLink previousTopLink, nextTopLink, previousLink, nextLink; private FormLink highlightLink, dishighlightLink; private int currentPage; public static final int RESULT_PER_PAGE = 10; private boolean highlight = true; private SearchResults searchResults; private final List<ResultDocument> documents = new ArrayList<ResultDocument>(); private final List<ResultController> resultsCtrl = new ArrayList<ResultController>(); public ResultsController(UserRequest ureq, WindowControl wControl, Form mainForm) { super(ureq, wControl, LAYOUT_CUSTOM, "results", mainForm); initForm(ureq); } @Override protected void doDispose() { // } @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { previousLink = uifactory.addFormLink("previous.page", formLayout); previousTopLink = uifactory.addFormLink("previous.top.page", null, "previous.page", formLayout, Link.LINK); nextLink = uifactory.addFormLink("next.page", formLayout); nextTopLink = uifactory.addFormLink("next.top.page", null, "next.page", formLayout, Link.LINK); highlightLink = uifactory.addFormLink("highlight.page", "enable.highlighting", "enable.highlighting", formLayout, Link.LINK); dishighlightLink = uifactory.addFormLink("dishighlight.page", "disable.highlighting", "disable.highlighting", formLayout, Link.LINK); flc.contextPut("highlight", true); reset(); } public int getCurrentPage() { return currentPage; } public SearchResults getSearchResults() { return searchResults; } public void setSearchResults(UserRequest ureq, SearchResults results) { reset(); searchResults = results; if(searchResults == null) { searchResults = SearchResults.EMPTY_SEARCH_RESULTS; } documents.addAll(searchResults.getList()); setSearchResults(ureq, 0); } private void setSearchResults(UserRequest ureq, int page) { currentPage = page; updateUI(ureq); } public void nextSearchResults(UserRequest ureq, SearchResults results) { searchResults = results; if(searchResults == null) { searchResults = SearchResults.EMPTY_SEARCH_RESULTS; } //the last result set can be empty if(!searchResults.getList().isEmpty()) { currentPage++; int pos = currentPage * RESULT_PER_PAGE; for (int i = 0 ; (i < RESULT_PER_PAGE) && (i < searchResults.getList().size() ); i++) { ResultDocument document = searchResults.getList().get(i); if(documents.size() > pos + i) { documents.set(pos + i, document); } else { documents.add(document); } } } updateUI(ureq); } private void updateUI(UserRequest ureq) { removeResultsController(); int start = currentPage * RESULT_PER_PAGE; SearchServiceUIFactory searchUIFactory = (SearchServiceUIFactory)CoreSpringFactory.getBean(SearchServiceUIFactory.class); int count = 0; for (int i = start; (count < RESULT_PER_PAGE) && (i < documents.size() ); i++) { ResultDocument document = documents.get(i); ResultController ctrl = searchUIFactory.createController(ureq, getWindowControl(), mainForm, document); ctrl.setHighlight(highlight); listenTo(ctrl); flc.add("result_" + (++count), ctrl.getInitialFormItem()); resultsCtrl.add(ctrl); } flc.contextPut("numOfPages", getMaxPage() + 1); flc.contextPut("numOfResults", getNumOfResults()); flc.contextPut("results", resultsCtrl); flc.contextPut("hasResult", searchResults != null); flc.contextPut("emptyResult", documents.isEmpty()); flc.contextPut("searchResults", searchResults); flc.contextPut("currentPage", currentPage + 1); previousLink.setEnabled(currentPage != 0); previousTopLink.setEnabled(currentPage != 0); nextLink.setEnabled(currentPage != getMaxPage()); nextTopLink.setEnabled(currentPage != getMaxPage()); String [] args = {Integer.toString(getStartResult()), Integer.toString(getEndResult()), Integer.toString(getNumOfResults())}; flc.contextPut("resultTitle", getTranslator().translate("search.result.title",args)); } public void reload(UserRequest ureq) { updateUI(ureq); } @Override protected void formOK(UserRequest ureq) { // } @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { super.formInnerEvent(ureq, source, event); if (source == highlightLink) { highlight = true; flc.contextPut("highlight", highlight); reload(ureq); } else if (source == dishighlightLink) { highlight = false; flc.contextPut("highlight", highlight); reload(ureq); } else if (source == previousLink || source == previousTopLink) { setSearchResults(ureq, Math.max(0, --currentPage)); } else if (source == nextLink || source == nextTopLink) { if(documents.size() <= (currentPage + 1) * RESULT_PER_PAGE) { SearchEvent e = new SearchEvent(getLastLucenePosition() + 1, RESULT_PER_PAGE); fireEvent(ureq, e); } else { setSearchResults(ureq, Math.min(getMaxPage(), ++currentPage)); } } } @Override protected void event(UserRequest ureq, Controller source, Event event) { if (event instanceof SearchEvent) { if(resultsCtrl.contains(source)) { fireEvent(ureq, event); } } } private void reset() { flc.contextPut("numOfResults", 0); flc.contextPut("hasResult", Boolean.FALSE); flc.contextPut("emptyResult", Boolean.TRUE); documents.clear(); removeResultsController(); } private void removeResultsController() { if(resultsCtrl != null && !resultsCtrl.isEmpty()) { for(int i=0; i<resultsCtrl.size(); i++) { flc.remove("result_" + (i+1)); removeAsListenerAndDispose(resultsCtrl.get(i)); } resultsCtrl.clear(); flc.contextPut("results", resultsCtrl); } } public int getStartResult() { return currentPage * RESULT_PER_PAGE + 1; } public int getEndResult() { if ( (currentPage * RESULT_PER_PAGE + RESULT_PER_PAGE) > documents.size() ) { return documents.size(); } else { return getStartResult() + RESULT_PER_PAGE - 1; } } /** * @return Number of pages for current result-list. */ public int getMaxPage() { int numOfResults = getNumOfResults(); int maxPage = numOfResults / RESULT_PER_PAGE; if ((numOfResults) % RESULT_PER_PAGE == 0) { maxPage--; } return maxPage; } public int getNumOfResults() { if(searchResults.getList().size() < RESULT_PER_PAGE) { //last result set, all documents are loaded return documents.size(); } return searchResults.getTotalDocs() - getLastLucenePosition() + documents.size() - 1; } private int getLastLucenePosition() { if(documents.isEmpty()) return 0; return documents.get(documents.size() - 1).getLucenePosition(); } public FormItem getFormItem() { return this.flc; } }