Index: lams_build/3rdParty.userlibraries =================================================================== RCS file: /usr/local/cvsroot/lams_build/3rdParty.userlibraries,v diff -u -r1.37 -r1.38 --- lams_build/3rdParty.userlibraries 6 Feb 2009 02:11:23 -0000 1.37 +++ lams_build/3rdParty.userlibraries 28 Feb 2009 13:46:21 -0000 1.38 @@ -1,14 +1,14 @@ - + - + - + @@ -26,29 +26,29 @@ - - - - - - + + + + + + - - + + - + - + - + @@ -89,7 +89,7 @@ - + @@ -102,7 +102,6 @@ - @@ -111,5 +110,7 @@ + + Index: lams_build/build.xml =================================================================== RCS file: /usr/local/cvsroot/lams_build/build.xml,v diff -u -r1.75 -r1.76 --- lams_build/build.xml 19 Feb 2009 14:01:20 -0000 1.75 +++ lams_build/build.xml 28 Feb 2009 13:46:21 -0000 1.76 @@ -133,6 +133,7 @@ + Index: lams_build/conf/j2ee/lams.application.xml =================================================================== RCS file: /usr/local/cvsroot/lams_build/conf/j2ee/lams.application.xml,v diff -u -r1.8 -r1.9 --- lams_build/conf/j2ee/lams.application.xml 13 Feb 2009 17:31:36 -0000 1.8 +++ lams_build/conf/j2ee/lams.application.xml 28 Feb 2009 13:46:20 -0000 1.9 @@ -244,6 +244,12 @@ JabberHTTPBind-1.1.1.jar + + lucene-core-2.4.0.jar + + + lucene-snowball-2.4.0.jar + Index: lams_build/lib/lucene/lucene-core-2.4.0.jar =================================================================== RCS file: /usr/local/cvsroot/lams_build/lib/lucene/lucene-core-2.4.0.jar,v diff -u Binary files differ Index: lams_build/lib/lucene/lucene-snowball-2.4.0.jar =================================================================== RCS file: /usr/local/cvsroot/lams_build/lib/lucene/lucene-snowball-2.4.0.jar,v diff -u Binary files differ Index: lams_build/lib/lucene/src/lucene-2.4.0-src.zip =================================================================== RCS file: /usr/local/cvsroot/lams_build/lib/lucene/src/Attic/lucene-2.4.0-src.zip,v diff -u Binary files differ Index: lams_build/lib/lucene/src/lucene-snowball-2.4.0-src.zip =================================================================== RCS file: /usr/local/cvsroot/lams_build/lib/lucene/src/Attic/lucene-snowball-2.4.0-src.zip,v diff -u Binary files differ Index: lams_central/conf/language/lams/ApplicationResources.properties =================================================================== RCS file: /usr/local/cvsroot/lams_central/conf/language/lams/ApplicationResources.properties,v diff -u -r1.62 -r1.63 --- lams_central/conf/language/lams/ApplicationResources.properties 25 Feb 2009 18:23:40 -0000 1.62 +++ lams_central/conf/language/lams/ApplicationResources.properties 28 Feb 2009 13:46:32 -0000 1.63 @@ -297,4 +297,9 @@ label.planner.import.instruction=Please select Pedagogical Planner node to import. The import file must be a .zip file exported from LAMS 2 or above. label.planner.grouping.view.students=View students before selection + +error.planner.filter.parse=There was an error when parsing the filter query. +label.planner.filter.output=These nodes are filtered. +label.planner.filter.clear=View nodes without filtering. +label.planner.filter=Filter #======= End labels: Exported 222 labels for en AU ===== Index: lams_central/conf/language/lams/ApplicationResources_en_AU.properties =================================================================== RCS file: /usr/local/cvsroot/lams_central/conf/language/lams/ApplicationResources_en_AU.properties,v diff -u -r1.59 -r1.60 --- lams_central/conf/language/lams/ApplicationResources_en_AU.properties 25 Feb 2009 18:23:40 -0000 1.59 +++ lams_central/conf/language/lams/ApplicationResources_en_AU.properties 28 Feb 2009 13:46:32 -0000 1.60 @@ -297,4 +297,9 @@ label.planner.import.instruction=Please select Pedagogical Planner node to import. The import file must be a .zip file exported from LAMS 2 or above. label.planner.grouping.view.students=View students before selection + +error.planner.filter.parse=There was an error when parsing the filter query. +label.planner.filter.output=These nodes are filtered. +label.planner.filter.clear=View nodes without filtering. +label.planner.filter=Filter #======= End labels: Exported 222 labels for en AU ===== Index: lams_central/src/java/org/lamsfoundation/lams/util/CentralConstants.java =================================================================== RCS file: /usr/local/cvsroot/lams_central/src/java/org/lamsfoundation/lams/util/CentralConstants.java,v diff -u -r1.23 -r1.24 --- lams_central/src/java/org/lamsfoundation/lams/util/CentralConstants.java 26 Feb 2009 19:20:09 -0000 1.23 +++ lams_central/src/java/org/lamsfoundation/lams/util/CentralConstants.java 28 Feb 2009 13:46:32 -0000 1.24 @@ -166,4 +166,6 @@ public static final String PARAM_EDIT = "edit"; public static final String USER_MANAGEMENT_SERVICE_BEAN_NAME = "userManagementService"; + + public static final String PARAM_FILTER_TEXT = "filterText"; } \ No newline at end of file Index: lams_central/src/java/org/lamsfoundation/lams/web/planner/PedagogicalPlannerAction.java =================================================================== RCS file: /usr/local/cvsroot/lams_central/src/java/org/lamsfoundation/lams/web/planner/PedagogicalPlannerAction.java,v diff -u -r1.11 -r1.12 --- lams_central/src/java/org/lamsfoundation/lams/web/planner/PedagogicalPlannerAction.java 26 Feb 2009 19:20:10 -0000 1.11 +++ lams_central/src/java/org/lamsfoundation/lams/web/planner/PedagogicalPlannerAction.java 28 Feb 2009 13:46:32 -0000 1.12 @@ -32,9 +32,11 @@ import java.io.OutputStreamWriter; import java.io.Writer; import java.util.ArrayList; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.TreeSet; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; @@ -44,6 +46,20 @@ import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.analysis.StopAnalyzer; +import org.apache.lucene.analysis.snowball.SnowballAnalyzer; +import org.apache.lucene.document.Document; +import org.apache.lucene.document.Field; +import org.apache.lucene.index.CorruptIndexException; +import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.queryParser.MultiFieldQueryParser; +import org.apache.lucene.queryParser.ParseException; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreDoc; +import org.apache.lucene.search.TopDocs; +import org.apache.lucene.store.RAMDirectory; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; @@ -151,6 +167,7 @@ private static final String ERROR_KEY_EDITOR = "error.planner.editor"; private static final String ERROR_KEY_EXPORT = "error.planner.export"; private static final String ERROR_KEY_IMPORT = "error.planner.import"; + private static final String ERROR_KEY_FILTER_PARSE = "error.planner.filter.parse"; // Error messages used in this class. They are ment to be thrown. private static final String ERROR_USER_NOT_FOUND = "User not found."; @@ -188,6 +205,14 @@ private static final int FILE_COPY_BUFFER_SIZE = 1024; + // Filter constants + private static final String FIELD_NAME_TITLE = "title"; + private static final String FIELD_NAME_BRIEF_DESCRIPTION = "briefDescription"; + private static final String FIELD_NAME_FULL_DESCRIPTION = "fullDescription"; + private static final String FIELD_NAME_ANCESTOR_UID = "ancestorUid"; + // not sfinal as it may be later swapped by different language + private static Analyzer ANALYZER = new SnowballAnalyzer("English", StopAnalyzer.ENGLISH_STOP_WORDS); + @Override /** * Go straight to open sequence node. @@ -241,7 +266,7 @@ } } } catch (ServletException e) { - PedagogicalPlannerAction.log.error(e); + PedagogicalPlannerAction.log.error(e, e); errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage( PedagogicalPlannerAction.ERROR_KEY_LEARNING_DESIGN_COULD_NOT_BE_RETRIEVED)); saveErrors(request, errors); @@ -549,8 +574,23 @@ // Fill the DTO List titlePath = getPedagogicalPlannerDAO().getTitlePath(node); - PedagogicalPlannerSequenceNodeDTO dto = new PedagogicalPlannerSequenceNodeDTO(node, titlePath); + String filterText = WebUtil.readStrParam(request, CentralConstants.PARAM_FILTER_TEXT, true); + Set filteredNodeUids = null; + try { + filteredNodeUids = filterSubnodes(node, filterText); + } catch (Exception e) { + PedagogicalPlannerAction.log.error(e, e); + ActionMessages errors = new ActionMessages(); + errors.add(ActionMessages.GLOBAL_MESSAGE, + new ActionMessage(PedagogicalPlannerAction.ERROR_KEY_FILTER_PARSE)); + saveErrors(request, errors); + } + if (filteredNodeUids != null) { + request.setAttribute(CentralConstants.PARAM_FILTER_TEXT, filterText); + } + PedagogicalPlannerSequenceNodeDTO dto = new PedagogicalPlannerSequenceNodeDTO(node, titlePath, filteredNodeUids); + // Additional DTO parameters Boolean createSubnode = WebUtil.readBooleanParam(request, CentralConstants.PARAM_CREATE_SUBNODE, false); Boolean importNode = WebUtil.readBooleanParam(request, CentralConstants.PARAM_IMPORT_NODE, false); @@ -573,7 +613,7 @@ String contentFolderId = FileUtil.generateUniqueContentFolderID(); nodeForm.setContentFolderId(contentFolderId); } catch (Exception e) { - PedagogicalPlannerAction.log.error(e); + PedagogicalPlannerAction.log.error(e, e); dto.setEdit(false); dto.setCreateSubnode(false); ActionMessages errors = new ActionMessages(); @@ -693,7 +733,7 @@ } catch (RepositoryCheckedException e) { errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage( PedagogicalPlannerAction.ERROR_KEY_REPOSITORY)); - PedagogicalPlannerAction.log.error(e); + PedagogicalPlannerAction.log.error(e, e); } } @@ -862,7 +902,7 @@ // response.setContentType("application/zip"); response.setHeader(PedagogicalPlannerAction.HEADER_CONTENT_DISPOSITION, "attachment;filename=" + filename); } catch (Exception e) { - PedagogicalPlannerAction.log.error(e); + PedagogicalPlannerAction.log.error(e, e); errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(PedagogicalPlannerAction.ERROR_KEY_EXPORT)); saveErrors(request, errors); return openSequenceNode(mapping, form, request, nodeUid); @@ -1014,7 +1054,7 @@ node.setOrder(order); getPedagogicalPlannerDAO().saveOrUpdateNode(node); } catch (Exception e) { - PedagogicalPlannerAction.log.error(e); + PedagogicalPlannerAction.log.error(e, e); errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(PedagogicalPlannerAction.ERROR_KEY_IMPORT)); } } @@ -1041,7 +1081,7 @@ InputStream inputStream = getContentHandler().getFileNode(fileUuid).getFile(); copyFileFromRepository(inputStream, designFile); } catch (Exception e) { - PedagogicalPlannerAction.log.error(e); + PedagogicalPlannerAction.log.error(e, e); errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(PedagogicalPlannerAction.ERROR_KEY_FILE_OPEN)); return null; } @@ -1071,7 +1111,7 @@ toolsErrorMsgs = (List) ldResults[2]; learningDesign = getAuthoringService().getLearningDesign(learningDesignID); } catch (ImportToolContentException e) { - PedagogicalPlannerAction.log.error(e); + PedagogicalPlannerAction.log.error(e, e); errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage( PedagogicalPlannerAction.ERROR_KEY_LEARNING_DESIGN_COULD_NOT_BE_RETRIEVED)); @@ -1186,6 +1226,72 @@ inputStream.close(); } + private Set filterSubnodes(PedagogicalPlannerSequenceNode node, String filterText) throws ParseException, + CorruptIndexException, IOException { + if (!StringUtils.isEmpty(filterText)) { + + Set docs = new HashSet(); + extractSubnodeDocuments(docs, node, null); + if (docs.isEmpty()) { + return null; + } + + MultiFieldQueryParser queryParser = new MultiFieldQueryParser(new String[] { + PedagogicalPlannerAction.FIELD_NAME_TITLE, PedagogicalPlannerAction.FIELD_NAME_FULL_DESCRIPTION, + PedagogicalPlannerAction.FIELD_NAME_BRIEF_DESCRIPTION }, PedagogicalPlannerAction.ANALYZER); + + Query query = queryParser.parse(filterText); + + RAMDirectory dir = new RAMDirectory(); + IndexWriter indexWriter = new IndexWriter(dir, PedagogicalPlannerAction.ANALYZER, true, + IndexWriter.MaxFieldLength.UNLIMITED); + for (Document doc : docs) { + indexWriter.addDocument(doc); + } + indexWriter.optimize(); + indexWriter.close(); + + IndexSearcher searcher = new IndexSearcher(dir); + int maxHits = node.getSubnodes().size(); + TopDocs topDocs = searcher.search(query, null, maxHits); + + Set matchingSubnodeUids = new TreeSet(); + for (ScoreDoc scoreDoc : topDocs.scoreDocs) { + Document doc = searcher.doc(scoreDoc.doc); + String ancestorUid = doc.get(PedagogicalPlannerAction.FIELD_NAME_ANCESTOR_UID); + Long uid = new Long(ancestorUid); + matchingSubnodeUids.add(uid); + } + return matchingSubnodeUids; + } + return null; + } + + private void extractSubnodeDocuments(Set docs, PedagogicalPlannerSequenceNode node, String ancestorNodeUid) { + if (node != null && node.getSubnodes() != null) { + for (PedagogicalPlannerSequenceNode subnode : node.getSubnodes()) { + Field titleField = new Field(PedagogicalPlannerAction.FIELD_NAME_TITLE, subnode.getTitle(), + Field.Store.NO, Field.Index.ANALYZED); + Field briefDescField = new Field(PedagogicalPlannerAction.FIELD_NAME_BRIEF_DESCRIPTION, subnode + .getBriefDescription(), Field.Store.NO, Field.Index.ANALYZED); + Field fullDescField = new Field(PedagogicalPlannerAction.FIELD_NAME_FULL_DESCRIPTION, subnode + .getFullDescription(), Field.Store.NO, Field.Index.ANALYZED); + String uid = ancestorNodeUid == null ? subnode.getUid().toString() : ancestorNodeUid; + Field ancestorUidField = new Field(PedagogicalPlannerAction.FIELD_NAME_ANCESTOR_UID, uid, + Field.Store.YES, Field.Index.NOT_ANALYZED); + + Document doc = new Document(); + doc.add(titleField); + doc.add(briefDescField); + doc.add(fullDescField); + doc.add(ancestorUidField); + docs.add(doc); + + extractSubnodeDocuments(docs, subnode, uid); + } + } + } + /*----------------------- GROUPING METHODS -------------------------*/ /** Index: lams_central/web/includes/javascript/pedagogicalPlanner.js =================================================================== RCS file: /usr/local/cvsroot/lams_central/web/includes/javascript/pedagogicalPlanner.js,v diff -u -r1.10 -r1.11 --- lams_central/web/includes/javascript/pedagogicalPlanner.js 26 Feb 2009 19:20:09 -0000 1.10 +++ lams_central/web/includes/javascript/pedagogicalPlanner.js 28 Feb 2009 13:46:32 -0000 1.11 @@ -184,4 +184,17 @@ document.getElementById("fullDescriptionArea").style.display="none"; document.getElementById("fileArea").style.display="block"; } - } \ No newline at end of file + } + + function filterNodes(url,doFilter){ + if (doFilter){ + url += "&filterText="+document.getElementById("filterText").value; + } + document.location.href=url; + } + + function filterNodesOnEnter(url){ + if (window.event && window.event.keyCode == 13){ + filterNodes(url,true); + } + } \ No newline at end of file Index: lams_central/web/pedagogical_planner/sequenceChooser.jsp =================================================================== RCS file: /usr/local/cvsroot/lams_central/web/pedagogical_planner/Attic/sequenceChooser.jsp,v diff -u -r1.5 -r1.6 --- lams_central/web/pedagogical_planner/sequenceChooser.jsp 26 Feb 2009 19:20:09 -0000 1.5 +++ lams_central/web/pedagogical_planner/sequenceChooser.jsp 28 Feb 2009 13:46:32 -0000 1.6 @@ -20,6 +20,7 @@
+ ${lamsFound} <%-- We might need to alter that for RTL layout --%>

@@ -35,7 +36,7 @@ <%-- List of the existing nodes --%> - + + +
+ <%-- This part creates path like "> Root > Some node > Some subnode" with links to upper level nodes --%> @@ -57,7 +58,29 @@ <%-- Add title (but no link) of the current node at the end --%> - + + + + + + + + + + + + " + onclick="javascript:filterNodes('${filterNodeUrl}',false)" /> + +
+ + + + + + + + <%-- List of subnodes --%> <%-- If the list of subnodes is empty, we display only a message --%> @@ -103,7 +134,7 @@ - " onclick="javascript:leaveNodeEditor('','${removeNodeUrl}')" /> Index: lams_common/src/java/org/lamsfoundation/lams/planner/dto/PedagogicalPlannerSequenceNodeDTO.java =================================================================== RCS file: /usr/local/cvsroot/lams_common/src/java/org/lamsfoundation/lams/planner/dto/PedagogicalPlannerSequenceNodeDTO.java,v diff -u -r1.3 -r1.4 --- lams_common/src/java/org/lamsfoundation/lams/planner/dto/PedagogicalPlannerSequenceNodeDTO.java 25 Feb 2009 18:24:11 -0000 1.3 +++ lams_common/src/java/org/lamsfoundation/lams/planner/dto/PedagogicalPlannerSequenceNodeDTO.java 28 Feb 2009 13:45:12 -0000 1.4 @@ -25,6 +25,7 @@ import java.util.LinkedList; import java.util.List; +import java.util.Set; import org.lamsfoundation.lams.planner.PedagogicalPlannerSequenceNode; @@ -47,7 +48,8 @@ public PedagogicalPlannerSequenceNodeDTO() { } - public PedagogicalPlannerSequenceNodeDTO(PedagogicalPlannerSequenceNode node, List titlePath) { + public PedagogicalPlannerSequenceNodeDTO(PedagogicalPlannerSequenceNode node, List titlePath, + Set filteredUids) { uid = node.getUid(); title = node.getTitle(); briefDescription = node.getBriefDescription(); @@ -60,13 +62,15 @@ } subnodes = new LinkedList(); for (PedagogicalPlannerSequenceNode subnode : node.getSubnodes()) { - PedagogicalPlannerSequenceNodeDTO subnodeDTO = new PedagogicalPlannerSequenceNodeDTO(); - subnodeDTO.setTitle(subnode.getTitle()); - subnodeDTO.setBriefDescription(subnode.getBriefDescription()); - subnodeDTO.setLocked(subnode.getLocked()); - subnodeDTO.setFileName(subnode.getFileName()); - subnodeDTO.setUid(subnode.getUid()); - subnodes.add(subnodeDTO); + if (filteredUids == null || filteredUids.contains(subnode.getUid())) { + PedagogicalPlannerSequenceNodeDTO subnodeDTO = new PedagogicalPlannerSequenceNodeDTO(); + subnodeDTO.setTitle(subnode.getTitle()); + subnodeDTO.setBriefDescription(subnode.getBriefDescription()); + subnodeDTO.setLocked(subnode.getLocked()); + subnodeDTO.setFileName(subnode.getFileName()); + subnodeDTO.setUid(subnode.getUid()); + subnodes.add(subnodeDTO); + } } }
<%-- Title and full description of the node --%> @@ -69,10 +92,18 @@
${node.fullDescription}
-
+

+ +

+