From 3bf5f1983bfbdac409eb19e180880a85a60520a6 Mon Sep 17 00:00:00 2001
From: fkiefer <none@none>
Date: Mon, 27 Feb 2017 09:18:58 +0100
Subject: [PATCH] OO-2581 Course search as course tool in toolbar

---
 .../title/_content/titled_wrapper.html        |  5 +++
 .../org/olat/course/config/CourseConfig.java  | 24 +++++++++-
 .../config/ui/CourseOptionsController.java    | 11 ++++-
 .../ui/_i18n/LocalStrings_de.properties       |  1 +
 .../ui/_i18n/LocalStrings_en.properties       |  1 +
 .../course/run/CourseRuntimeController.java   | 44 ++++++++++++++++++-
 .../run/_i18n/LocalStrings_de.properties      |  1 +
 .../run/_i18n/LocalStrings_en.properties      |  1 +
 .../olat/search/service/QuickSearchEvent.java | 41 +++++++++++++++++
 .../olat/search/ui/SearchInputController.java |  3 ++
 10 files changed, 127 insertions(+), 5 deletions(-)
 create mode 100644 src/main/java/org/olat/search/service/QuickSearchEvent.java

diff --git a/src/main/java/org/olat/core/gui/control/generic/title/_content/titled_wrapper.html b/src/main/java/org/olat/core/gui/control/generic/title/_content/titled_wrapper.html
index 2d28c22ad1e..61d95e4a22d 100644
--- a/src/main/java/org/olat/core/gui/control/generic/title/_content/titled_wrapper.html
+++ b/src/main/java/org/olat/core/gui/control/generic/title/_content/titled_wrapper.html
@@ -16,6 +16,11 @@
 #if($r.available("description"))
 	$r.render("description")
 #end
+#if($r.available("courseSearch"))
+    <div id="o_forum_fulltextsearch" class="o_forum_fulltextsearch">
+	$r.render("courseSearch")
+	</div>
+#end
 #if($separator)
 	<hr />
 #end
diff --git a/src/main/java/org/olat/course/config/CourseConfig.java b/src/main/java/org/olat/course/config/CourseConfig.java
index 819cd8eeb20..e248e3def5b 100644
--- a/src/main/java/org/olat/course/config/CourseConfig.java
+++ b/src/main/java/org/olat/course/config/CourseConfig.java
@@ -72,7 +72,7 @@ public class CourseConfig implements Serializable, Cloneable {
 	/**
 	 * current config file version
 	 */
-	transient private final static int CURRENTVERSION = 11;
+	transient private final static int CURRENTVERSION = 12;
 	/**
 	 * Log levels
 	 */
@@ -108,7 +108,10 @@ public class CourseConfig implements Serializable, Cloneable {
 	 * The toolbar is enabled by default
 	 */
 	transient public static final String TOOLBAR_ENABLED = "TOOLBAR_ENABLED";
-	
+	/**
+	 * The course search is enabled by default
+	 */
+	transient public static final String COURSESEARCH_ENABLED = "COURSESEARCH_ENABLED";
 	/**
 	 * course calendar
 	 */
@@ -181,6 +184,8 @@ public class CourseConfig implements Serializable, Cloneable {
 
 		configuration.put(MENU_ENABLED, Boolean.TRUE);
 		configuration.put(TOOLBAR_ENABLED, Boolean.TRUE);
+		
+		configuration.put(COURSESEARCH_ENABLED, Boolean.TRUE);
 
 		this.version = CURRENTVERSION;
 	}
@@ -265,6 +270,11 @@ public class CourseConfig implements Serializable, Cloneable {
 				this.version = 11;
 			}
 			
+			if (version == 11) {
+				if (!configuration.containsKey(COURSESEARCH_ENABLED)) configuration.put(COURSESEARCH_ENABLED, Boolean.TRUE);
+				this.version = 12;
+			}
+			
 			/*
 			 * after resolving the issues, the version number is merged to the
 			 * CURRENTVERSION !! leave this!
@@ -527,6 +537,15 @@ public class CourseConfig implements Serializable, Cloneable {
 		configuration.put(MENU_ENABLED, new Boolean(b));
 	}
 	
+	public boolean isCourseSearchEnabled() {
+		Boolean bool = (Boolean) configuration.get(COURSESEARCH_ENABLED);
+		return bool.booleanValue();
+	}
+	
+	public void setCourseSearchEnabled(boolean b) {
+		configuration.put(COURSESEARCH_ENABLED, new Boolean(b));
+	}
+	
 	public boolean isToolbarEnabled() {
 		Boolean bool = (Boolean) configuration.get(TOOLBAR_ENABLED);
 		return bool.booleanValue();
@@ -559,6 +578,7 @@ public class CourseConfig implements Serializable, Cloneable {
 		clone.setRecertificationTimelapseUnit(getRecertificationTimelapseUnit());
 		clone.setMenuEnabled(isMenuEnabled());
 		clone.setToolbarEnabled(isToolbarEnabled());
+		clone.setCourseSearchEnabled(isCourseSearchEnabled());
 		return clone;
 	}
 
diff --git a/src/main/java/org/olat/course/config/ui/CourseOptionsController.java b/src/main/java/org/olat/course/config/ui/CourseOptionsController.java
index 76ad1da8f71..df15573bf93 100644
--- a/src/main/java/org/olat/course/config/ui/CourseOptionsController.java
+++ b/src/main/java/org/olat/course/config/ui/CourseOptionsController.java
@@ -90,7 +90,7 @@ public class CourseOptionsController extends FormBasicController {
 	private static final String[] onKeys = new String[] {"xx"};
 	private static final String[] onValues = new String[] {""};
 
-	private SelectionElement menuEl, toolbarEl, calendarEl, chatEl;
+	private SelectionElement menuEl, toolbarEl, calendarEl, searchEl, chatEl;
 	private FormLink addGlossaryCommand, removeGlossaryCommand;
 	private StaticTextElement glossaryNameEl;
 	private FormLink saveButton;
@@ -209,7 +209,11 @@ public class CourseOptionsController extends FormBasicController {
 			if(managedCal && calendarEnabled) {
 				canHideToolbar &= false;
 			}
-		}
+		}		
+		//searchbar
+		searchEl = uifactory.addCheckboxesHorizontal("searchIsOn", "chkbx.search.onoff", menuCont, onKeys, onValues);
+		searchEl.select(onKeys[0], courseConfig.isCourseSearchEnabled());
+		searchEl.addActionListener(FormEvent.ONCHANGE);
 		
 		//chat
 		chatCont = FormLayoutContainer.createDefaultFormLayout("chat", getTranslator());
@@ -457,6 +461,9 @@ public class CourseOptionsController extends FormBasicController {
 		boolean updateChat = courseConfig.isChatEnabled() != enableChat;
 		courseConfig.setChatIsEnabled(enableChat && toolbarEnabled);
 		
+		boolean enableSearch = searchEl.isSelected(0);
+		courseConfig.setCourseSearchEnabled(enableSearch && toolbarEnabled);
+		
 		boolean enableCalendar = calendarEl == null ? false : calendarEl.isSelected(0);
 		boolean updateCalendar = courseConfig.isCalendarEnabled() != enableCalendar && calendarModule.isEnableCourseToolCalendar();
 		courseConfig.setCalendarEnabled(enableCalendar && toolbarEnabled);
diff --git a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_de.properties
index 4ff0aee0892..33fb2a6af68 100644
--- a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_de.properties
@@ -2,6 +2,7 @@
 chkbx.calendar.onoff=Kalender in der Werkzeugbox anzeigen
 chkbx.chat.onoff=Kurs-Chat verwenden
 chkbx.efficency.onoff=Leistungsnachweis verwenden
+chkbx.search.onoff=Kurssuche verwenden
 chkbx.menu.onoff=Menu sichtbar f\u00FCr Teilnehmer und Betreuer
 chkbx.toolbar.onoff=Toolbar sichtbar f\u00FCr Teilnehmer
 chkbx.toolbar.off.warning=Wenn sie den Toolbar abschalten, stehen die folgende Werkzeuge nicht mehr zur Verf\u00fcgung: Glossar, Kurs-Chat und Kalendar.
diff --git a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_en.properties
index c1a756daec7..5863d9b48fe 100644
--- a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_en.properties
@@ -1,6 +1,7 @@
 #Fri Jan 21 11:22:00 CET 2011
 chkbx.calendar.onoff=Show calendar in the course's tool box
 chkbx.chat.onoff=Use course chat
+chkbx.search.onoff=Enable course search
 chkbx.efficency.onoff=Use evidence of achievement
 chkbx.menu.onoff=Menu visible for participants and coaches
 chkbx.toolbar.onoff=Toolbar visible for participants
diff --git a/src/main/java/org/olat/course/run/CourseRuntimeController.java b/src/main/java/org/olat/course/run/CourseRuntimeController.java
index 501c0288b12..b0dbd4d2382 100644
--- a/src/main/java/org/olat/course/run/CourseRuntimeController.java
+++ b/src/main/java/org/olat/course/run/CourseRuntimeController.java
@@ -54,6 +54,7 @@ import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.VetoableCloseController;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.creator.ControllerCreator;
+import org.olat.core.gui.control.generic.closablewrapper.CloseableCalloutWindowController;
 import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController;
 import org.olat.core.gui.control.generic.dtabs.Activateable2;
 import org.olat.core.gui.control.generic.dtabs.DTab;
@@ -133,6 +134,10 @@ import org.olat.repository.model.RepositoryEntrySecurity;
 import org.olat.repository.ui.RepositoryEntryLifeCycleChangeController;
 import org.olat.repository.ui.RepositoryEntryRuntimeController;
 import org.olat.resource.OLATResource;
+import org.olat.search.SearchServiceUIFactory;
+import org.olat.search.SearchServiceUIFactory.DisplayOption;
+import org.olat.search.service.QuickSearchEvent;
+import org.olat.search.ui.SearchInputController;
 import org.olat.util.logging.activity.LoggingResourceable;
 import org.springframework.beans.factory.annotation.Autowired;
 
@@ -159,7 +164,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 		layoutLink, optionsLink, certificatesOptionsLink, reminderLink,
 		assessmentModeLink, lifeCycleChangeLink,
 		//my course
-		efficiencyStatementsLink, calendarLink, noteLink, chatLink, leaveLink,
+		efficiencyStatementsLink, calendarLink, noteLink, chatLink, leaveLink, searchLink,
 		//glossary
 		openGlossaryLink, enableGlossaryLink;
 	private Link currentUserCountLink;
@@ -167,10 +172,12 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 
 	private CloseableModalController cmc;
 	private CourseAreasController areasCtrl;
+	
 	private ConfirmLeaveController leaveDialogBox;
 	private ArchiverMainController archiverCtrl;
 	private CustomDBMainController databasesCtrl;
 	private FolderRunController courseFolderCtrl;
+	private SearchInputController searchController;
 	private StatisticMainController statisticsCtrl;
 	private CourseOptionsController optionsToolCtr;
 	private CourseRemindersController remindersCtrl;
@@ -180,6 +187,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 	private AssessmentModeListController assessmentModeCtrl;
 	private CourseLayoutGeneratorController courseLayoutCtrl;
 	private CertificatesOptionsController certificatesOptionsCtrl;
+	private CloseableCalloutWindowController courseSearchCalloutCtr;
 	protected RepositoryEntryLifeCycleChangeController lifeCycleChangeCtr;
 
 	private int currentUserCount;
@@ -769,6 +777,14 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 			chatLink.setVisible(imModule.isCourseEnabled() && cc.isChatEnabled());
 			toolbarPanel.addTool(chatLink);
 		}
+		
+		// add course search to toolbox 
+		if (!assessmentLock && cc.isCourseSearchEnabled() && !isGuestOnly) {
+			searchLink = LinkFactory.createToolLink("coursesearch", translate("command.coursesearch"), this, "o_icon_search");
+			searchLink.setVisible(imModule.isCourseEnabled() && cc.isChatEnabled());
+			toolbarPanel.addTool(searchLink);
+		}
+		
 	}
 
 	@Override
@@ -858,6 +874,8 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 			launchCalendar(ureq);
 		} else if(chatLink == source) {
 			launchChat(ureq);
+		} else if(searchLink == source) {
+			launchCourseSearch(ureq);
 		} else if(efficiencyStatementsLink == source) {
 			doEfficiencyStatements(ureq);
 		} else if(noteLink == source) {
@@ -921,6 +939,10 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 			}else{
 				cmc.deactivate();
 			}
+		} else if (source == searchController) {
+			if (QuickSearchEvent.QUICKSEARCH.equals(event.getCommand())) {
+				doDeactivateQuickSearch();
+			}
 		}
 		
 		if(editorCtrl == source && source instanceof VetoableCloseController) {
@@ -1208,6 +1230,10 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 		doClose(ureq);
 	}
 	
+	private void doDeactivateQuickSearch() {
+		courseSearchCalloutCtr.deactivate();
+	}
+	
 	private void doLifeCycleChange(UserRequest ureq) {
 		List<Link> breadCrumbs = toolbarPanel.getBreadCrumbs();
 		BreadCrumb lastCrumb = null;
@@ -1534,6 +1560,22 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 		ureq.getUserSession().getSingleUserEventCenter().fireEventToListenersOf(event, InstantMessagingService.TOWER_EVENT_ORES);
 	}
 	
+	private void launchCourseSearch(UserRequest ureq) {
+		// do not dispose SearchInputController after search to remain able to listen to its events 
+		removeAsListenerAndDispose(courseSearchCalloutCtr);
+		courseSearchCalloutCtr = null;
+		removeAsListenerAndDispose(searchController);
+		searchController = null;
+		SearchServiceUIFactory searchServiceUIFactory = (SearchServiceUIFactory)CoreSpringFactory.getBean(SearchServiceUIFactory.class);
+		searchController = searchServiceUIFactory.createInputController(ureq, getWindowControl(), DisplayOption.STANDARD, null);
+		listenTo(searchController);		
+		courseSearchCalloutCtr = new CloseableCalloutWindowController(ureq, getWindowControl(),
+				searchController.getInitialComponent(), searchLink.getDispatchID(), null, true, null);
+		courseSearchCalloutCtr.addDisposableChildController(searchController);
+		courseSearchCalloutCtr.activate();
+		listenTo(courseSearchCalloutCtr);
+	}
+	
 	private void launchCalendar(UserRequest ureq) {
 		ControllerCreator ctrlCreator = new ControllerCreator() {
 			@Override
diff --git a/src/main/java/org/olat/course/run/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/run/_i18n/LocalStrings_de.properties
index b50088b7991..0898b2fbc3d 100644
--- a/src/main/java/org/olat/course/run/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/course/run/_i18n/LocalStrings_de.properties
@@ -11,6 +11,7 @@ command.coursechat=Kurs-Chat
 command.coursechatlog=Log von Chat
 command.courseconfig=Kursinfo
 command.coursefolder=Ablageordner
+command.coursesearch=Kurssuche
 command.efficiencystatement=Leistungsnachweis
 command.glossary=Glossar
 command.glossary.open=Glossar in separatem Fenster \u00f6ffnen
diff --git a/src/main/java/org/olat/course/run/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/run/_i18n/LocalStrings_en.properties
index afee36d5e18..dc9d5e5deb4 100644
--- a/src/main/java/org/olat/course/run/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/course/run/_i18n/LocalStrings_en.properties
@@ -11,6 +11,7 @@ command.coursechat=Course chat
 command.coursechatlog=Chat log
 command.courseconfig=Course info
 command.coursefolder=Storage folder
+command.coursesearch=Course search
 command.efficiencystatement=Evidence of achievement
 command.glossary=Glossary
 command.glossary.off=off
diff --git a/src/main/java/org/olat/search/service/QuickSearchEvent.java b/src/main/java/org/olat/search/service/QuickSearchEvent.java
new file mode 100644
index 00000000000..856803e8b5c
--- /dev/null
+++ b/src/main/java/org/olat/search/service/QuickSearchEvent.java
@@ -0,0 +1,41 @@
+/**
+ * <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.service;
+
+import org.olat.core.gui.control.Event;
+
+/**
+ * Initial Date: 23.02.2017
+ * @author fkiefer, fabian.kiefer@frentix.com, www.frentix.com
+ */
+public class QuickSearchEvent extends Event {
+
+	private static final long serialVersionUID = 4731572700415529941L;
+
+	public static final String QUICKSEARCH = "command.quicksearch";
+	
+	public static final QuickSearchEvent QUICKSEARCH_EVENT = new QuickSearchEvent(QUICKSEARCH);
+
+
+	public QuickSearchEvent(String command) {
+		super(command);
+	}
+
+}
diff --git a/src/main/java/org/olat/search/ui/SearchInputController.java b/src/main/java/org/olat/search/ui/SearchInputController.java
index 1b29b448eeb..ededb34a509 100644
--- a/src/main/java/org/olat/search/ui/SearchInputController.java
+++ b/src/main/java/org/olat/search/ui/SearchInputController.java
@@ -67,6 +67,7 @@ import org.olat.search.SearchServiceUIFactory.DisplayOption;
 import org.olat.search.ServiceNotAvailableException;
 import org.olat.search.model.AbstractOlatDocument;
 import org.olat.search.model.ResultDocument;
+import org.olat.search.service.QuickSearchEvent;
 import org.olat.search.service.searcher.SearchClient;
 
 /**
@@ -270,6 +271,7 @@ public class SearchInputController extends FormBasicController implements Generi
 
 	@Override
 	public void formOK(UserRequest ureq) {
+	fireEvent(ureq, QuickSearchEvent.QUICKSEARCH_EVENT);
 		doSearch(ureq);
 	}
 	
@@ -281,6 +283,7 @@ public class SearchInputController extends FormBasicController implements Generi
 	@Override
 	public void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
 		if (source == searchButton) {
+			fireEvent(ureq, QuickSearchEvent.QUICKSEARCH_EVENT);
 			doSearch(ureq);
 		} else if (didYouMeanLinks != null && didYouMeanLinks.contains(source)) {
 			String didYouMeanWord = (String)source.getUserObject();
-- 
GitLab