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 0000000000..7dfebb7d8e
Binary files /dev/null and b/source/web/images/icons/edit_search.gif differ
diff --git a/source/web/images/icons/edit_search_large.gif b/source/web/images/icons/edit_search_large.gif
new file mode 100644
index 0000000000..7d4df20a69
Binary files /dev/null and b/source/web/images/icons/edit_search_large.gif differ
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 --%>
+
+
+ <%@ include file="../parts/titlebar.jsp" %>
+ |
+
+
+ <%-- Main area --%>
+
+ <%-- Shelf --%>
+
+ <%@ include file="../parts/shelf.jsp" %>
+ |
+
+ <%-- Work Area --%>
+
+
+ <%-- Breadcrumb --%>
+ <%@ include file="../parts/breadcrumb.jsp" %>
+
+ <%-- Status and Actions --%>
+
+ |
+
+
+ <%-- Status and Actions inner contents table --%>
+ <%-- Generally this consists of an icon, textual summary and actions for the current object --%>
+
+
+ |
+ |
+
+
+ <%-- separator row with gradient shadow --%>
+
+ %>/images/parts/statuspanel_7.gif) |
+ |
+ %>/images/parts/statuspanel_9.gif) |
+
+
+ <%-- Details --%>
+
+ |
+
+
+
+
+
+
+
+ <% 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"); %>
+ |
+
+
+ |
+ |
+
+
+ <%-- separator row with bottom panel graphics --%>
+
+ %>/images/parts/whitepanel_7.gif) |
+ |
+ %>/images/parts/whitepanel_9.gif) |
+
+
+
+ |
+
+
+
+
+
+
+
+
\ 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"); %>
-
-
-
- <% PanelGenerator.generatePanelStart(out, request.getContextPath(), "yellowInner", "#ffffcc"); %>
-
- <% PanelGenerator.generatePanelEnd(out, request.getContextPath(), "yellowInner"); %>
- |
-
-
-
|
@@ -157,6 +138,12 @@
+
+ |
+
+
+ |
+
<% PanelGenerator.generatePanelEnd(out, request.getContextPath(), "white"); %>
@@ -166,7 +153,7 @@
|