From e7ce03d4cf010c3220466bfdc11c82d749832d82 Mon Sep 17 00:00:00 2001 From: Kevin Roast Date: Tue, 17 Jan 2006 11:57:32 +0000 Subject: [PATCH] =?UTF-8?q?.=20Saved=20Searches=20UI=20improvements=20as?= =?UTF-8?q?=20suggested=20by=20Linton=20.=20Fix=20to=20quoted=20term=20sea?= =?UTF-8?q?rch=20to=20allow=20quoted=20string=20of=20a=20single=20word=20o?= =?UTF-8?q?nly=20e.g.=20"baboon"=20(not=20very=20useful,=20but=20should=20?= =?UTF-8?q?at=20least=20work=E2=80=A6!)=20.=20Checkpoint=20of=20the=20Temp?= =?UTF-8?q?lating=20language=20enhancements=20ready=20for=20the=20addition?= =?UTF-8?q?=20of=20saved=20search=20support?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2124 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- config/alfresco/messages/webclient.properties | 8 +- .../app/servlet/TemplateContentServlet.java | 48 +-- .../alfresco/web/bean/AdvancedSearchBean.java | 371 ++++++++++++++---- .../org/alfresco/web/bean/SearchContext.java | 2 +- .../template/DefaultModelHelper.java | 107 +++++ .../repo/component/template/UITemplate.java | 32 +- .../web/WEB-INF/faces-config-navigation.xml | 6 +- source/web/images/icons/edit_search.gif | Bin 0 -> 925 bytes source/web/images/icons/edit_search_large.gif | Bin 0 -> 1402 bytes source/web/jsp/browse/browse.jsp | 7 +- source/web/jsp/dialog/advanced-search.jsp | 17 +- source/web/jsp/dialog/document-details.jsp | 2 +- source/web/jsp/dialog/edit-search.jsp | 203 ++++++++++ source/web/jsp/dialog/save-search.jsp | 31 +- 14 files changed, 644 insertions(+), 190 deletions(-) create mode 100644 source/java/org/alfresco/web/ui/repo/component/template/DefaultModelHelper.java create mode 100644 source/web/images/icons/edit_search.gif create mode 100644 source/web/images/icons/edit_search_large.gif create mode 100644 source/web/jsp/dialog/edit-search.jsp diff --git a/config/alfresco/messages/webclient.properties b/config/alfresco/messages/webclient.properties index bd766cc4f7..b7cc5a68a8 100644 --- a/config/alfresco/messages/webclient.properties +++ b/config/alfresco/messages/webclient.properties @@ -281,13 +281,17 @@ show_results_categories=Show me results in the categories include_sub_categories=Include sub-categories also_search_results=More search options additional_options=Additional options -save_search=Save Search -saved_searches=Saved Searches +save_new_search=Save New Search +save_edit_search=Save Modified Search +saved_searches=Saved Search Options title_save_search=Save Search Query save_search_description=Save a search query for use again later search_props=Saved Search Properties select_saved_search=Select a Saved Search... saved_search_warning=This operation will attempt to overwrite the existing saved search ''{0}'' +user_searches=Your Searches +global_searches=Public Searches +save_search_global=Save as a public search available to all users. # Forum messages forums=Forum Space diff --git a/source/java/org/alfresco/web/app/servlet/TemplateContentServlet.java b/source/java/org/alfresco/web/app/servlet/TemplateContentServlet.java index 84a215bbf0..79ad7d7e09 100644 --- a/source/java/org/alfresco/web/app/servlet/TemplateContentServlet.java +++ b/source/java/org/alfresco/web/app/servlet/TemplateContentServlet.java @@ -19,13 +19,10 @@ package org.alfresco.web.app.servlet; import java.io.IOException; import java.net.SocketException; import java.text.MessageFormat; -import java.util.Date; -import java.util.HashMap; import java.util.Map; import java.util.StringTokenizer; import javax.servlet.ServletException; -import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -34,22 +31,16 @@ import javax.transaction.UserTransaction; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; -import org.alfresco.repo.template.DateCompareMethod; -import org.alfresco.repo.template.HasAspectMethod; -import org.alfresco.repo.template.I18NMessageMethod; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.TemplateException; -import org.alfresco.service.cmr.repository.TemplateImageResolver; import org.alfresco.service.cmr.repository.TemplateNode; import org.alfresco.service.cmr.repository.TemplateService; import org.alfresco.web.app.Application; import org.alfresco.web.bean.LoginBean; -import org.alfresco.web.bean.repository.Repository; -import org.alfresco.web.bean.repository.User; -import org.alfresco.web.ui.common.Utils; +import org.alfresco.web.ui.repo.component.template.DefaultModelHelper; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.web.context.WebApplicationContext; @@ -232,48 +223,17 @@ public class TemplateContentServlet extends HttpServlet */ private Object getModel(ServiceRegistry services, HttpSession session, NodeRef nodeRef) { - // create FreeMarker default model and merge - Map root = new HashMap(11, 1.0f); - - // supply the CompanyHome space as "companyhome" - NodeRef companyRootRef = new NodeRef(Repository.getStoreRef(), Application.getCompanyRootId()); - TemplateNode companyRootNode = new TemplateNode(companyRootRef, services, imageResolver); - root.put("companyhome", companyRootNode); - - // supply the users Home Space as "userhome" - User user = Application.getCurrentUser(session); - NodeRef userRootRef = new NodeRef(Repository.getStoreRef(), user.getHomeSpaceId()); - TemplateNode userRootNode = new TemplateNode(userRootRef, services, imageResolver); - root.put("userhome", userRootNode); + // build FreeMarker default model and merge + Map root = DefaultModelHelper.buildDefaultModel(services, Application.getCurrentUser(session)); // put the current NodeRef in as "space" and "document" - TemplateNode node = new TemplateNode(nodeRef, services, imageResolver); + TemplateNode node = new TemplateNode(nodeRef, services, DefaultModelHelper.imageResolver); root.put("space", node); root.put("document", node); - // supply the current user Node as "person" - root.put("person", new TemplateNode(user.getPerson(), services, imageResolver)); - - // current date/time is useful to have and isn't supplied by FreeMarker by default - root.put("date", new Date()); - - // add custom method objects - root.put("hasAspect", new HasAspectMethod()); - root.put("message", new I18NMessageMethod()); - root.put("dateCompare", new DateCompareMethod()); - return root; } - /** Template Image resolver helper */ - private TemplateImageResolver imageResolver = new TemplateImageResolver() - { - public String resolveImagePathForName(String filename, boolean small) - { - return Utils.getFileTypeImage(filename, small); - } - }; - /** * Helper to generate a URL to process a template against a node. *

diff --git a/source/java/org/alfresco/web/bean/AdvancedSearchBean.java b/source/java/org/alfresco/web/bean/AdvancedSearchBean.java index 65d523f983..0e5c46cc22 100644 --- a/source/java/org/alfresco/web/bean/AdvancedSearchBean.java +++ b/source/java/org/alfresco/web/bean/AdvancedSearchBean.java @@ -55,17 +55,20 @@ import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; +import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.util.CachingDateFormat; import org.alfresco.web.app.Application; import org.alfresco.web.bean.SearchContext.RangeProperties; import org.alfresco.web.bean.repository.MapNode; import org.alfresco.web.bean.repository.Node; import org.alfresco.web.bean.repository.Repository; +import org.alfresco.web.bean.repository.User; import org.alfresco.web.config.ClientConfigElement; import org.alfresco.web.config.ClientConfigElement.CustomProperty; import org.alfresco.web.data.IDataContainer; import org.alfresco.web.data.QuickSort; import org.alfresco.web.ui.common.Utils; +import org.alfresco.web.ui.common.component.UIModeList; import org.alfresco.web.ui.common.component.UIPanel.ExpandedEvent; import org.alfresco.web.ui.repo.component.UICategorySelector; import org.alfresco.web.ui.repo.component.UISearchCustomProperties; @@ -81,6 +84,8 @@ import org.alfresco.web.ui.repo.component.UISearchCustomProperties; */ public class AdvancedSearchBean { + private static final String OUTCOME_BROWSE = "browse"; + /** * Default constructor */ @@ -207,6 +212,22 @@ public class AdvancedSearchBean { this.editSearchName = editSearchName; } + + /** + * @return Returns the searchSaveGlobal. + */ + public boolean isSearchSaveGlobal() + { + return this.searchSaveGlobal; + } + + /** + * @param searchSaveGlobal The searchSaveGlobal to set. + */ + public void setSearchSaveGlobal(boolean searchSaveGlobal) + { + this.searchSaveGlobal = searchSaveGlobal; + } /** * @return Returns the folder to search, null for all. @@ -256,6 +277,38 @@ public class AdvancedSearchBean this.mode = mode; } + /** + * @return Returns the savedSearchMode. + */ + public String getSavedSearchMode() + { + return this.savedSearchMode; + } + + /** + * @param savedSearchMode The savedSearchMode to set. + */ + public void setSavedSearchMode(String savedSearchMode) + { + this.savedSearchMode = savedSearchMode; + } + + /** + * @return Returns the allow Edit mode. + */ + public boolean isAllowEdit() + { + return (this.savedSearch != null && NO_SELECTION.equals(this.savedSearch) == false); + } + + /** + * @param allowEdit The allow Edit mode to set. + */ + public void setAllowEdit(boolean allowEdit) + { + // dummy method for Bean interface compliance + } + /** * @return Returns the text to search for. */ @@ -754,56 +807,74 @@ public class AdvancedSearchBean // this causes the browse screen to switch into search results view this.navigator.setSearchContext(search); - return "browse"; + return OUTCOME_BROWSE; } /** - * Action handler called to initiate the saved search screen + * Action handler called to initiate the saved search screen for Create */ - public String saveSearch() + public String saveNewSearch() + { + this.searchDescription = null; + this.searchName = null; + this.searchSaveGlobal = false; + + return "saveNewSearch"; + } + + /** + * Action handler called to initiate the saved search screen for Edit + */ + public String saveEditSearch() { this.searchDescription = null; this.searchName = null; this.editSearchName = null; - if (this.savedSearch != null && NO_SELECTION.equals(this.savedSearch) == false) + // load previously selected search for overwrite + try { - // load previous for overwrite - try + NodeRef searchRef = new NodeRef(Repository.getStoreRef(), this.savedSearch); + Node searchNode = new Node(searchRef); + if (this.nodeService.exists(searchRef) && searchNode.hasPermission(PermissionService.WRITE)) { - NodeRef searchRef = new NodeRef(Repository.getStoreRef(), this.savedSearch); - Node searchNode = new Node(searchRef); - if (this.nodeService.exists(searchRef) && searchNode.hasPermission(PermissionService.WRITE)) - { - Node node = new Node(searchRef); - this.searchName = node.getName(); - this.editSearchName = this.searchName; - this.searchDescription = (String)node.getProperties().get(ContentModel.PROP_DESCRIPTION); - } - else - { - // unable to overwrite existing saved search - this.savedSearch = null; - } + Node node = new Node(searchRef); + this.searchName = node.getName(); + this.editSearchName = this.searchName; + this.searchDescription = (String)node.getProperties().get(ContentModel.PROP_DESCRIPTION); } - catch (Throwable err) + else { - // unable to overwrite existing saved search for some other reason + // unable to overwrite existing saved search this.savedSearch = null; } } + catch (Throwable err) + { + // unable to overwrite existing saved search for some other reason + this.savedSearch = null; + } - return "saveSearch"; + return "saveEditSearch"; } /** - * Action handler called to save the current search + * Action handler called to save a new search */ - public String saveSearchOK() + public String saveNewSearchOK() { - String outcome = "browse"; + String outcome = OUTCOME_BROWSE; + + NodeRef searchesRef; + if (isSearchSaveGlobal() == true) + { + searchesRef = getGlobalSearchesRef(); + } + else + { + searchesRef = getUserSearchesRef(); + } - NodeRef searchesRef = getSavedSearchesRef(); SearchContext search = this.navigator.getSearchContext(); if (searchesRef != null && search != null) { @@ -814,45 +885,19 @@ public class AdvancedSearchBean tx = Repository.getUserTransaction(context); tx.begin(); - Map props = null; - - // handle Edit e.g. Overwrite of existing search - // detect if was previously selected saved search (e.g. NodeRef not null) - boolean edit = false; - if (this.savedSearch != null && NO_SELECTION.equals(this.savedSearch) == false) - { - NodeRef searchRef = new NodeRef(Repository.getStoreRef(), this.savedSearch); - edit = (this.nodeService.exists(searchRef)); - } + // create new content node as the saved search object + Map props = new HashMap(2, 1.0f); + props.put(ContentModel.PROP_NAME, this.searchName); + props.put(ContentModel.PROP_DESCRIPTION, this.searchDescription); + ChildAssociationRef childRef = this.nodeService.createNode( + searchesRef, + ContentModel.ASSOC_CONTAINS, + QName.createQName(NamespaceService.ALFRESCO_URI, QName.createValidLocalName(this.searchName)), + ContentModel.TYPE_CONTENT, + props); ContentService contentService = Repository.getServiceRegistry(context).getContentService(); - ContentWriter writer; - if (edit) - { - // edit existing saved search - NodeRef searchRef = new NodeRef(Repository.getStoreRef(), this.savedSearch); - props = this.nodeService.getProperties(searchRef); - props.put(ContentModel.PROP_NAME, this.searchName); - props.put(ContentModel.PROP_DESCRIPTION, this.searchDescription); - this.nodeService.setProperties(searchRef, props); - - writer = contentService.getWriter(searchRef, ContentModel.PROP_CONTENT, true); - } - else - { - // create new content node as the saved search object - props = new HashMap(2, 1.0f); - props.put(ContentModel.PROP_NAME, this.searchName); - props.put(ContentModel.PROP_DESCRIPTION, this.searchDescription); - ChildAssociationRef childRef = this.nodeService.createNode( - searchesRef, - ContentModel.ASSOC_CONTAINS, - QName.createQName(NamespaceService.ALFRESCO_URI, QName.createValidLocalName(this.searchName)), - ContentModel.TYPE_CONTENT, - props); - - writer = contentService.getWriter(childRef.getChildRef(), ContentModel.PROP_CONTENT, true); - } + ContentWriter writer = contentService.getWriter(childRef.getChildRef(), ContentModel.PROP_CONTENT, true); // get a writer to our new node ready for XML content writer.setMimetype(MimetypeMap.MIMETYPE_XML); @@ -878,6 +923,61 @@ public class AdvancedSearchBean return outcome; } + /** + * Action handler called to save an existing search + */ + public String saveEditSearchOK() + { + String outcome = OUTCOME_BROWSE; + + SearchContext search = this.navigator.getSearchContext(); + if (search != null) + { + UserTransaction tx = null; + try + { + FacesContext context = FacesContext.getCurrentInstance(); + tx = Repository.getUserTransaction(context); + tx.begin(); + + // handle Edit e.g. Overwrite of existing search + // detect if was previously selected saved search (e.g. NodeRef not null) + NodeRef searchRef = new NodeRef(Repository.getStoreRef(), this.savedSearch); + if (this.nodeService.exists(searchRef)) + { + Map props = this.nodeService.getProperties(searchRef); + props.put(ContentModel.PROP_NAME, this.searchName); + props.put(ContentModel.PROP_DESCRIPTION, this.searchDescription); + this.nodeService.setProperties(searchRef, props); + + ContentService contentService = Repository.getServiceRegistry(context).getContentService(); + ContentWriter writer = contentService.getWriter(searchRef, ContentModel.PROP_CONTENT, true); + + // get a writer to our new node ready for XML content + writer.setMimetype(MimetypeMap.MIMETYPE_XML); + writer.setEncoding("UTF-8"); + + // output an XML serialized version of the SearchContext object + writer.putContent(search.toXML()); + + tx.commit(); + } + + this.cachedSavedSearches.clear(); + this.savedSearch = null; + } + catch (Throwable e) + { + try { if (tx != null) {tx.rollback();} } catch (Exception ex) {} + Utils.addErrorMessage(MessageFormat.format(Application.getMessage( + FacesContext.getCurrentInstance(), MSG_ERROR_SAVE_SEARCH), e.getMessage()), e); + outcome = null; + } + } + + return outcome; + } + /** * @return list of saved searches as SelectItem objects */ @@ -887,26 +987,35 @@ public class AdvancedSearchBean if (savedSearches == null) { FacesContext fc = FacesContext.getCurrentInstance(); - String xpath = ".//*"; - ServiceRegistry services = Repository.getServiceRegistry(fc); - NodeRef searchesRef = getSavedSearchesRef(); + // get the searches list from the current user or global searches location + NodeRef searchesRef = null; + if (SAVED_SEARCHES_USER.equals(getSavedSearchMode()) == true) + { + searchesRef = getUserSearchesRef(); + } + else if (SAVED_SEARCHES_GLOBAL.equals(getSavedSearchMode()) == true) + { + searchesRef = getGlobalSearchesRef(); + } + + // read the content nodes under the folder if (searchesRef != null) { - List results = searchService.selectNodes( - searchesRef, - xpath, - null, - namespaceService, - false); - savedSearches = new ArrayList(results.size() + 1); - if (results.size() != 0) + DictionaryService dd = services.getDictionaryService(); + + List childRefs = nodeService.getChildAssocs( + searchesRef, + ContentModel.ASSOC_CONTAINS, + RegexQNamePattern.MATCH_ALL); + + savedSearches = new ArrayList(childRefs.size() + 1); + if (childRefs.size() != 0) { - DictionaryService dd = services.getDictionaryService(); - for (NodeRef ref : results) + for (ChildAssociationRef ref : childRefs) { - Node childNode = new Node(ref); + Node childNode = new Node(ref.getChildRef()); if (dd.isSubClass(childNode.getType(), ContentModel.TYPE_CONTENT)) { savedSearches.add(new SelectItem(childNode.getId(), childNode.getName())); @@ -920,7 +1029,7 @@ public class AdvancedSearchBean } else { - // handle missing folder case + // handle missing/access denied folder case savedSearches = new ArrayList(1); } @@ -935,6 +1044,25 @@ public class AdvancedSearchBean return savedSearches; } + /** + * Change the current saved searches list mode based on user selection + */ + public void savedSearchModeChanged(ActionEvent event) + { + UIModeList savedModeList = (UIModeList)event.getComponent(); + + // get the saved searches list mode + String viewMode = savedModeList.getValue().toString(); + + // persist + setSavedSearchMode(viewMode); + + // clear existing caches and values + // the values will be re-queried when the client requests the saved searches list + this.cachedSavedSearches.clear(); + this.savedSearch = null; + } + /** * Action handler called when a saved search is selected by the user */ @@ -1142,9 +1270,66 @@ public class AdvancedSearchBean /** * @return the cached reference to the shared Saved Searches folder */ - private NodeRef getSavedSearchesRef() + private NodeRef getUserSearchesRef() { - if (savedSearchesRef == null) + if (userSearchesRef == null) + { + NodeRef globalRef = getGlobalSearchesRef(); + if (globalRef != null) + { + FacesContext fc = FacesContext.getCurrentInstance(); + User user = Application.getCurrentUser(fc); + String xpath = NamespaceService.APP_MODEL_PREFIX + ":" + QName.createValidLocalName(user.getUserName()); + + List results = null; + try + { + results = searchService.selectNodes( + globalRef, + xpath, + null, + namespaceService, + false); + } + catch (AccessDeniedException err) + { + // ignore and return null + } + + if (results != null) + { + if (results.size() == 1) + { + userSearchesRef = results.get(0); + } + else if (results.size() == 0) + { + // attempt to create folder for this user for first time + // create the preferences Node for this user + Map props = new HashMap(2, 1.0f); + props.put(ContentModel.PROP_NAME, user.getUserName()); + ChildAssociationRef childRef = nodeService.createNode( + globalRef, + ContentModel.ASSOC_CONTAINS, + QName.createQName(NamespaceService.APP_MODEL_1_0_URI, QName.createValidLocalName(user.getUserName())), + ContentModel.TYPE_FOLDER, + props); + + userSearchesRef = childRef.getChildRef(); + } + } + } + } + + return userSearchesRef; + } + + /** + * @return the cached reference to the global Saved Searches folder + */ + private NodeRef getGlobalSearchesRef() + { + if (globalSearchesRef == null) { FacesContext fc = FacesContext.getCurrentInstance(); String xpath = Application.getRootPath(fc) + "/" + @@ -1169,11 +1354,11 @@ public class AdvancedSearchBean if (results != null && results.size() == 1) { - savedSearchesRef = results.get(0); + globalSearchesRef = results.get(0); } } - return savedSearchesRef; + return globalSearchesRef; } /** @@ -1292,7 +1477,10 @@ public class AdvancedSearchBean private static final String LOOKIN_ALL = "all"; private static final String LOOKIN_OTHER = "other"; - private static final String NO_SELECTION = "none"; + private static final String SAVED_SEARCHES_USER = "user"; + private static final String SAVED_SEARCHES_GLOBAL = "global"; + + private static final String NO_SELECTION = "NONE"; /** The NodeService to be used by the bean */ private NodeService nodeService; @@ -1379,11 +1567,24 @@ public class AdvancedSearchBean private boolean modifiedDateChecked = false; private boolean createdDateChecked = false; - private NodeRef savedSearchesRef = null; + /** cached ref to the global saved searches folder */ + private NodeRef globalSearchesRef = null; + /** cached ref to the current users saved searches folder */ + private NodeRef userSearchesRef = null; + + /** ID to the last selected saved search */ private String savedSearch = null; + /** ModeList component value for selecting user/global searches */ + private String savedSearchMode = SAVED_SEARCHES_USER; + + /** name of the saved search to edit */ private String editSearchName = null; + /** form field for saving search as user/global */ + private boolean searchSaveGlobal = false; + + /** auto-expiring cache of the list of saved searches */ private ExpiringValueCache> cachedSavedSearches = new ExpiringValueCache>(); } diff --git a/source/java/org/alfresco/web/bean/SearchContext.java b/source/java/org/alfresco/web/bean/SearchContext.java index b026a5574b..f1e183c6ca 100644 --- a/source/java/org/alfresco/web/bean/SearchContext.java +++ b/source/java/org/alfresco/web/bean/SearchContext.java @@ -138,7 +138,7 @@ public final class SearchContext implements Serializable if (text.length() != 0 && text.length() >= minimum) { - if (text.indexOf(' ') == -1) + if (text.indexOf(' ') == -1 && text.charAt(0) != '"') { // simple single word text search if (text.charAt(0) != '*') diff --git a/source/java/org/alfresco/web/ui/repo/component/template/DefaultModelHelper.java b/source/java/org/alfresco/web/ui/repo/component/template/DefaultModelHelper.java new file mode 100644 index 0000000000..3c9a7c40da --- /dev/null +++ b/source/java/org/alfresco/web/ui/repo/component/template/DefaultModelHelper.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.web.ui.repo.component.template; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import org.alfresco.repo.template.DateCompareMethod; +import org.alfresco.repo.template.HasAspectMethod; +import org.alfresco.repo.template.I18NMessageMethod; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.TemplateImageResolver; +import org.alfresco.service.cmr.repository.TemplateNode; +import org.alfresco.web.app.Application; +import org.alfresco.web.bean.repository.Repository; +import org.alfresco.web.bean.repository.User; +import org.alfresco.web.ui.common.Utils; + +/** + * Helper class to generate the default template model. + *

+ * See {@link http://www.alfresco.org/mediawiki/index.php/Template_Guide} + * + * @author Kevin Roast + */ +public class DefaultModelHelper +{ + /** + * Private Constructor + */ + private DefaultModelHelper() + { + } + + /** + * Construct the default FreeMarker template model. + *

+ * Other root level objects such as the current Space or Document are generally + * added by the appropriate bean responsible for provided access to those nodes. + *

+ * See {@link http://www.alfresco.org/mediawiki/index.php/Template_Guide} + * + * @return Map containing the default model. + */ + public static Map buildDefaultModel(ServiceRegistry services, User user) + { + if (services == null) + { + throw new IllegalArgumentException("ServiceRegistry is mandatory."); + } + if (user == null) + { + throw new IllegalArgumentException("Current User is mandatory."); + } + + // create FreeMarker default model and merge + Map root = new HashMap(16, 1.0f); + + // supply the CompanyHome space as "companyhome" + NodeRef companyRootRef = new NodeRef(Repository.getStoreRef(), Application.getCompanyRootId()); + TemplateNode companyRootNode = new TemplateNode(companyRootRef, services, imageResolver); + root.put("companyhome", companyRootNode); + + // supply the users Home Space as "userhome" + NodeRef userRootRef = new NodeRef(Repository.getStoreRef(), user.getHomeSpaceId()); + TemplateNode userRootNode = new TemplateNode(userRootRef, services, imageResolver); + root.put("userhome", userRootNode); + + // supply the current user Node as "person" + root.put("person", new TemplateNode(user.getPerson(), services, imageResolver)); + + // current date/time is useful to have and isn't supplied by FreeMarker by default + root.put("date", new Date()); + + // add custom method objects + root.put("hasAspect", new HasAspectMethod()); + root.put("message", new I18NMessageMethod()); + root.put("dateCompare", new DateCompareMethod()); + + return root; + } + + /** Template Image resolver helper */ + public static TemplateImageResolver imageResolver = new TemplateImageResolver() + { + public String resolveImagePathForName(String filename, boolean small) + { + return Utils.getFileTypeImage(filename, small); + } + }; +} diff --git a/source/java/org/alfresco/web/ui/repo/component/template/UITemplate.java b/source/java/org/alfresco/web/ui/repo/component/template/UITemplate.java index 444a44b835..fc429f431d 100644 --- a/source/java/org/alfresco/web/ui/repo/component/template/UITemplate.java +++ b/source/java/org/alfresco/web/ui/repo/component/template/UITemplate.java @@ -191,33 +191,11 @@ public class UITemplate extends SelfRenderingComponent if (getEngine().equals(ENGINE_DEFAULT)) { - // create FreeMarker default model and merge - Map root = new HashMap(11, 1.0f); - - FacesContext context = FacesContext.getCurrentInstance(); - ServiceRegistry services = Repository.getServiceRegistry(context); - - // supply the CompanyHome space as "companyhome" - NodeRef companyRootRef = new NodeRef(Repository.getStoreRef(), Application.getCompanyRootId()); - TemplateNode companyRootNode = new TemplateNode(companyRootRef, services, imageResolver); - root.put("companyhome", companyRootNode); - - // supply the users Home Space as "userhome" - User user = Application.getCurrentUser(context); - NodeRef userRootRef = new NodeRef(Repository.getStoreRef(), user.getHomeSpaceId()); - TemplateNode userRootNode = new TemplateNode(userRootRef, services, imageResolver); - root.put("userhome", userRootNode); - - // supply the current user Node as "person" - root.put("person", new TemplateNode(user.getPerson(), services, imageResolver)); - - // current date/time is useful to have and isn't supplied by FreeMarker by default - root.put("date", new Date()); - - // add custom method objects - root.put("hasAspect", new HasAspectMethod()); - root.put("message", new I18NMessageMethod()); - root.put("dateCompare", new DateCompareMethod()); + // create an instance of the default FreeMarker template object model + FacesContext fc = FacesContext.getCurrentInstance(); + ServiceRegistry services = Repository.getServiceRegistry(fc); + User user = Application.getCurrentUser(fc); + Map root = DefaultModelHelper.buildDefaultModel(services, user); // merge models if (model instanceof Map) diff --git a/source/web/WEB-INF/faces-config-navigation.xml b/source/web/WEB-INF/faces-config-navigation.xml index 8e00322898..82e80f23fb 100644 --- a/source/web/WEB-INF/faces-config-navigation.xml +++ b/source/web/WEB-INF/faces-config-navigation.xml @@ -175,9 +175,13 @@ /jsp/forums/topic.jsp - saveSearch + saveNewSearch /jsp/dialog/save-search.jsp + + saveEditSearch + /jsp/dialog/edit-search.jsp + diff --git a/source/web/images/icons/edit_search.gif b/source/web/images/icons/edit_search.gif new file mode 100644 index 0000000000000000000000000000000000000000..7dfebb7d8e2677fc24dfbfb9a8b50de970cba9d6 GIT binary patch literal 925 zcmZ?wbhEHbnv4f_j*opDpM?88jtzZYm%6pX za{najwQT{Lx&Bt)!@_|qo=!Uuk_ShSmtnKamkToRc{VC zemU*&|7O(xTk-#Ir~JQH^#4J{|A%$0EiL_hb0<%lG-dUU1q&AJ-n3%Vrp-Xme)Q>) z6%D61Pd>9{^2t5R-u6#^JFV->&fQn{9lm;O)0g}6U*F#G|8evGrxX7_pZ5R7oG;Jz z{eQdZ-@6_EKkPqt?AW<;XK&rQb^XE9*M|;0y?OHG0f~Bj=EksM5~Pe%hj4uwVhQFq@>i< zX_H7uBCgql&`eMSAt_446%mPuIO2-9)w}Kf8~c2CzCXX;JQsrkJkCYi0=B>o@GT$+ zPM`Og&&gY;|7W1N-VY7()O;#$_YRFU1ISXfXF4i13w%y!0e6$h#L6bMd6 zf}-2t)E!Wg3`$c$*$Yrn2r5g#1)OH499(HQT4jOj?F#mzqhxyySuxyv$MUuy|uNa(P%a|H`QwO#>U3_`uf`1 z+Un}+%F2pLrCMHIURqjOTwGlEx?icBpPyGK6mxTPa=CnVc2*{nNu|=6nHh;hGCe&l z7K^8*rbHsq$9X5eNjs!^1;EL!Uo?9{h@OV4%OhpU>y> zc)Z@;UM`p0)6>({)y3g(Iy*Z%Iy&0h+uPdOT3TAzY&MI^(84bz7C1v5j z=rcGPX6NcClg@Piu8+wSzzB8$Le_0$yZd=FGxf4x{ediiX}e_VS7xX9 z`9#nI%L#S{`KC~FbA(#)N$oXgd;|_xP|{M=o_Eqy0T^;e5wo7E{>x~n^k8l+p*lLo zKg;Cj)Dvj)Sh4GEzn6(5>B}f7kf~=LNYpl8&qty&G!|!bPTYLD5N&WO&R0wS9LklL zb$4PT2z}gGfIopqi|&HjL>Xxr=$HfsSlkmbV*Jpd5bkqVR6*ylGb&$O%)PhB-q#RV z%xv*5tsNQ1ZTk_r7%xH+x5&k$xX(PM*fGG~hlS9FdKEBYi~b~LaIHg6k|7p1;v<4} z40nh8Exg{z>@4q-VR{bHhD-=C&q=G-MDMI)91i6Tzvz$)?am=zvd=)BF5*X2TRx;4 z>rwUHXB9P7yGTcpVd3wQ53CY%-Z(nFCc|oISzIS)t4GXXu2rQN%Jc8DKX9gVpvwUa z{l{)Rrtqp?kX=c54A1WEor+xh_lbgB#}s&RmSu{Rw8~aBx5V2#_#3{~s&O(k0?z*n DoHT*x literal 0 HcmV?d00001 diff --git a/source/web/jsp/browse/browse.jsp b/source/web/jsp/browse/browse.jsp index 3d051d3c3e..b05d2ed1fc 100644 --- a/source/web/jsp/browse/browse.jsp +++ b/source/web/jsp/browse/browse.jsp @@ -159,11 +159,14 @@ <%--

--%> - + <%-- Current object actions --%>
- + + + + diff --git a/source/web/jsp/dialog/advanced-search.jsp b/source/web/jsp/dialog/advanced-search.jsp index d3704146d7..bc9300437f 100644 --- a/source/web/jsp/dialog/advanced-search.jsp +++ b/source/web/jsp/dialog/advanced-search.jsp @@ -92,14 +92,21 @@ - + <%-- Available Saved Searches --%> - -
+
+
+ + + + +
+
<%-- Saved Searches drop-down selector --%> - <%-- uses a nasty hack to execute an ActionListener for the drop-down + <%-- uses a nasty hack to execute an ActionListener for the drop-down. tried using a valueChangedListener+formsubmit but the valueChangedListener - is called too late in the lifecycle for the form controls to be managed --%> + is called too late in the lifecycle for the form controls to be modified --%> diff --git a/source/web/jsp/dialog/document-details.jsp b/source/web/jsp/dialog/document-details.jsp index 10dd7d70ad..85d83b0714 100644 --- a/source/web/jsp/dialog/document-details.jsp +++ b/source/web/jsp/dialog/document-details.jsp @@ -148,7 +148,7 @@ actionListener="#{ClipboardBean.copyNode}"> - + <%-- delete --%> diff --git a/source/web/jsp/dialog/edit-search.jsp b/source/web/jsp/dialog/edit-search.jsp new file mode 100644 index 0000000000..d75ff85684 --- /dev/null +++ b/source/web/jsp/dialog/edit-search.jsp @@ -0,0 +1,203 @@ +<%-- + Copyright (C) 2005 Alfresco, Inc. + + Licensed under the Mozilla Public License version 1.1 + with a permitted attribution clause. You may obtain a + copy of the License at + + http://www.alfresco.org/legal/license.txt + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + either express or implied. See the License for the specific + language governing permissions and limitations under the + License. +--%> +<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> +<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> +<%@ taglib uri="/WEB-INF/alfresco.tld" prefix="a" %> +<%@ taglib uri="/WEB-INF/repo.tld" prefix="r" %> + +<%@ page buffer="32kb" contentType="text/html;charset=UTF-8" %> +<%@ page isELIgnored="false" %> +<%@ page import="org.alfresco.web.ui.common.PanelGenerator" %> + + + + + + + + <%-- load a bundle of properties with I18N strings --%> + + + + + <%-- Main outer table --%> + + + <%-- Title bar --%> + + + + + <%-- Main area --%> + + <%-- Shelf --%> + + + <%-- Work Area --%> + + +
+ <%@ include file="../parts/titlebar.jsp" %> +
+ <%@ include file="../parts/shelf.jsp" %> + + + <%-- Breadcrumb --%> + <%@ include file="../parts/breadcrumb.jsp" %> + + <%-- Status and Actions --%> + + + + + + + <%-- separator row with gradient shadow --%> + + + + + + + <%-- Details --%> + + + + + + + <%-- separator row with bottom panel graphics --%> + + + + + + +
+ + <%-- Status and Actions inner contents table --%> + <%-- Generally this consists of an icon, textual summary and actions for the current object --%> + + + + + +
+ +
+
+
+ +
+ + + + + + +
+ + + + <% PanelGenerator.generatePanelStart(out, request.getContextPath(), "white", "white"); %> + + + + + + + + + + + + + + + + + + +
+ <% PanelGenerator.generatePanelStart(out, request.getContextPath(), "yellowInner", "#ffffcc"); %> + + + + + +
+ + + +
+ <% PanelGenerator.generatePanelEnd(out, request.getContextPath(), "yellowInner"); %> +
: +  * +
: + +
+ <% PanelGenerator.generatePanelEnd(out, request.getContextPath(), "white"); %> +
+ <% PanelGenerator.generatePanelStart(out, request.getContextPath(), "blue", "#D3E6FE"); %> + + + + + + + +
+ +
+ +
+ <% PanelGenerator.generatePanelEnd(out, request.getContextPath(), "blue"); %> +
+
+
+ +
+ +
+ +
\ No newline at end of file diff --git a/source/web/jsp/dialog/save-search.jsp b/source/web/jsp/dialog/save-search.jsp index 460534c508..e5dc57b374 100644 --- a/source/web/jsp/dialog/save-search.jsp +++ b/source/web/jsp/dialog/save-search.jsp @@ -90,10 +90,10 @@ @@ -122,25 +122,6 @@ <% PanelGenerator.generatePanelStart(out, request.getContextPath(), "white", "white"); %>
- -
+
- - - - - - @@ -157,6 +138,12 @@ + + + +
- <% PanelGenerator.generatePanelStart(out, request.getContextPath(), "yellowInner", "#ffffcc"); %> - - - - - -
- - - -
- <% PanelGenerator.generatePanelEnd(out, request.getContextPath(), "yellowInner"); %> -
+ +
<% PanelGenerator.generatePanelEnd(out, request.getContextPath(), "white"); %> @@ -166,7 +153,7 @@
-